Sound aufnehmen im PCM-Wave-Format

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

Es gibt 15 Antworten in diesem Thema. Der letzte Beitrag () ist von Bartosz.

    Sound aufnehmen im PCM-Wave-Format

    Hallo,

    ich möchte, dass mein Programm in einem ganz bestimmten Fall einen Sound abspielt. Dieser Code funktioniert nur mit PCM-Wave-Dateien. Ich habe bereits Online-Converter probiert, aber diese geben auch nicht das richtige PCM-Wave-Format zurück. Es gibt mehrere Wav-Formate.

    Ich möchte nun ein Programm schreiben, welches mir Audio aufnimmt, den ich dann später in anderen Programmen abspielen kann. Ich möchte nicht „irgendein“ Format aufnehmen und dann mit mehreren Online-Tools auf gut Glück umwandeln, sondern dann gleich richtig aufnehmen. Wie kann ich so etwas programmieren? Ich kenne bereits eine Sound-Aufnahme mittels NAudio, auch augenscheinlich im WAV-Format, aber leider nicht das richtige. Bereits ausprobiert.
    Ich habe eine Lösung bei SO gesehen, dass man sich für das Abspielen eines Sounds ein Paket bei NuGet herunterlädt. Das wäre übertrieben. Da bleibe ich bei
    My.Computer.Audio.Play(..,..)


    VB.NET-Quellcode

    1. If System.IO.File.Exists(Application.StartupPath & "\Piano_C1_Wav.wav") Then
    2. Try
    3. My.Computer.Audio.Play(Application.StartupPath & "\Piano_C1_Wav.wav", Microsoft.VisualBasic.AudioPlayMode.Background)
    4. Catch ex As System.InvalidOperationException
    5. MessageBox.Show(ex.Message)
    6. End Try
    7. End If



    C#-Quellcode

    1. private static readonly NAudio.CoreAudioApi.MMDeviceEnumerator MMDE = new NAudio.CoreAudioApi.MMDeviceEnumerator();
    2. private readonly NAudio.CoreAudioApi.MMDeviceCollection DevCol = MMDE.EnumerateAudioEndPoints(NAudio.CoreAudioApi.DataFlow.All, NAudio.CoreAudioApi.DeviceState.Active);
    3. private static NAudio.CoreAudioApi.MMDevice gewaehlte_Quelle;

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

    @Bartosz Sieh Dir doch einfach mal den Wave-Header an, da stehen die Informationen drinne, die Du zum Konvertieren brauchst.
    Dann kannst Du Dir Deinen eigenen Konverter bauen.
    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!
    @RodFromGermany Die Datei ist in der Tat eine WAV-Datei, aber keine PCM. Zu erkennen an data(21)

    VB.NET-Quellcode

    1. Imports Microsoft.VisualBasic.ControlChars
    2. Imports Microsoft.WindowsAPICodePack.Dialogs
    3. Public NotInheritable Class FormMain
    4. Private Sub FormMain_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    5. End Sub
    6. Private Sub Button_load_File_Click(sender As Object, e As EventArgs) Handles Button_load_File.Click
    7. Dim Path As String
    8. Using OFD1 As New CommonOpenFileDialog
    9. OFD1.Title = "Datei auswählen"
    10. OFD1.Filters.Add(New CommonFileDialogFilter("Musik-Dateien", ".mp3;.wav"))
    11. OFD1.IsFolderPicker = False
    12. OFD1.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop)
    13. If OFD1.ShowDialog = CommonFileDialogResult.Ok Then
    14. Path = OFD1.FileName
    15. Else
    16. Return
    17. End If
    18. End Using
    19. Dim data As Byte() = System.IO.File.ReadAllBytes(Path)
    20. check_for_WAV(data)
    21. End Sub
    22. Private Function check_for_WAV(ByVal data As Byte()) As Boolean
    23. 'RIFF
    24. If Not (data(0) = 82 AndAlso data(1) = 73 AndAlso data(2) = 70 AndAlso data(3) = 70) Then
    25. Return False
    26. End If
    27. 'Der Wert muss 8 Bytes kleiner sein als der unter Windows angegebene.
    28. Dim FileSize As ULong = CULng(data(4) * Math.Pow(256, 0) + data(5) * Math.Pow(256, 1) + data(6) * Math.Pow(256, 2) + data(7) * Math.Pow(256, 3))
    29. 'WAVE
    30. If Not (data(8) = 87 AndAlso data(9) = 65 AndAlso data(10) = 86 AndAlso data(11) = 69) Then
    31. Return False
    32. End If
    33. If data(21) = 1 Then
    34. Debug.WriteLine("PCM")
    35. Else
    36. Debug.WriteLine("kein PCM")
    37. End If
    38. Return True
    39. End Function
    40. End Class

    Dokumentation von hier docs.fileformat.com/audio/wav/

    Wie baue ich einen Converter?

    @Bartosz Ich bin mir ziemlich sicher das Du das mit Audacity realisieren kannst (war/ist wohl immer noch kostenlos). Am PC ein Mikrofon anschließen oder eben "SystemSound" als Eingabe wählen AudioSignal aufnehmen und im PCM-Format speichern.
    Lg

    Bilder
    • vb11.jpg

      37,7 kB, 342×397, 73 mal angesehen
    codewars.com Rank: 4 kyu

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „nogood“ ()

    Du kannst die Datei auch mit FFMpeg konvertieren, da kannst du zwischen mehreren PCM formaten wählen. Hab mal mit ffmpeg -formats | findstr PCM > out.txt geschaut, diese PCM formate stehen zur Verfügung

    Quellcode

    1. alaw PCM A-law
    2. f32be PCM 32-bit floating-point big-endian
    3. f32le PCM 32-bit floating-point little-endian
    4. f64be PCM 64-bit floating-point big-endian
    5. f64le PCM 64-bit floating-point little-endian
    6. mulaw PCM mu-law
    7. s16be PCM signed 16-bit big-endian
    8. s16le PCM signed 16-bit little-endian
    9. s24be PCM signed 24-bit big-endian
    10. s24le PCM signed 24-bit little-endian
    11. s32be PCM signed 32-bit big-endian
    12. s32le PCM signed 32-bit little-endian
    13. s8 PCM signed 8-bit
    14. u16be PCM unsigned 16-bit big-endian
    15. u16le PCM unsigned 16-bit little-endian
    16. u24be PCM unsigned 24-bit big-endian
    17. u24le PCM unsigned 24-bit little-endian
    18. u32be PCM unsigned 32-bit big-endian
    19. u32le PCM unsigned 32-bit little-endian
    20. u8 PCM unsigned 8-bit


    Wenn du die BASS DLL nimmst, kannste direkt konvertiert aufnehmen, dazu brauchst du dann auch FFMpeg. (Live konvertierung) Mein weg wäre BASS + ffmpeg. Aber wenn du eine Bibliothek zum aufnehmen nimmst, kannste die selbe auch zum absielen nehmen.

    Edit @Bartosz
    das klappt mit ffmpeg konvertiert und my.computer.audio.play:
    ffmpeg -i "fileIn.mp3" -f wav -ar 44.1k -ac 2 "fileOut.wav"

    Mit der Bass dll kannst auch ohne ffmpeg so aufnehmen.

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

    Ich danke euch allen. Ich habe es jetzt provisorisch mittels Audacity gelöst.
    In Zukunft will ich trotzdem ein Programm schreiben, das Sound von der Soundkarte nimmt und als PCM-Wave-Format abspeichert. Weil warum etwas "anders" abspeichern und dann konvertieren?

    @RodFromGermany Was meinst du mit Bedeutung? Das Programm ist nur für mich. Es dient nur zum Zwecke, dass ich problemfrei einen Sound abspielen kann.
    @Bartosz
    WaveFormatTag 6 = WAVE_FORMAT_ALAW. Du prüfst aber auch nur data(21). Der WaveFormatTag ist aber ein Short. Von daher sollte das passen -> data(21) = 0 und data(22) = 6. Dennoch komisch das der in .NET eingebaute Player sowas nicht abspielen kann.

    Bartosz schrieb:

    Weil warum etwas "anders" abspeichern und dann konvertieren?

    Dann könnte man auch einen Player nehmen der ALAW abspielen kann. Erspart man sich das konvertieren. Nicht getestet da ich keine ALAW-Waves hab, aber die Media Foundation sollte das abspielen können.

    Nachtrag: ALAW-Testwave von hier: www-mmsp.ece.mcgill.ca/Documen…Formats/WAVE/Samples.html Jupp, die Media Foundation spielt ALAW problemlos ab.



    Mfg -Franky-

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

    UShort meinst du?
    Also ich soll dies nutzen?

    VB.NET-Quellcode

    1. Dim Value As UShort = CUShort(data(21) * Math.Pow(256, 1) + data(22) * Math.Pow(256, 0))
    2. Label_WAV.Text = "WAVE"
    3. If Value = 1 Then
    4. Label_PCM.Text = "PCM"
    5. Else
    6. Label_PCM.Text = "kein PCM"
    7. End If


    Warum muss ich hier bei 256^1 anfangen und runtergehen und oben bei der FileSize die Potenzen aufsteigen lassen?

    VB.NET-Quellcode

    1. Dim FileSize As ULong = CULng(
    2. data(4) * Math.Pow(256, 0) +
    3. data(5) * Math.Pow(256, 1) +
    4. data(6) * Math.Pow(256, 2) +
    5. data(7) * Math.Pow(256, 3))

    Einmal Big Endian und einmal Little Endian? Wer macht sowas?


    Hmm, ich will ja nicht so viel DLLs einbauen.

    Ich schau mir morgen mal die Bass.Dll an. Schon oft beim Stöbern gesehen, aber nie gebraucht. Na mal sehen.
    @Bartosz

    Du liest, soweit ich das sehe die komplette Datei ein (ReadAllBytes).Brauchst Du gar nicht, für einen einfachen Check sollten 44 Byte reichen (Standardgröße des WaveHeader). Eigentlich reicht auch ein BinaryReader auf die Wave-Datei. zb liest darüber per BinaryReader.ReadInt32 den Anfang der Datei ein. Dann sollte für RIFF = ReadInt32 -> 1179011410 sein, dann kommt die Größe des nachfolgenden Chunks -> ReadInt32, dann WAVE -> ReadInt32 -> 1163280727, dann fmt -> ReadInt32 -> 544501094 usw usw mal ReadInt32, mal ReadInt16, je nach Größe des Structure-Member des WaveHeader .

    Bartosz schrieb:

    Hmm, ich will ja nicht so viel DLLs einbauen.

    Bei der Media Foundation? Die ist Bestandteil von Windows. Du brauchst eigentlich nur die COM-Interfaces IMFMediaEngineClassFactory::CreateInstance und ein IMFAttributes (API MFCreateAttributes -> IMFAttributes) das Du mit Eigenschaften fütterst plus das IMFMediaEngineNotify wegen den Events (zwangsweise) um eine IMFMediaEngine(Ex) zu erstellen . Und dann IMFMediaEngine(Ex)::SetSource(File/http(s)-Stream) -> IMFMediaEngine(Ex)::Play/Pause/Stop. Mehr ist es nicht für einen einfachen Player wenn Du das ganze Extrazeug, was man da noch drum rum bauen kann, weg lässt.
    Mfg -Franky-
    Ich finde gar nicht mal schlimm DLLs zu nutzen, solange die brauchbar und ausreichend dokumentiert sind.
    Hier hast du ein C++ Projekt, weil nix ausführbares ausserhalb des Showrooms erlaubt ist, musst du die DLLs und LIBs wie hier beschrieben hinzufügen.

    Download auf un4seen.com/, die Packete erkennst du am Namen, also bass, bassenc, basswasapi und bassmix- Die Aufnahmen sind mit MyCOmputer.Audio.Play abspielbar. Projektmappe ist portable, bass-header hinzugefügt und libs verlinkt.

    Spoiler anzeigen

    Quellcode

    1. bass24.zip
    2. bass24/bass.dll copy to Projektmappe/Library/x86/bass.dll
    3. bass24/c/bass.lib copy to Projektmappe/Library/x86/bass.lib
    4. bass24/x64/bass.dll copy to Projektmappe/Library/x64/bass.dll
    5. bass24/c/x64/bass.lib copy to Projektmappe/Library/x64/bass.lib
    6. ####################################################################################################################
    7. basswasapi24.zip
    8. basswasapi24/basswasapi.dll copy to Projektmappe/Library/x86/basswasapi.dll
    9. basswasapi24/c/basswasapi.lib copy to Projektmappe/Library/x86/basswasapi.lib
    10. basswasapi24/x64/basswasapi.dll copy to Projektmappe/Library/x64/basswasapi.dll
    11. basswasapi24/c/x64/basswasapi.lib copy to Projektmappe/Library/x64/basswasapi.lib
    12. ####################################################################################################################
    13. bassenc24.zip
    14. bassenc24/bassenc.dll copy to Projektmappe/Library/x86/bassenc.dll
    15. bassenc24/c/bassenc.lib copy to Projektmappe/Library/x86/bassenc.lib
    16. bassenc24/x64/bassenc.dll copy to Projektmappe/Library/x64/bassenc.dll
    17. bassenc24/c/x64/bassenc.lib copy to Projektmappe/Library/x64/bassenc.lib
    18. ####################################################################################################################
    19. bassmix24.zip
    20. bassmix24/bassmix.dll copy to Projektmappe/Library/x86/bassmix.dll
    21. bbassmix24/c/bassmix.lib copy to Projektmappe/Library/x86/bassmix.lib
    22. bassmix24/x64/bassmix.dll copy to Projektmappe/Library/x64/bassmix.dll
    23. bassmix24/c/x64/bassmix.lib copy to Projektmappe/Library/x64/bassmix.lib



    Spoiler anzeigen

    C-Quellcode

    1. #include <Windows.h>
    2. #include <string>
    3. #include "BASS/bass.h"
    4. #include "BASS/bassmix.h"
    5. #include "BASS/basswasapi.h"
    6. #include "BASS/bassenc.h"
    7. using namespace std;
    8. HSTREAM push = 0;
    9. HSTREAM mixer = 0; //nötig siehe kommentar unten
    10. HWND hwnd = NULL;
    11. HINSTANCE hinstance = NULL;
    12. wstring windowTitle = L"Sound-Recorder";
    13. wstring windowClass = L"Sound_Recorder_Class";
    14. int width = 800;
    15. int height = 600;
    16. DWORD CALLBACK InWasapiProc(void* buffer, DWORD length, void* user)
    17. {
    18. BASS_StreamPutData(push, buffer, length);
    19. return 1;
    20. }
    21. LRESULT CALLBACK WinProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    22. {
    23. switch (uMsg)
    24. {
    25. case WM_KEYDOWN:
    26. {
    27. unsigned char keycode = static_cast<unsigned char>(wParam);
    28. const bool wasPressed = lParam & 0x40000000;
    29. if (!wasPressed)
    30. {
    31. }
    32. return 0;
    33. }
    34. case WM_KEYUP:
    35. {
    36. unsigned char keycode = static_cast<unsigned char>(wParam);
    37. return 0;
    38. }
    39. default:
    40. return DefWindowProc(hwnd, uMsg, wParam, lParam);
    41. }
    42. }
    43. int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow)
    44. {
    45. hinstance = hInstance;
    46. WNDCLASSEX wc;
    47. wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
    48. wc.lpfnWndProc = WinProc;
    49. wc.cbClsExtra = 0;
    50. wc.cbWndExtra = 0;
    51. wc.hInstance = hinstance;
    52. wc.hIcon = LoadIcon(hinstance, IDI_APPLICATION);
    53. wc.hIconSm = LoadIcon(hinstance, IDI_APPLICATION);
    54. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    55. wc.hbrBackground = NULL;
    56. wc.lpszMenuName = NULL;
    57. wc.lpszClassName = windowClass.c_str();
    58. wc.cbSize = sizeof(WNDCLASSEX);
    59. RegisterClassEx(&wc);
    60. hwnd = CreateWindowExW(0, windowClass.c_str(), windowTitle.c_str(), WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU, 0, 0, width, height, NULL, NULL, hinstance, NULL);
    61. if (hwnd == NULL)
    62. {
    63. return -1;
    64. }
    65. ShowWindow(hwnd, SW_SHOW);
    66. SetForegroundWindow(hwnd);
    67. SetFocus(hwnd);
    68. if (!BASS_Init(-1, 44100, 0, 0, 0))
    69. {
    70. return -2;
    71. }
    72. if (!BASS_Init(0, 44100, 0, 0, 0))
    73. {
    74. return -3;
    75. }
    76. int defaultDevice = -1;
    77. BASS_WASAPI_DEVICEINFO info;
    78. for (int i = 0; BASS_WASAPI_GetDeviceInfo(i, &info); i++)
    79. {
    80. if ((info.flags & BASS_DEVICE_INPUT) && (info.flags & BASS_DEVICE_ENABLED))
    81. {
    82. BASS_WASAPI_Init(i, 0, 0, 0, 0, 0.1, InWasapiProc, NULL);
    83. }
    84. if (info.flags & BASS_DEVICE_DEFAULT)
    85. {
    86. defaultDevice = i;
    87. }
    88. if (info.flags & BASS_DEVICE_LOOPBACK)
    89. {
    90. BASS_WASAPI_Init(i - 1, 0, 0, 0, 0, 0, NULL, NULL);
    91. }
    92. }
    93. BASS_WASAPI_SetDevice(defaultDevice);
    94. BASS_WASAPI_GetDeviceInfo(defaultDevice, &info);
    95. BASS_WASAPI_Start();
    96. BASS_SetDevice(0);
    97. // Device 0 = NoSound
    98. // Wenn wir BASS_STREAM_DECODE nutzen wird BASS_MIXER_NONSTOP ignoriert, so haben wir hätten fehelrhaften ton
    99. // also stille könnte dann nicht aufgezeichnet werden, weil keine Daten im InWasapiProc reinkommen
    100. // der push stream also nicht gefüttert wird, ohne BASS_STREAM_DECODE und das NoSound Device haben wir
    101. // einen kontinuirlich laufenden mixerstream welchen wir aufnehmen, zudem werden wenn Daten welche im InWasapiProc reinkommen
    102. // in den push-stream gepuscht und kommen somit im mixer-stream an, somit wir auch stille aufgezeichnet
    103. mixer = BASS_Mixer_StreamCreate(info.mixfreq, info.mixchans, BASS_MIXER_BUFFER | BASS_SAMPLE_FLOAT | BASS_MIXER_NONSTOP);
    104. BASS_ChannelPlay(mixer,true);
    105. push = BASS_StreamCreate(info.mixfreq, info.mixchans, BASS_SAMPLE_FLOAT | BASS_STREAM_DECODE, STREAMPROC_PUSH, NULL);
    106. BASS_Mixer_StreamAddChannel(mixer, push, BASS_MIXER_BUFFER);
    107. BASS_Encode_Start(mixer, "output.wav", BASS_ENCODE_PCM | BASS_ENCODE_FP_16BIT | BASS_ENCODE_AUTOFREE, NULL, NULL);
    108. while (true)
    109. {
    110. Sleep(1);
    111. MSG msg;
    112. ZeroMemory(&msg, sizeof(MSG));
    113. if (PeekMessage(&msg, hwnd, 0, 0, PM_REMOVE))
    114. {
    115. TranslateMessage(&msg);
    116. DispatchMessage(&msg);
    117. }
    118. if (msg.message == WM_NULL)
    119. {
    120. if (!IsWindow(hwnd))
    121. {
    122. hwnd = NULL;
    123. UnregisterClass(windowClass.c_str(), hinstance);
    124. BASS_Encode_Stop(mixer);
    125. BASS_ChannelStop(mixer);
    126. BASS_ChannelStop(push);
    127. BASS_ChannelFree(mixer);
    128. BASS_ChannelFree(push);
    129. BASS_Free();
    130. BASS_WASAPI_Free();
    131. return 0;
    132. }
    133. }
    134. }
    135. return 0;
    136. }


    Die DLLs werden automatisch aus dem Library Ordner in die Debug und Release Ordner kopiert, jeweils x86/x64

    Nachdem du das kopiert hast kannst du das Projekt im Studio öffnen, beim Starten wird aufgenommen, beim schliessen beendet, die aufnahme ist wenn im Studio getstartet direkt in der Projektmappe direkt neben der SLN Datei, ohne studio gestartet neben der exe. Buttons und Dateinameselektion kannste selbst noch machen. Oder auch mit NET nachbauen.
    Dateien
    • SoundRekorder.zip

      (442,27 kB, 73 mal heruntergeladen, zuletzt: )

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „Takafusa“ ()

    Bartosz schrieb:

    Bedeutung
    Was bedeutet es, wenn in diesem Byte eine { 0, 1, 2, ... 254, 255 } drinne steht?
    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!
    @RodFromGermany Die Bytes an Position 21 und 22 im Waveheader dienen zur Erkennung des WAV-Encodings. 0 && 1 ist zum Beispiel das von mir gewünschte PCM-Encoding, im falsch heruntergeladenen WAV war es jedoch 0 && 6. Deswegen konnte das nicht abgespielt werden. Diese Quelle habe ich gefunden
    docs.fileformat.com/audio/wav/

    @Takafusa Danke, schau ich mir an. Melde mich.

    @-Franky-
    Du liest, soweit ich das sehe die komplette Datei ein (ReadAllBytes).Brauchst Du gar nicht, für einen einfachen Check sollten 44 Byte reichen (Standardgröße des WaveHeader).
    Ja stimmt...

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