• <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>

            天行健 君子當自強而不息

            創建游戲內核(19)

             

            本篇是創建游戲內核(18)的續篇,有關DirectAudio和DirectShow的基礎知識請參閱用DirectX Audio和DirectShow播放聲音和音樂。

             

            使用SOUND_CHANNEL播放聲音

            前面介紹了如何初始化聲音系統以及如何加載聲音數據,很自然地,接下來就要講述如何播放聲音了,這也正是SOUND_CHANNEL類的用途所在。

            首先定義兩個全局變量來保存音頻緩沖的大小和每個音頻數據塊的大小。

            // these are the fixed sizes for sound channel buffers
            const long g_sound_buffer_size = 65536;
            const long g_sound_buffer_chunk = g_sound_buffer_size / 4;

            第一個變量g_sound_buffer_size表示分配給用于播放聲音的每個DirectSound緩沖區的字節數,這里使用65536字節,因為此大小的緩沖區足夠保存相當于數秒高品質的聲音數據。第二個g_sound_buffer_chunk是單個聲音數據塊的大小,使用4個數據塊,每個數據塊存儲了流式聲音的一個小的采樣。每播放完一個數據塊,緊接著就 開始播放下一個數據塊,同時使用新的聲音數據加載前一個數據塊。

            一般不必改變這兩個變量的值,除非想要節約內存。如果想節約內存,只需將g_sound_buffer_size變量的值改變成較小的數字即可。g_sound_buffer_size變量使用不同的大小,各有其優勢,比如g_sound_buffer_size變量的值越大,聲音內核將新數據放到流中的頻率就越小,當然這也意味著要占用更多的內存。

            來看看SOUND_CHANNEL的定義:

            //======================================================================================
            // This class encapsulate sound buffer playing.
            //======================================================================================
            class SOUND_CHANNEL
            {
            private:
                friend 
            class SOUND;

            protected:
                SOUND*                  _sound;         
            // pointer to parent sound object
                IDirectSoundBuffer8*    _ds_buffer;     // pointer to DirectSound buffer object
                IDirectSoundNotify8*    _ds_notify;     // pointer to DirectSound notify object
                short                   _event_index;   

                
            long                    _volume;        // sound buffer volume
                signed long             _pan;           // sound buffer pan
                BOOL                    _is_playing;    // sound buffer playing flag
                long                    _loop_times;    // loop times

                
            long                    _frequency;
                
            short                   _bits_per_sample;
                
            short                   _channels;

                SOUND_DATA              _sound_data;

                
            short                   _load_section;  // sound section will to be loaded
                short                   _stop_section;  // sound section will to be stoped
                short                   _next_notify;   // sound notification index will to be played

                BOOL _buffer_data();
                
            void _update();

            public:
                SOUND_CHANNEL();
                ~SOUND_CHANNEL();

                IDirectSoundBuffer8*    get_sound_buffer_com();
                IDirectSoundNotify8*    get_notify_com();

                BOOL create(SOUND* sound, 
            long frequency = 22050, short channels = 1, short bits_per_sample = 16);
                BOOL create(SOUND* sound, SOUND_DATA* sound_data);
                
            void free();

                BOOL play(SOUND_DATA* sound_data, 
            long volume_percent = 100, long loop = 1);
                
            void stop();

                
            long get_volume();
                BOOL set_volume(
            long percent);

                signed 
            long get_pan();
                BOOL set_pan(signed 
            long level);

                
            long get_frequency();
                BOOL set_frequency(
            long frequency);

                BOOL is_playing();
            };
             

            接著來看看它的實現:

            //------------------------------------------------------------------------------
            // Constructor, initialize member data.
            //------------------------------------------------------------------------------
            SOUND_CHANNEL::SOUND_CHANNEL()
            {
                _sound     = NULL;
                _ds_buffer = NULL;
                _ds_notify = NULL;

                _event_index = -1;

                _volume     = 0;
                _pan        = 0;
                _frequency  = 0;
                _is_playing = FALSE;
            }

            //------------------------------------------------------------------------------
            // Destructor, release sound buffer and sound notification, set the event state 
            // to nonsignaled.
            //------------------------------------------------------------------------------
            SOUND_CHANNEL::~SOUND_CHANNEL()
            {
                free();
            }

            //------------------------------------------------------------------------------
            // Return pointer to DirectSound buffer.
            //------------------------------------------------------------------------------
            IDirectSoundBuffer8* SOUND_CHANNEL::get_sound_buffer_com()
            {
                
            return _ds_buffer;
            }

            //------------------------------------------------------------------------------
            // Return pointer to DirectSound notify.
            //------------------------------------------------------------------------------
            IDirectSoundNotify8* SOUND_CHANNEL::get_notify_com()
            {
                
            return _ds_notify;
            }

            //------------------------------------------------------------------------------
            // Create sound buffer, set sound notification and event.
            //------------------------------------------------------------------------------
            BOOL SOUND_CHANNEL::create(SOUND* sound, long frequency, short channels, short bits_per_sample)
            {
                
            // free a prior channel
                free();

                
            if((_sound = sound) == NULL)
                    
            return FALSE;

                
            if(_sound->get_directsound_com() == NULL)
                    
            return FALSE;

                
            // save playback format
                _frequency       = frequency;
                _bits_per_sample = bits_per_sample;
                _channels        = channels;

                WAVEFORMATEX wave_format;

                
            // create a new sound buffer for this channel, using specified format.
                ZeroMemory(&wave_format, sizeof(WAVEFORMATEX));

                wave_format.wFormatTag      = WAVE_FORMAT_PCM;
                wave_format.nChannels       = (WORD) _channels;
                wave_format.nSamplesPerSec  = _frequency;
                wave_format.wBitsPerSample  = (WORD) _bits_per_sample;
                wave_format.nBlockAlign     = wave_format.wBitsPerSample / 8 * wave_format.nChannels;
                wave_format.nAvgBytesPerSec = wave_format.nSamplesPerSec * wave_format.nBlockAlign;

                DSBUFFERDESC buffer_desc;

                ZeroMemory(&buffer_desc, 
            sizeof(DSBUFFERDESC));

                buffer_desc.dwSize          = 
            sizeof(DSBUFFERDESC);
                buffer_desc.dwFlags         = DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLPAN | DSBCAPS_CTRLFREQUENCY | 
                                              DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_LOCSOFTWARE;
                buffer_desc.dwBufferBytes   = g_sound_buffer_size;
                buffer_desc.lpwfxFormat     = &wave_format;

                IDirectSoundBuffer* ds_buffer;

                
            if(FAILED(_sound->get_directsound_com()->CreateSoundBuffer(&buffer_desc, &ds_buffer, NULL)))
                    
            return FALSE;

                
            // query for newer interface
                if(FAILED(ds_buffer->QueryInterface(IID_IDirectSoundBuffer8, (void**) &_ds_buffer)))
                {
                    ds_buffer->Release();
                    
            return FALSE;
                }

                
            // release old object - we have the newer one now
                ds_buffer->Release();

                
            // create the notification interface
                if(FAILED(_ds_buffer->QueryInterface(IID_IDirectSoundNotify8, (void**) &_ds_notify)))
                    
            return FALSE;

                HANDLE event_handle;

                
            // get an event for this
                if(! _sound->assign_event(this, &_event_index, &event_handle))
                    
            return FALSE;

                DSBPOSITIONNOTIFY pos_notify[4];

                
            // setup the 4 notification positions
                pos_notify[0].dwOffset     = g_sound_buffer_chunk - 1;
                pos_notify[0].hEventNotify = event_handle;
                pos_notify[1].dwOffset     = g_sound_buffer_chunk * 2 - 1;
                pos_notify[1].hEventNotify = event_handle;
                pos_notify[2].dwOffset     = g_sound_buffer_chunk * 3 - 1;
                pos_notify[2].hEventNotify = event_handle;
                pos_notify[3].dwOffset     = g_sound_buffer_size - 1;
                pos_notify[3].hEventNotify = event_handle;

                
            if(FAILED(_ds_notify->SetNotificationPositions(4, pos_notify)))
                    
            return FALSE;

                
            // set the pan and default volume
                set_volume(100);
                set_pan(0);

                
            return TRUE;
            }

            //------------------------------------------------------------------------------
            // Create sound buffer.
            //------------------------------------------------------------------------------
            BOOL SOUND_CHANNEL::create(SOUND* sound, SOUND_DATA* sound_data)
            {
                
            return create(sound, sound_data->_frequency, sound_data->_channels, sound_data->_bits_per_sample);
            }

            //------------------------------------------------------------------------------
            // Release sound buffer and sound notification, set the event state to nonsignaled.
            //------------------------------------------------------------------------------
            void SOUND_CHANNEL::free()
            {
                
            // stop any playback
                stop();

                
            // release the notification
                release_com(_ds_notify);

                
            // release the sound buffer
                release_com(_ds_buffer);

                
            // release event from parent SOUND class
                _sound->release_event(this, &_event_index);

                
            // set to no parent sound
                _sound = NULL;
            }

            //------------------------------------------------------------------------------
            // Play sound buffer.
            //------------------------------------------------------------------------------
            BOOL SOUND_CHANNEL::play(SOUND_DATA* sound_data, long volume_percent, long loop_times)
            {
                
            if(sound_data == NULL || _ds_buffer == NULL || _ds_notify == NULL)
                    
            return FALSE;

                
            // stop any playback
                stop();

                
            // restore a lost buffer just in case
                _ds_buffer->Restore();

                
            // setup playing information
                _sound_data.copy(sound_data);

                
            // set looping times
                _loop_times = loop_times;

                
            // calculate stop section position
                if(_loop_times == 0)
                    _stop_section = -1;
                
            else
                    _stop_section = (
            short
                        (((_sound_data._buffer_size * _loop_times) % g_sound_buffer_size) / g_sound_buffer_chunk) ;

                _load_section = 0;

                
            // load sound data into sound buffer from sound file or sound data object
                _buffer_data();
                _buffer_data();
                _buffer_data();
                _buffer_data();

                
            // set the volume
                set_volume(volume_percent);

                
            // set position and begin play

                _next_notify = 0;

                
            if(FAILED(_ds_buffer->SetCurrentPosition(0)))
                    
            return FALSE;

                
            if(FAILED(_ds_buffer->Play(0, 0, DSBPLAY_LOOPING)))
                    
            return FALSE;

                
            // flag as playing
                _is_playing = TRUE;

                
            return TRUE;
            }

            //------------------------------------------------------------------------------
            // Stop playing DirectSound buffer.
            //------------------------------------------------------------------------------
            void SOUND_CHANNEL::stop()
            {
                
            if(_ds_buffer)
                    _ds_buffer->Stop();

                _is_playing = FALSE;
            }

            //------------------------------------------------------------------------------
            // Get sound buffer volume.
            //------------------------------------------------------------------------------
            long SOUND_CHANNEL::get_volume()
            {
                
            return _volume;
            }

            //------------------------------------------------------------------------------
            // Set volume for sound buffer.
            //------------------------------------------------------------------------------
            BOOL SOUND_CHANNEL::set_volume(long percent)
            {
                
            long volume;

                
            if(_ds_buffer == NULL)
                    
            return FALSE;

                
            // calculate a usable volume level
                if(percent == 0)
                    volume = DSBVOLUME_MIN;
                
            else
                    volume = -20 * (100 - (percent % 101));

                
            if(FAILED(_ds_buffer->SetVolume(volume)))
                    
            return FALSE;

                _volume = percent % 101;

                
            return TRUE;
            }

            //------------------------------------------------------------------------------
            // Get sound buffer pan.
            //------------------------------------------------------------------------------
            signed long SOUND_CHANNEL::get_pan()
            {
                
            return _pan;
            }

            //------------------------------------------------------------------------------
            // Set pan for sound buffer.
            //------------------------------------------------------------------------------
            BOOL SOUND_CHANNEL::set_pan(long level)
            {
                signed 
            long pan;
                
                
            if(_ds_buffer == NULL)
                    
            return FALSE;

                
            // calculate a suable setting
                if(level < 0)
                    pan = DSBPAN_LEFT / 100 * (-level % 101);
                
            else
                    pan = DSBPAN_LEFT / 100 * (level % 101);

                
            if(FAILED(_ds_buffer->SetPan(pan)))
                    
            return FALSE;

                _pan = level % 101;

                
            return TRUE;
            }

            //------------------------------------------------------------------------------
            // Get sound buffer frequency.
            //------------------------------------------------------------------------------
            long SOUND_CHANNEL::get_frequency()
            {
                
            return _frequency;
            }

            //------------------------------------------------------------------------------
            // Set frequency for sound buffer.
            //------------------------------------------------------------------------------
            BOOL SOUND_CHANNEL::set_frequency(long frequency)
            {
                
            if(_ds_buffer == NULL)
                    
            return FALSE;

                
            if(FAILED(_ds_buffer->SetFrequency(frequency)))
                    
            return FALSE;

                _frequency = frequency;

                
            return TRUE;
            }

            //------------------------------------------------------------------------------
            // Checks whether sound buffer is playing.
            //------------------------------------------------------------------------------
            BOOL SOUND_CHANNEL::is_playing()
            {
                
            if(_sound == NULL || _ds_buffer == NULL || _ds_notify == NULL)
                    
            return FALSE;

                
            return _is_playing;
            }

            //------------------------------------------------------------------------------
            // Load sound data into sound buffer from sound file or sound data object.
            //------------------------------------------------------------------------------
            BOOL SOUND_CHANNEL::_buffer_data()
            {
                
            if(_ds_buffer == NULL)
                    
            return FALSE;

                
            // setup position to load in
                long lock_pos = (_load_section % 4) * g_sound_buffer_chunk;

                
            long size;
                
            char* ptr;

                
            // lock sound buffer to get pointer to sound data
                if(FAILED(_ds_buffer->Lock(lock_pos, g_sound_buffer_chunk, (void**) &ptr, (DWORD*)&size, NULL, NULL, 0)))
                    
            return FALSE;

                
            // clear out buffer if nothing left to load
                if(_sound_data._left_size == 0)
                    ZeroMemory(ptr, size);
                
            else
                {
                    
            // load in the data - take looping into account
                    long load_size = size;
                    
            long load_pos  = 0;

                    
            // load sound data until specfied load size is satisfied
                    for(;;)
                    {
                        
            if(_sound_data._left_size > load_size)
                        {
                            
            // load in sound data
                            if(_sound_data._fp != NULL)
                            {
                                
            // load in sound data from file
                                fseek(_sound_data._fp, _sound_data._file_curr_pos, SEEK_SET);
                                fread(&ptr[load_pos], 1, load_size, _sound_data._fp);
                            }
                            
            else
                                
            // load into sound data from buffer
                                memcpy(&ptr[load_pos], &_sound_data._ptr[_sound_data._file_curr_pos], load_size);

                            
            // decrease sound data, advance current sound buffer position.
                            _sound_data._left_size     -= load_size;
                            _sound_data._file_curr_pos += load_size;
                            
            break;
                        }
                        
            else        // _sound_data._left_size <= load_size
                        {
                            
            // load in sound data
                            if(_sound_data._fp != NULL)
                            {
                                
            // load in sound data from file
                                fseek(_sound_data._fp, _sound_data._file_curr_pos, SEEK_SET);
                                fread(&ptr[load_pos], 1, _sound_data._left_size, _sound_data._fp);
                            }
                            
            else
                                
            // load in sound data from buffer
                                memcpy(&ptr[load_pos], &_sound_data._ptr[_sound_data._file_curr_pos], _sound_data._left_size);

                            
            // decrease sound data, advance current sound buffer position.
                            load_size -= _sound_data._left_size;
                            load_pos  += _sound_data._left_size;

                            
            // check if we need to stop loop
                            if(_loop_times >= 1)
                            {
                                _loop_times--;

                                
            if(_loop_times == 0)
                                {
                                    
            // clear out remaining buffer space
                                    if(load_size)
                                        ZeroMemory(&ptr[load_pos], load_size);

                                    _sound_data._left_size = 0L;
                                    
            break;
                                }
                            }

                            
            // reset sound data current position and left size
                            _sound_data._file_curr_pos = _sound_data._file_start_pos;
                            _sound_data._left_size     = _sound_data._buffer_size;

                            
            // set if we need to stop loading data
                            if(load_size == 0)
                                
            break;
                        }
                    }
                }

                
            // unlock the buffer
                _ds_buffer->Unlock(ptr, size, NULL, 0);

                
            // mark next section to load
                if(++_load_section > 3)
                    _load_section = 0;

                
            return TRUE;
            }

            //------------------------------------------------------------------------------
            // Update for sound buffer palying.
            //------------------------------------------------------------------------------
            void SOUND_CHANNEL::_update()
            {
                
            // check for end of sound
                if(_next_notify == _stop_section && _sound_data._left_size == 0)
                    stop();
                
            else
                {
                    
            // buffer in more data
                    _buffer_data();

                    
            if(++_next_notify > 3)
                        _next_notify = 0;
                }
            }
             

            最多可以將SOUND_CHANNEL類實例化32次,也就是說同時可以用多達32個聲道進行播放(聲音內核不允許同時32個以上的實例,任何超過32的值,都無法被成功初始化)。調用SOUND_CHANNEL::create函數可以初始化各個聲道,需要提供一個預初始化的SOUND類以及回放格式。為方便起見,甚至可以使用存儲在SOUND_DATA類中的回放格式創建聲道。

            使用SOUND_CHANNEL類進行的操作中,最頻繁的就是播放聲音、停止播放聲音以及改變聲音的音量。要播放聲音,需要給SOUND_CHANNEL::play函數傳遞三個參數:保存在SOUND_DATA類中要播放的聲音數據、音量的大小以及連續播放聲音的次數。

            接著我們編寫測試代碼:

            點擊下載源碼和工程

            /*****************************************************************************
            PURPOSE:
                Test for class SOUND, SOUND_DATA, SOUND_CHANNEL.
            *****************************************************************************/


            #include "Core_Global.h"

            class APP : public APPLICATION
            {
            private:
                SOUND _sound;
                SOUND_DATA _sound_data[2];
                SOUND_CHANNEL _sound_channel[2];

                FILE* _fp;

            public:
                APP()
                {
                    _fp = NULL;
                }

                BOOL init();
                BOOL frame();
                BOOL shutdown();
            };

            BOOL APP::init()
            {
                
            // Initialize DierctSound and DirectMusic.
                _sound.init(get_hwnd());

                
            // load into sound data from wave file
                _sound_data[0].load_wav("test1.wav", NULL);
                _sound_data[1].load_wav("test2.wav", NULL);
                
                
            // create sound channel
                _sound_channel[0].create(&_sound, &_sound_data[0]);
                _sound_channel[1].create(&_sound, &_sound_data[1]);

                
            // play sound
                _sound_channel[0].play(&_sound_data[0]);
                _sound_channel[1].play(&_sound_data[1], 100, 0); 
            // lopping forever   
                
                
            return TRUE;
            }

            BOOL APP::frame()
            {    
                
            return TRUE;
            }

            BOOL APP::shutdown()
            {
                
            if(_fp) 
                    fclose(_fp);

                
            return TRUE;
            }

            int PASCAL WinMain(HINSTANCE inst, HINSTANCE, LPSTR cmd_line, int cmd_show)
            {
                APP app;

                
            return app.run();
            }

            posted on 2007-09-29 22:03 lovedday 閱讀(366) 評論(0)  編輯 收藏 引用

            公告

            導航

            統計

            常用鏈接

            隨筆分類(178)

            3D游戲編程相關鏈接

            搜索

            最新評論

            久久精品国产AV一区二区三区| 99久久香蕉国产线看观香| 青青草原精品99久久精品66| 久久国语露脸国产精品电影| 亚洲精品乱码久久久久久按摩| 色综合久久88色综合天天| 久久免费视频6| 99精品久久精品一区二区| 精品久久久久久国产牛牛app| 亚洲一级Av无码毛片久久精品| 东方aⅴ免费观看久久av| 久久夜色精品国产亚洲| 久久99久国产麻精品66| AAA级久久久精品无码区| 色综合久久无码中文字幕| 久久精品国产一区二区| 97久久精品无码一区二区| 香蕉久久夜色精品国产2020| 一级做a爰片久久毛片人呢| 色综合久久综合中文综合网| 欧美一级久久久久久久大| 久久九九亚洲精品| 国产精品欧美久久久天天影视| 久久天天躁狠狠躁夜夜2020一| 久久一本综合| 久久强奷乱码老熟女网站| 丁香久久婷婷国产午夜视频| 国产麻豆精品久久一二三| 久久男人Av资源网站无码软件 | 99久久国产热无码精品免费久久久久 | 久久久99精品成人片中文字幕| 久久精品亚洲一区二区三区浴池 | 久久99精品久久久久久久久久 | 国产免费久久久久久无码| 狠狠色丁香婷婷综合久久来| 久久综合香蕉国产蜜臀AV| 久久夜色精品国产噜噜麻豆| 无码精品久久久久久人妻中字| 无遮挡粉嫩小泬久久久久久久 | 亚洲人成精品久久久久| 色综合久久无码五十路人妻|