您的位置:首页 > 其它

用DirectX Audio和DirectShow播放声音和音乐(6)

2010-05-22 01:59 267 查看
本篇是
用DirectX Audio和DirectShow播放声音和音乐(5)
的续篇。

加载音色库(乐器)

DirectMusic
加载器在使用固有文件或者MIDI文件的时候会自动加载默认的音色库。乐器总是被一组一组地使用,很多组乐器音色的集合被称之为DLS音色库(可下载的音
乐)。每组乐器使用三个值编号,它们是:最高有效位(most-significant
byte,MSB),最低有效位(least-significant byte,LSB)和组编号。

通常播放MIDI文件的乐器组是标准化的,也就是说编号为1的乐器总是钢琴,如果想使用新的钢琴作为乐器,可以从DLS集合中加载。
DirectMusic包含了标准的乐器集合,通常称之为GM/GS集合(GM
= General MIDI,GS = General
Synthesizer),这个集合由日本罗兰(Roland)公司提出,称为MIDI合成器标准。

如果使用新的乐器取代标准MIDI乐器库中的乐器,需要确定该乐器的MSB和LSB为0,否则就需要为乐器库中的每个乐器都尝试新的赋值,以免打乱乐器库
乐器排列。如果只想修改音色库中的一对乐器,只需要将它们保存在乐器库中即可。在下次加载DLS的时候,就会自动用新修改的乐器覆盖住内存中的旧乐器,如
下图所示:



当DLS加载完成的时候,就可以通知 DirectMusic使用音色库对音乐进行播放了。

加载DLS音色库,需要从加载器中获取一个IDirectMusicCollection8对象,然后再次使用
IDirectMusicLoader8::GetObject加载音色库,但是这一次指定的是音色库对象和音色库文件名。

以下代码演示了如何加载指定的音色库:

//--------------------------------------------------------------------------------

// Load DirectMusic collection object.

//--------------------------------------------------------------------------------

IDirectMusicCollection8* Load_DLS_Collection(
char
* filename)

{

DMUS_OBJECTDESC dm_obj_desc;

IDirectMusicCollection8* dm_collection;


// get the object

ZeroMemory(&dm_obj_desc,
sizeof
(DMUS_OBJECTDESC));

dm_obj_desc.dwSize =
sizeof
(DMUS_OBJECTDESC);

dm_obj_desc.guidClass = CLSID_DirectMusicCollection;

dm_obj_desc.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH;


// Converts a sequence of multibyte characters to a corresponding sequence of wide characters

mbstowcs(dm_obj_desc.wszFileName, filename, MAX_PATH);


// retrieves an object from a file or resource and returns the speficied interface


if
(FAILED(g_dm_loader->GetObject(&dm_obj_desc, IID_IDirectMusicCollection8, (LPVOID*)&dm_collection)))


return
NULL;


return
dm_collection;

}

音色库被加载后,还需要给音乐片段指定音色库,这个工作通过设置指定的音乐片段的音轨参数来完成,设置参数使用函数
IDirectMusicSegment8::SetParam。

The SetParam
method sets data on a track inside this
segment.

Syntax

[code]HRESULT SetParam(

 REFGUID 
rguidType
,

 DWORD 
dwGroupBits
,

 DWORD 
dwIndex
,

 MUSIC_TIME 
mtTime
,

 void* 
pParam

);

[/code]
Parameters

rguidType

Reference to (C++) or address of (C) the type of data
to set.
See Standard Track Parameters.
dwGroupBits

Group that the desired track is in. Use 0xFFFFFFFF for
all
groups. For more information, see Identifying the Track.
dwIndex

Index of the track in the group identified by dwGroupBits
in which to set the data, or DMUS_SEG_ALLTRACKS to set the parameter on
all
tracks in the group that contain the parameter.
mtTime

Time at which to set the data.
pParam

Address of a structure containing the data, or NULL if
no data
is required for this parameter. The structure must be of the appropriate
kind
and size for the data type identified by rguidType
.
Return Values

If the method succeeds, the return value is S_OK.

If it fails, the method can return one of the error values shown in
the
following table.


Return code


DMUS_E_SET_UNSUPPORTED
DMUS_E_TRACK_NOT_FOUND
E_POINTER
MIDI的配置

一首歌曲如果已经和音色库一起被完整地加载到了内存中,这首音乐基本上已经可以使用了,唯一存在的问题是因为系统需要进行配置,以便适应一般MIDI文件
的配置,所以需要告诉系统加载的文件是否是一个MIDI文件。告诉DirectMusic使用的是MIDI文件,需要再一次调用参数配置函数
IDirectMusicSegment8:: SetParam。

以下代码演示了如何使用设置MIDI配置:


// retrieves an object from a file or resource and returns the speficied interface


if
(FAILED(g_dm_loader->GetObject(&dm_obj_desc, IID_IDirectMusicSegment8, (LPVOID*)&g_dm_segment)))


return
FALSE;


// setup midi playing


