0

I want to record audio from microphone and save data to raw format and i find WASAPICaptureSharedEventDriven,This sample application uses the Core Audio APIs to capture audio data from an input device specified by the user and writes it to wav file. This is code:

//  WAV file writer.
//
//  This is a VERY simple .WAV file writer.
//

//
//  A wave file consists of:
//
//  RIFF header:    8 bytes consisting of the signature "RIFF" followed by a 4 byte file length.
//  WAVE header:    4 bytes consisting of the signature "WAVE".
//  fmt header:     4 bytes consisting of the signature "fmt " followed by a WAVEFORMATEX 
//  WAVEFORMAT:     <n> bytes containing a waveformat structure.
//  DATA header:    8 bytes consisting of the signature "data" followed by a 4 byte file length.
//  wave data:      <m> bytes containing wave data.
//
//
//  Header for a WAV file - we define a structure describing the first few fields in the header for convenience.
//
struct WAVEHEADER
{
    DWORD   dwRiff;                     // "RIFF"
    DWORD   dwSize;                     // Size
    DWORD   dwWave;                     // "WAVE"
    DWORD   dwFmt;                      // "fmt "
    DWORD   dwFmtSize;                  // Wave Format Size
};

//  Static RIFF header, we'll append the format to it.
const BYTE WaveHeader[] = 
{
    'R',   'I',   'F',   'F',  0x00,  0x00,  0x00,  0x00, 'W',   'A',   'V',   'E',   'f',   'm',   't',   ' ', 0x00, 0x00, 0x00, 0x00
};

//  Static wave DATA tag.
const BYTE WaveData[] = { 'd', 'a', 't', 'a'};

//
//  Write the contents of a WAV file.  We take as input the data to write and the format of that data.
//
bool WriteWaveFile(HANDLE FileHandle, const BYTE *Buffer, const size_t BufferSize, const WAVEFORMATEX *WaveFormat)
{
    DWORD waveFileSize = sizeof(WAVEHEADER) + sizeof(WAVEFORMATEX) + WaveFormat->cbSize + sizeof(WaveData) + sizeof(DWORD) + static_cast<DWORD>(BufferSize);
    BYTE *waveFileData = new (std::nothrow) BYTE[waveFileSize];
    BYTE *waveFilePointer = waveFileData;
    WAVEHEADER *waveHeader = reinterpret_cast<WAVEHEADER *>(waveFileData);

    if (waveFileData == NULL)
    {
        printf("Unable to allocate %d bytes to hold output wave data\n", waveFileSize);
        return false;
    }

    //
    //  Copy in the wave header - we'll fix up the lengths later.
    //
    CopyMemory(waveFilePointer, WaveHeader, sizeof(WaveHeader));
    waveFilePointer += sizeof(WaveHeader);

    //
    //  Update the sizes in the header.
    //
    waveHeader->dwSize = waveFileSize - (2 * sizeof(DWORD));
    waveHeader->dwFmtSize = sizeof(WAVEFORMATEX) + WaveFormat->cbSize;

    //
    //  Next copy in the WaveFormatex structure.
    //
    CopyMemory(waveFilePointer, WaveFormat, sizeof(WAVEFORMATEX) + WaveFormat->cbSize);
    waveFilePointer += sizeof(WAVEFORMATEX) + WaveFormat->cbSize;


    //
    //  Then the data header.
    //
    CopyMemory(waveFilePointer, WaveData, sizeof(WaveData));
    waveFilePointer += sizeof(WaveData);
    *(reinterpret_cast<DWORD *>(waveFilePointer)) = static_cast<DWORD>(BufferSize);
    waveFilePointer += sizeof(DWORD);

    //
    //  And finally copy in the audio data.
    //
    CopyMemory(waveFilePointer, Buffer, BufferSize);

    //
    //  Last but not least, write the data to the file.
    //
    DWORD bytesWritten;
    if (!WriteFile(FileHandle, waveFileData, waveFileSize, &bytesWritten, NULL))
    {
        printf("Unable to write wave file: %d\n", GetLastError());
        delete []waveFileData;
        return false;
    }

    if (bytesWritten != waveFileSize)
    {
        printf("Failed to write entire wave file\n");
        delete []waveFileData;
        return false;
    }
    delete []waveFileData;
    return true;
}

