Здравствуйте.
В Windows Vista/7 нужно иногда захватывать небольшой кусок звука и анализировать его. Позже я хочу переделать захват звука с устройства воспроизведения, а не захвата. Но пока есть другие вопросы.
Будьте добры, подскажите, правильно ли я делаю, и намекните, каков формат данных в звуковом буфере.
В этом тестовом примере я сделал как знаю, но почему-то при выбранном микрофоне в качестве устройства записи по-умолчанию когда он отключен необычно большие значения получаются.
#include <Windows.h>
#include <Mmdeviceapi.h>
#include <Audioclient.h>
#include <Strsafe.h>
#include <stdio.h>
const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator);
const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator);
const IID IID_IAudioClient = __uuidof(IAudioClient);
const IID IID_IAudioCaptureClient = __uuidof(IAudioCaptureClient);
int main(void)
{
HRESULT hr;
IMMDeviceEnumerator *pEnumerator = NULL;
IMMDevice *pDevice = NULL;
IAudioClient *pAudioClient = NULL;
WAVEFORMATEX *pwfx = NULL;
UINT32 bufferFrameCount;
IAudioCaptureClient *pCaptureClient = NULL;
UINT32 packetLength;
BYTE *pData;
UINT32 numFramesAvailable;
DWORD flags;
UINT32 i;
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
hr = CoCreateInstance(CLSID_MMDeviceEnumerator, NULL,
CLSCTX_ALL, IID_IMMDeviceEnumerator,
(void**)&pEnumerator);
hr = pEnumerator->GetDefaultAudioEndpoint(eCapture, eConsole,
&pDevice);
hr = pDevice->Activate(IID_IAudioClient, CLSCTX_ALL,
NULL, (void**)&pAudioClient);
hr = pAudioClient->GetMixFormat(&pwfx);
printf("Channels: %d\n"
"Sample rate: %d\n"
"Bytes rate: %d\n"
"Block align: %d\n"
"Bits per sample: %d\n",
pwfx->nChannels,
pwfx->nSamplesPerSec,
pwfx->nAvgBytesPerSec,
pwfx->nBlockAlign,
pwfx->wBitsPerSample);
hr = pAudioClient->Initialize(AUDCLNT_SHAREMODE_SHARED, 0,
0, 0, pwfx, NULL);
hr = pAudioClient->GetBufferSize(&bufferFrameCount);
hr = pAudioClient->GetService(IID_IAudioCaptureClient,
(void**)&pCaptureClient);
hr = pAudioClient->Start();
do
{
do
{
Sleep(100);
hr = pCaptureClient->GetNextPacketSize(&packetLength);
}
while (packetLength == 0);
hr = pCaptureClient->GetBuffer(&pData,
&numFramesAvailable,
&flags, NULL, NULL);
hr = pCaptureClient->ReleaseBuffer(numFramesAvailable);
}
while (flags & AUDCLNT_BUFFERFLAGS_SILENT);
if (pwfx->nChannels == 2 && pwfx->wBitsPerSample == 32)
{
for (i = 0; i < numFramesAvailable; i += 2)
{
printf("%15u %15u\n",
((UWORD*)pData)[i],
((UWORD*)pData)[i + 1]);
}
}
hr = pAudioClient->Stop();
return 0;
}
Выводится следующее:
Channels: 2
Sample rate: 44100
Bytes rate: 352800
Block align: 8
Bits per sample: 32
0 0
0 47104
0 47104
0 47104
0 47104
0 47104
0 0
0 47104
0 47104
0 47104
[..]
0 47104
0 0
0 47104
0 47104
0 47104
0 47104
0 47104
0 47104
0 47104
0 47104
0 47104
0 47104
Заметил ошибку, из-за которой выводится только половина.
for (i = 0; i < numFramesAvailable; i += 2)
{
printf("%15u %15u\n",
((UWORD*)pData)[i],
((UWORD*)pData)[i + 1]);
}
Должно быть:
printf("%15u %15u\n",
((WORD*)&((DWORD*)pData)[i])[0],
((WORD*)&((DWORD*)pData)[i])[1]);
Цикл должен быть таким:
for (i = 0; i < numFramesAvailable; i++)
{
printf("%15u %15u\n",
((WORD*)&((DWORD*)pData)[i])[0],
((WORD*)&((DWORD*)pData)[i])[1]);
}
Всё, я разобрался. На самом деле там данные типа float. Например, если размер пакета возвращает 441, и там 2 канала, значит там будет 882 семпла, левый и правый чередуются. Такой код выдаёт правдоподобный результат для синусоиды в одном канале:
do
{
Sleep(10);
hr = pCaptureClient->GetNextPacketSize(&packetLength);
if (packetLength != 0)
{
hr = pCaptureClient->GetBuffer(&pData,
&numFramesAvailable,
&flags, NULL, NULL);
if (!(flags & AUDCLNT_BUFFERFLAGS_SILENT))
{
printf("Packet size: %d\n", packetLength);
if (pwfx->nChannels == 2 && pwfx->wBitsPerSample == 32)
{
for (i = 0; i < numFramesAvailable * 2; i+=2)
{
CopyMemory(&f[0], &((float*)pData)[i], sizeof(float));
CopyMemory(&f[1], &((float*)pData)[i+1], sizeof(float));
//printf("%8d %7.4f %7.4f\n", i, f[0], f[1]);
}
}
}
hr = pCaptureClient->ReleaseBuffer(numFramesAvailable);
}
}
while (1);