if
(strstr(filename, ".mid"))

{


// set data on a track inside the segment


if
(FAILED(g_dm_segment->SetParam(GUID_StandardMIDIFile, 0xFFFFFFFF, 0, 0, NULL)))


return
FALSE;

}

播放音乐的下一个准备工作就是配置音色库,将音色库装载到演奏器中,通过调用IDirectMusicSegment8::
Download函数来完成操作。

The Download
method downloads band data to a
performance or
audiopath.

Syntax

[code]HRESULT Download(

 IUnknown* 
pAudioPath

);

[/code]
Parameters

pAudioPath

Pointer to the IUnknown
interface of
the
performance or audiopath that receives the data.
Return Values

If the method succeeds, the return value is S_OK or
DMUS_S_PARTIALDOWNLOAD.
See Remarks for IDirectMusicBand8::Download
.

If it fails, the method may return one of the error values shown in
the
following table.


Return code


DMUS_E_NOT_FOUND
DMUS_E_TRACK_NOT_FOUND
E_POINTER
Remarks

All bands and waveform data in the segment are downloaded.

Always call IDirectMusicSegment8::Unload
before
releasing
the segment.

仅当音乐文件为MIDI文件的时候,才需要调用这个函数,因为该函数会改变音乐文件的信息,如果在不适当的时候强制调用该函数,会导致主音轨改变或者丢
失。如果要改变音色库(比如重新指定一个新的DLS给一个段音乐),必须首先卸载音色库数据,然后再加载新的音色库,并重新播放音乐。

以下代码示例了如何使用Download。



// downloads band data to a performance

if
(FAILED(g_dm_segment->Download(g_dm_performance)))


return
FALSE;

当完成播放或者切换音色库时,必须调用一个卸载函数IDirectMusicSegment8::Unload,用它释放音色库及其他资源。

g_pDMSegment->Unload(g_pDS);


循环和重复

在播放之前最后一个要做的工作是设置重复点和重复次数。例如有一小段音乐,希望重复播放这段音乐里的一小部分,这时就需要设置循环起始点和结束点,然后设
置重复播放次数,如下图所示:



设置循环点是IDirectMusicSegment8::SetLoopPoints函数的职责。

The SetLoopPoints
method sets the start and end
points of
the part of the segment that repeats the number of times set by the
IDirectMusicSegment8::SetRepeats

method.

Syntax

[code]HRESULT SetLoopPoints(

 MUSIC_TIME 
mtStart
,

 MUSIC_TIME 
mtEnd

);

[/code]
Parameters

mtStart

Point at which to begin the loop.
mtEnd

Point at which to end the loop. A value of 0 loops the
entire
segment.
Return Values

If the method succeeds, the return value is S_OK.

If it fails, the method can return DMUS_E_OUT_OF_RANGE.

Remarks

When the segment is played, it plays from the segment start time
until
mtEnd
, then loops to mtStart
, plays the looped portion the
number
of times set by IDirectMusicSegment8::SetRepeats
, and
then
plays to the end.

The default values are set to loop the entire segment from beginning
to end.

The method fails if mtStart
is greater than or equal to the
length
of the segment, or if mtEnd
is greater than the length of the
segment.
If mtEnd
is 0, mtStart
must be 0 as well.

This method does not affect any currently playing segment states
created from
this segment.

The loop points of a cached segment persist even if the segment is
released,
and then reloaded. To ensure that a segment is not subsequently reloaded
from
the cache, call IDirectMusicLoader8::ReleaseObject
on
it before
releasing it.

很多情况下,我们希望重复播放整首歌曲,这个时候就不需要使用SetLoopPoints函数。设置完循环点后,就可以设置重复次数了(当然,先设置重复
次数也是可以的)。如果希望音乐播放一次后就停止,设置重复次数为0,如果希望将曲目播放两次,需要将重复次数设置为1。设置重复次数使用
IDirectMusicSegment8::SetRepeats函数,这个函数只有一个参数,就是曲目重复的次数,如果将这个值设置为
DMUS_SEG_REPEAT_INFINITE,那么播放就会一直持续。

The SetRepeats
method sets the number of times the
looping
portion of the segment is to repeat.

Syntax

[code]HRESULT SetRepeats(

 DWORD 
dwRepeats

);

[/code]
Parameters

dwRepeats

Number of times that the looping portion of the
segment is to
repeat, or DMUS_SEG_REPEAT_INFINITE to repeat until explicitly stopped. A
value
of 0 specifies a single play with no repeats.
Return Values

The method returns S_OK.

播放和停止播放

如果要让演奏器播放音乐片段,只需要调用 IDirectMusicPerformance8::PlaySegmentEx函数就可以了。

The PlaySegmentEx
method begins playback of a
segment. The
method offers greater functionality than
IDirectMusicPerformance8::PlaySegment

.

Syntax