//
//  Write the captured wave data to an output file so that it can be examined later.
//
void SaveWaveData(BYTE *CaptureBuffer, size_t BufferSize, const WAVEFORMATEX *WaveFormat)
{
    wchar_t waveFileName[MAX_PATH];
    HRESULT hr = StringCbCopy(waveFileName, sizeof(waveFileName), L"WASAPICaptureEventDriven-");
    if (SUCCEEDED(hr))
    {
        GUID testGuid;
        if (SUCCEEDED(CoCreateGuid(&testGuid)))
        {
            wchar_t *guidString;
            if (SUCCEEDED(StringFromCLSID(testGuid, &guidString)))
            {
                hr = StringCbCat(waveFileName, sizeof(waveFileName), guidString);
                if (SUCCEEDED(hr))
                {
                    hr = StringCbCat(waveFileName, sizeof(waveFileName), L".WAV");
                    if (SUCCEEDED(hr))
                    {
                        HANDLE waveHandle = CreateFile(waveFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 
                            FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, 
                            NULL);
                        if (waveHandle != INVALID_HANDLE_VALUE)
                        {
                            if (WriteWaveFile(waveHandle, CaptureBuffer, BufferSize, WaveFormat))
                            {
                                printf("Successfully wrote WAVE data to %S\n", waveFileName);
                            }
                            else
                            {
                                printf("Unable to write wave file\n");
                            }
                            CloseHandle(waveHandle);
                        }
                        else
                        {
                            printf("Unable to open output WAV file %S: %d\n", waveFileName, GetLastError());
                        }
                    }
                }
                CoTaskMemFree(guidString);
            }
        }
    }
}

I try to save audio from buffer:

FILE* _file;
int16_t* _data;
_data = (int16_t*)Buffer;
_file = fopen("utterance", "wb +");
fwrite(_data, 1,BufferSize, _file);
fclose(_file);

output audio is so bad,To view it I use this code to plot Raw file:

import numpy as np
import matplotlib.pyplot as plt
with open ('test.raw', 'rb') as f:
    buf = f.read ()
    data = np.frombuffer (buf, dtype = 'int16')
    L = data [:: 2]
    R = data [1 :: 2]

newdata = np.squeeze(data) # Shape is now: (10, 80)
plt.plot(newdata) # plotting by columns
plt.show()

And output is this,you can it is a rectangle,the sound is very shy:

enter image description here

