• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            天行健 君子當自強而不息

            用DirectX Audio和DirectShow播放聲音和音樂(6)


            本篇是 用DirectX Audio和DirectShow播放聲音和音樂(5)的續(xù)篇。

             

            加載音色庫(樂器)

            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;
            }

            音色庫被加載后,還需要給音樂片段指定音色庫,這個工作通過設置指定的音樂片段的音軌參數(shù)來完成,設置參數(shù)使用函數(shù) IDirectMusicSegment8::SetParam。

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

            Syntax

            HRESULT SetParam(
            REFGUID
            rguidType,
            DWORD dwGroupBits,
            DWORD dwIndex,
            MUSIC_TIME mtTime,
            void* pParam
            );

            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的配置

            一首歌曲如果已經和音色庫一起被完整地加載到了內存中,這首音樂基本上已經可以使用了,唯一存在的問題是因為系統(tǒng)需要進行配置,以便適應一般MIDI文件的配置,所以需要告訴系統(tǒng)加載的文件是否是一個MIDI文件。告訴DirectMusic使用的是MIDI文件,需要再一次調用參數(shù)配置函數(shù) 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函數(shù)來完成操作。

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

            Syntax

            HRESULT Download(
            IUnknown*
            pAudioPath
            );

            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文件的時候,才需要調用這個函數(shù),因為該函數(shù)會改變音樂文件的信息,如果在不適當?shù)臅r候強制調用該函數(shù),會導致主音軌改變或者丟失。如果要改變音色庫(比如重新指定一個新的DLS給一個段音樂),必須首先卸載音色庫數(shù)據(jù),然后再加載新的音色庫,并重新播放音樂。

            以下代碼示例了如何使用Download。
             
            // downloads band data to a performance
            if(FAILED(g_dm_segment->Download(g_dm_performance)))
               
            return FALSE;

            當完成播放或者切換音色庫時,必須調用一個卸載函數(shù)IDirectMusicSegment8::Unload,用它釋放音色庫及其他資源。

            g_pDMSegment->Unload(g_pDS);

             

            循環(huán)和重復

            在播放之前最后一個要做的工作是設置重復點和重復次數(shù)。例如有一小段音樂,希望重復播放這段音樂里的一小部分,這時就需要設置循環(huán)起始點和結束點,然后設置重復播放次數(shù),如下圖所示:

            設置循環(huán)點是IDirectMusicSegment8::SetLoopPoints函數(shù)的職責。

            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

            HRESULT SetLoopPoints(
            MUSIC_TIME
            mtStart,
            MUSIC_TIME mtEnd
            );

            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函數(shù)。設置完循環(huán)點后,就可以設置重復次數(shù)了(當然,先設置重復次數(shù)也是可以的)。如果希望音樂播放一次后就停止,設置重復次數(shù)為0,如果希望將曲目播放兩次,需要將重復次數(shù)設置為1。設置重復次數(shù)使用 IDirectMusicSegment8::SetRepeats函數(shù),這個函數(shù)只有一個參數(shù),就是曲目重復的次數(shù),如果將這個值設置為 DMUS_SEG_REPEAT_INFINITE,那么播放就會一直持續(xù)。

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

            Syntax

            HRESULT SetRepeats(
            DWORD
            dwRepeats
            );

            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函數(shù)就可以了。

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

            Syntax

            HRESULT PlaySegmentEx(
            IUnknown*
            pSource,
            WCHAR *pwzSegmentName,
            IUnknown* pTransition,
            DWORD dwFlags,
            __int64 i64StartTime,
            IDirectMusicSegmentState** ppSegmentState,
            IUnknown* pFrom,
            IUnknown* pAudioPath
            );

            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函數(shù)就可以了。

            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

            HRESULT Stop(
            IDirectMusicSegment*
            pSegment,
            IDirectMusicSegmentState* pSegmentState,
            MUSIC_TIME mtTime,
            DWORD dwFlags
            );

            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.


            卸載音樂數(shù)據(jù)

            使用完音樂之后,第一件要做的事就是卸載音色庫數(shù)據(jù),可以通過IDirectMusicSegment8::Unload來完成。

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

            Syntax

            HRESULT Unload(
            IUnknown *
            pAudioPath
            );

            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.


            還要釋放加載器中的高速緩存數(shù)據(jù),通過IDirectMusicLoader8::ReleaseObjectByUnknown來實現(xiàn)。

            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

            HRESULT ReleaseObject(
            IUnknown *
            pObject
            );

            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.


            如果開始的時候加載了音色庫,現(xiàn)在是時候從加載器對象中將它卸載掉了,就像剛才從加載器中卸載音樂片段對象一樣。另外,清空緩存很重要,有一個函數(shù)可以強制清空整個緩存區(qū),但是并不需要在卸載加載器前調用它,因為在卸載過程中這個操作是自動完成的。

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

            Syntax

            HRESULT ClearCache(
            REFGUID
            rguidClass
            );

            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聲音緩沖對象改變音量、節(jié)拍、加入特殊效果等。

             

            音量設置

            我們可以改變兩個音量設置。第一個是演奏器的音量(整個音樂系統(tǒng)的音量),第二個是每個音樂片段對象的回放音量。如下圖所示,當每個音樂片段被加載到演奏器中的時候,音樂片段的音量會被修改,演奏器的音量又被全局音量所影響。

            演奏器音量(主音量)是一個全局參數(shù),調用IDirectMusicPerformance8::SetGlobalParam設置。

            The SetGlobalParam method sets global values for the performance.

            Syntax

            HRESULT SetGlobalParam(
            REFGUID
            rguidType,
            void* pParam,
            DWORD dwSize
            );

            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.

             

            參數(shù)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.

            為了簡化音量的操作,我們不使用分貝來設置音量,而是使用百分數(shù)。百分數(shù)的范圍從0 - 100,0表示沒有聲音,100表示最大音量。最大音量的時候對音樂有少許的放大效果,有些時候這個放大效果會使得音樂發(fā)生扭曲,所以設置音量的時候需要格外小心。

            下面這個小函數(shù)的作用就是用百分數(shù)來設置主音量:

            //--------------------------------------------------------------------------------
            // 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;
            }
             

            如果要對音樂片段設置音量,需要獲取對音頻通道接口的控制。因為在播放音樂的時候已經創(chuàng)建了音頻通道,現(xiàn)在只需要用函數(shù)將這個對象獲取即可,可以通過調用IDirectMusicPerformance8::GetDefaultAudioPath來實現(xiàn)。

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

            Syntax

            HRESULT GetDefaultAudioPath(
            IDirectMusicAudioPath**
            ppAudioPath
            );

            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函數(shù)修改變量了。

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

            Syntax

            HRESULT SetVolume(
            long
            lVolume,
            DWORD dwDuration
            );

            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.

            下面這個函數(shù)使用0-100之間的數(shù)值來設置音樂片段的音量,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;
            }
             

            改變節(jié)拍

            想象一下?lián)碛懈淖円魳饭?jié)拍的魔法。比如,當玩家靠近一個怪物,正要引發(fā)一場激烈戰(zhàn)斗的時候,節(jié)奏突然變快了,游戲者立刻就能知道他已經進入了麻煩之中。這一切很不錯,很讓人激動,而這一切在DirectMusic實現(xiàn)起來并不困難。

            DirectMusic中,節(jié)奏速度的度量單位通常是每分鐘多少個拍子(beats per minute BPM)。一般來說這個數(shù)值通常會是120,我們有很多方法可以改變節(jié)拍速度,最簡單的方法就是使用一個縮放因子調節(jié)演奏器的主節(jié)拍速度。比如設置縮放因子為0.5,使得拍子的速度變?yōu)檎E淖拥囊话耄O置縮放因子為2使得拍子速度變?yōu)檎E淖拥膬杀丁?/span>

            下面這個函數(shù)修改演奏器的節(jié)拍,取值從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;
            }

            需要注意,改變節(jié)拍速度不是立即生效的,需要過幾秒鐘。另外需要記住的是set_tempo函數(shù)影響的是全局節(jié)拍速度,也就是說所有音樂的節(jié)拍速度都被修改了,所以當播放完歌曲后,需要將拍子設置回原來的值。

             

            獲取聲道控制

            在這么多音樂效果的特性里面,最后獲取的是DirectSound緩存對象,因為DirectSound緩存是音色庫合成音樂的關鍵所在,所以能對它做很多事情。想要獲取緩存,首先可以獲取音頻通道對象,然后用它來獲取音頻緩沖區(qū)對象。

            在下圖中,可以看到音樂數(shù)據(jù)從演奏器中通過音頻通道合成音樂的一個默認流程,我們可以在這個流程的任何步驟中截取并修改。

            獲取音頻通道是函數(shù)IDirectMusicAudioPath8::GetObjectInPath的工作。

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

            Syntax

            RESULT GetObjectInPath(
            DWORD
            dwPChannel,
            DWORD dwStage,
            DWORD dwBuffer,
            REFGUID guidObject,
            DWORD dwIndex,
            REFGUID iidInterface,
            void ** ppObject
            );

            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:

            1. dwStage.
            2. 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.
            3. dwPChannel. If the stage is channel-specific and this value is not DMUS_PCHANNEL_ALL, only objects on the channel are searched.
            4. 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.
            5. 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:

            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();
            }
            }

            下面這個函數(shù)從演奏器獲取默認的音頻通道對象,并返回一個可以演奏的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)
             

            posted on 2007-07-31 01:42 lovedday 閱讀(3805) 評論(0)  編輯 收藏 引用

            公告

            導航

            統(tǒng)計

            常用鏈接

            隨筆分類(178)

            3D游戲編程相關鏈接

            搜索

            最新評論

            久久久久久亚洲Av无码精品专口 | 久久综合久久久| 久久99这里只有精品国产| 精品久久久无码中文字幕| 国产精品99久久精品| 97r久久精品国产99国产精| 久久久久高潮毛片免费全部播放| 亚洲欧美日韩久久精品第一区| 亚洲人成电影网站久久| 久久夜色精品国产亚洲| 97久久国产露脸精品国产| 无遮挡粉嫩小泬久久久久久久| 一本色道久久99一综合| 久久精品一本到99热免费| 国产精品久久永久免费| 精品久久人人做人人爽综合| 久久天天躁狠狠躁夜夜2020| 久久久久波多野结衣高潮| av午夜福利一片免费看久久| 色成年激情久久综合| 久久久久久A亚洲欧洲AV冫| 久久亚洲国产最新网站| 亚洲成色WWW久久网站| 国产精品无码久久综合| 久久国产V一级毛多内射| 久久精品中文字幕一区| 久久精品视频网| 久久人人爽人人人人爽AV| 狠狠色丁香久久婷婷综| 亚洲国产成人乱码精品女人久久久不卡| 久久久久久免费视频| 久久精品国产亚洲综合色| 亚洲精品综合久久| 国内精品久久九九国产精品| 久久亚洲国产成人精品无码区| 亚洲va中文字幕无码久久不卡| 精品久久久久久无码中文野结衣| 久久99精品久久久大学生| 97久久精品人人做人人爽| 亚洲精品无码久久一线| 亚洲欧美国产日韩综合久久|