[code]HRESULT PlaySegmentEx(

 IUnknown* 
pSource
,

 WCHAR *
pwzSegmentName,

 
IUnknown* 
pTransition,

 DWORD 
dwFlags
,

 __int64 
i64StartTime
,

 IDirectMusicSegmentState** 
ppSegmentState,

 IUnknown* 
pFrom
, 

 IUnknown* 
pAudioPath

);

[/code]
Parameters

pSource

Address of the IUnknown
interface of
the
object to play.
pwzSegmentName

Reserved. Set to NULL.
pTransition

IUnknown
interface pointer of a
template
segment to use in composing a transition to this segment. Can be NULL.
See
Remarks.
dwFlags

Flags that modify the method's behavior. See
DMUS_SEGF_FLAGS

.
i64StartTime

Performance time at which to begin playing the
segment,
adjusted to any resolution boundary specified in dwFlags
. The
time is
in music time unless the DMUS_SEGF_REFTIME flag is set. A value of zero
causes
the segment to start playing as soon as possible.
ppSegmentState

Address of a variable that receives an
IDirectMusicSegmentState

interface pointer for this instance of
the
playing segment. Use QueryInterface
to obtain
IDirectMusicSegmentState8

. The reference count of the interface
is
incremented. This parameter can be NULL if no segment state pointer is
wanted.
pFrom

IUnknown
interface pointer of a
segment state
or audiopath to stop when the new segment begins playing. If it is an
audiopath,
all segment states playing on that audiopath are stopped. This value can
be
NULL. See Remarks.
pAudioPath

IUnknown
interface pointer of an
object that
represents the audiopath on which to play, or NULL to play on the
default path.
Return Values

If the method succeeds, the return value is S_OK.

If it fails, the method can return one of the error values shown in
the
following table.


Return code


DMUS_E_AUDIOPATH_INACTIVE
DMUS_E_AUDIOPATH_NOPORT
DMUS_E_NO_MASTER_CLOCK
DMUS_E_SEGMENT_INIT_FAILED
DMUS_E_TIME_PAST
E_OUTOFMEMORY
E_POINTER
如果希望停止播放,只需要调用IDirectMusicPerformance8::Stop函数就可以了。

The Stop
method stops playback of a segment or
segment
state.

This method has been superseded by IDirectMusicPerformance8::StopEx
,
which can stop playback of a segment, segment state, or audiopath.

Syntax

[code]HRESULT Stop(

 IDirectMusicSegment* 
pSegment
, 

 IDirectMusicSegmentState* 
pSegmentState
, 

 MUSIC_TIME 
mtTime
, 

 DWORD 
dwFlags

);

[/code]
Parameters

pSegment

Segment to stop playing. All segment states based on
this
segment are stopped at mtTime
. See Remarks.
pSegmentState

Segment state to stop playing. See Remarks.
mtTime

Time at which to stop the segment, segment state, or
both. If
the time is in the past or if 0 is passed in this parameter, the
specified
segment and segment states stop playing immediately.
dwFlags

Flag that indicates when the stop should occur.
Boundaries are
in relation to the current primary segment. For a list of values, see
IDirectMusicPerformance8::StopEx

.
Return Values

If the method succeeds, the return value is S_OK.

If it fails, the method can return E_POINTER.

Remarks

If pSegment
and pSegmentState
are both NULL, all
music
stops, and all currently cued segments are released. If either pSegment
or pSegmentState
is not NULL, only the requested segment states
are
removed from the performance. If both are non-NULL and DMUS_SEGF_DEFAULT
is
used, the default resolution from the pSegment
is used.

If you set all parameters to NULL or 0, everything stops immediately,
and
controller reset messages and note-off messages are sent to all mapped
performance channels.

卸载音乐数据

使用完音乐之后,第一件要做的事就是卸载音色库数据,可以通过IDirectMusicSegment8::Unload来完成。

The Unload
method unloads instrument data from a
performance
or audiopath.

Syntax

[code]HRESULT Unload(

 IUnknown *
pAudioPath

);

[/code]
Parameters

pAudioPath

Pointer to the IUnknown
interface of
the
performance or audiopath from which to unload the instrument data.
Return Values

If the method succeeds, the return value is S_OK.

If it fails, the method can return one of the error values shown in
the
following table.


Return code


DMUS_E_TRACK_NOT_FOUND
E_POINTER
Remarks

The method succeeds even if no data was previously downloaded.

还要释放加载器中的高速缓存数据,通过IDirectMusicLoader8::ReleaseObjectByUnknown来实现。

The ReleaseObjectByUnknown
method releases the
loader's
reference to an object. This method is similar to
IDirectMusicLoader8::ReleaseObject

and is suitable for
releasing
objects for which the IDirectMusicObject8
interface is
not
readily available.

Syntax

[code]HRESULT ReleaseObject(

 IUnknown * 
pObject

);

[/code]
Parameters

pObject

Address of the IUnknown
interface
pointer of
the object to release.
Return Values

If the method succeeds, the return value is S_OK, or S_FALSE if the
object
has already been released or cannot be found in the cache.

