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

            天行健 君子當(dāng)自強(qiáng)而不息

            創(chuàng)建游戲內(nèi)核(19)

             

            本篇是創(chuàng)建游戲內(nèi)核(18)的續(xù)篇,有關(guān)DirectAudio和DirectShow的基礎(chǔ)知識(shí)請(qǐng)參閱用DirectX Audio和DirectShow播放聲音和音樂

             

            使用SOUND_CHANNEL播放聲音

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

            首先定義兩個(gè)全局變量來(lái)保存音頻緩沖的大小和每個(gè)音頻數(shù)據(jù)塊的大小。

            // 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è)變量g_sound_buffer_size表示分配給用于播放聲音的每個(gè)DirectSound緩沖區(qū)的字節(jié)數(shù),這里使用65536字節(jié),因?yàn)榇舜笮〉木彌_區(qū)足夠保存相當(dāng)于數(shù)秒高品質(zhì)的聲音數(shù)據(jù)。第二個(gè)g_sound_buffer_chunk是單個(gè)聲音數(shù)據(jù)塊的大小,使用4個(gè)數(shù)據(jù)塊,每個(gè)數(shù)據(jù)塊存儲(chǔ)了流式聲音的一個(gè)小的采樣。每播放完一個(gè)數(shù)據(jù)塊,緊接著就 開始播放下一個(gè)數(shù)據(jù)塊,同時(shí)使用新的聲音數(shù)據(jù)加載前一個(gè)數(shù)據(jù)塊。

            一般不必改變這兩個(gè)變量的值,除非想要節(jié)約內(nèi)存。如果想節(jié)約內(nèi)存,只需將g_sound_buffer_size變量的值改變成較小的數(shù)字即可。g_sound_buffer_size變量使用不同的大小,各有其優(yōu)勢(shì),比如g_sound_buffer_size變量的值越大,聲音內(nèi)核將新數(shù)據(jù)放到流中的頻率就越小,當(dāng)然這也意味著要占用更多的內(nèi)存。

            來(lái)看看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();
            };
             

            接著來(lái)看看它的實(shí)現(xiàn):

            //------------------------------------------------------------------------------
            // 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類實(shí)例化32次,也就是說同時(shí)可以用多達(dá)32個(gè)聲道進(jìn)行播放(聲音內(nèi)核不允許同時(shí)32個(gè)以上的實(shí)例,任何超過32的值,都無(wú)法被成功初始化)。調(diào)用SOUND_CHANNEL::create函數(shù)可以初始化各個(gè)聲道,需要提供一個(gè)預(yù)初始化的SOUND類以及回放格式。為方便起見,甚至可以使用存儲(chǔ)在SOUND_DATA類中的回放格式創(chuàng)建聲道。

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

            接著我們編寫測(cè)試代碼:

            點(diǎn)擊下載源碼和工程

            /*****************************************************************************
            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) 評(píng)論(0)  編輯 收藏 引用


            只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


            公告

            導(dǎo)航

            統(tǒng)計(jì)

            常用鏈接

            隨筆分類(178)

            3D游戲編程相關(guān)鏈接

            搜索

            最新評(píng)論

            狠狠色丁香婷婷久久综合五月 | 国产精品久久久久久久久久影院| 久久99精品久久久久久野外| 精品人妻伦九区久久AAA片69| 亚洲成人精品久久| 久久亚洲精品无码观看不卡| 日韩精品无码久久久久久| 99久久国产综合精品麻豆| 国产福利电影一区二区三区久久久久成人精品综合 | 中文字幕日本人妻久久久免费 | 无码国内精品久久人妻| 伊人久久综在合线亚洲2019 | 日本久久久久亚洲中字幕| 欧美精品一本久久男人的天堂| 2020久久精品亚洲热综合一本| 精品国产乱码久久久久久郑州公司 | 午夜福利91久久福利| 久久精品成人免费看| 狠狠色综合网站久久久久久久高清| 久久久久99精品成人片欧美 | 精品久久久久久亚洲精品| 亚洲国产成人久久精品99| 久久久久亚洲AV综合波多野结衣| 伊人久久无码中文字幕| 久久九九免费高清视频 | 欧美午夜A∨大片久久| 精品国产91久久久久久久| 久久精品国产2020| 亚洲综合伊人久久大杳蕉| 久久精品亚洲福利| 91超碰碰碰碰久久久久久综合| 欧美一区二区三区久久综合 | 日日狠狠久久偷偷色综合免费 | 久久精品国产黑森林| 亚洲国产成人久久综合一| 72种姿势欧美久久久久大黄蕉| 国产精品99久久久精品无码| 中文字幕无码av激情不卡久久| 亚洲精品97久久中文字幕无码| 欧美日韩中文字幕久久久不卡| 久久无码AV中文出轨人妻|