Я хочу записать аудиовыход системы с помощью 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;
производит все случайные шумы.
Итак, наконец, после долгих часов экспериментов я нашел решение.
Было несколько проблем с кодом.
WAVE_FORMAT_EXTENSIBLE
использует расположение файлов, будучи немного другим. Смотрите это здорово ссылка на сайт Больше подробностей.fopen
Таким образом, аудио данные были повреждены, потому что fwrite
обнаруживает новые строки (\n
) в данных и добавляет возврат каретки (\r
). Я должен был использовать fopen("foo.wav", "wb")
вместо fopen("foo.wav", "w")
,Вторая проблема, была решающей причиной, потому что я уже пытался заменить WAVE_FORMAT_EXTENSIBLE
-тег с WAVE_FORMAT_IEEE_FLOAT
-tag, который должен был работать, потому что дополнительная информация не нужна для работы файла .wav.