If it fails, the method can return E_POINTER.

如果开始的时候加载了音色库,现在是时候从加载器对象中将它卸载掉了,就像刚才从加载器中卸载音乐片段对象一样。另外,清空缓存很重要,有一个函数可以强
制清空整个缓存区,但是并不需要在卸载加载器前调用它,因为在卸载过程中这个操作是自动完成的。

The ClearCache
method removes all saved references
to a
specified object type.

Syntax

[code]HRESULT ClearCache(

 REFGUID 
rguidClass

);

[/code]
Parameters

rguidClass

Reference to (C++) or address of (C) the identifier of
the
class of objects to clear, or GUID_DirectMusicAllTypes to clear all
types. For a
list of standard loadable classes, see IDirectMusicLoader8
.

Return Values

The method returns S_OK.

Remarks

This method clears all objects that are currently being held, but
does not
turn off caching. Use the IDirectMusicLoader8::EnableCache
method to turn off automatic caching.

To clear a single object from the cache, call the
IDirectMusicLoader8::ReleaseObject

method.

修改音乐

在使用DirectMusic缓冲的时候,我们可以在播放音乐的时候对音乐做很多处理,比如通过DirectSound声音缓冲对象改变音量、节拍、加入
特殊效果等。



音量设置

我们可以改变两个音量设置。第一个是演奏器的音量(整个音乐系统的音量),第二个是每个音乐片段对象的回放音量。如下图所示,当每个音乐片段被加载到演奏
器中的时候,音乐片段的音量会被修改,演奏器的音量又被全局音量所影响。



演奏器音量(主音量)是一个全局参数,调用IDirectMusicPerformance8::SetGlobalParam设置。

The SetGlobalParam
method sets global values for the
performance.

Syntax

[code]HRESULT SetGlobalParam(

  REFGUID 
rguidType
, 

  void* 
pParam
, 

  DWORD 
dwSize

);

[/code]
Parameters

rguidType

Reference to (C++) or address of (C) the identifier of
the
type of data.
pParam

Address of data to be copied and stored by the
performance.
dwSize

Size of the data. This is constant for each rguidType
.

Return Values

If the method succeeds, the return value is S_OK.

If it fails, the method can return one of the error values shown in
the
following table.


Return code


E_FAIL
E_POINTER
E_OUTOFMEMORY
Remarks

The dwSize
parameter is needed because the performance does
not know
about all types of data. New types can be created as needed.

For the parameters defined by DirectMusic and their associated data
types,
see Setting and Retrieving Global Parameters.



参数rguidType指定允许的GUID类型如下:

By using the IDirectMusicPerformance8::SetGlobalParam
and
IDirectMusicPerformance8::GetGlobalParam
methods, you
can set
and retrieve parameters that affect the entire performance rather than a
single
track.

The parameter to be set or retrieved is identified by a GUID in the
rguidType
parameter of the method. Each parameter is associated
with a
particular data type, whose size is given in the dwSize

parameter. The
predefined GUIDs and their data types are shown in the following table.


Parameter type GUID

(rguidType
)



Data

(*pParam
)



Description


GUID_PerfAutoDownload

BOOL


This
parameter controls whether instruments are automatically
downloaded when
a segment is played. By default, it is off. See Downloading
and
Unloading Bands.
GUID_PerfMasterGrooveLevel

char


The
master
groove level
is a value that is always
added to the
groove level established by the command track. The resulting
value is
adjusted, if necessary, to fall within the range from 1
through 100.
GUID_PerfMasterTempo

float


The
master
tempo is a scaling factor applied to the tempo by the final
output tool.
By default, it is 1. A value of 0.5 would halve the tempo,
and a value
of 2.0 would double it. This value can be set in the range
from
DMUS_MASTERTEMPO_MIN through DMUS_MASTERTEMPO_MAX.
GUID_PerfMasterVolume

long


The
master
volume is an amplification or attenuation factor, in
hundredths of a
decibel, applied to the default volume of the entire
performance and any
other performances using the same synthesizer. The range of
permitted
values is determined by the port. For the default software
synthesizer,
the allowed range is +20db to -200dB, but the useful range
is +10db to
-100db. Hardware MIDI ports do not support changing master
volume.
Setting this parameter is equivalent to calling
IKsControl::KsProperty

for the
GUID_DMUS_PROP_Volume property
set on every port in the performance.
Applications can also use custom types of global parameters. To
create a new
type, establish a GUID and a data type for it.

Note
All parameters have to be set
before
they can be retrieved. When a parameter is set, the performance
allocates memory
for the data in a linked list of items that are identified by GUID. If
SetGlobalParam

has never been called on the parameter, it does
not
appear in this linked list, and GetGlobalParam
fails.
为了简化音量的操作,我们不使用分贝来设置音量,而是使用百分数。百分数的范围从0 -
100,0表示没有声音,100表示最大音量。最大音量的时候对音乐有少许的放大效果,有些时候这个放大效果会使得音乐发生扭曲,所以设置音量的时候需要
格外小心。
下面这个小函数的作用就是用百分数来设置主音量:

