简体   繁体   English

使用 waveIn 和 waveOut 在 windows 中进行录音和实时播放

[英]audio recording and real-time playing in windows using waveIn and waveOut

I want to record microphone audio input and, with some small time delay, play the recorded sound immediately.我想录制麦克风音频输入,并有一些小的时间延迟,立即播放录制的声音。 This will be done continuously using a queue of buffers.这将使用缓冲区队列连续完成。

I got the code running to the point that it almost continuously plays the microphone audio input, but there are very short but still noticeable repeated pauses throughout the whole audio output using waveOut.我让代码运行到几乎连续播放麦克风音频输入的程度,但是在使用 waveOut 的整个音频输出中存在非常短但仍然明显的重复暂停。 What is causing these annoying pauses?是什么导致了这些烦人的停顿? and how to remove them?以及如何删除它们?

Another question is, I'm not using any thing like mutex, I'm relying on the fact that waveIn and waveOut have the same sampling rate and the same amount of data, so hopefully waveOut always follows waveIn and waveIn will not write to buffer being played.另一个问题是,我没有使用任何像互斥锁这样的东西,我依赖于 waveIn 和 waveOut 具有相同的采样率和相同的数据量这一事实,因此希望 waveOut 始终遵循 waveIn 并且 waveIn 不会写入缓冲区正在播放。 Would this be a problem?这会是个问题吗?

Here's the code, it should compile and run.这是代码,它应该编译并运行。 I only made the code run, and it's far from being well written.我只是让代码运行起来,它远没有写好。 Any comment on improving the code is highly welcome.非常欢迎任何关于改进代码的评论。

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

    using namespace std;
    HANDLE hEvent_BufferReady;
    HANDLE hEvent_FinishedPlaying;
    #define Samplerate 44100
    #define nSec  1

    int _iBuf;
    int _iplaying;
    unsigned long result;


    HWAVEIN hWaveIn;
    HWAVEOUT hWaveOut;
    WAVEFORMATEX pFormat;

    enum { NUM_BUF = 3 };
    WAVEHDR _header [NUM_BUF];

    DWORD WINAPI RecordingWaitingThread(LPVOID ivalue)
    {
        while(1)
        {
        WaitForSingleObject(hEvent_BufferReady,INFINITE);


        result = waveInUnprepareHeader (hWaveIn, &_header[_iBuf], sizeof (WAVEHDR));
        _iplaying = _iBuf;
        result = waveOutPrepareHeader(hWaveOut, &_header[_iBuf], sizeof(WAVEHDR));
        result = waveOutWrite(hWaveOut, &_header[_iBuf], sizeof(WAVEHDR));   // play audio
        ++_iBuf;
        if (_iBuf == NUM_BUF)   _iBuf = 0;
        result = waveInPrepareHeader(hWaveIn, & _header[_iBuf], sizeof(WAVEHDR));
        result = waveInAddBuffer (hWaveIn, & _header[_iBuf], sizeof (WAVEHDR)); 
        }
        return 0;
    }

    DWORD WINAPI PlayingWaitingThread(LPVOID ivalue)
    {
        while(1){
            WaitForSingleObject(hEvent_FinishedPlaying,INFINITE);
            waveOutUnprepareHeader(hWaveOut, &_header[_iplaying], sizeof(WAVEHDR));
        }
    }

    static void CALLBACK waveOutProc(HWAVEOUT hWaveOut, UINT uMsg, DWORD dwInstance, DWORD dwParam1,DWORD dwParam2 )
    {
    if(uMsg != WOM_DONE)
    return;
    SetEvent(hEvent_FinishedPlaying);
    }


    void CALLBACK myWaveInProc(HWAVEIN hwi, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)
    {
    if(uMsg != WIM_DATA)
    return;
    SetEvent(hEvent_BufferReady);
    }

    int main(int argc, _TCHAR* argv[])
    {

        hEvent_BufferReady=CreateEvent(NULL,FALSE, FALSE, NULL);
        hEvent_FinishedPlaying = CreateEvent(NULL,FALSE, FALSE, NULL);


        pFormat.wFormatTag = WAVE_FORMAT_PCM; // simple, uncompressed format
        pFormat.nChannels = 1; // 1=mono, 2=stereo
        pFormat.nSamplesPerSec = Samplerate; 
        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;


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

        result = waveInOpen(&hWaveIn, WAVE_MAPPER,&pFormat, (DWORD)myWaveInProc, 0L, CALLBACK_FUNCTION);
        result = waveOutOpen(&hWaveOut, WAVE_MAPPER, &pFormat, (DWORD_PTR)waveOutProc, 0, CALLBACK_FUNCTION);
        // 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*sizeof(*_pBuf);
            _header[i].dwFlags = 0L;
            _header[i].dwLoops = 0L;
        }

        DWORD myThreadID;
        DWORD myThreadIDPlay;
        HANDLE hThread;
        HANDLE hThreadPlay;
        hThread = CreateThread(NULL, 0, RecordingWaitingThread,NULL,0,&myThreadID);
        hThreadPlay = CreateThread(NULL, 0, PlayingWaitingThread,NULL,0,&myThreadIDPlay);

        _iBuf = 0;

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

        waveInStart(hWaveIn);

        getchar();
        waveInClose(hWaveIn);
        waveOutClose(hWaveOut);
        CloseHandle(hThread);
        CloseHandle(hThreadPlay);

        CloseHandle(hEvent_BufferReady);
        CloseHandle(hEvent_FinishedPlaying);

        return 0;
    }

