2014년 11월 21일 금요일

waveIn/waveOut 함수 안전하게 사용하는 법

윈도우의 waveIn/waveOut 계열 함수는 콜백을 등록해서 호출받는 방식으로 동작하는데 콜백함수는 wave 드라이버의 쓰레드에서 호출하기 때문에 콜백함수에서 윈도우 시스템 API를 호출하면 죽거나 데드락이 걸리는 문제가 발생한다. 이것을 해결하기 위해 큐를 사용해 외부 쓰레드에서 waveIn/waveOut 결과를 처리한다.

< WaveBuffer.h >
 #ifndef __WAVE_BUFFER_H__  
 #define __WAVE_BUFFER_H__  
   
 #include <windows.h>  
 #include <MMSystem.h>  
   
 #include "BufferQueue.h"  
   
 class WaveBuffer {  
 public:  
      WAVEHDR*     pWaveHdr;  
      int               length;  
      bool          bDeleteData;  
   
      WaveBuffer(WAVEHDR *hdr, int len, bool deleteData = true) {  
           pWaveHdr = hdr;  
           length = len;  
           bDeleteData = deleteData;  
      }  
   
      virtual ~WaveBuffer() {  
           if (pWaveHdr && bDeleteData) {  
                delete[] pWaveHdr->lpData;  
                delete pWaveHdr;  
           }  
      }  
 };  
   
 class WaveBufferQueue {  
 public:  
      WaveBufferQueue(bool deleteData = true);  
      virtual ~WaveBufferQueue();  
   
      int push_back(WAVEHDR *pWaveHdr);  
      WaveBuffer* pop_front();  
   
      void clear() { m_pWaveQue->clear(); }  
      int count() { return m_pWaveQue->count(); }  
   
 private:  
      BufferQueue<WaveBuffer>     *m_pWaveQue;  
      int          m_nCount;  
      bool     m_bDeleteData;  
 };  
   
   
 #endif  
   
BufferQueue 템플릿 클래스는 C++ double linked-list Template Queue 포스트 참조

< WaveBuffer.cpp >
 #include "WaveBuffer.h"  
   
   
 WaveBufferQueue::WaveBufferQueue(bool deleteData)  
 {  
      m_pWaveQue = new BufferQueue<WaveBuffer>(0);     // 무제한 버퍼  
      m_bDeleteData = deleteData;  
 }  
   
 WaveBufferQueue::~WaveBufferQueue()  
 {  
      if (m_pWaveQue) {  
           delete m_pWaveQue;  
           m_pWaveQue = NULL;  
      }  
 }  
   
 int WaveBufferQueue::push_back(WAVEHDR *pWaveHdr)  
 {  
      WaveBuffer *wave = new WaveBuffer(pWaveHdr, pWaveHdr->dwBufferLength, m_bDeleteData);  
      return m_pWaveQue->push_back(wave);  
 }  
   
 WaveBuffer* WaveBufferQueue::pop_front()  
 {  
      return m_pWaveQue->pop_front();  
 }  
   

< WaveIn.h >
 #ifndef __WAVE_IN_H__  
 #define __WAVE_IN_H__  
   
 #include <windows.h>  
 #include <MMSystem.h>  
   
 #include "WaveBuffer.h"  
   
 class WaveIn  
 {  
 public:  
      WaveIn();  
      virtual ~WaveIn();  
   
      /* WaveIn API */  
      int open(WAVEFORMATEX waveInFormat, int buff_count, double duration);  
      void close();  
      void setWaveInFunc(void (*func)(WAVEHDR *pHdr, void *pData), void *pData)   
      {   
           waveInHandlerFunc = func;   
           m_pWaveInHandlerData = pData;   
      }  
   
 public:  
      void processWaveInDone(WAVEHDR *pHdr);  
      void processWaveInClose();  
      void running();       
   
 protected:  
      HWAVEIN          m_hWaveIn;  
      HANDLE          m_hWaveInThread;  
      BOOL          m_bWaveInRun;  
      WAVEHDR*     m_pWaveInHdr;  
      int               m_nWaveInHdrCount;  
   
      int                         m_nWaveInHdrPrepareCount;  
      WaveBufferQueue*     m_pWaveBufferQue;  
   
      WAVEFORMATEX     m_waveInFormatEx;  
   
      void (*waveInHandlerFunc)(WAVEHDR *pHdr, void *pData);  
      void *m_pWaveInHandlerData;  
   
      void waveInPrintError(MMRESULT result, LPCTSTR str);  
 };  
   
 #endif  
   