//--------------------------------------------------------------------------------

// Set volume for performance.

//--------------------------------------------------------------------------------

BOOL set_master_volume(
long
level)

{


// get volume range and calculate volume


long
range = labs(DMUS_VOLUME_MAX - DMUS_VOLUME_MIN);


long
volume = DMUS_VOLUME_MIN + range / 100 * level;


// set volume for performance


if
(FAILED(g_dm_performance->SetGlobalParam(GUID_PerfMasterVolume, &volume,
sizeof
(
long
))))


return
FALSE;


return
TRUE;

}



如果要对音乐片段设置音量,需要获取对音频通道接口的控制。因为在播放音乐的时候已经创建了音频通道,现在只需要用函数将这个对象获取即可,可以通过调用
IDirectMusicPerformance8::GetDefaultAudioPath来实现。

The GetDefaultAudioPath
method retrieves the default
audiopath set by IDirectMusicPerformance8::InitAudio
or

IDirectMusicPerformance8::SetDefaultAudioPath

.

Syntax

[code]HRESULT GetDefaultAudioPath(

  IDirectMusicAudioPath**  
ppAudioPath

);

[/code]
Parameters

ppAudioPath

Address of a variable that receives the
IDirectMusicAudioPath8

interface pointer of the default
audiopath.
Return Values

If the method succeeds, the return value is S_OK.

If it fails, the method can return one of the error values shown in
the
following table.


Return code


DMUS_E_AUDIOPATHS_NOT_VALID
DMUS_E_NOT_INIT
E_POINTER
一旦获得了指向
IDirectMusicAudioPath8对象的指针,就能使用
IDirectMusicAudioPath8::SetVolume函数修改变量了。

The SetVolume
method sets the audio volume on the
audiopath.
The volume can be faded in or out.

Syntax

[code]HRESULT SetVolume(

  long 
lVolume
,

  DWORD 
dwDuration

);

[/code]
Parameters

lVolume

Value that specifies the attenuation, in hundredths of
a
decibel. This value must be in the range from -9600 to 0. Zero is full
volume.
dwDuration

Value that specifies the time, in milliseconds, over
which the
volume change takes place. A value of 0 ensures maximum efficiency.
Return Values

If the method succeeds, the return value is S_OK.

If it fails, the method can return one of the error values shown in
the
following table.


Return code


DMUS_E_NOT_INIT
E_INVALIDARG
Remarks

This method works by sending a volume curve
message.
Any
volume events occurring later, such as a band change, override the
volume set by
this method. IDirectMusicAudioPath8::SetVolume
is
useful mainly
for adjusting currently playing sounds; for example, to fade out before
stopping
a segment. If you want to make a global change that affects all
playback, use
one of the following techniques:

Obtain the buffer object from the audiopath and use
IDirectSoundBuffer8::SetVolume

.

Obtain the port object from the audiopath and use
IKsControl::KsProperty

to change the GUID_DMUS_PROP_Volume
property
set.

Set the master volume for the performance. See Setting and
Retrieving
Global Parameters.

下面这个函数使用0-100之间的数值来设置音乐片段的音量,100表示音
量最大,0表示静音。

//--------------------------------------------------------------------------------

// Set volume for DirectMusic segment.

//--------------------------------------------------------------------------------

BOOL set_segment_volume(
long
level)

{

IDirectMusicAudioPath8* audio_path;


// get pointer to audio path


if
(FAILED(g_dm_performance->GetDefaultAudioPath(&audio_path)))


return
FALSE;


// calculate audio volume and set volume for audio path


long
volume = -96 * (100 - level);


if
(FAILED(audio_path->SetVolume(volume, 0)))

{

audio_path->Release();


return
FALSE;

}


return
TRUE;

}


改变节拍

想象一下拥有改变音乐节拍的魔法。比如,当玩家靠近一个怪物,正要引发一场激烈战斗的时候,节奏突然变快了,游戏者立刻就能知道他已经进入了麻烦之中。这
一切很不错,很让人激动,而这一切在
DirectMusic实现起来并不困难。


DirectMusic中,节奏速度的度量单位通
常是每分钟多少个拍子(
beats
per minute BPM)。一般来说这个数值通常会是
120,我们有很多方法可以改变节拍速度,最简单的方法就是使用一个缩放因子调节演奏器的主节拍速度。比如设置缩放因子为
0.5,使得拍子的速度变为正常拍子的一半,设置缩放因子为2使得拍子速度变为正常拍子的两倍。

下面这个函数修改演奏器的节拍,取值从
0 - 100。

//--------------------------------------------------------------------------------

// Set tempo for DirectMusic performance.

//--------------------------------------------------------------------------------

BOOL set_tempo(
long
level)

{


float
tempo = (
float
) level / 100.0f;




if
(FAILED(g_dm_performance->SetGlobalParam(GUID_PerfMasterTempo, &tempo,
sizeof
(
float
))))


return
FALSE;


return
TRUE;

}

