C ++ PCM捕获到wave文件,质量差

时间:2017-02-08 14:08:36

标签: c++ audio pcm wasapi

我尝试捕获并保存计算机的音频环回流。我使用MSDN的示例代码。我可以将声音捕捉到波形文件中并且我可以播放它,但声音质量很糟糕(很多静电,声音是溅射)。我不知道我的代码中出了什么问题。这是:

#include "stdafx.h"

#define REFTIMES_PER_SEC  10000000
#define REFTIMES_PER_MILLISEC  10000

#define SAMPLE_TO_REC 10

#define EXIT_ON_ERROR(hres)  \
          if (FAILED(hres)) { goto Exit; }
#define SAFE_RELEASE(punk)  \
          if ((punk) != NULL)  \
            { (punk)->Release(); (punk) = NULL; }

const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator);
const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator);
const IID IID_IAudioClient = __uuidof(IAudioClient);
const IID IID_IAudioCaptureClient = __uuidof(IAudioCaptureClient);

UINT32 packetLength = 0;
UINT32 totalRecorded = 0;

UINT32  getPacketSize()
{
    return packetLength;
}

void writeToFile(std::ofstream *myFile, BYTE** buffer, WAVEFORMATEX *wfmt)
{
PWAVEFORMATEXTENSIBLE pEx = reinterpret_cast<PWAVEFORMATEXTENSIBLE>(wfmt);

pEx->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;

pEx->Samples.wValidBitsPerSample = wfmt->wBitsPerSample;
wfmt->nBlockAlign = wfmt->nChannels * wfmt->wBitsPerSample / 8;
wfmt->nAvgBytesPerSec = wfmt->nBlockAlign * wfmt->nSamplesPerSec;

int chunksize, pcmsize, NumSamples, subchunk1size;
int audioFormat = 1;
int numChannels = wfmt->nChannels;
int bitsPerSample = wfmt->wBitsPerSample;

pcmsize = sizeof(PCMWAVEFORMAT);

subchunk1size = 40;
int byteRate = wfmt->nAvgBytesPerSec;
int blockAlign = wfmt->nBlockAlign;
int sampleRate = wfmt->nSamplesPerSec;
int subchunk2size = totalRecorded*numChannels*4;
int chunkfactsize = 4;
int sampleNumber = totalRecorded / 2 / 4;
chunksize = subchunk2size + sizeof(chunksize) + 4 + 4 + sizeof(subchunk1size) + sizeof(wfmt->wFormatTag) + sizeof(wfmt->nChannels) + sizeof(wfmt->nSamplesPerSec) + sizeof(wfmt->nAvgBytesPerSec) + sizeof(wfmt->nBlockAlign) +
    sizeof(wfmt->wBitsPerSample) + sizeof(wfmt->cbSize) + sizeof(pEx->Samples.wValidBitsPerSample) + sizeof(pEx->dwChannelMask) + sizeof(pEx->SubFormat) + 4 + sizeof(chunkfactsize) + sizeof(sampleNumber);

printf("channels = %d\nbyterate = %d\nblockAlign = %d\nsampleRate = %d\nData size = %d\nbitsPerSample = %d\nwValidBitsPerSample = %d\n", numChannels, byteRate, blockAlign, sampleRate, subchunk2size, wfmt->wBitsPerSample, pEx->Samples.wValidBitsPerSample);

// write the wav file per the wav file format
myFile->seekp(0, std::ios::beg);
myFile->write("RIFF", 4);                   // chunk id
myFile->write((char*)&chunksize, 4);                // chunk size (36 + SubChunk2Size))
myFile->write("WAVE", 4);                   // format
myFile->write("fmt ", 4);
myFile->write((char*)&subchunk1size, sizeof(subchunk1size));

myFile->write((char*)&wfmt->wFormatTag, sizeof(wfmt->wFormatTag));
myFile->write((char*)&wfmt->nChannels, sizeof(wfmt->nChannels));
myFile->write((char*)&wfmt->nSamplesPerSec, sizeof(wfmt->nSamplesPerSec));
myFile->write((char*)&wfmt->nAvgBytesPerSec, sizeof(wfmt->nAvgBytesPerSec));
myFile->write((char*)&wfmt->nBlockAlign, sizeof(wfmt->nBlockAlign));
myFile->write((char*)&wfmt->wBitsPerSample, sizeof(wfmt->wBitsPerSample));
myFile->write((char*)&wfmt->cbSize, sizeof(wfmt->cbSize));
myFile->write((char*)&pEx->Samples.wValidBitsPerSample, sizeof(pEx->Samples.wValidBitsPerSample));
myFile->write((char*)&pEx->dwChannelMask, sizeof(pEx->dwChannelMask));
myFile->write((char*)&pEx->SubFormat, sizeof(pEx->SubFormat));

myFile->write("fact", 4);
myFile->write((char*)&chunkfactsize, sizeof(chunkfactsize));
myFile->write((char*)&sampleNumber, sizeof(sampleNumber));

myFile->write("data", 4);
myFile->write((char*)&subchunk2size, 4);

int i = -1;
while (++i < SAMPLE_TO_REC)
{
    if (buffer[i] != NULL)
        myFile->write((char *)buffer[i], 384000);
}
}

