• DirectSound 混音的实现


    啥叫混音呢,其实很简单,如果两个人同时说话 ,他们俩发出的声波在空气中进行了波的叠加,这其实就是个混音。计算机的混音,其实是一个虚拟的混音操作,因为计算机其实是只有一个声源(现在的计算机通常有两声道甚至5声道的立体声,先忽略这些,我们先抽象,把计算机看作一个声源),通过在计算机内部进行运算,把两个波形进行叠加运算,然后由计算机唯一的音箱输出,这就是计算机混音技术。微软的API PlaySound是不支持混音的,调用一个PlaySound的时候,会终止上一个PlaySound调用所播放的声音(异步调用),如果要用PlaySound来实现混音效果,就需要自己写一个混音算法。幸运的是,该叠加算法不需要我们去写,微软的DirectX早已提供给我们了现成的算法,而且非常强大,参与叠加的每个声音分量甚至都能够有自己独立的空间坐标,这也就是3D音效了。我们不需要3d音效,只要能够多路混音就可以了,晚上找到一个开源的对DirectSound的封装,非常好用,现把代码公开如下:

    -------------------------------------------------------------------------------------------------

    // DSBuffer.h : Definition of CDSBuffer class
    //

    #if !defined(AFX_DSBUFFER_H__7517D749_96E3_11D2_BBF3_9EB4940D843C__INCLUDED_)
    #define AFX_DSBUFFER_H__7517D749_96E3_11D2_BBF3_9EB4940D843C__INCLUDED_

    #if _MSC_VER > 1000
    #pragma once
    #endif // _MSC_VER > 1000

    #include <mmsystem.h>
    #include <dsound.h>

    struct WaveHeader
    {
    BYTE RIFF[4]; // "RIFF"
    DWORD dwSize; // Size of data to follow
    BYTE WAVE[4]; // "WAVE"
    BYTE fmt_[4]; // "fmt "
    DWORD dw16; // 16
    WORD wOne_0; // 1
    WORD wChnls; // Number of Channels
    DWORD dwSRate; // Sample Rate
    DWORD BytesPerSec; // Sample Rate
    WORD wBlkAlign; // 1
    WORD BitsPerSample; // Sample size
    BYTE DATA[4]; // "DATA"
    DWORD dwDSize; // Number of Samples
    };

    class CDSBuffer : public CObject
    {
    // Attribute
    protected:
    LPDIRECTSOUNDBUFFER m_lpDSBuffer; // Sound buffer
    LPDIRECTSOUND3DBUFFER m_lpDS3DBuffer; // 3D buffer

    // Construction / Destruction
    public:
    CDSBuffer();
    CDSBuffer(const char* FileName, LPDIRECTSOUND lpDS, DWORD dwFlags = DSBCAPS_CTRLDEFAULT);
    ~CDSBuffer();

    // Methods
    public:
    BOOL PlaySound(DWORD dwFlags);
    BOOL StopSound();
    BOOL CreateSoundBuffer(LPDIRECTSOUND lpDS, DWORD dwFlags, DWORD dwBufSize, DWORD dwFreq, DWORD dwBitsPerSample, DWORD dwBlkAlign, BOOL bStereo);
    BOOL ReadData(FILE* pFile, DWORD dwSize, DWORD dwPos);
    BOOL IsValid();
    LPDIRECTSOUNDBUFFER GetBuffer() { return m_lpDSBuffer;}
    LPDIRECTSOUND3DBUFFER Get3DBuffer() { return m_lpDS3DBuffer;}
    };


    #endif // !defined(AFX_DSBUFFER_H__7517D749_96E3_11D2_BBF3_9EB4940D843C__INCLUDED_)

    -------------------------------------------------------------------------------------------------

    -------------------------------------------------------------------------------------------------

    ///////////////////////////////////////////////////////////////////////////////
    // //
    // DirectSound Mixer //
    // //
    // V1.0 by lob_b@hotmail.com 1999 //
    // //
    // with core inputs from //
    // Stack-Up //
    // V1.0 ?Tool@theWaterCooler.com 1998 //
    // http://www.theWaterCooler.com/Tool //
    // also Petr.Stejskal@vslib.cz //
    // //
    ///////////////////////////////////////////////////////////////////////////////

    // DSBuffer.cpp : Implementation of CDSBuffer class
    //

    #include "stdafx.h"
    #include "DSBuffer.h"

    #ifdef _DEBUG
    #define new DEBUG_NEW
    #undef THIS_FILE
    static char THIS_FILE[] = __FILE__;
    #endif

    /////////////////////////////////////////////////////////////////////////////
    // CDSBuffer

    CDSBuffer::CDSBuffer()
    {
    // Reset the sound buffer
    m_lpDSBuffer = NULL;

    // Reset the 3D buffer
    m_lpDS3DBuffer = NULL;
    }

    CDSBuffer::CDSBuffer(const char *FileName, LPDIRECTSOUND lpDS, DWORD dwFlags)
    {
    // Reset the sound buffer
    m_lpDSBuffer = NULL;

    // Reset the 3D buffer
    m_lpDS3DBuffer = NULL;

    // Open the wave file
    FILE* pFile = fopen(FileName, "rb");
    if(!pFile)
    return;

    // Read in the wave header
    WaveHeader wavHdr;
    if (fread(&wavHdr, sizeof(wavHdr), 1, pFile) != 1)
    {
    fclose(pFile);
    return;
    }

    // Figure out the size of the data region
    DWORD dwSize = wavHdr.dwDSize;

    // Is this a stereo or mono file?
    BOOL bStereo = wavHdr.wChnls > 1 ? true : false;

    // Create the sound buffer for the wave file
    if(CreateSoundBuffer(lpDS, dwFlags, dwSize, wavHdr.dwSRate, wavHdr.BitsPerSample, wavHdr.wBlkAlign, bStereo))
    {
    // Read the data for the wave file into the sound buffer
    if (!ReadData(pFile, dwSize, sizeof(wavHdr)))
    AfxMessageBox("Error - DS - Reading Data");
    else if (dwFlags & DSBCAPS_CTRL3D)
    {
    // Get pointer to 3D buffer
    if (S_OK != m_lpDSBuffer->QueryInterface(IID_IDirectSound3DBuffer, (void **)&m_lpDS3DBuffer))
    AfxMessageBox("DirectSound3DBuffer not available");
    }
    }

    fclose(pFile);
    }


    CDSBuffer::~CDSBuffer()
    {
    StopSound();
    if(m_lpDSBuffer)
    {
    m_lpDSBuffer->Release();
    }

    if(m_lpDS3DBuffer)
    {
    m_lpDS3DBuffer->Release();
    }
    }


    BOOL CDSBuffer::CreateSoundBuffer(LPDIRECTSOUND lpDS, DWORD dwFlags, DWORD dwBufSize, DWORD dwFreq, DWORD dwBitsPerSample, DWORD dwBlkAlign, BOOL bStereo)
    {
    PCMWAVEFORMAT pcmwf;
    DSBUFFERDESC dsbdesc;

    // Set up wave format structure.
    memset( &pcmwf, 0, sizeof(PCMWAVEFORMAT) );
    pcmwf.wf.wFormatTag = WAVE_FORMAT_PCM;
    pcmwf.wf.nChannels = bStereo ? 2 : 1;
    pcmwf.wf.nSamplesPerSec = dwFreq;
    pcmwf.wf.nBlockAlign = (WORD)dwBlkAlign;
    pcmwf.wf.nAvgBytesPerSec = pcmwf.wf.nSamplesPerSec * pcmwf.wf.nBlockAlign;
    pcmwf.wBitsPerSample = (WORD)dwBitsPerSample;

    // Set up DSBUFFERDESC structure.
    memset(&dsbdesc, 0, sizeof(DSBUFFERDESC)); // Zero it out.
    dsbdesc.dwSize = sizeof(DSBUFFERDESC);
    dsbdesc.dwFlags = dwFlags;
    dsbdesc.dwBufferBytes = dwBufSize;
    dsbdesc.lpwfxFormat = (LPWAVEFORMATEX)&pcmwf;

    if (DS_OK != lpDS->CreateSoundBuffer(&dsbdesc, &m_lpDSBuffer, NULL))
    {
    AfxMessageBox("Error - DS - CreateSoundBuffer");
    return FALSE;
    }

    return TRUE;
    }


    BOOL CDSBuffer::ReadData(FILE* pFile, DWORD dwSize, DWORD dwPos)
    {
    // Seek to correct position in file (if necessary)
    if (dwPos != 0xffffffff)
    {
    if (fseek(pFile, dwPos, SEEK_SET) != 0)
    {
    return FALSE;
    }
    }

    // Lock data in buffer for writing
    LPVOID pData1;
    DWORD dwData1Size;
    LPVOID pData2;
    DWORD dwData2Size;
    HRESULT rval;

    rval = m_lpDSBuffer->Lock(0, dwSize, &pData1, &dwData1Size, &pData2, &dwData2Size, DSBLOCK_FROMWRITECURSOR);
    if (rval != DS_OK)
    {
    return FALSE;
    }

    // Read in first chunk of data
    if (dwData1Size > 0)
    {
    if (fread(pData1, dwData1Size, 1, pFile) != 1)
    {
    return FALSE;
    }
    }

    // read in second chunk if necessary
    if (dwData2Size > 0)
    {
    if (fread(pData2, dwData2Size, 1, pFile) != 1)
    {
    return FALSE;
    }
    }

    // Unlock data in buffer
    rval = m_lpDSBuffer->Unlock(pData1, dwData1Size, pData2, dwData2Size);
    if (rval != DS_OK)
    {
    return FALSE;
    }

    return TRUE;
    }

    BOOL CDSBuffer::PlaySound(DWORD dwFlags)
    {
    if(m_lpDSBuffer) // Make sure we have a valid sound buffer
    {
    DWORD dwStatus;
    if (DS_OK != m_lpDSBuffer->GetStatus(&dwStatus))
    {
    AfxMessageBox("Error - DS - GetStatus");
    return FALSE;
    }

    if((dwStatus & DSBSTATUS_PLAYING) != DSBSTATUS_PLAYING)
    {
    if (DS_OK != m_lpDSBuffer->Play(0, 0, dwFlags)) // Play the sound
    {
    AfxMessageBox("Error - DS - Play");
    return FALSE;
    }
    }
    }

    return TRUE;
    }

    BOOL CDSBuffer::StopSound()
    {
    if(m_lpDSBuffer) // Make sure we have a valid sound buffer
    {
    DWORD dwStatus;
    if (DS_OK != m_lpDSBuffer->GetStatus(&dwStatus))
    {
    AfxMessageBox("Error - DS - GetStatus");
    return FALSE;
    }

    if ((dwStatus & DSBSTATUS_PLAYING) == DSBSTATUS_PLAYING)
    {
    if (DS_OK != m_lpDSBuffer->Stop()) // Stop the sound
    {
    AfxMessageBox("Error - DS - Stop");
    return FALSE;
    }

    }
    }
    return TRUE;
    }


    BOOL CDSBuffer::IsValid()
    {
    if (m_lpDSBuffer)
    return TRUE;
    else
    return FALSE;
    }

    -------------------------------------------------------------------------------------------------

    -------------------------------------------------------------------------------------------------

    // DSList.h : Definition of CDSList class
    //

    #if !defined(AFX_DSLIST_H__7517D749_96E3_11D2_BBF3_9EB4940D843C__INCLUDED_)
    #define AFX_DSLIST_H__7517D749_96E3_11D2_BBF3_9EB4940D843C__INCLUDED_

    #if _MSC_VER > 1000
    #pragma once
    #endif // _MSC_VER > 1000

    #include "DSBuffer.h"

    class CDSList : virtual protected CObList
    {
    // Attribute
    private:
    LPDIRECTSOUND m_lpDS; // DirectSound Object

    // Construction / Destruction
    public:
    CDSList();
    ~CDSList();

    // Methods
    public:
    BOOL Init();
    BOOL StopAllBuffers();
    BOOL AddNewBuffer(const char* FileName);
    BOOL RemoveBuffer(int nBuffer);
    BOOL PlayBuffer(int nBuffer, DWORD dwFlags);
    BOOL StopBuffer(int nBuffer);
    LPDIRECTSOUND GetDSObject() {return m_lpDS;}
    };

    #endif // !defined(AFX_DSLIST_H__7517D749_96E3_11D2_BBF3_9EB4940D843C__INCLUDED_)

    -------------------------------------------------------------------------------------------------

    -------------------------------------------------------------------------------------------------

    ///////////////////////////////////////////////////////////////////////////////
    // //
    // DirectSound Mixer //
    // //
    // V1.0 by lob_b@hotmail.com 1999 //
    // //
    // with core inputs from //
    // Stack-Up //
    // V1.0 ?Tool@theWaterCooler.com 1998 //
    // http://www.theWaterCooler.com/Tool //
    // also Petr.Stejskal@vslib.cz //
    // //
    ///////////////////////////////////////////////////////////////////////////////

    // DSList.cpp : Implementation of CDSList class
    //

    #include "stdafx.h"
    #include "DSList.h"

    #ifdef _DEBUG
    #define new DEBUG_NEW
    #undef THIS_FILE
    static char THIS_FILE[] = __FILE__;
    #endif

    /////////////////////////////////////////////////////////////////////////////
    // CDSList

    CDSList::CDSList()
    {
    // Reset the DirectSound pointer
    m_lpDS = NULL;
    }


    CDSList::~CDSList()
    {
    // Stop all playing buffers
    StopAllBuffers();

    if(m_lpDS)
    {
    m_lpDS->Release();
    }
    }


    BOOL CDSList::Init()
    {
    // Create DirectSound Object
    if (DS_OK != DirectSoundCreate(NULL, &m_lpDS, NULL))
    {
    AfxMessageBox("Error - DS - Create/nAudio cannot be used");
    return FALSE;
    }

    // Set Cooperative Level
    if (DS_OK != m_lpDS->SetCooperativeLevel(*AfxGetMainWnd(), DSSCL_NORMAL))
    {
    AfxMessageBox("Error - DS - SetCooperativeLevel");
    return FALSE;
    }

    return TRUE;
    }


    BOOL CDSList::AddNewBuffer(const char* FileName)
    {
    // Make sure that audio is initialized
    if (!m_lpDS)
    {
    AfxMessageBox("Error - DS - Audio not initialized");
    return FALSE;
    }

    // Try creating the new buffer
    CDSBuffer* pNewBuffer = new CDSBuffer(FileName, m_lpDS);

    // If succesfull add to playlist
    if (pNewBuffer->IsValid())
    {
    AddTail(pNewBuffer);
    return TRUE;
    }

    // Else forget it
    else
    {
    delete(pNewBuffer);
    return FALSE;
    }
    }


    BOOL CDSList::RemoveBuffer(int nBuffer)
    {
    // Make sure that the buffer index is valid
    if ((nBuffer < 0) || (nBuffer >= GetCount()))
    {
    AfxMessageBox("Error - DS - Invalid buffer selection index");
    return FALSE;
    }

    // First stop the buffer
    if (StopBuffer(nBuffer))
    {
    // Find the buffer
    POSITION Pos = FindIndex(nBuffer);

    // Remove it
    RemoveAt(Pos);
    return TRUE;
    }
    return FALSE;
    }


    BOOL CDSList::PlayBuffer(int nBuffer, DWORD dwFlags)
    {
    // Make sure that the buffer index is valid
    if ((nBuffer < 0) || (nBuffer >= GetCount()))
    {
    AfxMessageBox("Error - DS - Invalid buffer selection index");
    return FALSE;
    }

    // Find the buffer
    POSITION Pos = FindIndex(nBuffer);

    // Retrieve a pointer
    CDSBuffer* DSBuffer = (CDSBuffer *)GetAt(Pos);

    // Try playing it
    return DSBuffer->PlaySound(dwFlags);
    }


    BOOL CDSList::StopBuffer(int nBuffer)
    {
    // Make sure that the buffer index is valid
    if ((nBuffer < 0) || (nBuffer >= GetCount()))
    {
    AfxMessageBox("Error - DS - Invalid buffer selection index");
    return FALSE;
    }

    // Find the buffer
    POSITION Pos = FindIndex(nBuffer);

    // Retrieve a pointer
    CDSBuffer* DSBuffer = (CDSBuffer *)GetAt(Pos);

    // Try stopping it
    return DSBuffer->StopSound();
    }


    BOOL CDSList::StopAllBuffers()
    {
    for (POSITION Pos = GetHeadPosition(); Pos != NULL; )
    {
    CDSBuffer* DSBuffer = (CDSBuffer *)GetNext(Pos);
    DSBuffer->StopSound();
    }
    return TRUE;
    }

    -------------------------------------------------------------------------------------------------

    代码使用方法:

    1、首先把四个文件添加到工程中。

    2、包含相应的头文件,在自己的代码中添加如下代码:

    #include "DSList.h"

    3、链接DirectSound的相关静态链接库

    在自己的代码中加入如下静态链接代码:
    //连接LIB库
    #pragma comment (lib,"winmm.lib")
    #pragma comment(lib,"dxguid.lib")
    #pragma comment(lib,"dsound.lib")

    4、在初始化代码中载入波形文件到缓冲区:

    代码示例:


    //初始化DirectSound混音器;
    m_dslist.Init ();
    m_dslist.AddNewBuffer(GetAppPath()+"//sound//one.wav");
    m_dslist.AddNewBuffer(GetAppPath()+"//sound//two.wav");
    m_dslist.AddNewBuffer(GetAppPath()+"//sound//three.wav");

    5、在需要播放声音的时候调用:m_dslist.PlayBuffer(index,0);

    index参数指的是添加缓冲区索引,最先添加的缓冲区索引为0,依此类推。

    该函数是异步执行,自动与以前调用该函数所产生的尚未结束的声音混音输出。

  • 相关阅读:
    d3js 添加数据
    d3js 画布 概念
    Python中的 socket示例
    swift学习笔记
    加密原理介绍,代码实现DES、AES、RSA、Base64、MD5
    socket编程中客户端常用函数
    WBS 与 甘特图
    C/C++ 数据结构之算法
    Linux集群服务 LVS
    Linux内核架构与底层--读书笔记
  • 原文地址:https://www.cnblogs.com/lzhitian/p/2348601.html
Copyright © 2020-2023  润新知