需要注意,改变节拍速度不是立即生效的,需要过几秒钟。另外需要记住的是
set_tempo函数影响的是全局节拍速度,也就是说所有音乐的节拍速度都被修改了,所以当播放完歌曲后,需要将拍子设置回原来的值。



获取声道控制



在这么多音乐效果的特性里面,最后获取的是
DirectSound缓存对象,因为
DirectSound缓存是音色库合成音乐的关键所
在,所以能对它做很多事情。想要获取缓存,首先可以获取音频通道对象,然后用它来获取音频缓冲区对象。

在下图中,可以看到音乐数据从演奏器中通过音频通道合成音乐的一个默认流程,我们可以在这个流程的任何步骤
中截取并修改。



获取音频通道是函数IDirectMusicAudioPath8::GetObjectInPath的工
作。

The GetObjectInPath
method retrieves an interface
for an
object in the audiopath.

Syntax

[code]RESULT GetObjectInPath(

  DWORD 
dwPChannel
,

  DWORD 
dwStage
,

  DWORD
 dwBuffer
,

  REFGUID 
guidObject
,

  DWORD 
dwIndex
,

  REFGUID 
iidInterface
,

  void ** 
ppObject

);

[/code]
Parameters

dwPChannel

Performance channel
to search, or
DMUS_PCHANNEL_ALL to search all channels. The first channel is numbered
0. (See
Remarks.)
dwStage

Stage in the audiopath. Can be one of the values in
the
following table.

Value



Description


DMUS_PATH_AUDIOPATH_GRAPH
Get
the
audiopath toolgraph. One is created if none exists.
DMUS_PATH_AUDIOPATH_TOOL
Get
a tool
from the audiopath toolgraph.
DMUS_PATH_BUFFER
Get
a
DirectSound buffer.
DMUS_PATH_BUFFER_DMO
Get
a
DMO
in a buffer.
DMUS_PATH_MIXIN_BUFFER
Get
a
global mix-in buffer
.
DMUS_PATH_MIXIN_BUFFER_DMO
Get
a DMO
in a global mix-in buffer.
DMUS_PATH_PERFORMANCE
Get
the
performance.
DMUS_PATH_PERFORMANCE_GRAPH
Get
the
performance toolgraph. One is created if none exists.
DMUS_PATH_PERFORMANCE_TOOL
Get
a tool
from the performance toolgraph.
DMUS_PATH_PORT
Get
the
synthesizer.
DMUS_PATH_PRIMARY_BUFFER
Get
the
primary buffer
.
dwBuffer

Index of the buffer (if dwStage
is
DMUS_PATH_BUFFER
or DMUS_PATH_MIXIN_BUFFER), or index of the buffer in which the DMO
resides (if
dwStage
is DMUS_PATH_BUFFER_DMO or DMUS_PATH_MIXIN_BUFFER_DMO).
guidObject

Class identifier of the object, or GUID_All_Objects to
search
for an object of any class. This parameter is ignored if only a single
class of
object can exist at the stage specified by dwStage
, and can be
set to
GUID_NULL.
dwIndex

Index of the object within a list of matching objects.
Set to
0 to find the first matching object. If dwStage
is
DMUS_PATH_BUFFER or
DMUS_PATH_MIXIN_BUFFER, this parameter is ignored, and the buffer index
is
specified by dwBuffer
.
iidInterface

Identifier of the desired interface, such as
IID_IDirectMusicTool.
ppObject

Address of a variable that receives a pointer to the
requested
interface.
Return Values

If the method succeeds, the return value is S_OK.

If it fails, the method can return one of the error values shown in
the
following table.


Return code


DMUS_E_NOT_FOUND
E_INVALIDARG
E_OUTOFMEMORY
E_NOINTERFACE
E_POINTER
Remarks

The value in dwPChannel
must be 0 for any stage that is not
channel-specific. Objects in the following stages are channel-specific
and can
be retrieved by setting a channel number or DMUS_PCHANNEL_ALL in dwPChannel
:

DMUS_PATH_AUDIOPATH_TOOL

DMUS_PATH_BUFFER

DMUS_PATH_BUFFER_DMO

DMUS_PATH_PERFORMANCE_TOOL

DMUS_PATH_PORT

The precedence of the parameters in filtering out unwanted objects is
as
follows:

dwStage
.

guidObject
. If this value is not GUID_All_Objects, only
objects
whose class identifier equals guidObject
are searched.
However,
this parameter is ignored for stages where only a single class of
object can
exist, such as DMUS_PATH_AUDIOPATH_GRAPH.

dwPChannel
. If the stage is channel-specific and this
value is
not DMUS_PCHANNEL_ALL, only objects on the channel are searched.

dwBuffer
. This is used only if dwStage
is
DMUS_PATH_BUFFER, DMUS_PATH_MIXIN_BUFFER, DMUS_PATH_BUFFER_DMO, or
DMUS_PATH_MIXIN_BUFFER_DMO.

