• <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 閱讀(362) 評論(0)  編輯 收藏 引用

            公告

            導航

            統計

            常用鏈接

            隨筆分類(178)

            3D游戲編程相關鏈接

            搜索

            最新評論

            国产成人无码精品久久久性色 | 久久国产高潮流白浆免费观看| 亚洲AV乱码久久精品蜜桃| 久久久精品午夜免费不卡| 一本色道久久88综合日韩精品 | 很黄很污的网站久久mimi色| 久久精品亚洲一区二区三区浴池| 99久久综合狠狠综合久久止| 97精品依人久久久大香线蕉97| 久久婷婷五月综合色高清| 久久夜色精品国产噜噜亚洲a| 久久黄色视频| 久久影院午夜理论片无码| 国产成人久久777777| 天天久久狠狠色综合| 综合久久久久久中文字幕亚洲国产国产综合一区首 | 亚洲∧v久久久无码精品| 亚洲国产精品久久| 日本一区精品久久久久影院| 伊人久久大香线蕉综合5g| 青草影院天堂男人久久| 日韩AV无码久久一区二区 | 久久人人爽人人爽人人片av麻烦 | 久久精品国产精品国产精品污| 久久久久久人妻无码| 欧美色综合久久久久久| 久久一区二区三区99| 久久午夜电影网| 99久久99久久| 77777亚洲午夜久久多喷| 亚洲精品无码久久久久久| 亚洲精品无码久久久| 亚洲а∨天堂久久精品| 久久综合色之久久综合| 久久青青草原精品国产软件| 国产69精品久久久久99| 精品久久一区二区| 99热热久久这里只有精品68| 99久久精品国产一区二区| 久久精品不卡| 久久免费视频1|