HRESULT WINAPI RecordAudioStream(LPVOID _hnd)
{
HRESULT hr;
REFERENCE_TIME hnsRequestedDuration = REFTIMES_PER_SEC;
REFERENCE_TIME hnsActualDuration;
UINT32 bufferFrameCount;
UINT32 numFramesAvailable;
IMMDeviceEnumerator *pEnumerator = NULL;
IMMDevice *pDevice = NULL;
IAudioClient *pAudioClient = NULL;
IAudioCaptureClient *pCaptureClient = NULL;
WAVEFORMATEX *pwfx = NULL;
BOOL bDone = FALSE;
DWORD flags;
BYTE** pData;
BYTE*  pDataTemp;
std::string bufTemp;
AudioStreamHandler* hnd = (AudioStreamHandler *)_hnd;

int totalPerSecond = 0;

printf("addr CAPTURE thread = %p\n", hnd);

std::ofstream myFile("C:\\Users\\tanguy\\Documents\\GitHub\\bobomb\\x64\\Release\\test.wav", std::fstream::out | std::fstream::binary);
myFile.imbue(std::locale::classic());

pData = (BYTE **)malloc(sizeof(*pData) * (SAMPLE_TO_REC));

hr = CoInitialize(NULL);
    EXIT_ON_ERROR(hr)
hr = CoCreateInstance(
    CLSID_MMDeviceEnumerator, NULL,
    CLSCTX_ALL, IID_IMMDeviceEnumerator,
    (void**)&pEnumerator);
EXIT_ON_ERROR(hr)

    hr = pEnumerator->GetDefaultAudioEndpoint(
        eRender, eConsole, &pDevice);
EXIT_ON_ERROR(hr)

    hr = pDevice->Activate(
        IID_IAudioClient, CLSCTX_ALL,
        NULL, (void**)&pAudioClient);
EXIT_ON_ERROR(hr)

    hr = pAudioClient->GetMixFormat(&pwfx);
EXIT_ON_ERROR(hr)

    hr = pAudioClient->Initialize(
        AUDCLNT_SHAREMODE_SHARED,
        AUDCLNT_STREAMFLAGS_LOOPBACK,
        hnsRequestedDuration,
        0,
        pwfx,
        NULL);
EXIT_ON_ERROR(hr)

    // Get the size of the allocated buffer.
    hr = pAudioClient->GetBufferSize(&bufferFrameCount);
EXIT_ON_ERROR(hr)

    hr = pAudioClient->GetService(
        IID_IAudioCaptureClient,
        (void**)&pCaptureClient);
EXIT_ON_ERROR(hr)

    // Calculate the actual duration of the allocated buffer.
    hnsActualDuration = (double)REFTIMES_PER_SEC *
    bufferFrameCount / pwfx->nSamplesPerSec;

hr = pAudioClient->Start();  // Start recording.
EXIT_ON_ERROR(hr)

    int i = -1;
while (++i < SAMPLE_TO_REC && hnd->_bExit == false)
{
    Sleep(1000);
    hr = pCaptureClient->GetNextPacketSize(&packetLength);
    EXIT_ON_ERROR(hr)
        totalPerSecond = 0;
    pData[i] = (BYTE*)malloc(sizeof(BYTE) * pwfx->nAvgBytesPerSec);
    while (packetLength != 0)
    {
        totalRecorded += packetLength;
        // Get the available data in the shared buffer.
        hr = pCaptureClient->GetBuffer(
            &pDataTemp,
            &numFramesAvailable,
            &flags, NULL, NULL);
        EXIT_ON_ERROR(hr)

            memcpy(pData[i] + totalPerSecond, pDataTemp, numFramesAvailable * 2 * 4);
        totalPerSecond += numFramesAvailable * 2 * 4;
        //printf("%d\n", numFramesAvailable);
        if (flags & AUDCLNT_BUFFERFLAGS_SILENT)
        {
            pData[i] = NULL;  // Tell CopyData to write silence.
        }

        //hnd->setAudioBuffer(&pData);

        hr = pCaptureClient->ReleaseBuffer(numFramesAvailable);
        EXIT_ON_ERROR(hr)

            hr = pCaptureClient->GetNextPacketSize(&packetLength);
        EXIT_ON_ERROR(hr)
    }
}
hr = pAudioClient->Stop();  // Stop recording.
EXIT_ON_ERROR(hr)

if (hnd->_bExit == false)
{
    printf("writing ...\n");
    writeToFile(&myFile, pData, pwfx);
    myFile.close();
}
    Exit:
CoTaskMemFree(pwfx);
SAFE_RELEASE(pEnumerator)
    SAFE_RELEASE(pDevice)
    SAFE_RELEASE(pAudioClient)
    SAFE_RELEASE(pCaptureClient)

    return hr;
}

这是一些输出(来自我的printf):

channels = 2
byterate = 384000
blockAlign = 8
sampleRate = 48000
Data size = 3840000
bitsPerSample = 32
wValidBitsPerSample = 32

我不知道我在这里缺少什么。

0 个答案:

没有答案