<WaveIn.cpp >
 #include "WaveIn.h"  
 #include "GlobalEnv.h"  
 #include <assert.h>  
 #include <process.h>  
 #include <stdio.h>  
   
 #pragma comment(lib, "winmm.lib")  
   
 WaveIn::WaveIn()  
 {  
      m_hWaveIn = NULL;  
      m_hWaveInThread = NULL;  
      m_bWaveInRun = FALSE;  
   
      memset(&m_waveInFormatEx, 0, sizeof(m_waveInFormatEx));  
      m_pWaveInHdr = NULL;  
      m_nWaveInHdrCount = 0;  
   
      m_pWaveBufferQue = NULL;  
   
      waveInHandlerFunc = NULL;  
      m_pWaveInHandlerData = NULL;  
 }  
   
 WaveIn::~WaveIn()  
 {  
      close();  
 }  
   
 unsigned __stdcall Thread_WaveIn(LPVOID lpParam)  
 {  
      WaveIn *pWaveIn = (WaveIn *)lpParam;  
      pWaveIn->running();  
      return 0;  
 }  
   
 void WaveIn::running()  
 {  
      MMRESULT mRes;  
      WAVEHDR *pHdr;  
      WaveBuffer *pWave;  
   
      while (1)  
      {  
           pWave = m_pWaveBufferQue->pop_front();  
           if (pWave == NULL)  
           {  
                Sleep(1);  
                continue;  
           }  
   
           pHdr = pWave->pWaveHdr;  
   
           mRes = waveInUnprepareHeader(m_hWaveIn, pHdr, sizeof(WAVEHDR));  
           if (mRes != MMSYSERR_NOERROR) {  
                waveInPrintError(mRes, "waveInUnprepareHeader");  
                assert(FALSE);  
                continue;  
           }  
           m_nWaveInHdrPrepareCount--;  
   
           if (waveInHandlerFunc)  
                waveInHandlerFunc(pHdr, m_pWaveInHandlerData);  
   
           delete pWave;  
   
           if (m_bWaveInRun)  
           {  
                mRes = waveInPrepareHeader(m_hWaveIn, pHdr, sizeof(WAVEHDR));  
                if (mRes != MMSYSERR_NOERROR) {  
                     waveInPrintError(mRes, "waveInPrepareHeader");  
                     assert(FALSE);  
                     continue;  
                }  
   
                mRes = waveInAddBuffer(m_hWaveIn, pHdr, sizeof(WAVEHDR));  
                if (mRes != MMSYSERR_NOERROR) {  
                     waveInPrintError(mRes, "waveInAddBuffer");  
                     assert(FALSE);  
                     continue;  
                }  
                m_nWaveInHdrPrepareCount++;  
           }  
           else  
           {  
                //DXPRINTF("[%s] WaveIn Hdr Count:%d\n", __FUNCTION__, m_nWaveInHdrPrepareCount);  
                if (m_pWaveBufferQue->count() == 0 && m_nWaveInHdrPrepareCount == 0) {  
                     break;  
                }  
           }  
      }  
 }  
   
 void CALLBACK waveInProc(HWAVEIN hwi, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)  
 {  
      WaveIn *pWaveIn = (WaveIn *)dwInstance;  
   
      switch(uMsg)  
      {  
      case WIM_OPEN:  
           DXPRINTF("WIM_OPEN\n");  
           break;  
      case WIM_CLOSE:  
           DXPRINTF("WIM_CLOSE\n");  
           pWaveIn->processWaveInClose();  
           break;  
      case WIM_DATA:   
           pWaveIn->processWaveInDone((WAVEHDR *)dwParam1);  
           break;  
      default:  
           break;  
      }  
 }  
   
 void WaveIn::processWaveInDone(WAVEHDR *pHdr)  
 {  
      if (m_pWaveBufferQue)  
           m_pWaveBufferQue->push_back(pHdr);  
 }  
   
 void WaveIn::processWaveInClose()  
 {  
 }  
   
 int WaveIn::open(WAVEFORMATEX waveInFormat, int buff_count, double duration)  
 {  
      MMRESULT mRes;  
   
      if (m_bWaveInRun)  
           return -1;  
   
      memset(&m_waveInFormatEx, 0, sizeof(m_waveInFormatEx));  
      m_waveInFormatEx.wFormatTag = WAVE_FORMAT_PCM;  
      m_waveInFormatEx.nChannels = waveInFormat.nChannels;  
      m_waveInFormatEx.nSamplesPerSec = waveInFormat.nSamplesPerSec;  
      m_waveInFormatEx.wBitsPerSample = waveInFormat.wBitsPerSample;  
      m_waveInFormatEx.nBlockAlign = m_waveInFormatEx.nChannels*m_waveInFormatEx.wBitsPerSample/8;  
      m_waveInFormatEx.nAvgBytesPerSec = m_waveInFormatEx.nSamplesPerSec*m_waveInFormatEx.nBlockAlign;  
      m_waveInFormatEx.cbSize = 0;  
   
      mRes = waveInOpen(&m_hWaveIn, WAVE_MAPPER, &m_waveInFormatEx,   
           (DWORD_PTR)waveInProc, (DWORD_PTR)this, CALLBACK_FUNCTION);  
   
      if (mRes != MMSYSERR_NOERROR) {  
           waveInPrintError(mRes, "waveInOpen");  
           return -2;  
      }  
   
      /* prepare wavein header */  
      int buff_size = (int)(m_waveInFormatEx.nAvgBytesPerSec*duration);  
      buff_size *= m_waveInFormatEx.nChannels;  
   
      m_nWaveInHdrCount = buff_count;  
      m_pWaveInHdr = new WAVEHDR[m_nWaveInHdrCount];  
   
      for (int i=0; i<m_nWaveInHdrCount; i++)  
      {  
           memset(&m_pWaveInHdr[i], 0, sizeof(WAVEHDR));  
           m_pWaveInHdr[i].lpData = new char[buff_size];  
           m_pWaveInHdr[i].dwBufferLength = buff_size;  
           m_pWaveInHdr[i].dwUser = i;  
   
           mRes = waveInPrepareHeader(m_hWaveIn, &m_pWaveInHdr[i], sizeof(WAVEHDR));  
           if (mRes != MMSYSERR_NOERROR) {  
                waveInPrintError(mRes, "waveInPrepareHeader");  
                assert(FALSE);  
                continue;  
           }  
   
           mRes = waveInAddBuffer(m_hWaveIn, &m_pWaveInHdr[i], sizeof(WAVEHDR));  
           if (mRes != MMSYSERR_NOERROR) {  
                waveInPrintError(mRes ,"waveInAddBuffer");  
                assert(FALSE);  
                continue;  
           }  
      }  
   
      m_nWaveInHdrPrepareCount = m_nWaveInHdrCount;  
   
      m_pWaveBufferQue = new WaveBufferQueue(false);  
   
      m_bWaveInRun = TRUE;  
      m_hWaveInThread = (HANDLE)_beginthreadex(NULL, 0, Thread_WaveIn, this, 0, NULL);  
   
      mRes = waveInStart(m_hWaveIn);  
      if (mRes != MMSYSERR_NOERROR) {  
           waveInPrintError(mRes, "waveInStart");  
           return -1;  
      }  
   
      return 0;  
 }  
   
 void WaveIn::close()  
 {  
      MMRESULT mRes;  
   
      if (!m_bWaveInRun || !m_hWaveIn)  
           return;  
   
      m_bWaveInRun = FALSE;  
   
      WaitForSingleObject(m_hWaveInThread, INFINITE);  
   
      mRes = waveInStop(m_hWaveIn);  
      if (mRes != MMSYSERR_NOERROR)  
           waveInPrintError(mRes, "waveInStop");  
   
      for (int i=0; i<m_nWaveInHdrCount; i++)  
           delete[] m_pWaveInHdr[i].lpData;  
      delete m_pWaveInHdr;  
   
      mRes = waveInClose(m_hWaveIn);  
      if (mRes != MMSYSERR_NOERROR)  
           waveInPrintError(mRes ,"waveInClose");  
   
      if (m_pWaveBufferQue) {  
           delete m_pWaveBufferQue;  
           m_pWaveBufferQue = NULL;  
      }  
   
      CloseHandle(m_hWaveInThread);  
 }  
   
 void WaveIn::waveInPrintError(MMRESULT result, LPCTSTR str)  
 {  
      char errmsg[128] = {0};  
      waveInGetErrorText(result, errmsg, sizeof(errmsg));  
      DXPRINTF("%s waveInError: %d %s\n", str, result, errmsg);  
 }  
   