where are i wrong? Please help me!

  • please help me! –  Oct 25 '20 at 01:46
  • 1
    What does raw format mean? Do you want to get wav files? BTW,what is output? Waveform? – Strive Sun Oct 26 '20 at 06:01
  • @StriveSun-MSFT RAW Audio format or just RAW Audio is an audio file format for storing uncompressed audio in raw form. Comparable to WAV or AIFF in size, RAW Audio file does not include any header information (sampling rate, bit depth, endian, or number of channels). it is a example for raw audio: http://cpham.perso.univ-pau.fr/SmartSantanderSample/test.raw –  Oct 26 '20 at 06:43
  • You already have the raw audio data, so all you have to do is write a file in .raw format. I am not sure if the data is binary. See [raw file format C++](https://stackoverflow.com/questions/11103249/raw-file-format-c) – Strive Sun Oct 26 '20 at 09:14
  • @StriveSun-MSFT my data is a byte array and it can be float or int because it's 16 bits per sample –  Oct 26 '20 at 17:12
  • Is the size of the utterance file 0? How do you judge whether the output of utterance file is valid? I can get a file with a size of 3446kb using your code. See the [pic](https://i.stack.imgur.com/QuJdb.png). – Strive Sun Oct 27 '20 at 09:44
  • @StriveSun-MSFT i don't know how vaild but when i use this code to record music after save in utterance file and use this code python to convert to wav file: import sys import wave import os x='utterance' with open(x, 'rb') as pcmfile: pcmdata = pcmfile.read() with wave.open(x+'.wav', 'wb') as wavfile: wavfile.setparams((2, 4, 48000, 0, 'NONE', 'NONE')) wavfile.writeframes(pcmdata) i can listen speech but the recorded sound has poor sound quality, is full of gagging and glitches –  Oct 27 '20 at 12:35
  • This is another question... **How to parse raw audio file into wav file?** You can create a new thread to ask, beacuse you already own raw audio file. – Strive Sun Oct 28 '20 at 08:57
  • @StriveSun-MSFT Maybe you misunderstanding. My problem is With this code I recorded voice and save in Raw file but the Raw file is poor quality and I don't know where is wrong in this code i tried. –  Oct 28 '20 at 09:04
  • There is a raw file true,it is not like rectangle: https://ibb.co/S6KV5GR . Please help me! –  Oct 28 '20 at 09:07
  • The python sample seems from [How to convert .pcm files to .wav files](https://stackoverflow.com/a/16111188/11128312). And the test audio sample is 16-bit little-endian 44.1k PCM files. I think what you need to do now is to check the properties of the raw audio file obtained using the `WASAPICaptureSharedEventDriven `sample. – Strive Sun Oct 29 '20 at 09:39
  • @StriveSun-MSFT Maybe I was wrong at saving data to raw file because when the data is saved to wav file it's perfectly fine and t don't know where is the wrong in code save raw file. –  Oct 29 '20 at 12:12

1 Answers1

1

After checking, there is no problem with the properties of the raw audio sample. Please try my code sample and add wav header to re-encode.

#include <Windows.h>
#include <stdio.h>
#include <MMDeviceAPI.h>
#include <AudioClient.h>
#include <assert.h>
#include <avrt.h>
#include <strsafe.h>
#include <fstream> 

using namespace std;

#pragma warning(disable:4996)

struct WAVEHEADER
{
    DWORD   dwRiff;                     // "RIFF"
    DWORD   dwSize;                     // Size
    DWORD   dwWave;                     // "WAVE"
    DWORD   dwFmt;                      // "fmt "
    DWORD   dwFmtSize;                  // Wave Format Size
};

const BYTE WaveHeader[] =
{
    'R',   'I',   'F',   'F',  0x00,  0x00,  0x00,  0x00, 'W',   'A',   'V',   'E',   'f',   'm',   't',   ' ', 0x00, 0x00, 0x00, 0x00
};

const BYTE WaveData[] = { 'd', 'a', 't', 'a' };

bool WriteWaveFile(HANDLE FileHandle, const BYTE* Buffer, const size_t BufferSize, WAVEFORMATEX* WaveFormat)
{
    DWORD waveFileSize = sizeof(WAVEHEADER) + sizeof(WAVEFORMATEX) + WaveFormat->cbSize + sizeof(WaveData) + sizeof(DWORD) + static_cast<DWORD>(BufferSize);
    BYTE* waveFileData = new (std::nothrow) BYTE[waveFileSize];
    BYTE* waveFilePointer = waveFileData;
    WAVEHEADER* waveHeader = reinterpret_cast<WAVEHEADER*>(waveFileData);

    if (waveFileData == NULL)
    {
        printf("Unable to allocate %d bytes to hold output wave data\n", waveFileSize);
        return false;
    }

    //
    //  Copy in the wave header - we'll fix up the lengths later.
    //
    CopyMemory(waveFilePointer, WaveHeader, sizeof(WaveHeader));
    waveFilePointer += sizeof(WaveHeader);

    //
    //  Update the sizes in the header.
    //
    waveHeader->dwSize = waveFileSize - (2 * sizeof(DWORD));
    waveHeader->dwFmtSize = sizeof(WAVEFORMATEX) + WaveFormat->cbSize;

    //
    //  Next copy in the WaveFormatex structure.
    //
    CopyMemory(waveFilePointer, WaveFormat, sizeof(WAVEFORMATEX) + WaveFormat->cbSize);
    waveFilePointer += sizeof(WAVEFORMATEX) + WaveFormat->cbSize;


    //
    //  Then the data header.
    //
    CopyMemory(waveFilePointer, WaveData, sizeof(WaveData));
    waveFilePointer += sizeof(WaveData);
    *(reinterpret_cast<DWORD*>(waveFilePointer)) = static_cast<DWORD>(BufferSize);
    waveFilePointer += sizeof(DWORD);

    //
    //  And finally copy in the audio data.
    // 

    CopyMemory(waveFilePointer, Buffer, BufferSize);
    //
    //  Last but not least, write the data to the file.
    //
    DWORD bytesWritten;
    if (!WriteFile(FileHandle, waveFileData, waveFileSize, &bytesWritten, NULL))
    {
        printf("Unable to write wave file: %d\n", GetLastError());
        delete[]waveFileData;
        return false;
    }

    if (bytesWritten != waveFileSize)
    {
        printf("Failed to write entire wave file\n");
        delete[]waveFileData;
        return false;
    }
    delete[]waveFileData;
    return true;
}

//
//  Write the captured wave data to an output file so that it can be examined later.
//
void SaveWaveData(BYTE* CaptureBuffer, size_t BufferSize, WAVEFORMATEX* WaveFormat)
{
    wchar_t waveFileName[MAX_PATH];
    HRESULT hr = StringCbCopy(waveFileName, sizeof(waveFileName), L"WASAPICaptureEventDriven-");
    if (SUCCEEDED(hr))
    {
        GUID testGuid;
        if (SUCCEEDED(CoCreateGuid(&testGuid)))
        {
            wchar_t* guidString;
            if (SUCCEEDED(StringFromCLSID(testGuid, &guidString)))
            {
                hr = StringCbCat(waveFileName, sizeof(waveFileName), guidString);
                if (SUCCEEDED(hr))
                {
                    hr = StringCbCat(waveFileName, sizeof(waveFileName), L".WAV");
                    if (SUCCEEDED(hr))
                    {
                        HANDLE waveHandle = CreateFile(waveFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS,
                            FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
                            NULL);
                        if (waveHandle != INVALID_HANDLE_VALUE)
                        {
                            if (WriteWaveFile(waveHandle, CaptureBuffer, BufferSize, WaveFormat))
                            {
                                printf("Successfully wrote WAVE data to %S\n", waveFileName);
                            }
                            else
                            {
                                printf("Unable to write wave file\n");
                            }
                            CloseHandle(waveHandle);
                        }
                        else
                        {
                            printf("Unable to open output WAV file %S: %d\n", waveFileName, GetLastError());
                        }
                    }
                }
                CoTaskMemFree(guidString);
            }
        }
    }
}

int main()
{
    long buffersize = 3528000;// For 10s audio sample, we can set the value of buffersize to 3528000
    BYTE* captureBuffer = new (std::nothrow) BYTE[buffersize]; 
    
    FILE* _file;
    _file = fopen("utterance.raw", "rb"); //raw audio path
    fread(captureBuffer, 1, buffersize, _file);
    fclose(_file);

    WAVEFORMATEX wavformat;
    wavformat.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
    wavformat.nChannels = 2;
    wavformat.nSamplesPerSec = 44100;
    wavformat.nAvgBytesPerSec = 352800;
    wavformat.nBlockAlign = 8;
    wavformat.wBitsPerSample = 32;
    wavformat.cbSize = 22;
    SaveWaveData(captureBuffer, buffersize, &wavformat);

    return 0;
}

You can also use ofstream to write raw audio file.

Some code:

//  Write the contents of a WAV file.  We take as input the data to write and the format of that data.
//Added in WASAPICaptureSharedEventDriven sample
bool WriteWaveFile(HANDLE FileHandle, const BYTE *Buffer, const size_t BufferSize, const WAVEFORMATEX *WaveFormat)
{
    ofstream binaryFile("file.raw", ios::out | ios::binary);
    binaryFile.write((char*)Buffer, BufferSize);
    binaryFile.close();

    ...

After getting the raw file, use ifstream to open the file and add wav header.

ifstream infile("utterance.raw", std::ifstream::binary);
 // get size of file
infile.seekg(0, infile.end);
long size = infile.tellg();
infile.seekg(0);

BYTE* captureBuffer = new (std::nothrow) BYTE[size];

infile.read((char*)captureBuffer, size);
infile.close();

WAVEFORMATEX wavformat;
wavformat.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
wavformat.nChannels = 2;
wavformat.nSamplesPerSec = 44100;
wavformat.nAvgBytesPerSec = 352800;
wavformat.nBlockAlign = 8;
wavformat.wBitsPerSample = 32;
wavformat.cbSize = 22;
SaveWaveData(captureBuffer, size, &wavformat);
Strive Sun
  • 5,988
  • 1
  • 9
  • 26
  • Thanks for your answer. But the raw file save with ofstream is too noise. –  Nov 03 '20 at 13:21
  • @Tuấn `ifstream` and `ofstream` should be used together, my side is working properly. If there is still noise, please try the first method, using `fread`. See the first part of the code in the answer. BTW, don't use python sample, please use the sample I provided for testing. – Strive Sun Nov 04 '20 at 01:14
  • Sun - MSF Thanks for help. Great answer. Thanks you so much. And I would be very grateful if you have some sample code for this [question](https://stackoverflow.com/questions/64629571/send-audio-data-from-usermode-to-sysvad-virtual-audio-driver-use-ioctl) –  Nov 04 '20 at 03:50