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,依此类推。

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

 

转载于:https://www.cnblogs.com/lzhitian/archive/2012/02/13/2348601.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/296052.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Codeforces Round #330 (Div. 2) B. Pasha and Phone 容斥定理

B. Pasha and Phone Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/595/problem/B Description Pasha has recently bought a new phone jPager and started adding his friends phone numbers there. Each phone number consists of exact…

美女晕倒怎么办?二哈:这不是一滋就醒......

1 永远不要质疑二哈▼2 睡觉也不耽误练功▼3 谁还没为数学考试受过伤呢&#xff1f;▼4 可能我的嘴巴安装了笑话过滤器吧▼5 我书读得少&#xff0c;你别吓唬我▼6 希望狗没事儿▼7 海王的微信壁纸事实证明&#xff0c;会计确实不赚钱▼你点的每个赞&#xff0c;我都认真…

linux at java,Linux-Tutorial/Java-bin.md at master · linsanityHuang/Linux-Tutorial · GitHub

Java bin 目录下的工具JVM 内存结构运行时数据区(JVM 规范)VM 栈(JVM 虚拟机栈)是线程私有的&#xff0c;它的生命周期和线程相同。它描述的是 Java 方法执行的内存模式。Java 堆区(Heap)是 Java 虚拟机所管理的内存中最大的一块。是被所有线程共享的一块内存区域&#xff0c;在…

如何在 C# 中使用 FTP 上传文件

咨询区 webvision&#xff1a;我尝试用 C# 上传一个文件到 FTP-Server 上&#xff0c;文件已显示上传成功但显示 0Byte&#xff0c;我的代码大概是这样的。private void button2_Click(object sender, EventArgs e) {var dirPath "C:/Documents and Settings/sander.GD/B…

POJ 3274 Gold Balanced Lineup(哈希)

题目链接 很难想。会哈希&#xff0c;但是想不出。需要一个转化&#xff0c;本来是求某一段上的二进制上每一位的1数目相等&#xff0c;转化为找两段相等的&#xff0c;换元可推出公式。最后注意特判。。 1 #include <iostream>2 #include <cstdio>3 #include <…

java Ant build.xml

Java Ant build.xml详解1,什么是antant是构建工具 2,什么是构建 概念到处可查到&#xff0c;形象来说&#xff0c;你要把代码从某个地方拿来&#xff0c;编译&#xff0c;再拷贝到某个地方去等等操作&#xff0c;当然不仅与此&#xff0c;但是主要用来干这个 3,ant的好处 跨平台…

15℃!人类首次实现高压下室温超导,研究登上Nature封面

全世界只有3.14 % 的人关注了爆炸吧知识本文转自&#xff1a;机器之心今天一项新纪录&#xff0c;轰动整个物理界。「室温超导有可能实现吗&#xff1f;」这个问题困惑了人们许多年。而最新一期的 Nature 杂志封面研究给出了肯定的答案&#xff0c;该研究制造出了第一个无需冷却…

系统日子打印记录

#import <Foundation/Foundation.h>//DmLog----------------------------- #define DmLog_TYPE_1 1 //日志打印 1:开/0:关 #define __DmLOGWITHFUNCTION(s, ...) \ NSLog("%s : %",__FUNCTION__,[NSString stringWithFormat:(s), #…

linux下ui c语言编程,编写的C语言程序,怎么样制作一个UI界面?

c语言制作UI界面需要相关的UI库如windows操作系统本身就提供了UI的接口一个简单的示例代码如下#include LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);int WINAPI WinMain(HINSTANCE hinstance,HINSTANCE hprevinstance,LPSTR line,int cmd){ static TCHAR AppName[]TEX…

使用自定义卫语句写出更简洁的代码

前言上次&#xff0c;我们介绍了Pitcher,可以帮我们简化卫语句&#xff1a;public User(string name, int age) {Throw.When(string.IsNullOrWhiteSpace(name), new ArgumentNullException(nameof(name)));Throw.When(age < 0, new ArgumentOutOfRangeException(nameof(age)…

Struts2的ResultType和Action处理链

Struts2的ResultType和Action处理链Struts2的结果类型在struts-default.xml中定义了Struts2内置的所有可用的<result-type/> 所有的Struts2结果处理类都要直接或间接的实现com.opensymphony.xwork2.Result接口 在struts-default.xml中的<result-types/>里面&#x…

git fork

http://help.github.com/fork-a-repo/ 概要&#xff1a; 克隆别人的代码库到自己的项目中&#xff0c;可以作为子模块的形式使用&#xff0c;或二次开发 操作流程&#xff1a; 在开源项目中点击fork按钮&#xff0c;稍等一会儿&#xff0c;该项目便会拷贝一份到你的respositori…

转软件开发过程中的各种文档

在项目开发过程中&#xff0c;应该按要求编写好十三种文档&#xff0c;文档编制要求具有  针对性、精确性、清晰性、完整性、灵活性、可追溯性。   ◇ 可行性分析报告&#xff1a;     说明该软件开发项目的实现在技术上、经济上和社会因素上的可行性&#xff0c;评述 …

【ACR2015】依那西普按需维持治疗策略有效抑制RA骨破坏进展

标签: 类风湿关节炎; 依那西普; 药物减停; 复发重治 对RA疾病复发患者, 依那西普按需治疗与持续足剂量治疗是否存在疗效差异&#xff1f; Inui K, et al. ACR 2015. Presentation ID: 477. 背景/目的: 生物DMARDs&#xff08;bDMARDs&#xff09;对RA治疗而言非常重要, 尤其对…

堪称经典!这部由苏联最杰出数学家编写的数学教材,为何能大受推崇?

全世界只有3.14 % 的人关注了爆炸吧知识安德列柯尔莫哥洛夫&#xff0c;20世纪苏联最杰出的数学家&#xff0c;也是20世纪世界上为数极少的几个最有影响的数学家之一。1924年他念大学四年级时就和当时的苏联数学家辛钦一起建立了关于独立随机变量的三级数定理。1928年他得到了随…

浅议NetMQ常见模式和消息加密机制

题图来自https://www.pexels.com/概述在传统企业级开发中&#xff0c;消息队列机制已经成为一种非常常见的技术实现手段&#xff0c;而基于NetMQ则看起来有点像一朵“奇葩”&#xff0c;看起来从名字似乎是一个消息队列&#xff08;Message Quene&#xff09;&#xff0c;但事实…

linux python matplotlib 使用,python绘图工具matplotlib在linux下安装和使用

工具介绍&#xff1a;matplotlib 是Python编程语言的一个绘图库及其数值数学扩展 NumPy。它为利用通用的图形用户界面工具包&#xff0c;如Tkinter, wxPython, Qt或GTK向应用程序嵌入式绘图提供了面向对象的应用程序接口(API)。还有一个基于状态机(如开放图形库OpenGL)的程序py…

Struts2的Interceptor和Listener以及Plugin

Struts2的Interceptor和Listener以及PluginStruts2的拦截器在struts-default.xml中定义了很多拦截器&#xff0c;这些拦截器就是用来完成许多强劲功能的保证 而且可以根据已定义的若干拦截器中的某几个拦截器构建成interceptor-stack拦截器栈 其实拦截器栈还可以由拦截器栈组成…

with(nolock)简解

eg&#xff1a;select top 200 from 表A with(nolock) where 条件 为了性能&#xff0c;查询时不锁定表&#xff0c;从而达到提高查询速度的目的。 &#xff08;转&#xff09;SQL中with(nolock)详解 大家在写查询时,为了性能,往往会在表后面加一个nolock,或者是with(nolock),其…

CentOS 5.5下搭建部署独立SVN服务器全程详解

SVN服务器有2种运行方式&#xff1a; 1、独立服务器 (例如&#xff1a;svn://xxx.com/xxx)&#xff1b; 2、借助apache (例如&#xff1a;http://svn.xxx.com/xxx)&#xff1b; 为了不依赖apache&#xff0c;我选择第一种方式&#xff1a;独立的svn服务器。SVN存储版本数据也…