< WaveOut.h >
 #ifndef __WAVE_OUT_H__  
 #define __WAVE_OUT_H__  
   
 #include <windows.h>  
 #include <MMSystem.h>  
 #include <MMReg.h>  
 #include <stdio.h>  
   
 #include "WaveBuffer.h"  
   
 class WaveOut  
 {  
 public:  
      WaveOut();  
      virtual ~WaveOut();  
   
      /* WaveOut API */  
      int open(WAVEFORMATEX waveOutFormat, DWORD channel_layout);  
      void close();  
      int waveOutAdd(unsigned char *buff, int len);  
   
      void setAudioVolume(int val);  
      DWORD getAudioVolume();  
      void reset();  
      void setMaxWaveOutBufferCount(int maxCount) { m_nMaxWaveOutBufferCount = maxCount; }  
        
      int channels() { return m_waveOutFormatEx.Format.nChannels; }  
      int sampleRate() { return m_waveOutFormatEx.Format.nSamplesPerSec; }  
      int channelLayout() { return m_waveOutFormatEx.dwChannelMask; }  
   
 public:  
      void processWaveOutDone(WAVEHDR *pHdr);  
      void processWaveOutClose();  
      void running();  
   
 protected:  
      HWAVEOUT     m_hWaveOut;  
      HANDLE          m_hWaveOutThread;  
      BOOL          m_bWaveOutRun;  
      int               m_nMaxWaveOutBufferCount;  
   
      int                         m_nWaveOutHdrPrepareCount;  
      WaveBufferQueue*     m_pWaveBufferQue;  
   
      DWORD          m_nAudioVolume;  
   
      WAVEFORMATEXTENSIBLE     m_waveOutFormatEx;  
      WAVEOUTCAPS                    m_waveOutCaps;  
   
      void waveOutPrintError(MMRESULT result, LPCTSTR str);  
   
      FILE     *m_pFile;     // audio dump  
 };  
   
 #endif  
   

< WaveOut.cpp >
 #include "WaveOut.h"  
 #include "GlobalEnv.h"  
 #include <assert.h>  
 #include <process.h>  
 #include <stdio.h>  
   
 #pragma comment(lib, "winmm.lib")  
   
 WaveOut::WaveOut()  
 {  
      m_hWaveOut = NULL;  
      m_hWaveOutThread = NULL;  
      m_bWaveOutRun = FALSE;  
   
      m_nWaveOutHdrPrepareCount = 0;  
      m_pWaveBufferQue = new WaveBufferQueue();  
   
      m_nAudioVolume = 0xFFFFFFFF;  
   
      ZeroMemory(&m_waveOutCaps, sizeof(WAVEOUTCAPS));  
      ZeroMemory(&m_waveOutFormatEx, sizeof(WAVEFORMATEXTENSIBLE));  
   
      m_nMaxWaveOutBufferCount = 3;  
   
      m_pFile = NULL;  
 }  
   
 WaveOut::~WaveOut()  
 {  
      close();  
      DX_DELETE_OBJECT(m_pWaveBufferQue);  
 }  
   
 unsigned __stdcall Thread_WaveOut(LPVOID lpParam)  
 {  
      WaveOut *pWaveOut = (WaveOut *)lpParam;  
      pWaveOut->running();  
      return 0;  
 }  
   
 void WaveOut::running()  
 {  
      MMRESULT mRes;  
      WaveBuffer *pWave;  
      WAVEHDR *pHdr;  
   
      while (1)  
      {  
           pWave = m_pWaveBufferQue->pop_front();  
           if (pWave == NULL) {  
                Sleep(1);  
                goto skip;  
           }  
             
           pHdr = pWave->pWaveHdr;  
   
           mRes = waveOutUnprepareHeader(m_hWaveOut, pHdr, sizeof(WAVEHDR));  
           if (mRes != MMSYSERR_NOERROR) {  
                waveOutPrintError(mRes, "waveOutUnprepareHeader");  
                assert(FALSE);  
                continue;  
           }  
   
           delete pWave;  
           InterlockedDecrement((LPLONG)&m_nWaveOutHdrPrepareCount);  
   
 skip:  
           if (!m_bWaveOutRun)  
           {  
                if (m_pWaveBufferQue->count() == 0 && m_nWaveOutHdrPrepareCount == 0) {  
                     break;  
                }  
           }  
      }  
 }  
   
 void WaveOut::processWaveOutDone(WAVEHDR *pHdr)  
 {       
      if (m_pWaveBufferQue) {  
           m_pWaveBufferQue->push_back(pHdr);  
      }  
 }  
   
 void CALLBACK waveOutProc(HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2)  
 {  
      WaveOut *pWaveOut = (WaveOut *)dwInstance;  
   
      switch(uMsg)  
      {  
      case WOM_OPEN:  
           DXPRINTF("WOM_OPEN\n");  
           break;  
      case WOM_CLOSE:  
           DXPRINTF("WOM_CLOSE\n");  
           break;  
      case WOM_DONE:  
           pWaveOut->processWaveOutDone((WAVEHDR *)dwParam1);  
           break;  
      default:  
           break;  
      }  
 }  
   
 int WaveOut::waveOutAdd(unsigned char *buff, int len)  
 {  
      MMRESULT mRes;  
   
      if (!m_bWaveOutRun)  
           return -1;  
   
      //DXPRINTF("wave out buffer count : %d (%d)\n", m_nWaveOutHdrPrepareCount, len);  
      if (m_nMaxWaveOutBufferCount > 0) {  
           if (m_nWaveOutHdrPrepareCount > m_nMaxWaveOutBufferCount) {  
                DXPRINTF("wave out buffer overflow : %d (%d)\n", m_nWaveOutHdrPrepareCount, len);  
                return 0;  
           }  
      }  
   
      WAVEHDR *pHdr = new WAVEHDR;  
      ZeroMemory(pHdr, sizeof(WAVEHDR));  
   
      pHdr->lpData = new char[len];  
      memcpy(pHdr->lpData, buff, len);  
      pHdr->dwBufferLength = len;  
      pHdr->dwFlags = 0;  
   
      mRes = waveOutPrepareHeader(m_hWaveOut, pHdr, sizeof(WAVEHDR));  
      if (mRes != MMSYSERR_NOERROR) {  
           waveOutPrintError(mRes, "waveOutPrepareHeader");  
           delete[] pHdr->lpData;  
           delete pHdr;  
           assert(FALSE);  
           return -2;  
      }  
   
      mRes = waveOutWrite(m_hWaveOut, pHdr, sizeof(WAVEHDR));  
      if (mRes != MMSYSERR_NOERROR) {  
           waveOutPrintError(mRes, "waveOutWrite");  
           delete[] pHdr->lpData;  
           delete pHdr;  
           assert(FALSE);  
           return -3;  
      }  
   
      InterlockedIncrement((LPLONG)&m_nWaveOutHdrPrepareCount);  
   
      if (m_pFile) fwrite(buff, len, 1, m_pFile);  
   
      return 0;  
 }  
   
 int WaveOut::open(WAVEFORMATEX waveOutFormat, DWORD channel_layout)  
 {  
      MMRESULT mRes;  
   
      if (m_bWaveOutRun)  
           return -1;  
   
      m_waveOutFormatEx;  
      memset(&m_waveOutFormatEx, 0, sizeof(WAVEFORMATEXTENSIBLE));  
      m_waveOutFormatEx.Format.wFormatTag = WAVE_FORMAT_PCM;  
      m_waveOutFormatEx.Format.nChannels = waveOutFormat.nChannels;  
      m_waveOutFormatEx.Format.nSamplesPerSec = waveOutFormat.nSamplesPerSec;  
      m_waveOutFormatEx.Format.wBitsPerSample = waveOutFormat.wBitsPerSample;  
      m_waveOutFormatEx.Format.nBlockAlign = waveOutFormat.nChannels*waveOutFormat.wBitsPerSample/8;  
      m_waveOutFormatEx.Format.nAvgBytesPerSec = waveOutFormat.nSamplesPerSec*waveOutFormat.nBlockAlign;  
   
      if (waveOutFormat.nChannels <= 2) {  
           m_waveOutFormatEx.Format.cbSize = 0;  
      } else {  
           m_waveOutFormatEx.dwChannelMask = channel_layout;  
           m_waveOutFormatEx.Samples.wValidBitsPerSample = waveOutFormat.wBitsPerSample;  
           m_waveOutFormatEx.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;  
           m_waveOutFormatEx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;  
           m_waveOutFormatEx.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);  
      }  
   
      mRes = waveOutOpen(&m_hWaveOut, WAVE_MAPPER, (WAVEFORMATEX *)&m_waveOutFormatEx,  
           (DWORD_PTR)waveOutProc, (DWORD_PTR)this, CALLBACK_FUNCTION);  
   
      if (mRes != MMSYSERR_NOERROR) {  
           waveOutPrintError(mRes, "waveOutOpen");  
           return -2;  
      }  
   
      mRes = waveOutSetVolume(m_hWaveOut, m_nAudioVolume);  
      if (mRes != MMSYSERR_NOERROR) {  
           waveOutPrintError(mRes, "waveOutWrite");  
      }  
   
      m_bWaveOutRun = TRUE;  
      m_hWaveOutThread = (HANDLE)_beginthreadex(NULL, 0, Thread_WaveOut, this, 0, NULL);  
      if (!m_hWaveOutThread) {  
           DXPRINTF("[%s] waveout thread create error, err:%d\n", __FUNCTION__, GetLastError());  
           return -3;  
      }  
   
      ZeroMemory(&m_waveOutCaps, sizeof(WAVEOUTCAPS));  
      mRes = waveOutGetDevCaps((UINT_PTR)m_hWaveOut, &m_waveOutCaps, sizeof(WAVEOUTCAPS));  
      if (mRes != MMSYSERR_NOERROR) {  
           waveOutPrintError(mRes, "waveOutGetDevCaps");  
      }  
   
 #if 0  
      m_pFile = fopen("audio.wav", "wb");  
 #endif  
   
      return 0;  
 }  
   
 void WaveOut::close()  
 {  
      MMRESULT mRes;  
   
      if (!m_bWaveOutRun || !m_hWaveOut)  
           return;  
   
      waveOutReset(m_hWaveOut);  
      m_bWaveOutRun = FALSE;  
   
      WaitForSingleObject(m_hWaveOutThread, INFINITE);  
   
      mRes = waveOutClose(m_hWaveOut);  
      if (mRes != MMSYSERR_NOERROR)  
           waveOutPrintError(mRes, "waveOutClose");  
   
      CloseHandle(m_hWaveOutThread);  
      m_hWaveOutThread = NULL;  
   
      if (m_pFile) {  
           fclose(m_pFile);  
           m_pFile = NULL;  
      }  
 }  
   
 void WaveOut::setAudioVolume(int val)  
 {  
      m_nAudioVolume = val;  
   
      if (m_hWaveOut) {  
           MMRESULT mRes = waveOutSetVolume(m_hWaveOut, m_nAudioVolume);  
           if (mRes != MMSYSERR_NOERROR) {  
                waveOutPrintError(mRes, "waveOutSetVolume");  
           }  
      }  
 }  
   
 DWORD WaveOut::getAudioVolume()  
 {  
      if (m_hWaveOut) {  
           MMRESULT mRes = waveOutGetVolume(m_hWaveOut, &m_nAudioVolume);  
           if (mRes == MMSYSERR_NOERROR) return m_nAudioVolume;  
           waveOutPrintError(mRes, "waveOutGetVolume");  
      }  
      return 0;  
 }  
   
 void WaveOut::reset()  
 {  
      if (m_hWaveOut)  
           waveOutReset(m_hWaveOut);  
 }  
   
 void WaveOut::waveOutPrintError(MMRESULT result, LPCTSTR str)  
 {  
      char errmsg[128] = {0};  
      waveOutGetErrorText(result, errmsg, sizeof(errmsg));  
      DXPRINTF("%s waveOutError: %d %s\n", str, result, errmsg);  
 }  
   

< WaveOut 사용법 >
WaveOut* m_pWaveOut = new WaveOut();
...
// waveout 열기
int open(int channel, int sample_rate, int channel_layout)
{
// open waveout
WAVEFORMATEX waveformat;
memset(&waveformat, 0, sizeof(WAVEFORMATEX));
waveformat.wFormatTag = WAVE_FORMAT_PCM;
waveformat.nChannels = channel;
waveformat.nSamplesPerSec = sample_rate;
waveformat.wBitsPerSample = 16;
waveformat.nBlockAlign = waveformat.nChannels*waveformat.wBitsPerSample/8;
waveformat.nAvgBytesPerSec = waveformat.nSamplesPerSec*waveformat.nBlockAlign;
waveformat.cbSize = 0;

int ret = m_pWaveOut->open(waveformat, channel_layout);
if (ret < 0) m_pWaveOut->close();
return ret;
}

// waveout 출력 - buff : 오디오 pcm 데이터, size : 오디오 pcm 데이터 사이즈
int waveout(unsigned char *buff, int size)
{
     return m_pWaveOut->waveOutAdd(buff, size);
}


// waveout 닫기
void close()
{
     m_pWaveOut->close();
}

댓글 3개:

  1. 혹시.. 풀소스 올려 주실수 있을까요??
    소스 내용 확인해 보면.. #include "WaveBuffer.h" 파일도 없고..
    호출 방법은 open 만 하면 될것 같긴 한데..
    예제가 없어 확실하지는 않네요..
    추가로.. 파일로 저장하는 방법도 있으면 좋겠구요^^

    답글삭제
    답글
    1. wavein/waveout 어느쪽을 사용하든 오디오 처리에 대한 기본적인 이해는 있어야하구요. 오디오 덤프파일을 들으려면 GoldWave 로 채널/샘플링레이트 등을 맞춰주면 됩니다.

      삭제
  2. 안녕하세요 ~ 글 잘 읽고 많이 배워갑니다.
    그런데 한가지 추가하고 싶은게 있는데, 어떤식으로 접근해야 할지 몰라서 혹시나 하는 마음에 질문드립니다. 전 지금 mfc랑 api를 이용해서 녹음기 소스를 만들고 있는데, 저장 방법을 저장 버퍼가 차면 파일로 변환하던지 , 그게 힘들다면 버퍼에 있는 샘플을 가지고 오는 식으로 만들려고 합니다.(녹음기 안에 다른 프로그램을 넣을 예정이거든요.) 혹시 가능하시다면 약간의 도움을 주실수 있을까요?

    답글삭제