例如有程序在播放伴奏,然后用麦克风跟着唱,只记录麦克风的声音,生成文件.

解决方案 »

  1.   

    speaker.h#ifndef _SPEAKER_H
    #define _SPEAKER_H#include "MMSystem.h"typedef enum _enum_speaker_status
    {
    SPEAKER_INVALID, ///< 无效的状态
    SPEAKER_RECORDING ///< 正在录音
    }SPEAK_STATUS;#define SPEAK_SUCCEED 0 ///< 正确
    #define SPEAK_ERR_FORMAT 1 ///< 没设置采样格式
    #define SPEAK_ERR_CALLBACK 2 ///< 没设置回调函数#define HDR_COUNT 2 ///< 录音的缓冲数量typedef void (__stdcall *PFN_SpeakerBufferCallBack)(BOOL result, char *buffer, int buf_len);class CSpeaker
    {
    public:
    //调用接口
    CSpeaker();
    ~CSpeaker(); /**
     * \brief 设置录音格式
     * \param sampels_per_sec: [in] 速率
     * \param bit_per_sample: [in] 采样
     * \param channels: [in] 声道数
     */
    void SetSpeakerFormat(DWORD sampels_per_sec, WORD bit_per_sample, WORD channels); /**
     * \brief 设置回调函数,录音后,以此回调函数返回音频数据
     * \param get_buffer_callback: [in] 回调函数
     */
    void SetSpeakerBufferCallBack(PFN_SpeakerBufferCallBack get_buffer_callback); /**
     * \brief 开始录音
     * \param buffer_size: [in] 设置缓存区大小
     * \param err_msg: [out] 如果有错误,则返回错误信息
     * \param err_len: [in] 错误信息的长度
     * \retval: 0为正确,否则为错误号
     *          注意: 如果返回值为SPEAK_ERR_FORMAT或SPEAK_ERR_CALLBACK,则应先调用SetFormat或SetGetWaveInBufferCallBack
     *                 其它的错误表明没有录音设备或设备不可用,或内存不够
     */
    int StartSpeaker(int buffer_size, char *err_msg, int err_len); /**
     * \brief 停止录音
     */
    void StopSpeaker();public:
    /**
     * \brief 录音函数,此函数被回调函数VoiceWaveInProc,外部程序不应该调用它
     */
        BOOL VoiceWaveInFun();private:
    void PrepareBuffer();
    void Clean();private:
    BOOL _is_format_setted; int _buffer_size;
    int _hdr_index; SPEAK_STATUS _speaker_status;
    HWAVEIN _wave_in_handle;
    WAVEFORMATEX _wave_in_format;
    PWAVEHDR _wave_in_hdr[HDR_COUNT];
    char *_wave_in_buffer[HDR_COUNT]; PFN_SpeakerBufferCallBack _speaker_buffer_callback_fun;
    HANDLE _stop_speak_event;
    };#endif //_SPEAKER_H
      

  2.   

    speaker.cpp#include <windows.h>
    #include "Speaker.h"#define WAVE_ERROR_MSG(result,msg,len) \
    if (msg != NULL)\
    {\
    memset(msg, 0, len);\
    waveInGetErrorText(result, msg, len);\
    }BOOL CALLBACK VoiceWaveInProc(
      HWAVEIN hwi,       
      UINT uMsg,         
      DWORD dwInstance,  
      DWORD dwParam1,    
      DWORD dwParam2     
      )
    {
    BOOL ret = TRUE;
    if (uMsg == WIM_DATA)
    {
    CSpeaker *pthis = (CSpeaker *)dwInstance;
    ret = pthis->VoiceWaveInFun();
    } return ret;
    }CSpeaker::CSpeaker() :
    _speaker_buffer_callback_fun(NULL),
    _is_format_setted(FALSE),
    _buffer_size(0),
    _hdr_index(0),
    _speaker_status(SPEAKER_INVALID),
    _wave_in_handle(NULL),
    //_wave_in_hdr(NULL),
    //_wave_in_buffer(NULL),
    _stop_speak_event(NULL)
    {
    for (int i = 0; i < HDR_COUNT; i++)
    {
    _wave_in_hdr[i] = NULL;
    _wave_in_buffer[i] = NULL;
    }
    memset(&_wave_in_format, 0, sizeof(WAVEFORMATEX));
    }CSpeaker::~CSpeaker()
    {
    StopSpeaker();
    if (_stop_speak_event != NULL)
    {
    CloseHandle(_stop_speak_event);
    _stop_speak_event = NULL;
    }
    }void CSpeaker::SetSpeakerFormat(DWORD sampels_per_sec, WORD bit_per_sample, WORD channels)
    {
    _wave_in_format.cbSize = 0;
    _wave_in_format.wFormatTag = WAVE_FORMAT_PCM;
    _wave_in_format.nChannels = channels;
    _wave_in_format.nSamplesPerSec = sampels_per_sec;
    _wave_in_format.wBitsPerSample = bit_per_sample;
    _wave_in_format.nBlockAlign = channels * bit_per_sample / 8;
    _wave_in_format.nAvgBytesPerSec = sampels_per_sec * channels * bit_per_sample / 8; _is_format_setted = TRUE;
    }void CSpeaker::SetSpeakerBufferCallBack(PFN_SpeakerBufferCallBack get_buffer_callback)
    {
    _speaker_buffer_callback_fun = get_buffer_callback;
    }int CSpeaker::StartSpeaker(int buffer_size, char *err_msg, int err_len)
    {
    MMRESULT mm_res = 0;
    int ret = SPEAK_SUCCEED;
    _buffer_size = buffer_size;
    do 
    {
    if (!_is_format_setted)
    {
    if (err_msg != NULL)
    strncpy(err_msg, "请先设置录音格式", err_len);
    ret = SPEAK_ERR_FORMAT;
    break;
    } if (_speaker_buffer_callback_fun == NULL)
    {
    if (err_msg != NULL)
    strncpy(err_msg, "请先设置回调函数", err_len);
    ret = SPEAK_ERR_CALLBACK;
    break;
    } if (0 != (mm_res = waveInOpen(&_wave_in_handle, (UINT)WAVE_MAPPER ,&_wave_in_format, (DWORD)VoiceWaveInProc, (DWORD)this, CALLBACK_FUNCTION)))
    {
    ret = mm_res;
    break;
    } PrepareBuffer(); _hdr_index = 0;
    waveInPrepareHeader(_wave_in_handle, _wave_in_hdr[_hdr_index], sizeof(WAVEHDR));
    waveInAddBuffer(_wave_in_handle, _wave_in_hdr[_hdr_index], sizeof (WAVEHDR)); if (_stop_speak_event == NULL)
    _stop_speak_event = CreateEvent(NULL, FALSE, FALSE, NULL); if (0 != (mm_res = waveInStart(_wave_in_handle)))
    {
    ret = mm_res;
    break;
    } _speaker_status = SPEAKER_RECORDING;
    return ret;
    }while (0);

    WAVE_ERROR_MSG(mm_res, err_msg, err_len)
    Clean();
    return ret;
    }void CSpeaker::StopSpeaker()
    {
    if (_speaker_status == SPEAKER_RECORDING)
    {
    _speaker_status = SPEAKER_INVALID;
    if (_stop_speak_event)
    WaitForSingleObject(_stop_speak_event, 1000);
    } Clean();
    }void CSpeaker::PrepareBuffer()
    {
    for (int i = 0; i < HDR_COUNT; i++)
    {
    if (_wave_in_buffer[i] != NULL)
    delete []_wave_in_buffer[i]; _wave_in_buffer[i] = new char[_buffer_size];
    memset(_wave_in_buffer[i], 0, _buffer_size); if (_wave_in_hdr[i] != NULL)
    delete _wave_in_hdr[i]; _wave_in_hdr[i] = new WAVEHDR;
    memset(_wave_in_hdr[i], 0, sizeof(WAVEHDR)); _wave_in_hdr[i]->lpData = (LPTSTR)_wave_in_buffer[i];
    _wave_in_hdr[i]->dwBufferLength = _buffer_size;
    _wave_in_hdr[i]->dwBytesRecorded = 0;
    _wave_in_hdr[i]->dwUser = 0;
    _wave_in_hdr[i]->dwFlags = 0;
    _wave_in_hdr[i]->dwLoops = 1;
    _wave_in_hdr[i]->lpNext = NULL;
    _wave_in_hdr[i]->reserved = 0;
    }
    }BOOL CSpeaker::VoiceWaveInFun()
    {
    if (_speaker_status == SPEAKER_INVALID)
    {
    if (_stop_speak_event != NULL)
    SetEvent(_stop_speak_event);
    return FALSE;
    } _speaker_buffer_callback_fun(TRUE, _wave_in_buffer[_hdr_index], _buffer_size); if (_speaker_status == SPEAKER_INVALID)
    {
    if (_stop_speak_event != NULL)
    SetEvent(_stop_speak_event);
    return FALSE;
    } MMRESULT mm_res = 0; do 
    {
    if (0 != (mm_res = waveInUnprepareHeader(_wave_in_handle, _wave_in_hdr[_hdr_index], sizeof(WAVEHDR))))
    break; _hdr_index++;
    _hdr_index %= HDR_COUNT; if (0 != (mm_res = waveInPrepareHeader(_wave_in_handle, _wave_in_hdr[_hdr_index], sizeof(WAVEHDR))))
    break; if (0 != (mm_res = waveInAddBuffer(_wave_in_handle, _wave_in_hdr[_hdr_index], sizeof(WAVEHDR))))
    break; return TRUE;
    }while (0);

    char msg[100];
    WAVE_ERROR_MSG(mm_res, msg, 100) _speaker_buffer_callback_fun(FALSE, msg, 100); Clean(); _speaker_status = SPEAKER_INVALID; return FALSE;
    }void CSpeaker::Clean()
    {
    if (_wave_in_handle != NULL)
    {
    waveInReset(_wave_in_handle);
    waveInClose(_wave_in_handle);
    _wave_in_handle = NULL;
    } for (int i = 0; i < HDR_COUNT; i++)
    {
    if (_wave_in_buffer[i] != NULL)
    {
    delete []_wave_in_buffer[i];
    _wave_in_buffer[i] = NULL;
    } if (_wave_in_hdr[i] != NULL)
    {
    delete _wave_in_hdr[i];
    _wave_in_hdr[i] = NULL;
    }
    }

    _hdr_index = 0;
    _is_format_setted = FALSE;
    _speaker_buffer_callback_fun = NULL;
    }
      

  3.   

    应用举例:CSpeaker _speaker;//设置采样
    _speaker.SetSpeakerFormat(BIT_RATE_16000, 16, 1);//设置录音回调函数
    _speaker.SetSpeakerBufferCallBack((PFN_SpeakerBufferCallBack)GetSpeakerDataFun);//开始录音
    char err_msg[100];
    memset(err_msg, 0, sizeof(err_msg));
    if (0 != _speaker.StartSpeaker(1024, err_msg, 100))
    {
    ....
    }//停止
    _speaker.StopSpeaker();然后在回调函数里处理采集的数据
      

  4.   

    请参考vckbase、codeproject、codeguru上的例子