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
Then, some other fixes need to be made to the Streaming update function
in audio.cc:alxStreamingUpdate, near line 1819
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:
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:
In platform/platformAL.h, we need to get rid of references to files that OpenAL doesn't have any more, starting at line 16:
In audio/vorbisStream.cc we need to fix a byte order problem near line 1495:
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 DEVINThen, 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
#endifIn 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
};
#endifIn 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
Torque Owner Devin Horsman