dwIndex
.

If a matching object is found but the interface specified by iidInterface

cannot be obtained, the method fails.

The following example function shows how to enumerate the buffers in
an
audiopath:

[code]void DumpAudioPathBuffers(IDirectMusicAudioPath *pDirectMusicAudioPath)

{

  DWORD dwBuffer = 0;

  IDirectSoundBuffer *pDirectSoundBuffer;

 

  while (S_OK == pDirectMusicAudioPath->GetObjectInPath( 

      DMUS_PCHANNEL_ALL, DMUS_PATH_BUFFER, dwBuffer,

      GUID_NULL, 0, IID_IDirectSoundBuffer, 

      (void**) &pDirectSoundBuffer))

  {

    // Do something with pDirectSoundBuffer.

    // . . .

    dwBuffer++;

    pDirectSoundBuffer->Release();

  }

}

[/code]
下面这个函数从演奏器获取默认的音频通道对象,并返回一个可以演奏的
IDirectSoundBuffer8对象。

//--------------------------------------------------------------------------------

// Get DirectSound buffer from audio path.

//--------------------------------------------------------------------------------

IDirectSoundBuffer8* get_sound_buffer()

{

IDirectMusicAudioPath8* audio_path;

IDirectSoundBuffer* ds_buffer;

IDirectSoundBuffer8* ds_buffer8;


// get autio path


if
(FAILED(g_dm_performance->GetDefaultAudioPath(&audio_path)))


return
NULL;


// create DirectSound buffer


if
(FAILED(audio_path->GetObjectInPath(DMUS_PCHANNEL_ALL, DMUS_PATH_BUFFER, 0, GUID_NULL, 0,

IID_IDirectSoundBuffer, (LPVOID*) &ds_buffer)))

{

audio_path->Release();


return
FALSE;

}

audio_path->Release();


// query interface to DirectSound buffer8


if
(FAILED(ds_buffer->QueryInterface(IID_IDirectSoundBuffer8, (
void
**) &ds_buffer8)))

{

ds_buffer->Release();


return
FALSE;

}

ds_buffer->Release();


return
ds_buffer8;

}

以下给出一个完整的示例,来演示如何加载和播放MIDI音乐。

点击下载源码和工程

完整源码示例:



/***************************************************************************************

PURPOSE:

Midi Playing Demo

***************************************************************************************/

#include <windows.h>

#include <stdio.h>

#include <dsound.h>

#include <dmusici.h>

#include "resource.h"

#pragma comment(lib, "dxguid.lib")

#pragma comment(lib, "dsound.lib")

#pragma warning(disable : 4996)

#define
Safe_Release(p) if((p)) (p)->Release();

// window handles, class.

HWND g_hwnd;

char
g_class_name[] = "MidiPlayClass";

IDirectSound8* g_ds;
// directsound component

IDirectMusicPerformance8* g_dm_performance;
// directmusic performance

IDirectMusicLoader8* g_dm_loader;
// directmusic loader

IDirectMusicSegment8* g_dm_segment;
// directmusic segment

//--------------------------------------------------------------------------------

// Window procedure.

//--------------------------------------------------------------------------------

long
WINAPI Window_Proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)

{


switch
(msg)

{


case
WM_DESTROY:

PostQuitMessage(0);


return
0;

}


return
(
long
) DefWindowProc(hwnd, msg, wParam, lParam);

}

//--------------------------------------------------------------------------------

// Load DirectMusic collection object.

//--------------------------------------------------------------------------------

IDirectMusicCollection8* Load_DLS_Collection(
char
* filename)

{

DMUS_OBJECTDESC dm_obj_desc;

IDirectMusicCollection8* dm_collection;


// get the object

ZeroMemory(&dm_obj_desc,
sizeof
(DMUS_OBJECTDESC));

dm_obj_desc.dwSize =
sizeof
(DMUS_OBJECTDESC);

dm_obj_desc.guidClass = CLSID_DirectMusicCollection;

dm_obj_desc.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH;


// Converts a sequence of multibyte characters to a corresponding sequence of wide characters

mbstowcs(dm_obj_desc.wszFileName, filename, MAX_PATH);


// retrieves an object from a file or resource and returns the speficied interface


if
(FAILED(g_dm_loader->GetObject(&dm_obj_desc, IID_IDirectMusicCollection8, (LPVOID*)&dm_collection)))


return
NULL;


return
dm_collection;

}

//--------------------------------------------------------------------------------

// Play midi file which specified with filename.

//--------------------------------------------------------------------------------

BOOL Play_Midi(
char
* filename)

