Game Development Community

dev|Pro Game Development Curriculum

Fixing non-looping, streaming audio in TGB

by Devin Horsman · 01/26/2010 (11:36 am) · 3 comments

co-authored by Daniel Brauer

Note: I have included links to other posts that helped us get to the solution, but all the actual code and fixes are on this page in order to avoid confusion.

Using only non-streaming audio isn't really an option in some games. We had a lot of voice and music, and loading them all as they were needed caused unreasonable memory usage. Unfortunately, TGB 1.7.4 doesn't support non-looping streaming audio. When we tried to use non-looping, streaming audio we would see audio stop playing entirely, or get stuck repeating the same small portion over and over. This happened on both PC and Mac builds.

Our first step was to follow Clint Brewer's fix for non-looping, streaming audio. However, the Culling priority he implemented is an issue and leads to streaming audio never being culled, eventually resulting in audio not being able to play.
From:
http://www.torquepowered.com/community/forums/viewthread/34446

implement only:
in audio.cc:alxCloseHandles, near line 1870
//
         // should be playing? must have encounted an error.. remove
		 // DEVIN was all commented out [ http://www.torquepowered.com/community/forums/viewthread/34446 ]
         StreamingList::iterator itr2 = mStreamingList.findImage(mHandle[i]);
         if(itr2 && !((*itr2)->mHandle & AUDIOHANDLE_INACTIVE_BIT))
         {
            AssertFatal(!mStreamingInactiveList.findImage((*itr2)->mHandle), "alxCloseHandles: image incorrectly in inactive list");
            AssertFatal(!mStreamingCulledList.findImage((*itr2)->mHandle), "alxCloseHandles: image already in culled list");
			//(*itr2)->freeStream();

            mStreamingCulledList.push_back(*itr2);
            (*itr2)->mHandle |= AUDIOHANDLE_INACTIVE_BIT;

            mHandle[i] = NULL_AUDIOHANDLE;
            mBuffer[i] = 0;
         }
		 // END DEVIN

Then, some other fixes need to be made to the Streaming update function
in audio.cc:alxStreamingUpdate, near line 1819
// remove from culled list
		 // DEVIN Added
		 if(!(*itr)->mDescription.mIsLooping){
			StreamingList::iterator tmp;
			tmp = mStreamingCulledList.findImage((*itr)->mHandle);
			AssertFatal(tmp, "alxStreamingUpdate: failed to find culled source");
			mStreamingCulledList.erase_fast(tmp);

			// remove from streaming list (and free)
			tmp = mStreamingList.findImage((*itr)->mHandle);
			if(tmp)
			{
			  delete(*tmp);
			  mStreamingList.erase_fast(tmp);
			}
			 continue;
		 }
		 // END DEVIN
         StreamingList::iterator tmp = mStreamingCulledList.findImage((*itr)->mHandle);
         AssertFatal(tmp, "alxStreamingUpdate: failed to find culled source");
         mStreamingCulledList.erase_fast(tmp);
         // restore all state data
         mHandle[index] = (*itr)->mHandle;
		 mHandle[index] |= AUDIOHANDLE_LOADING_BIT & AUDIOHANDLE_STREAMING_BIT;
         mScore[index] = (*itr)->mScore;
		 mSourceVolume[index] = (*itr)->mDescription.mVolume;
         mType[index] = (*itr)->mDescription.mType;
         mSampleEnvironment[index] = (*itr)->mEnvironment;
         ALuint source = mSource[index];
		 (*itr)->mSource = mSource[index];
         alxSourcePlay(*itr); // DEVIN moved from above restore all state data.


The result was that non-looping, streaming audio finally worked. The exception was that certain sounds would cause TGB to crash every time they were played. We traced this issue to OpenAL, which we updated using a variation of Vern Jensen's guide to updating OpenAL in TGB:
http://www.torquepowered.com/community/forums/viewthread/94821

Get OpenAL from the following svn repository:

svn co svn://connect.creativelabs.com/OpenAL/tags/MacOSX1-2_Spec1-1/OpenAL-MacOSX

svn co svn://connect.creativelabs.com/OpenAL/tags/MacOSX1-2_Spec1-1/include

Put these two directories next to one another, then open the Xcode project inside OpenAL-MacOSX. By default, it will only build for the build machine's architecture. For each of:

OpenAL (the project)

1. Right-click OpenAL (the project) in the Groups & Files list, choose Get Info.
2. Click the "Build" tab at the top, and set Configuration to "All Configurations"
3. Under Architectures>Architectures, choose "Other.."
4. In the resulting dialog, push the minus sign to remove the existing one
5. Push the plus sign and fill in "i386 ppc" then push Ok.

