为什么录制的音频数据仅使用缓冲区的一半(WaveIn)?

时间:2016-04-17 04:17:18

标签: c++ windows audio

我试图从麦克风录制音频数据并保存在文件中。问题是wavein设备只使用波头中指定的缓冲区的一半。特别是,音频文件中只有前2000个点,文件的其余部分如下所示

-12851
-12851
-12851
-12851
.....

不清楚出了什么问题。我发现如果我从

更改以下代码行
_header[i].dwBufferLength = bpbuff; 

_header[i].dwBufferLength = 2*bpbuff;

然后所有4000个值确实是音频输入。但显然这不是解决问题的正确方法。有什么想法吗?

这里是完整的代码:

#include "stdafx.h"
#include <Windows.h>
#pragma comment(lib, "winmm.lib")
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>

using namespace std;
HANDLE hEvent_BufferReady;
#define Samplerate 2000
#define nSec  3

BOOL BufferReady;

enum { NUM_BUF = 8 };

int _iBuf;
int prevBuf;

void CALLBACK myWaveInProc(HWAVEIN hwi, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)
{
    WAVEHDR *pHdr=NULL;
    switch(uMsg)
    {
        case WIM_CLOSE:
            cout << "waveInProc()... WIM_CLOSE" << endl;
            break;

        case WIM_DATA:
            {
                cout << "waveInProc()... WIM_DATA : " <<endl;
                SetEvent(hEvent_BufferReady);
            }
            break;

        case WIM_OPEN:
            cout << "waveInProc()... WIM_OPEN" << endl;
            break;

        default:
            break;
    }
}

    int _tmain(int argc, _TCHAR* argv[])
    {
    hEvent_BufferReady=CreateEvent(NULL,FALSE, FALSE, NULL);

    WAVEFORMATEX pFormat;
    pFormat.wFormatTag = WAVE_FORMAT_PCM; // simple, uncompressed format
    pFormat.nChannels = 1; // 1=mono, 2=stereo
    pFormat.nSamplesPerSec = Samplerate; // 44100
    pFormat.wBitsPerSample = 16; // 16 for high quality, 8 for telephone-grade
    pFormat.nBlockAlign = pFormat.nChannels*pFormat.wBitsPerSample/8; 
    pFormat.nAvgBytesPerSec = (pFormat.nSamplesPerSec)*(pFormat.nChannels)*(pFormat.wBitsPerSample)/8; 
    pFormat.cbSize=0;

    HWAVEIN hWaveIn;

    unsigned long result;

    WAVEHDR _header [NUM_BUF];
    short int  *_pBuf;
    size_t bpbuff = (pFormat.nSamplesPerSec) * (pFormat.nChannels) * (pFormat.wBitsPerSample)/8;

    result = waveInOpen(&hWaveIn, WAVE_MAPPER,&pFormat, (DWORD)myWaveInProc, 0L, CALLBACK_FUNCTION);

    _pBuf = new short int [bpbuff * NUM_BUF];

    // initialize all headers in the queue
    for ( int i = 0; i < NUM_BUF; i++ )
    {
        _header[i].lpData = (LPSTR)&_pBuf [i * bpbuff];
        _header[i].dwBufferLength = bpbuff;
        _header[i].dwFlags = 0L;
        _header[i].dwLoops = 0L;
        waveInPrepareHeader(hWaveIn, & _header[i], sizeof(WAVEHDR));
        waveInAddBuffer (hWaveIn, & _header[i], sizeof (WAVEHDR));
    }

    _iBuf = 0;
    int _prevBuf = NUM_BUF - 1;

    unsigned char* tempchar;
    waveInStart(hWaveIn);
    for(int iter=0;iter<5;iter++)
    {

        do {
        } while (!(_header[_iBuf].dwFlags & WHDR_DONE));
        waveInUnprepareHeader (hWaveIn, &_header[_iBuf], sizeof (WAVEHDR));

        std::ostringstream fn;
        fn << "file" << iter << ".txt";
        ofstream myfile;
        myfile.open (fn.str());


        for(int i=0;i<bpbuff;i++)
        {
            myfile<<_pBuf[_iBuf*bpbuff + i]<<"\n";
        }
        myfile.close();


        int prevBuf = _iBuf - 1;
        if (prevBuf < 0)
            prevBuf = NUM_BUF - 1;

        _header [prevBuf].lpData = (LPSTR)&_pBuf [prevBuf * bpbuff];
        _header [prevBuf].dwBufferLength = bpbuff;
        _header [prevBuf].dwFlags = 0L;
        _header [prevBuf].dwLoops = 0L;

        waveInPrepareHeader(hWaveIn, & _header[_iBuf], sizeof(WAVEHDR));
        waveInAddBuffer (hWaveIn, & _header[_iBuf], sizeof (WAVEHDR));

        ++_iBuf;
        if (_iBuf == NUM_BUF)   _iBuf = 0;

    }


    waveInClose(hWaveIn);


    cout<<"hello"<<endl;
    getchar();


    CloseHandle(hEvent_BufferReady);

    return 0;
}

1 个答案:

答案 0 :(得分:1)

WAVEHDR::dwBufferLength

  

dwBufferLength - 缓冲区的长度(以字节为单位)。

您的代码:

_pBuf = new short int [bpbuff * NUM_BUF];

// initialize all headers in the queue
for ( int i = 0; i < NUM_BUF; i++ )
{
    _header[i].lpData = (LPSTR)&_pBuf [i * bpbuff];
    _header[i].dwBufferLength = bpbuff;

您的缓冲区长度为bpbuff * sizeof (short int)个字节。但是,您将其路由到API以使其仅填充bpbuff个字节的数据。因此,缓冲区仅部分填充,其余部分保存未初始化的数据(您将其视为-12851,请参阅0xCDCDCDCD)。

你需要做到:

    _header[i].dwBufferLength = bpbuff * sizeof *_pBuf;