Frequenz messen aus Mikro-Input

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 11 Antworten in diesem Thema. Der letzte Beitrag () ist von Haudruferzappeltnoch.

    Frequenz messen aus Mikro-Input

    Jo, ich möchte ins Mikro singen, und gleichzeitig sehen, welche Frequenz ich produziere.
    (Endziel ist ein Programm, was anzeigt, ob man ein Lied richtig singt...).

    *Topic verschoben*

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Marcus Gräfe“ ()

    Hey,

    ich kann da wieder mal die BASS empfehlen, ein Beispiel wie du das Mikrofon anzapfen kannst und an die Daten kommst die du analysieren kannst. Bedenke das der Mikrofonzugriff erlaubt sein muss!
    Spoiler anzeigen

    C#-Quellcode

    1. public partial class Form1 : Form
    2. {
    3. List<Device> devices = new List<Device>();
    4. RECORDPROC? recordProc; //!!! Muss im Scope der Klasse bleiben, damit der GC das nicht freigibt, was er tun würde wenn das lokal in einer Funktion wäre !!!
    5. int recordHandle;
    6. public Form1()
    7. {
    8. InitializeComponent();
    9. }
    10. private void Form1_Load(object sender, EventArgs e)
    11. {
    12. if (!Bass.BASS_Init(-1, 44100, BASSInit.BASS_DEVICE_CPSPEAKERS, 0))
    13. {
    14. MessageBox.Show($"BASS_Init ERROR{Bass.BASS_ErrorGetCode()}");
    15. Close();
    16. }
    17. BASS_DEVICEINFO info = new BASS_DEVICEINFO();
    18. int counter = 1; // bei 1 starten, weil 0 wäre das default device und wir hätten nur den namen "Default" welcher nicht viel sagt, das Device wäre dann doppelt in der Liste
    19. while (Bass.BASS_RecordGetDeviceInfo(counter, info))
    20. {
    21. if ((info.type & BASSDeviceInfo.BASS_DEVICE_TYPE_MICROPHONE) == BASSDeviceInfo.BASS_DEVICE_TYPE_MICROPHONE)
    22. {
    23. devices.Add(new Device(counter, info.name));
    24. }
    25. counter++;
    26. }
    27. comboBoxDevices.DataSource = devices;
    28. comboBoxDevices.DisplayMember = "Name";
    29. comboBoxDevices.DropDownStyle = ComboBoxStyle.DropDownList;
    30. }
    31. private bool RecordProcCallback(int handle, nint buffer, int length, nint user)
    32. {
    33. Debug.WriteLine(length);
    34. //im buffer hast du dann was du brauchst, sowas sollte auch gehen:
    35. //float[] fft = new float[2048];
    36. //Bass.BASS_ChannelGetData(handle, fft, (int)BASSData.BASS_DATA_FFT4096);
    37. //int index = Utils.FFTFrequency2Index(100, 4096, 44100);
    38. //float gain = fft[index]
    39. return length > 0;
    40. }
    41. private void buttonStart_Click(object sender, EventArgs e)
    42. {
    43. if (comboBoxDevices.SelectedItem == null) return;
    44. Device device = (Device)comboBoxDevices.SelectedItem;
    45. Bass.BASS_RecordSetDevice(device.ID);
    46. Bass.BASS_RecordInit(device.ID);
    47. recordProc = new RECORDPROC(RecordProcCallback);
    48. recordHandle = Bass.BASS_RecordStart(44100, 2, BASSFlag.BASS_RECORD_PAUSE | BASSFlag.BASS_SAMPLE_FLOAT, 500/* periode in millisekunden*/, recordProc, 0);
    49. Bass.BASS_ChannelPlay(recordHandle, false);
    50. buttonStart.Enabled = false;
    51. buttonStop.Enabled = true;
    52. }
    53. private void buttonStop_Click(object sender, EventArgs e)
    54. {
    55. Bass.BASS_ChannelStop(recordHandle);
    56. buttonStart.Enabled = true;
    57. buttonStop.Enabled = false;
    58. }
    59. }

    C#-Quellcode

    1. internal class Device
    2. {
    3. public int ID { get; private set; }
    4. public string Name { get; private set; } = "DEVICE";
    5. public Device(int id, string name)
    6. {
    7. this.ID = id;
    8. this.Name = name;
    9. }
    10. }[/spoiler][spoiler]


    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D

    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „DTF“ ()

    @ErfinderDesRades Egal wie Du singst, da kommt keine "reine" Frequenz raus, sondern ein Frequenzgemisch.
    Im Idealfall ist das eine Grundwelle (niedrigste Frequenz, größte Intenität) und diverser Oberwellen mit Vielfachen der Frequenz der Grundwelle,
    wie bei einer Gitarre oder Trompete.
    Was Du suchst, ist die Frequenz der Grundwelle. Die ist für die Dauer des Tons sagen wir konstant.
    Dann wechselst Du den Ton, dazu die Dauer des Tons, das müsste das Programm erkennen.
    Vielleicht wechselst Du die Herangehensweise. Du sagst dem Rechner, was Du singst, und der Rechner vergleicht das mit Deinem Gesang.
    Ich kenne Deinen musikalischen Hintergrund nicht, vielleicht fängst Du an, einen konstanten Ton zu singen,
    und der Rechner sagt Dir, wie konstant dieser Ton wirklich ist, das geht ganz easy mit einer Lissajous-Figur:
    spektrum.de/lexikon/physik/lissajous-figuren/9114
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @ErfinderDesRades Abgesehen von der Bass.dll, kannst Du auch die MediaFoundation oder auch direkt die WASAPI verwenden. Das Prinzip ist immer gleich. Zuerst alle Geräte auflisten, von denen du ein Audio aufnehmen kannst, Gerät auswählen und Aufnahme starten. Am Ende hast Du immer ein Array, das die zu auswertenden Daten enthält. Diese müsstest dann evtl durch eine FFT -> de.m.wikipedia.org/wiki/Schnelle_Fourier-Transformation jagen um das ganze in die verschiedenen Frequenzen zu zerlegen. Keine Ahnung ob Dir das weiter hilft bzw ob das hier dazu rein passt. Es gab mal für die Bass.dll ein VB6 Beispiel, das sich LiveSpec nannte und die ich mal, auf Anfrage auf AVB so um 2017, auf VB.NET übersetzt hatte. Das .NET Beispiel findest Du hier: activevb.de/cgi-bin/upload/download.pl?id=3628 Evtl passt das ja zu Deiner Frage.
    Mfg -Franky-

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „-Franky-“ ()

    Hallo ErfinderDesRades,

    ich habe mal vor einiger Zeit eine Oberflächenanwendung geschrieben, die sich in regelmäßigen Abständen die Bytes der Soundkarte holt, eine Fourier-Transformation ausführt und die Amplituden von diskreten Frequenzen darstellt.
    Es hat zwar funktioniert, aber es war keine 100%-ige Lösung, denn eigentlich sollte man eine Fast-Fourier-Transformation (
    FFT) machen. Und für alle Frequenzen, nicht nur einige.

    Zum Verständnis der Fourier-Transformation kannst du dir dieses Video angucken:

    Es gibt einige Effekte, über die du dich nicht wundern solltest. Wenn du beispielsweise ein Testvideo hörst, das genau 1000 Hz abspielt, und die Amplitude, also das entsprechende Rechteck für 1000 Hz, beobachtest, wirst du feststellen, dass die Balken links und rechts davon leicht mitschwingen. Dieses Auf- und Abschwingen ist völlig normal. Leider kann ich meine Stackoverflow-Frage dazu momentan nicht finden. Das Signal ist von limitierter Länge, und das Sampling (Erfassen) ist nicht unendlich genau.

    Das Abfragen der Soundkarte war etwas tricky. Die Buffersize (Menge der Bytes) muss groß genug sein, damit du 40Hz messen kannst (du brauchst 25 Millisekunden), aber je größer der Buffer, desto seltener wird die Oberfläche aktualisiert. Rechne alles nach!

    Viele Grüße
    Bartosz

    Bilder
    • vlcsnap-2022-02-15-16h53m08s405.jpg

      35,36 kB, 524×703, 11 mal angesehen

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Bartosz“ ()

    @ErfinderDesRades Um mal meinen Weg weiter zu spinnen.
    Nach der FFT nimmst Du die maximale Freauenz und zwei weitere auf jeder Seite und rechnest Dir das Maximum über eine Parabelregression aus.
    Du bekommst eine Frequenz, die Du in die genannte Lissajous-Figur einspeist.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @ErfinderDesRades Das Mikrofon aufnehmen und die Daten verarbeiten ist das kleinste Problem. Das größere Problem wird sein aus einer MP3 den Gesang raus zufiltern so das dieser auf der einen Seite kaum zu hören ist und auf der anderen Seite brauchst auch nur den Gesang, ohne Musik, um das mit deinem Gesang zu vergleichen. Dann brauchst evtl. auch noch den Text, der auch noch zur richtigen Zeit eingeblendet werden soll.
    Mfg -Franky-

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „-Franky-“ ()