Now for each of:

Targets>OpenAL
Targets>openal.dylib

1. Right-click the item and Get Info
2. Click the "Build" tab at the top, and set Configuration to "All Configurations"
3. Click on the label for Architectures>Architectures (not the pop-up menu)
5. Click the cog at the bottom left of the window and choose Delete Definition at this Level

Once this is done for each of the above items, you can build and fetch the result from the build directory next to the project file.

Be careful to delete the old framework from the TGB Xcode project before adding the new one.

In audio/audio.cc, get the Mac version to use the new pointer type in OpenALInit() near line 2406:
// Open a device
#ifdef TORQUE_OS_LINUX
   const char* deviceSpecifier =
     Con::getVariable("Pref::Unix::OpenALSpecifier");
   if (dStrlen(deviceSpecifier) == 0)
     // use SDL for audio output by default
     deviceSpecifier = "'((devices '(sdl)))";
   mDevice = (ALCdevice *)alcOpenDevice((ALubyte*)deviceSpecifier);
#else
#if defined(TORQUE_OS_MAC)
   mDevice = (ALCdevice *)alcOpenDevice((ALCchar*)NULL); //OpenAL 1.2 for Mac
#else
   mDevice = (ALCdevice *)alcOpenDevice((ALubyte*)NULL);
#endif
#endif

In audio/audioDataBlock.cc we add the following enum to keep certain bits of TGB happy. It should go near the top. We put it at line 11:
#if defined(TORQUE_OS_MAC) //new OpenAL doesn't have these, and TGB only ever references them
// used by DSPROPERTY_EAXLISTENER_ENVIRONMENT  

enum  
{  
   EAX_ENVIRONMENT_GENERIC,  
   EAX_ENVIRONMENT_PADDEDCELL,  
   EAX_ENVIRONMENT_ROOM,  
   EAX_ENVIRONMENT_BATHROOM,  
   EAX_ENVIRONMENT_LIVINGROOM,  
   EAX_ENVIRONMENT_STONEROOM,  
   EAX_ENVIRONMENT_AUDITORIUM,  
   EAX_ENVIRONMENT_CONCERTHALL,  
   EAX_ENVIRONMENT_CAVE,  
   EAX_ENVIRONMENT_ARENA,  
   EAX_ENVIRONMENT_HANGAR,  
   EAX_ENVIRONMENT_CARPETEDHALLWAY,  
   EAX_ENVIRONMENT_HALLWAY,  
   EAX_ENVIRONMENT_STONECORRIDOR,  
   EAX_ENVIRONMENT_ALLEY,  
   EAX_ENVIRONMENT_FOREST,  
   EAX_ENVIRONMENT_CITY,  
   EAX_ENVIRONMENT_MOUNTAINS,  
   EAX_ENVIRONMENT_QUARRY,  
   EAX_ENVIRONMENT_PLAIN,  
   EAX_ENVIRONMENT_PARKINGLOT,  
   EAX_ENVIRONMENT_SEWERPIPE,  
   EAX_ENVIRONMENT_UNDERWATER,  
   EAX_ENVIRONMENT_DRUGGED,  
   EAX_ENVIRONMENT_DIZZY,  
   EAX_ENVIRONMENT_PSYCHOTIC,  
   EAX_ENVIRONMENT_UNDEFINED,  
   EAX_ENVIRONMENT_COUNT  
};  
#endif

In platform/platformAL.h, we need to get rid of references to files that OpenAL doesn't have any more, starting at line 16:
#if defined(TORQUE_OS_MAC)
#include <OpenAL/al.h>
#include <OpenAL/alc.h>
//#include <OpenAL/altypes.h>
//#include <OpenAL/alctypes.h>
//#include <OpenAL/eaxtypes.h>
#else

In audio/vorbisStream.cc we need to fix a byte order problem near line 1495:
//#if defined(TORQUE_OS_MAC) && !defined(TORQUE_BIG_ENDIAN)
//       *dest=((val << 8) & 0xFF00) | ((val >> 8) & 0x00FF);
//#else
                     *dest=val;
//#endif

About the author

Game developer from Halifax Nova Scotia.

Recent Blogs


#1
01/26/2010 (12:00 pm)
Edit: We're experiencing a couple more issues, we'll have the last bits up soon, for now, use with caution on Mac
#2
01/26/2010 (12:29 pm)
The issues were caused by the MacOS OpenAL. We're editing the above post with the location we got the new library.
EDIT: Post updated.
#3
01/26/2010 (8:01 pm)
Excellent stuff. I could see you going mad, slowly, on IRC ;)