{

DMUS_OBJECTDESC dm_obj_desc;


// get the object

ZeroMemory(&dm_obj_desc,
sizeof
(DMUS_OBJECTDESC));

dm_obj_desc.dwSize =
sizeof
(DMUS_OBJECTDESC);

dm_obj_desc.guidClass = CLSID_DirectMusicSegment;

dm_obj_desc.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH;


// Converts a sequence of multibyte characters to a corresponding sequence of wide characters

mbstowcs(dm_obj_desc.wszFileName, filename, MAX_PATH);


// retrieves an object from a file or resource and returns the speficied interface


if
(FAILED(g_dm_loader->GetObject(&dm_obj_desc, IID_IDirectMusicSegment8, (LPVOID*)&g_dm_segment)))


return
FALSE;


// setup midi playing


if
(strstr(filename, ".mid"))

{


// set data on a track inside the segment


if
(FAILED(g_dm_segment->SetParam(GUID_StandardMIDIFile, 0xFFFFFFFF, 0, 0, NULL)))


return
FALSE;

}


// downloads band data to a performance


if
(FAILED(g_dm_segment->Download(g_dm_performance)))


return
FALSE;


// set to loop forever

g_dm_segment->SetRepeats(DMUS_SEG_REPEAT_INFINITE);


// play on default audio path

g_dm_performance->PlaySegmentEx(g_dm_segment, NULL, NULL, 0, 0, NULL, NULL, NULL);


return
TRUE;

}

//--------------------------------------------------------------------------------

// Main function, routine entry.

//--------------------------------------------------------------------------------

int
WINAPI WinMain(HINSTANCE inst, HINSTANCE, LPSTR cmd_line,
int
cmd_show)

{

WNDCLASS win_class;

MSG msg;


// create window class and register it

win_class.style = CS_HREDRAW | CS_VREDRAW;

win_class.lpfnWndProc = Window_Proc;

win_class.cbClsExtra = 0;

win_class.cbWndExtra = DLGWINDOWEXTRA;

win_class.hInstance = inst;

win_class.hIcon = LoadIcon(inst, IDI_APPLICATION);

win_class.hCursor = LoadCursor(NULL, IDC_ARROW);

win_class.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);

win_class.lpszMenuName = NULL;

win_class.lpszClassName = g_class_name;


if
(! RegisterClass(&win_class))


return
FALSE;


// create the main window

g_hwnd = CreateDialog(inst, MAKEINTRESOURCE(IDD_MIDIPLAY), 0, NULL);

ShowWindow(g_hwnd, cmd_show);

UpdateWindow(g_hwnd);


// initialize and configure directsound

// creates and initializes an object that supports the IDirectSound8 interface


if
(FAILED(DirectSoundCreate8(NULL, &g_ds, NULL)))

{

MessageBox(NULL, "Unable to create DirectSound object", "Error", MB_OK);


return
0;

}


// set the cooperative level of the application for this sound device

g_ds->SetCooperativeLevel(g_hwnd, DSSCL_NORMAL);


// initialize COM

//

// initialize the COM library on the current thread and identifies the concurrency model as single-thread

// apartment (STA).

CoInitialize(0);


// create the DirectMusic performance object

//

// creates a single uninitialized object of the class associated with a specified CLSID.

CoCreateInstance(CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC, IID_IDirectMusicPerformance8,

(
void
**)&g_dm_performance);


// create the DirectMusic loader object

CoCreateInstance(CLSID_DirectMusicLoader, NULL, CLSCTX_INPROC, IID_IDirectMusicLoader8, (
void
**)&g_dm_loader);


// initialize the performance with the standard audio path.

// this initialize both directmusic and directsound and sets up the synthesizer.

g_dm_performance->InitAudio(NULL, NULL, g_hwnd, DMUS_APATH_SHARED_STEREOPLUSREVERB, 128, DMUS_AUDIOF_ALL, NULL);




// tell directmusic where the default search path is


char
path[MAX_PATH];

WCHAR search_path[MAX_PATH];

GetCurrentDirectory(MAX_PATH, path);


// maps a character string to a wide-character (Unicode) string

MultiByteToWideChar(CP_ACP, 0, path, -1, search_path, MAX_PATH);


// set a search path for finding object files

g_dm_loader->SetSearchDirectory(GUID_DirectMusicAllTypes, search_path, FALSE);


// play midi

Play_Midi("escape.mid");




// start message pump, waiting for signal to quit.

ZeroMemory(&msg,
sizeof
(MSG));


while
(msg.message != WM_QUIT)

{


if
(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}

}


// release directsound objects


if
(g_dm_segment)

g_dm_segment->Unload(g_ds);


if
(g_dm_loader)

g_dm_loader->ReleaseObjectByUnknown(g_dm_segment);


if
(g_dm_segment)

g_dm_segment->Release();


if
(g_ds)

g_ds->Release();

UnregisterClass(g_class_name, inst);


// release COM system

//

// Closes the COM library on the current thread, unloads all DLLs loaded by the thread, frees any other

// resources that the thread maintains, and forces all RPC connections on the thread to close.

CoUninitialize();




return
(
int
) msg.wParam;

}



运行截图:





阅读下篇:用
DirectX
Audio和DirectShow播放声音和音乐(7)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: