想同时播放两个wav文件,一个耳朵听一个

Arid 2001-12-31 11:45:43
左右声道分别播放不同的WAV文件如何实现
...全文
150 11 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
sdsuper 2001-12-31
  • 打赏
  • 举报
回复
左声道
右声道
不知道
sayu_yangyou 2001-12-31
  • 打赏
  • 举报
回复
impossible
xiaqq 2001-12-31
  • 打赏
  • 举报
回复
不可能吧?
呵呵
设备支持吗?
如果行的话,麻烦告诉我一声!
呵呵
qqxia@263.net
zhuang094 2001-12-31
  • 打赏
  • 举报
回复
呵呵,说了好大一堆。我来学习。
vc_xiaoxin 2001-12-31
  • 打赏
  • 举报
回复
转载一篇 DirectSound,希望能有帮助

第一节 关于声音
  声音是空气的一系列振荡,称为声波,一般可以用二维的波形图来表示。数字音频是指使用某种设备将声波记录下来并保存为一种数字化的文件。播放相应的文件就可以产生某种声音效果。数字音频的音质随着采样频率及所使用的位数不同而有很大的差异。因此,了解所使用音频文件格式的有关标准是很有必要的。例如,CD中的音频是16位,采样频率达到44.1MHz的立体声数字音频。
  在所有声音文件的格式中,WAV是最普遍的。这是Windows平台上最常见的格式,由微软公司创造。支持8位和16位的音质、多样本、对立体声和单声道音频均可播放。它还支持多种音频压缩算法。
  要在游戏中取得好的声音效果,例如,使用3D音效,可以有两种方法来实现:一是使用一定的工具软件对声音文件进行处理,生成播放效果足够好的文件,然后在游戏程序中直接将这样的文件播放。显然,这样比较简单,但是不灵活。如果需要音效随着游戏场景的变化而不断改变,且不受所具有声音文件数量的限制,就需要进行实时混音了。



第二节DirectSound结构


DirectSound的功能模块包括播放、声音缓冲区、三维音效、音频抓获、属性集等。
DirectSound playback建构于IDirectSound COM接口之上。IDirectSoundBuffer,IDirectSound3DBuffer和IDirectSound3DListener接口则用以实现对声音缓冲区和三维音效的操作。
DirectSound capture建构于IDirectSoundCapture和IDirectSoundCaptureBuffer COM接口之上。
其它的COM接口,如IKsPropertySet,使应用程序能够从声卡的扩展功能中最大地受益。
最后,IDirectSoundNotify接口用于在播放或音频抓获达到一定地方时向产生一个事件。


第三节 播放功能概述
  DirectSound缓冲区对象表示一个包含声音数据的缓冲区,这些数据以PCM格式被存储。该对象不仅可以用于开始、停止或暂停声音的播放,还能够设置声音数据中诸如频率和格式等属性。
  缓冲区分为主缓冲区和副缓冲区。主缓冲区中是听者将要听到的音频信号,一般是将副缓冲区中信号混音后的结果。而副缓冲区中存放着许多单独的声音信号,有的可以直接播放,有的要混音,有的循环播放。主缓冲区由DirectSound自动创建,而副缓冲区需由应用程序来创建。DirectSound将副缓冲区中的声音混合后,存入主缓冲区,再输出到相应播放设备。
 DirectSound中没有解析声音文件的功能,需要您自己在应用程序中将不同格式的声音信号改变(PCM)。
缓冲区可以在主板的RAM、波表存储器、DMA通道或虚拟存储器中。
  多个应用程序可以用同一声音设备来创建DirectSound对象。当输入焦点在应用程序中发生变化时,音频输出将自动在各个应用程序的流之间切换。于是,应用程序不用在输入焦点改变中反复地播放和停止它们的缓冲区。
  通过IDirectSoundNotify接口,当播放到了一个用户指定的地方,或播放结束时,DirectSound将动态地通知拥护这一事件。

第四节 音频抓获概述
  DirectSoundCapture对象可以查询音频抓获设备的性能,并为从输入源抓获音频而创建缓冲区。
  其实,在Win32中早已经有了抓获音频的功能,而目前的(版本5)DirectSoundCapture与只比较并没有什么新的功能。不过,DirectSoundCapture API使您能够编写使用相同接口的播放和音频抓获程序,而且,这也为将来可能出现的API改进提供了原始模型,使您可以从中受益。
  DirectSoundCapture还能够抓获压缩格式的音频。
  DirectSoundCaptureBuffer对象表示一个用于抓获音频的缓冲区。它可以循环利用,也就是说,当输入指针达到缓冲区的最后时,它会回到开始的地方。
DirectSoundCaptureBuffer对象的各种方式使您能够设定缓冲区的属性、开始或停止操作、锁定某部分存储器(这样就可以安全地将这些数据保存或用于其它目的)。
与播放类似,IDirectSoundNotify接口使在输入指针到达一定地方时通知用户。

第五节 初始化
  对于一些简单的操作,可以使用缺省的首选设备。不过,在游戏的制作中,我们可能还是需要知道一些特定的声音设备。于是,您应该先列举出可用的声音设备。
  在此之前,您需要先设定一个回收函数,在每一次DirectSound发现新设备后调用该函数。函数中您可以做任何事情,但您必须将它定义得与DSEnumCallback形式相同。如果希望列举继续,函数应返回真,否则返回假。
下面的例程来自光盘Example目录下的Dsenum.c文件。它列举可用的设备并在一个列表框中增加一条相应的信息。首先是他的回收函数:

BOOL CALLBACK DSEnumProc(LPGUID lpGUID,
LPCTSTR lpszDesc,
LPCTSTR lpszDrvName,
LPVOID lpContext )
{
HWND hCombo = *(HWND *)lpContext;
LPGUID lpTemp = NULL;

if( lpGUID != NULL )
{
if(( lpTemp = LocalAlloc( LPTR, sizeof(GUID))) == NULL )
return( TRUE );

memcpy( lpTemp, lpGUID, sizeof(GUID));
}

ComboBox_AddString( hCombo, lpszDesc );

ComboBox_SetItemData( hCombo,
ComboBox_FindString( hCombo, 0, lpszDesc ),
lpTemp );
return( TRUE );
}

当包含了列表框的对话框被初始化后,列举开始:

if (DirectSoundEnumerate((LPDSENUMCALLBACK)DSEnumProc, &hCombo)
!= DS_OK )
{
EndDialog( hDlg, TRUE );
return( TRUE );
}

创建DirectSound对象最简单的方法是使用DirectSoundCreate函数。其中的第一个参数为相应设备的全局独有标志符(GUID)。您可以通过列举声音设备得到GUID,或使用NULL来为缺省设备创建对象。

LPDIRECTSOUND lpDirectSound;
HRESULT hr;
hr = DirectSoundCreate(NULL, &lpDirectSound, NULL));

创建DirectSound对象后,应设置合作层。这是为了确定各个DirectSound应用程序被允许操作声音设备的范围,防止它们在错误的时间或通过错误的方式操作设备。
所使用的方式为IDirectSound::SetCooperativeLevel。这里hwnd参数是应用程序窗口的句柄:

HRESULT hr = lpDirectSound->lpVtbl->SetCooperativeLevel(
lpDirectSound, hwnd, DSSCL_NORMAL);

这里确定的合作层为normal,这样使用声卡的应用程序可以顺序地进行切换。合作层包括
Normal、Priority、Exclusive和Write-primary,级别依次增加。
正如在前面提到过,DirectSound可以充分发挥硬件的增强功能,因此,它需要先设法了解设备的特性。我们可以通过IDirectSound::GetCaps方式来达到这个要求。如下所示:

DSCAPS dscaps;

dscaps.dwSize = sizeof(DSCAPS);
HRESULT hr = lpDirectSound->lpVtbl->GetCaps(lpDirectSound,
&dscaps);

DSCAPS结构接收关于声音设备性能和资源的信息。注意,初始化该结构中dwSize成员是调用它之前所必须的。
除此之外,您还可以查询和设定扬声器的设置,以及整理声音存储器使尽量获得最大的备用空间。



第六节 如何播放
  初始化完成后,DirectSound将自动创建主缓冲区用于混音并传送至输出设备。而副缓冲区则需要您自己来创建了。
下面的例程演示了用IDirectSound::CreateSoundBuffer方式创建一个基本的副缓冲区:

BOOL AppCreateBasicBuffer(
LPDIRECTSOUND lpDirectSound,
LPDIRECTSOUNDBUFFER *lplpDsb)
{
PCMWAVEFORMAT pcmwf;
DSBUFFERDESC dsbdesc;
HRESULT hr;
// 设定声波格式结构
memset(&pcmwf, 0, sizeof(PCMWAVEFORMAT));
pcmwf.wf.wFormatTag = WAVE_FORMAT_PCM;
pcmwf.wf.nChannels = 2;
pcmwf.wf.nSamplesPerSec = 22050;
pcmwf.wf.nBlockAlign = 4;
pcmwf.wf.nAvgBytesPerSec =
pcmwf.wf.nSamplesPerSec * pcmwf.wf.nBlockAlign;

pcmwf.wBitsPerSample = 16;
// 设置DSBUFFERDESC结构,用以设定缓冲区控制选项
memset(&dsbdesc, 0, sizeof(DSBUFFERDESC));
dsbdesc.dwSize = sizeof(DSBUFFERDESC);
// 要求缺省的控制
dsbdesc.dwFlags = DSBCAPS_CTRLDEFAULT;
// 3秒的缓冲区
dsbdesc.dwBufferBytes = 3 * pcmwf.wf.nAvgBytesPerSec;
dsbdesc.lpwfxFormat = (LPWAVEFORMATEX)&pcmwf;
// 创建缓冲区
hr = lpDirectSound->lpVtbl->CreateSoundBuffer(lpDirectSound,

&dsbdesc, lplpDsb, NULL);
if(DS_OK == hr) {
// 成功,获得的接口在*lplpDsb当中
return TRUE;
} else {
// 失败
*lplpDsb = NULL;
return FALSE;
}
}

  您必须设定缓冲区的控制选项。这是使用DSBUFFERDESC结构中的dwFlags成员,具体细节请参见DirectX 5的帮助。副缓冲区不支持混音等特效,因此,您需要能够直接操作主缓冲区。不过,当您获权写主缓冲区时,其它特性将失去作用,从而硬件加速混音失效。所以,大部分应用程序几少直接操作主缓冲区。
  如果要求操作主缓冲区,可以在调用IDirectSound::CreateSoundBuffer方式时设定DSBUFFERDESC结构中的DSBCAPS_PRIMARYBUFFER标志符,而且,合作层必须是Write-primary。
下面的例程演示了如何得到对主缓冲区的写操作能力:

BOOL AppCreateWritePrimaryBuffer(
LPDIRECTSOUND lpDirectSound,
LPDIRECTSOUNDBUFFER *lplpDsb,
LPDWORD lpdwBufferSize,
HWND hwnd)
{
DSBUFFERDESC dsbdesc;
DSBCAPS dsbcaps;
HRESULT hr;
// 设置声波格式结构
memset(&pcmwf, 0, sizeof(PCMWAVEFORMAT));
pcmwf.wf.wFormatTag = WAVE_FORMAT_PCM;
pcmwf.wf.nChannels = 2;
pcmwf.wf.nSamplesPerSec = 22050;
pcmwf.wf.nBlockAlign = 4;
pcmwf.wf.nAvgBytesPerSec =

pcmwf.wf.nSamplesPerSec * pcmwf.wf.nBlockAlign;
pcmwf.wBitsPerSample = 16;
// 设置DSBUFFERDESC结构
memset(&lplpDsb, 0, sizeof(DSBUFFERDESC));
dsbdesc.dwSize = sizeof(DSBUFFERDESC);
dsbdesc.dwFlags = DSBCAPS_PRIMARYBUFFER;
// 缓冲区大小由声音硬件决定
dsbdesc.dwBufferBytes = 0;
dsbdesc.lpwfxFormat = NULL; // 对主缓冲区必须设为NULL

// 获得write-primary合作层

hr = lpDirectSound->lpVtbl->SetCooperativeLevel(lpDirectSound,
hwnd, DSSCL_WRITEPRIMARY);
if (DS_OK == hr) {
// 成功,试图创建缓冲区
hr = lpDirectSound->lpVtbl->CreateSoundBuffer(lpDirectSound,
&dsbdesc, lplpDsb, NULL);
if (DS_OK == hr) {
// 成功,设定主缓冲区为desired格式
hr = (*lplpDsb)->lpVtbl->SetFormat(*lplpDsb, &pcmwf);
if (DS_OK == hr) {

// 如果希望得知缓冲区大小,调用GetCaps
dsbcaps.dwSize = sizeof(DSBCAPS);
(*lplpDsb)->lpVtbl->GetCaps(*lplpDsb, &dsbcaps);
*lpdwBufferSize = dsbcaps.dwBufferBytes;
return TRUE;
}
}
}
// 设定合作层失败
// 创建缓冲区,或设定结构
*lplpDsb = NULL;
*lpdwBufferSize = 0;
return FALSE;
}

播放一段声音的过程包括以下四个步骤:
1 锁定(IDirectSoundBuffer::Lock)副缓冲区的一部分。由您设定的偏移量决定下一步写操作的起始点;
2 写数据;
3 解锁(IDirectSoundBuffer::Unlock);
4 将声音传送给主缓冲区,并由那里输出(IDirectSoundBuffer::Play)。
下面的C程序向缓冲区中写入数据,由dwOffset指定开始时的偏移量:

BOOL AppWriteDataToBuffer(
LPDIRECTSOUNDBUFFER lpDsb, // DirectSound缓冲区
DWORD dwOffset, // 自己的写标记位置
LPBYTE lpbSoundData, // 数据的起点
DWORD dwSoundBytes) // 拷贝块的大小
{
LPVOID lpvPtr1;
DWORD dwBytes1;
LPVOID lpvPtr2;
DWORD dwBytes2;
HRESULT hr;
// 得到被写块的地址
hr = lpDsb->lpVtbl->Lock(lpDsb, dwOffset, dwSoundBytes, &lpvPtr1,

&dwBytes1, &lpvPtr2, &dwBytes2, 0);

// 如果返回DSERR_BUFFERLOST,释放并重试锁定
if(DSERR_BUFFERLOST == hr) {
lpDsb->lpVtbl->Restore(lpDsb);
hr = lpDsb->lpVtbl->Lock(lpDsb, dwOffset, dwSoundBytes,
&lpvPtr1, &dwAudio1, &lpvPtr2, &dwAudio2, 0);
}
if(DS_OK == hr) {
// 写到指针
CopyMemory(lpvPtr1, lpbSoundData, dwBytes1);
if(NULL != lpvPtr2) {
CopyMemory(lpvPtr2, lpbSoundData+dwBytes1, dwBytes2);

}
// 释放
hr = lpDsb->lpVtbl->Unlock(lpDsb, lpvPtr1, dwBytes1, lpvPtr2,
dwBytes2);
if(DS_OK == hr) {
// 成功
return TRUE;
}
}
// 某步骤失败
return FALSE;
}


my_555 2001-12-31
  • 打赏
  • 举报
回复
up!
Leo 2001-12-31
  • 打赏
  • 举报
回复
用最简单的WAVE类函数,读取WAVE文件的数据,分别放到左右声道
必要时做格式转换,是一定可实现的
Arid 2001-12-31
  • 打赏
  • 举报
回复
u______p
Arid 2001-12-31
  • 打赏
  • 举报
回复
u______p
Arid 2001-12-31
  • 打赏
  • 举报
回复
谢谢各位捧场

如何知道硬件是否支持呢??
哪儿有direct sound 混音的资料下栽??
cjj 2001-12-31
  • 打赏
  • 举报
回复
有两种途径能实现同时播放:
1。需要硬件芯片支持,大部分台式机声卡的wave播放是独占方式的(如创新声卡),而笔记本的很多声卡支持硬件混音,别说两个,就是再多几个Wave文件都可以一起放;
2。使用Direct Sound混音,在游戏中常用,网上资料也很多,就不用多说了

呵呵
软件名称:Monkey's Audio 软件版本:4.06 运行环境:WinALL 汉化类型:汉化安装版 软件性质:免费 官方主页:http://www.monkeysaudio.com ━━━━━━━━━━━━━━━ 软件简介 ━━━━━━━━━━━━━━━ Monkey's Audio(http://www.monkeysaudio.com)是一种无损压缩技术。他并不是由什么大公司发明的,完全是一个个人业余兴趣作品。为了使Monkey's Audio能有更好的发展,现在这个软件已经公开了源代码。   这种压缩格式的特点是无损压缩,也就是说对压缩数据进行还原之后得到的数据与原来的数据是完全相同的。该格式的特点尤其适合那些拥有一对“金耳朵”并且一直对mp3的音质耿耿于怀的音乐发烧友。后者有人会问,要无损压缩,我随便找个压缩软件比如WINRAR都可以达到不错的效果了,还要这种格式干嘛? 所以这里要澄清一个误解:使用普通的压缩软件进行压缩无疑是可以得到不错的压缩效果,有时候甚至更优于使用Monkey's Audio,但是压缩软件生成的压缩包必须要先解压还原之后才能播放里面的内容,而Monkey's Audio这种无损压缩编码得到的文件可以直接使用播放器(比如WinAMP)进行播放。Monkey's Audio的压缩效果大约在2:1左右,也就是说压缩结果是原来的二分之一大小。一张CD大约需要330MB左右的空间存放,相比之下还是比较占空间的。由于这个原因,所以对音质要求不是太高的人通常都选择VBR方式的mp3而不是选择它。   与Monkey's Audio类似的编码格式还包括WavPack、RKAU、Shorten等等。由于相对不是那么出名,又或者在某些方面不够Monkey's Audio做得好,因此获得的关注程度就逊色很多。   Monkey's Audio 软件在Monkey‘s Audio官方网站可以下载,专用于压缩wav文件为ape文件或解压ape文件wav文件   Monkey's Audio 是一种快速且易于操作的数字音乐压缩方案,它所生成的 APE 无损压缩格式,压缩率接近50%,压缩后的品质跟原始声音的品质完全是一样的(据说有人将 Wav 文件生成 APE 格式后,再转换回 Wav 文件,结果对比两个Wav 文件的 MD5 值时,发现居然完全一样)!   APE 无损压缩音频格式已被绝大多数音频播放器如:Winamp、Media Jukebox以及越来越多的应用程序支持。Monkey's Audio 是 APE 的压缩、解压缩、转换操作的平台。   本汉化安装版包括了原版的一切组件,无需原版文件,另外,用于 Winamp的APE插件安装程序也替换为汉化版。 ━━━━━━━━━━━━━━━ 汉化历程 ━━━━━━━━━━━━━━━ 2006.01.11 发布 Monkey's Audio 4.01 b1 汉化版 2006.03.14 发布 Monkey's Audio 4.01 b2 汉化版 2009.02.02 发布 Monkey's Audio 4.03 汉化版 2009.02.03 发布 Monkey's Audio 4.04 汉化版 2009.02.05 发布 Monkey's Audio 4.05 汉化版 2009.03.19 发布 Monkey's Audio 4.06 汉化版

16,548

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • AIGC Browser
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