WASAPI Loopback: сохранить волновой файл

Я хочу записать аудиовыход системы с помощью WASAPI, а затем сохранить его в файл .wav.

До сих пор я следовал этим руководствам по WASAPI:

https://msdn.microsoft.com/en-us/library/windows/desktop/dd316551%28v=vs.85%29.aspx https://msdn.microsoft.com/en-us/library/windows/desktop/dd370800%28v=vs.85%29.aspx

Я получаю данные буфера, используя

audioCaptureClient->GetBuffer(&data, &numFramesAvailable, &flags, NULL, NULL);

затем я обрабатываю эти данные, просто записывая их в конец файла .wav:

size_t dataSize = format.nChannels * (format.wBitsPerSample / 8) * numFramesAvailable;
fwrite(data, dataSize, 1, fp);

format — это WAVEFORMATEX, полученное от audioClient->GetMixFormat(&format):

cbSize:          22
nAvgBytesPerSec: 352800
nBlockAlign:     8
nChannels:       2
nSamplesPerSec:  44100
wBitsPerSample:  32
wFormatTag:      65534 (WAVE_FORMAT_EXTENSIBLE)

По-видимому, подтипом WAVE_FORMAT_EXTENSIBLE является Float:

WAVEFORMATEXTENSIBLE *waveformatextensible = (WAVEFORMATEXTENSIBLE *)format;
if (IsEqualGUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, waveformatextensible->SubFormat)) { // true

Перед записью всех захваченных данных в файл я заполняю заголовки (следуя http://www.topherlee.com/software/pcm-tut-wavformat.html):

UINT32 sizePlaceholder = 0;
UINT32 fmtLength = 16;

// RIFF Header
fputs("RIFF", fp);                       // offset 0 (0x00)
fwrite(&sizePlaceholder, 4, 1, fp);      // offset 4 (0x04)
fputs("WAVE", fp);                       // offset 8 (0x08)
// fmt-Section
fputs("fmt ", fp);                         // offset 12 (0x0C)
fwrite(&fmtLength, 4, 1, fp);              // offset 16 (0x10)
fwrite(&format.wFormatTag, 2, 1, fp);      // offset 20 (0x14)
fwrite(&format.nChannels, 2, 1, fp);       // offset 22 (0x16)
fwrite(&format.nSamplesPerSec, 4, 1, fp);  // offset 24 (0x18)
fwrite(&format.nAvgBytesPerSec, 4, 1, fp); // offset 28 (0x1C)
fwrite(&format.nBlockAlign, 2, 1, fp);     // offset 32 (0x20)
fwrite(&format.wBitsPerSample, 2, 1, fp);  // offset 34 (0x22)
// Data-Section
fputs("data", fp);                         // offset 36 (0x24)
fwrite(&sizePlaceholder, 4, 1, fp);        // offset 40 (0x28)

После завершения записи данных за 3 секунды я заполняю заполнители для размера файла и размера раздела данных, используя fwrite.


Файл не читается. Я подозреваю, что это связано с WAVE_FORMAT_EXTENSIBLE, но я не мог этого понять.

Я попытался перезаписать несколько элементов format, например:

cbSize = 0;
wFormatTag = WAVE_FORMAT_IEEE_FLOAT;

Создается читаемый файл .wav, но воспроизводится как тишина с некоторыми щелчками в нем (я пытался записать песню).

wFormatTag = WAVE_FORMAT_PCM;

производит весь случайный шум.


person qwertz    schedule 07.06.2015    source источник


Ответы (1)


Итак, наконец, после долгих часов экспериментов я нашел решение.

Было несколько проблем с кодом.

  1. WAVE_FORMAT_EXTENSIBLE использует макет файла, который немного отличается. Подробнее см. по этой отличной ссылке.
  2. Я не установил двоичный режим в fopen, поэтому аудиоданные были повреждены, потому что fwrite обнаруживает новые строки (\n) в данных и добавляет возврат каретки (\r). Мне пришлось использовать fopen("foo.wav", "wb") вместо fopen("foo.wav", "w").

Вторая проблема была решающей, потому что я уже пытался заменить WAVE_FORMAT_EXTENSIBLE-тег на WAVE_FORMAT_IEEE_FLOAT-тег, что должно было сработать, потому что для работы .wav-файла дополнительная информация не нужна.

person qwertz    schedule 09.06.2015