🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

Recommendations for playing music in game using DirectXToolkit

Started by
4 comments, last by Steven Ford 3 years, 7 months ago

Hi,

I'm in the process of writing my second game and as part of the ‘lessons learnt' from game #1, I'm investing a lot more work in presentation / auxiliary information, including sounds.

For game #1, I had minimal music, and consumed it as wav files. Which lead to ~2.5 minutes of music and about 50MB of disc space. For simplicity's sake, I used the wav loader code from the DirectXToolkit (modified very slightly) so that everything was brought into memory and then played from there.

With game #2, I've commissioned about 20 minutes of music and so the idea of converting everything to wav files, loading them and keeping the data in memory permanently etc, probably isn't going to work. The game itself is raw c++ and uses the DirectXToolkit to play the existing wav files. Under the covers, this uses XAudio2.

My, quite possibly naïve (and apologies if this sounds stupid, audio very much isn't my thing), initial approach was to use ogg files instead of mp3 files to avoid any licensing questions. Looking online, the only starting material that I can find is the following link - https://www.gamedev.net/forums/topic/496350-xaudio2-and-ogg/​ - however, it's a decade+ old and was wondering if there's a better way / an updated guide?

Does anyone have any recommendations / starting guides / can point me in the right direction as to what to do here please?

Thanks

Steve

Advertisement

The STB library has a single header ogg decompressor which you could use. It completely open source: https://github.com/nothings/stb/blob/master/stb_vorbis.c

You will get back 16-bit uncompressed audio data which will just fit into your existing Wav playback implementation. A simple example:

std::vector<uint8_t> data; // ogg file data
// load the ogg binary file into data vector...

int channels = 0;
int sample_rate = 0;
short* output = nullptr;
int samples = stb_vorbis_decode_memory(data.data(), (int)data.size(), &channels, &sample_rate, &output);
free(output);

I think it can be used to decompress just in time by chunks, so not the entire ogg file in one go, but I haven't tried that yet.

what that old link u shared is doing is actually okay ?, essentially u need to feed the voice:

                    // pseudo
        			// call m_pAudioBg->Update(); // <<-- from that ol' link 
        			
        			...
                    XAUDIO2_BUFFER buf = {}
                    buf.AudioBytes = ...
                    buf.pAudioData = ...
                    pSourceVoice->SubmitSourceBuffer(&buf, nullptr);
                    ...

since u're using directxtk/audio already, i assume u already know how to create the audioengine( … ) and how to use soundeffecXXX( ) or soundstreamXXXX( ) then all u need to do is find a way to feed this pSourceVoice with buf

  • download the latest lib-vorbis 1.3.7 from https://xiph.org/downloads/
  • and look at the vorbisfile_example.c, it is similar to how vorbis is used in the link u shared
  • u read the next chunk by calling ov_read ( … )

you could derive the CAudio class from class IVoiceNotify:

// pseudo
class CAudio: // <<-- from that old link
  public IVoiceNotify // <<-- from DirectXTK/blob/master/Inc/Audio.h
{
        virtual void __cdecl OnBufferEnd()
        {
        	// define me 
        	...
        }
  
        virtual void __cdecl OnCriticalError() 
        {
        ...
        }

        // Notification of an audio engine per-frame update (opt-in)

        virtual void __cdecl OnUpdate()

        {

        		CALL ov_read( ) here like in the old link

        		

        		THEN PASS data to voice like in the old link

        		

                XAUDIO2_BUFFER buf = {}
                buf.AudioBytes = ...
                buf.pAudioData = ...
                pSourceVoice->SubmitSourceBuffer(&buf, nullptr);
    

        }
        virtual void __cdecl OnDestroyEngine() 
        {
        ...
        }

        virtual void __cdecl OnTrim() 
        {
        ...
        }

        virtual void __cdecl GatherStatistics(AudioStatistics& stats) 
        {
        ...
        }

      
        virtual void __cdecl OnDestroyParent() noexcept
        {
        ...
        }

	// you can define the other methods here as well if u need them...//
	// i leave it as an exercise for u to work out :) //
};

then u want to call RegisterNotify ( ) before the sound is played :

       ...
       CAudio my_sound;
       ...
       your_audio_engine->RegisterNotify(&my_sound, true /*bool usesUpdate*/);

this will then call your update( ) when the sound is played and when you're done with the sound , you can call:

        ...
        your_audio_engine->UnregisterNotify(&my_sound, ... );
        ...

This should get u going ?

have fun ?

Thank you sir! That becomes today's project to get working! :-)

Thanks @turanszkij

This topic is closed to new replies.

Advertisement