The problem on your program is that you are declaring a too small bpbuff .您程序的问题在于您声明的bpbuff Just try to declare it with size_t bpbuff = 4410;只需尝试使用size_t bpbuff = 4410;声明它size_t bpbuff = 4410; and you will get rid of all of these repeated breaks in your audio stream.并且您将摆脱音频流中的所有这些重复中断。

By the way, I think you could get rid of these threading approach making your code much more simple like this one below:顺便说一句,我认为您可以摆脱这些线程方法,使您的代码更简单,如下所示:

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

using namespace std;
#define Samplerate 44100

static HWAVEIN hWaveIn;
static HWAVEOUT hWaveOut;

enum { NUM_BUF = 3 };
WAVEHDR _header [NUM_BUF];

void CALLBACK myWaveInProc(HWAVEIN hwi, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)
{
    static int _iBuf;
    waveOutWrite(hWaveOut, &_header[_iBuf], sizeof(WAVEHDR));   // play audio
    ++_iBuf;
    if (_iBuf == NUM_BUF)   _iBuf = 0;
    waveInAddBuffer (hWaveIn, & _header[_iBuf], sizeof (WAVEHDR)); 
}

int main(int argc, _TCHAR* argv[])
{
    WAVEFORMATEX pFormat;
    pFormat.wFormatTag = WAVE_FORMAT_PCM; // simple, uncompressed format
    pFormat.nChannels = 1; // 1=mono, 2=stereo
    pFormat.nSamplesPerSec = Samplerate; 
    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;

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

    waveInOpen(&hWaveIn, WAVE_MAPPER,&pFormat, (DWORD)myWaveInProc, 0L, CALLBACK_FUNCTION);
    waveOutOpen(&hWaveOut, WAVE_MAPPER, &pFormat, (DWORD_PTR)nullptr, 0, CALLBACK_FUNCTION);
    // 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*sizeof(*_pBuf);
        _header[i].dwFlags = 0L;
        _header[i].dwLoops = 0L;
        waveInPrepareHeader(hWaveIn, & _header[i], sizeof(WAVEHDR));
    }
    waveInAddBuffer (hWaveIn, & _header[0], sizeof (WAVEHDR));

    waveInStart(hWaveIn);

    getchar();
    waveInClose(hWaveIn);
    waveOutClose(hWaveOut);
    delete _pBuf;

    return 0;
}

This piece of code performs exactly the same task with less code.这段代码用更少的代码执行完全相同的任务。 Cheers, mate!干杯,伙计!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM