DirectSound 播放自定义采集的数据

#pragma once 

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <limits.h>
#include <mmsystem.h>
#include <mmreg.h>
#include <msacm.h>
#include <dsound.h>

#pragma comment(lib, "dsound")
#pragma comment(lib, "uuid")
#pragma comment(lib, "winmm")
#pragma comment(lib, "dxguid")

static void OutDbgMsg(LPCTSTR format, ...)
{
  TCHAR szMsg[256];
  memset(szMsg, 0, sizeof(szMsg));
  va_list va;
  va_start(va, format);
  _vstprintf_s(szMsg, format, va);
  va_end(va);
  _tcscat_s(szMsg, _T("\r\n"));
  OutputDebugString(szMsg);
}

template<typename srcDataType>class CDirectSoundPlay
{
private:
  HWND m_hWnd;
  LPDIRECTSOUND gpds;
  LPDIRECTSOUNDBUFFER pMainDSB;

protected:
  class CDirectSoundPlayBuffer
  {
  protected:
    LPDIRECTSOUNDBUFFER pDSB;
    LPDIRECTSOUND lgpds;

    HRESULT Release()
    {
      HRESULT hr = Stop();
      if(pDSB != NULL)
      {
        IDirectSoundBuffer_Release(pDSB);
        pDSB = NULL;        
      }
      return hr;
    }

  public:
    CDirectSoundPlayBuffer(LPDIRECTSOUND gpds)
    {
      lgpds = gpds;
      pDSB = NULL;
    }

    virtual ~CDirectSoundPlayBuffer()
    {  
      Release();
    }

  public:

    HRESULT Play(BOOL bLoop)
    {
      HRESULT hr = DSERR_INVALIDCALL;
      if(pDSB != NULL)
      {
        hr = IDirectSoundBuffer_Play(pDSB, 0, 0, 
          bLoop ? DSBPLAY_LOOPING : 0); 
        if(hr != DS_OK)
        {
          OutDbgMsg(_T("Failed to DirectSoundBuffer Play (%ld)"), hr);
        }
      }
      return hr;
    }

    HRESULT Stop()
    {
      HRESULT hr = DS_OK;
      if(pDSB != NULL)
      {
        hr = IDirectSoundBuffer_Stop(pDSB);
        if(hr != DS_OK)
        {
          OutDbgMsg(_T("Failed to DirectSoundBuffer Stop (%ld)"), hr);
        }
      }
      return hr;
    }

    HRESULT CreateDSoundBuffer(srcDataType *pChnL, srcDataType *pChnR, 
      LONG iSampFreq, LONG iPtLength, double fGain=1)
    {
      HRESULT hr = S_OK;
      if(hr == S_OK)
      {
        hr = Release();
      }

      //检查参数
      if(hr == S_OK)
      {
        if(!(pChnL || pChnR)
          || iPtLength <= 0
          || iSampFreq < DSBFREQUENCY_MIN 
          || iSampFreq > DSBFREQUENCY_MAX)
        {
          OutDbgMsg(_T("Invalid Param"));
          hr = DSERR_INVALIDPARAM;
        }
      }

      //检查gpds是否有效
      if(hr == S_OK)
      {
        if(lgpds == NULL)
        {
          OutDbgMsg(_T("lgpds Can't be empty"));
          hr = DSERR_UNINITIALIZED;
        }
      }

      DWORD cbSize = iPtLength * 2 * 2; //数据总长度 (字节 = N × 两声道 × 16位)

      if(hr == S_OK)
      {
        WAVEFORMATEX waveFormatEx;
        {
          LPWAVEFORMATEX pwfx = &waveFormatEx;
          memset(pwfx, 0, sizeof(WAVEFORMATEX));

          pwfx->wFormatTag = WAVE_FORMAT_PCM;
          pwfx->nChannels = 2; //两通道
          pwfx->nBlockAlign = 4;
          pwfx->wBitsPerSample = 16; //16位
          pwfx->nSamplesPerSec = 44100; //采样频率(PCM) //8.0kHz, 11.025kHz 22.05kHz 44.1 kHz
          pwfx->nAvgBytesPerSec = pwfx->nSamplesPerSec
            * pwfx->nChannels * pwfx->wBitsPerSample/8; //每秒钟数据量(字节)
          pwfx->cbSize = 0; //后续扩展数据
        }

        // Set up the direct sound buffer. 
        DSBUFFERDESC dsbd;
        {
          memset(&dsbd, 0, sizeof(dsbd));
          dsbd.dwSize                 = sizeof(dsbd);
          dsbd.dwFlags                = 0;
          dsbd.dwFlags                |= DSBCAPS_STATIC;
          dsbd.dwFlags                |= DSBCAPS_CTRLPAN;
          dsbd.dwFlags                |= DSBCAPS_CTRLPAN;
          dsbd.dwFlags                |= DSBCAPS_CTRLVOLUME;
          dsbd.dwFlags                |= DSBCAPS_CTRLFREQUENCY;
          dsbd.dwFlags                |= DSBCAPS_GETCURRENTPOSITION2;
          dsbd.dwFlags                |= DSBCAPS_STICKYFOCUS;
          dsbd.dwBufferBytes          = cbSize;
          dsbd.lpwfxFormat            = &waveFormatEx;
        }

        hr = IDirectSound_CreateSoundBuffer(lgpds,
          &dsbd, &pDSB, NULL );
        if(hr != DS_OK || pDSB == NULL)
        {
          OutDbgMsg(_T("Failed to Create play SoundBuffer (%ld)"), hr);
          if(pDSB == NULL)
            hr = S_FALSE;
        }
      }

      BYTE *pbData = NULL, *pbData2 = NULL;
      DWORD dwLength = 0, dwLength2 = 0;

      // Ok, lock the sucker down
      if(hr == S_OK)
      {
        hr = IDirectSoundBuffer_Lock(pDSB,
          0,
          cbSize,
          (LPVOID*)&pbData,
          &dwLength,
          (LPVOID*)&pbData2,
          &dwLength2,
          0L);

        if(hr == S_OK)
        {
          if(pbData != NULL && dwLength > 0)
            memset(pbData, 0, dwLength);
        }
        else
        {
          OutDbgMsg(_T("Failed to SoundBuffer_Lock (%ld)"), hr);
        }
      }

      //create wave data memory
      if(hr == S_OK)
      {
        LONG dwPt = (LONG)min((DWORD)iPtLength, dwLength/4);
        typedef struct _WAVEDATA
        {
          SHORT chnL;
          SHORT chnR;
        }WAVEDATA, *LPWAVEDATA;
        LPWAVEDATA pWaveData = (LPWAVEDATA)pbData;

        double valL, valR;

        for(LONG i=0; i<dwPt; i++)
        {
          valL = valR = 0;
          #define CutShort(v) ( (v)>SHRT_MAX ? SHRT_MAX : ((v)<SHRT_MIN ? SHRT_MIN : (v)) )

          if(pChnL && pChnR)
          {
            valL = CutShort(pChnL[i] * fGain);
            valR = CutShort(pChnR[i] * fGain);
          }
          else if(pChnL)
          {
            valL = valR = CutShort(pChnL[i] * fGain);
          }
          else if(pChnR)
          {
            valL = valR = CutShort(pChnR[i] * fGain);
          }
          else
          {
          }
          pWaveData[i].chnL = (SHORT)valL;
          pWaveData[i].chnR = (SHORT)valR;
        }
      }

      // Ok, now unlock the buffer, we don't need it anymore.
      if(pDSB && pbData)
      {
        HRESULT hr2 = IDirectSoundBuffer_Unlock(pDSB,
          pbData, cbSize,  NULL, 0);
        if(hr2 != S_OK)
        {
          OutDbgMsg(_T("Falied to SoundBuffer_Unlock (%ld)"), hr);
          hr = hr2;
        }
      }

      //最大音量
      if(hr == S_OK)
      {
        hr = IDirectSoundBuffer_SetVolume(pDSB, DSBVOLUME_MAX); 
        if(hr != S_OK)
          OutDbgMsg(_T("Failed to SoundBuffer_SetVolume (%ld)"), hr);
      }

      //左右声道平衡
      if(hr == S_OK)
      {
        hr = IDirectSoundBuffer_SetPan(pDSB, DSBPAN_CENTER); 
        if(hr != S_OK)
          OutDbgMsg(_T("Failed to SoundBuffer_SetPan (%ld)"), hr);
      }

      //新采样频率
      if(hr == S_OK)
      {
        hr = IDirectSoundBuffer_SetFrequency(pDSB, iSampFreq);//= DSBFREQUENCY_ORIGINAL)
        if(hr != S_OK)
          OutDbgMsg(_T("Falied to SoundBuffer_SetFrequency (%ld)"), hr);
      }

      //
      if(hr == S_OK)
      {
        DSBCAPS dsbc;
        memset(&dsbc, 0, sizeof(dsbc));
        dsbc.dwSize = sizeof(dsbc);
        hr = IDirectSoundBuffer_GetCaps(pDSB, &dsbc);  
        if(hr != S_OK)
        {
          OutDbgMsg(_T("Failed to IDirectSoundBuffer_GetCaps (%ld)"), hr);
        }
        if (dsbc.dwFlags & DSBCAPS_LOCHARDWARE) 
        {          
          //hardware support
        }
        else 
        {
          //support
        }
      }

      if(hr != S_OK)
        Release();

      return hr;
    }

  };

protected:
  typedef struct _DsndBuffer_t
  {
    CDirectSoundPlayBuffer *pDsndBuffer;
    _DsndBuffer_t *pNext;

    _DsndBuffer_t(LPDIRECTSOUND gpds=NULL)
    {
      pDsndBuffer = new CDirectSoundPlayBuffer(gpds);
      pNext = NULL;
    }

    ~_DsndBuffer_t()
    {
      if(pDsndBuffer)
      {
        delete pDsndBuffer;
        pDsndBuffer = NULL;
      }
    }

    HRESULT Stop()
    {
      return pDsndBuffer ? pDsndBuffer->Stop() : DSERR_INVALIDCALL;
    }

    HRESULT Play(BOOL bLoop)
    {
      return pDsndBuffer ? pDsndBuffer->Play(bLoop) : DSERR_INVALIDCALL;
    }

  }DSNDBUFFER;
  DSNDBUFFER m_DsndBufferRoot;

public:
  HRESULT ReleaseDsndBuffer()
  {
    Stop();
    while(m_DsndBufferRoot.pNext != NULL)
    {
      _DsndBuffer_t *pNode = m_DsndBufferRoot.pNext;
      m_DsndBufferRoot.pNext = pNode->pNext;
      delete pNode;      
    }
    return DS_OK;
  }

  HRESULT Stop(int iIndex = -1)
  {
    int iPos=0;
    _DsndBuffer_t *pNode = m_DsndBufferRoot.pNext;
    while(pNode != NULL)
    {
      if(iIndex < 0 || iPos == iIndex)
        pNode->Stop();
      pNode = pNode->pNext;
    }    
    return DS_OK;
  }

  HRESULT Play(BOOL bLoop, int iIndex = -1)
  {
    int iPos = 0;
    _DsndBuffer_t *pNode = m_DsndBufferRoot.pNext;
    while(pNode != NULL)
    {
      if(iIndex < 0 || iPos == iIndex)
        pNode->Play(bLoop);
      pNode = pNode->pNext;
    }
    return DS_OK;
  }

  HRESULT AddDSoundBuffer(srcDataType *pChnL, srcDataType *pChnR, 
    DWORD uSampFreq, DWORD uPtLength, double fGain=1)
  {
    HRESULT hr = DS_OK;
    if(gpds == NULL)
    {
      hr = DSERR_UNINITIALIZED;
      OutDbgMsg(_T("gpds not valid"));
    }

    if(hr == DS_OK)
    {
      _DsndBuffer_t *pNewNode = new _DsndBuffer_t(gpds);

      hr = pNewNode->pDsndBuffer->CreateDSoundBuffer(pChnL, pChnR, 
        uSampFreq, uPtLength, fGain);
      if(hr == DS_OK)
      {
        _DsndBuffer_t *pNode = &m_DsndBufferRoot;
        while(pNode->pNext) pNode = pNode->pNext; //找到最后一个节点
        pNode->pNext = pNewNode; //连接到尾部
      }
      else
      {
        delete pNewNode;
      }
    }
  
    return hr;
  }

public:
  CDirectSoundPlay()
  {
    //initialize
    m_hWnd = NULL;
    gpds = NULL;
    pMainDSB = NULL;
  }

  virtual ~CDirectSoundPlay()
  {
    //Free All List
    ReleaseDsndBuffer();

    // Destroy the direct sound buffer.
    if(pMainDSB != NULL) 
    {
      IDirectSoundBuffer_Stop(pMainDSB);
      IDirectSoundBuffer_Release(pMainDSB);
      pMainDSB = NULL;
    }

    //Destroy the direct sound object.
    if (gpds != NULL)
    {
      IDirectSound_Release(gpds);
      gpds = NULL;
    }

    CoUninitialize();
  }

public:

  HRESULT Initilaize(HWND hWnd)
  {
    HRESULT hr = S_OK;
    m_hWnd = hWnd;

    //initialize COM library
    if(hr == S_OK)
    {
      hr = CoInitialize(NULL);
      if (!SUCCEEDED(hr)) 
      {
        OutDbgMsg(_T("Failed to initialize COM library(%ld)"), hr);
      }
    }
    
    //Create the direct sound object
    if(hr == S_OK)
    {
      // Create the direct sound object.
      hr = CoCreateInstance(CLSID_DirectSound,
        NULL, CLSCTX_INPROC_SERVER,
        IID_IDirectSound, (void **)&gpds);

      if(hr != S_OK || gpds == NULL)
      {
        OutDbgMsg(_T("Failed to Initialize DirectSound object(%ld)"), hr);
        if(hr == S_OK)
          hr = S_FALSE;
      }
    }

    //initializes the DirectSound object 
    if(hr == S_OK)
    {
      hr = IDirectSound_Initialize(gpds, NULL);
      if(hr != DS_OK)
      {
        OutDbgMsg(_T("Failed to initializes the DirectSound object(%ld)"), hr);
      }
    }

    //SetCooperativeLevel
    if(hr == S_OK)
    {
      hr = IDirectSound_SetCooperativeLevel(gpds, m_hWnd, DSSCL_PRIORITY);
      if(hr != DS_OK)
      {
        OutDbgMsg(_T("Failed to SetCooperativeLevel (%ld)"), hr);
      }
    }

    //Create primary buffer
    if (hr == S_OK)
    {
      DSBUFFERDESC dsbd;
      memset(&dsbd, 0, sizeof(dsbd));

      // Set up the primary direct sound buffer.
      ZeroMemory(&dsbd, sizeof(dsbd));
      dsbd.dwSize = sizeof(dsbd);
      dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER;
      
      hr = IDirectSound_CreateSoundBuffer(gpds, &dsbd, &pMainDSB, NULL);
      if(hr != DS_OK || pMainDSB == NULL)
    {
        OutDbgMsg(_T("Cannot Create primary buffer (%ld)"), hr);
        if(hr != DS_OK)
          hr = S_FALSE;
      }
    }

    //specifies the speaker configuration 
    if(hr == S_OK)
    {
      hr = IDirectSound_SetSpeakerConfig(gpds, DSSPEAKER_STEREO);
      if(hr != DS_OK)
      {
        OutDbgMsg(_T("Failed to Specifies the speaker configuration (%ld)"), hr);
      }
    }

    //Play primary buffer
    if(hr == S_OK)
    {
      hr = IDirectSoundBuffer_Play(pMainDSB, 0, 0, DSBPLAY_LOOPING);
      if(hr != DS_OK)
      {
        OutDbgMsg(_T("Cannot play primary buffer (%ld)"), hr);
      }
    }

    return hr;
  }


public:
  LPDIRECTSOUND Get_gpds() { return gpds; }

};


 

 

CDirectSoundPlay <double> dsd;

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
  //……
  switch (message) 
  {
  case WM_CREATE:
    //播放2秒钟纯音数据
    if(dsd.Initilaize(hWnd) == S_OK)
    {
      DWORD uSampFreq = 100000U; //采样频率
      DWORD dwPtLen = (DWORD)(uSampFreq * 2.0); //2秒采样
      double *pBuffL = new double [dwPtLen];
      double fAngle = 0, fGain = SHRT_MAX,//SHRT_MAX,
        dAngle = 1000.0 * (atan(1.0) * 8.0) / (double)uSampFreq; //正弦波 2πf/fs
      for(DWORD i=0; i<dwPtLen; i++)
      {
        pBuffL[i] = fGain * sin(fAngle);
        fAngle += dAngle;
      }
      dsd.AddDSoundBuffer(pBuffL, NULL, uSampFreq, dwPtLen);
      delete []pBuffL;
      dsd.Play(false);
    }
    break;
    //……后续略


 

 

 

你可能感兴趣的:(DirectSound 播放自定义采集的数据)