Add pausing, seeking, and dynamic volume to Torque audio code
by Robert Geiman · 12/18/2005 (6:39 pm) · 44 comments
Download Code File
Description
This resource explains how to add pause, unpause, seek, and dynamic per-audio file volume changing to the audio classes in TGE, TGB, and TSE, controllable from within TorqueScript. Pausing/unpausing works on any streaming or non-streaming audio file TGE supports, seeking works on all seekable OGG files, and dynamic volume changes works on any audio file.
Note that this resource supports TGE 1.5, TGE 1.3, TGE 1.4, TSE, and TGB.
Installation Instructions
Integrating these changes requires modifying 11 source/header files in Torque. There are two ways of implementing these changes: via replacing the affected files on your system with the versions included in the zip file attached to this resource, or by manually merging in the changes yourself. I describe both procedures below:
File replacement for TGE 1.5, TGE 1.4, TGE 1.3, and TGB.
1) Simply place the following files located in the zip file into the engine\audio folder:
* audio.cc
* audioBuffer.cc
* audioFunctions.cc
* audioStreamSource.h
* oggMixedStreamSource.cc
* oggMixedStreamSource.h
* vorbisStreamSource.cc
* vorbisStreamSource.h
* wavStreamSource.cc
* wavStreamSource.h
2) Simply place the following files located in the TGE 1.4 directory of the zip file into the engine\platform folder:
* platformAudio.h
3) Recompile Torque and that's it!
File replacement for TSE
1) Simply place the following files located in the TGE 1.3 directory of the zip file into the engine\audio folder:
* audio.cc
* audioBuffer.cc
* audioFunctions.cc
* audioStreamSource.h
* vorbisStreamSource.cc
* vorbisStreamSource.h
* wavStreamSource.cc
* wavStreamSource.h
2) Rename each .cc file to .cpp, replacing any previous existing .cpp files!
3) Simply place the following files located in the zip file into the engine\platform folder:
* platformAudio.h
4) Recompile Torque and that's it!
Manual integration for TGE 1.5 and TGE 1.4
1) Modify engine\audio\audio.cc and insert the following code after the definition of the alxStopAll() function:
Search for the function alxUpdateTypeGain(U32 type) and replace this line:
Search for the function alxGatherMetrics() and replace this line:
Search for the function alxCloseHandles() and replace this line:
Insert the following code at the very end of the file:
Manual integration for TGE 1.3
1) Follow the steps outlined in Manual integration for TGE 1.4, except skip steps 4 and 5. Note that the actual TGE 1.3 files included in this resource contain a few more fixes that are NOT described above so even though the implementing the changes manually will successfully add pausing and seeking, it's highly recommended that you instead use the files included in this resource.
Features
* Ability to pause/unpause playing of one or all audio files
* Ability to skip ahead/back to any specified time position while playing an OGG file
* Ability to modify the volume of any single playing audio file dynamically
Supported TorqueScript Functions
bool alxIsPaused(handle);
void alxPause(handle);
void alxPauseAll();
void alxUnpause(handle);
void alxUnpauseAll();
void alxSeekToStreamPosition(handle, seconds);
bool alxSetVolume(handle, volume);
F32 alxGetVolume(handle);
Updates
12/24/2005 - Added bug fix to seekToTime function. The zip file attached has the fix, or you can simply replace this function with the version posted in this resource under the Manual integration for TGE 1.4 section.
03/09/2006 - Merged both TGE 1.3 audio files and TGE 1.4 audio files into one set, so you can now use the same audio files to update TGE 1.3 as you do to update TGE 1.4. Note that this update has also added add some extra functionality to TGE 1.3 audio that is needed for my VMPlayer resource.
7/01/2006 - Added instructions for adding adding this resouce to TSE Milestone 3.5. Also added support for pausing/unpausing of non-streaming audio files (many thanks goes out to Gary Preston for taking the time to post all the changes necessary to add support of non-streaming audio file). Lastly added another fix by Gary Preston where in some rare circumstances unpausing sounds did not work. The fix is included in the latest release but you must also download OpenAl 1.1 for this fix to take effect.
1/07/2007 - Added fix for memory leak when playing streaming OGG files (many thanks goes out to Richard McKinney for this fix!). Also added support to dynamically change the volume on any playing audio file. Previously the Torque audio code only supported volume changes on a per-channel level.
1/07/2007 - Just added some fixes to the Manual Install section of this resource.
Enjoy!
Description
This resource explains how to add pause, unpause, seek, and dynamic per-audio file volume changing to the audio classes in TGE, TGB, and TSE, controllable from within TorqueScript. Pausing/unpausing works on any streaming or non-streaming audio file TGE supports, seeking works on all seekable OGG files, and dynamic volume changes works on any audio file.
Note that this resource supports TGE 1.5, TGE 1.3, TGE 1.4, TSE, and TGB.
Installation Instructions
Integrating these changes requires modifying 11 source/header files in Torque. There are two ways of implementing these changes: via replacing the affected files on your system with the versions included in the zip file attached to this resource, or by manually merging in the changes yourself. I describe both procedures below:
File replacement for TGE 1.5, TGE 1.4, TGE 1.3, and TGB.
1) Simply place the following files located in the zip file into the engine\audio folder:
* audio.cc
* audioBuffer.cc
* audioFunctions.cc
* audioStreamSource.h
* oggMixedStreamSource.cc
* oggMixedStreamSource.h
* vorbisStreamSource.cc
* vorbisStreamSource.h
* wavStreamSource.cc
* wavStreamSource.h
2) Simply place the following files located in the TGE 1.4 directory of the zip file into the engine\platform folder:
* platformAudio.h
3) Recompile Torque and that's it!
File replacement for TSE
1) Simply place the following files located in the TGE 1.3 directory of the zip file into the engine\audio folder:
* audio.cc
* audioBuffer.cc
* audioFunctions.cc
* audioStreamSource.h
* vorbisStreamSource.cc
* vorbisStreamSource.h
* wavStreamSource.cc
* wavStreamSource.h
2) Rename each .cc file to .cpp, replacing any previous existing .cpp files!
3) Simply place the following files located in the zip file into the engine\platform folder:
* platformAudio.h
4) Recompile Torque and that's it!
Manual integration for TGE 1.5 and TGE 1.4
1) Modify engine\audio\audio.cc and insert the following code after the definition of the alxStopAll() function:
bool alxIsPaused(AUDIOHANDLE handle)
{
if(handle == NULL_AUDIOHANDLE)
return(false);
U32 idx = alxFindIndex(handle);
if(idx == MAX_AUDIOSOURCES)
return(false);
ALint state = 0;
alGetSourcei(mSource[idx], AL_SOURCE_STATE, &state);
return(state == AL_PAUSED);
}
void alxPauseAll()
{
S32 i;
for(i = mNumSources - 1; i >= 0; i--)
if(mHandle[i] != NULL_AUDIOHANDLE)
alxPause(mHandle[i]);
}
void alxPause(AUDIOHANDLE handle)
{
if (handle == NULL_AUDIOHANDLE)
return;
ALuint source = alxFindSource(handle);
alSourcePause(source);
}
void alxUnpauseAll()
{
S32 i;
for(i = mNumSources - 1; i >= 0; i--)
if(mHandle[i] != NULL_AUDIOHANDLE)
alxUnpause(mHandle[i]);
}
void alxUnpause(AUDIOHANDLE handle)
{
if (handle == NULL_AUDIOHANDLE)
return;
ALuint source = alxFindSource(handle);
alSourcePlay(source);
}
bool alxSetVolume(AUDIOHANDLE handle, F32 volume)
{
if (handle == NULL_AUDIOHANDLE)
return false;
U32 idx = alxFindIndex(handle);
if (idx == MAX_AUDIOSOURCES)
return false;
mSourceVolume[idx] = volume;
F32 new_volume = mClampF(mSourceVolume[idx] * mAudioTypeVolume[mType[idx]] * mMasterVolume, 0.f, 1.f);
alSourcef(mSource[idx], AL_GAIN, Audio::linearToDB(new_volume));
return true;
}
F32 alxGetVolume(AUDIOHANDLE handle)
{
if (handle == NULL_AUDIOHANDLE)
return 0.0f;
U32 idx = alxFindIndex(handle);
if (idx == MAX_AUDIOSOURCES)
return 0.0f;
return mSourceVolume[idx];
}
F32 alxGetStreamPosition( AUDIOHANDLE handle )
{
if(handle == NULL_AUDIOHANDLE)
return -1.f;
StreamingList::iterator itr = mStreamingList.findImage(handle);
if( !itr )
return -1.f;
return (*itr)->getElapsedTime();
}
F32 alxGetStreamDuration( AUDIOHANDLE handle )
{
if(handle == NULL_AUDIOHANDLE)
return -1.f;
StreamingList::iterator itr = mStreamingList.findImage(handle);
if( !itr )
return -1.f;
return (*itr)->getTotalTime();
}
bool alxSeekToStreamPosition( AUDIOHANDLE handle, F32 seconds)
{
if(handle == NULL_AUDIOHANDLE)
return false;
StreamingList::iterator itr = mStreamingList.findImage(handle);
if( !itr )
return false;
return (*itr)->seekToTime(seconds);
}Search for the function alxIsValidHandle(AUDIOHANDLE handle) and replace this line:return(state == AL_PLAYING);with this:
return(state == AL_PLAYING || state == AL_PAUSED);
Search for the function alxUpdateTypeGain(U32 type) and replace this line:
if(state == AL_PLAYING)with this:
if(state == AL_PLAYING || state == AL_PAUSED)
Search for the function alxGatherMetrics() and replace this line:
if(state == AL_PLAYING)with this:
if(state == AL_PLAYING || state == AL_PAUSED)
Search for the function alxCloseHandles() and replace this line:
if(state == AL_PLAYING)with this:
if(state == AL_PLAYING || state == AL_PAUSED)2) Modify engine\audio\audioFunctions.cc and insert the following code after the definition of the alxStopAll() console function:
//-----------------------------------------------
ConsoleFunction(alxGetStreamPosition, F32, 2, 2, "alxGetStreamPosition(handle)" )
{
AUDIOHANDLE handle = dAtoi(argv[1]);
if(handle == NULL_AUDIOHANDLE)
return -1;
return alxGetStreamPosition( handle );
}
//-----------------------------------------------
ConsoleFunction(alxGetStreamDuration, F32, 2, 2, "alxGetStreamDuration(handle)" )
{
AUDIOHANDLE handle = dAtoi(argv[1]);
if(handle == NULL_AUDIOHANDLE)
return -1;
return alxGetStreamDuration( handle );
}
//-----------------------------------------------
ConsoleFunction(alxSeekToStreamPosition, bool, 3, 3, "alxSeekToStreamPosition(handle)" )
{
AUDIOHANDLE handle = dAtoi(argv[1]);
F32 seconds = dAtof(argv[2]);
if(handle == NULL_AUDIOHANDLE)
return false;
return alxSeekToStreamPosition( handle, seconds );
}
//-----------------------------------------------
ConsoleFunction(alxIsPaused, bool, 2, 5, "alxIsPaused(handle)")
{
AUDIOHANDLE handle = dAtoi(argv[1]);
if(handle == NULL_AUDIOHANDLE)
return false;
return alxIsPaused(handle);
}
//-----------------------------------------------
ConsoleFunction(alxPauseAll, void, 1, 1, "()")
{
alxPauseAll();
}
//-----------------------------------------------
ConsoleFunction(alxPause, void, 2, 2, "alxPause(handle)" )
{
AUDIOHANDLE handle = dAtoi(argv[1]);
if(handle == NULL_AUDIOHANDLE)
return;
alxPause( handle );
}
//-----------------------------------------------
ConsoleFunction(alxUnpauseAll, void, 1, 1, "()")
{
alxUnpauseAll();
}
//-----------------------------------------------
ConsoleFunction(alxUnpause, void, 2, 2, "alxUnpause(handle)" )
{
AUDIOHANDLE handle = dAtoi(argv[1]);
if(handle == NULL_AUDIOHANDLE)
return;
alxUnpause( handle );
}
//-----------------------------------------------
ConsoleFunction(alxSetVolume, bool, 3, 3, "alxSetVolume(handle, float volume)\n\n"
"@param handle Handle of audio.\n"
"@param volume New volume of audio, from 0.0f - 1.0f"
)
{
AUDIOHANDLE handle = dAtoi(argv[1]);
F32 volume = mClampF(dAtof(argv[2]), 0.f, 1.f);
return alxSetVolume(handle, volume);
}
//-----------------------------------------------
ConsoleFunction(alxGetVolume, F32, 2, 2, "alxGetVolume(handle)" )
{
AUDIOHANDLE handle = dAtoi(argv[1]);
return alxGetVolume(handle);
}3) Modify engine\audio\audioStreamSource.h and insert the following code after the declaraction of the freeStream() function:virtual F32 getElapsedTime() = 0; virtual F32 getTotalTime() = 0; virtual bool seekToTime(F32 seconds) = 0; virtual void pause() = 0; virtual void unpause() = 0;4) Modify engine\audio\oggMixedStreamSource.cc and insert the following code at the very end of the file:
void OggMixedStreamSource::pause()
{
alSourcePause(mSource);
}
void OggMixedStreamSource::unpause()
{
alSourcePlay(mSource);
}5) Modify engine\audio\oggMixedStreamSource.h and insert the following code after the declaration of the freeStream() function:virtual F32 getElapsedTime()
{
return 0.0;
}
virtual F32 getTotalTime()
{
return 1.0f;
}
virtual bool seekToTime(F32 seconds)
{
return false;
}
virtual void pause();
virtual void unpause();6) Modify engine\audio\vorbisStreamSource.cc and insert the following code at the very end of the file:F32 VorbisStreamSource::getElapsedTime()
{
return vf.ov_time_tell();
}
F32 VorbisStreamSource::getTotalTime()
{
return vf.ov_time_total(-1);
}
bool VorbisStreamSource::seekToTime(F32 seconds)
{
static char data[BUFFERSIZE*2];
ALint error;
bFinished = false;
// Verify we were currently playing or paused
ALint state = 0;
alGetSourcei(mSource, AL_SOURCE_STATE, &state);
if (state != AL_PLAYING && state != AL_PAUSED)
return false;
// Don't bother if this file isn't seekable
if (vf.ov_seekable() == false)
return false;
alSourceStop(mSource);
alSourcei(mSource, AL_BUFFER, 0);
alSourcePlay(mSource);
// Don't try to seek past the end of the song or before the begining
seconds = getMin(seconds, (F32)vf.ov_time_total(-1) - 0.001f);
seconds = getMax(seconds, 0.0f);
// Seek to specified time position
vf.ov_time_seek(seconds);
long samples = (long)vf.ov_pcm_tell();
if(format == AL_FORMAT_MONO16)
DataLeft = DataSize - (2 * samples);
else
DataLeft = DataSize - (4 * samples);
bBuffersAllocated = true;
int numBuffers = 0;
for(int loop = 0; loop < NUMBUFFERS; loop++)
{
ALuint DataToRead = (DataLeft > BUFFERSIZE) ? BUFFERSIZE : DataLeft;
if (DataToRead == DataLeft)
bFinished = AL_TRUE;
long ret = oggRead(data, BUFFERSIZE, ENDIAN, ¤t_section);
if(ret <= 0) {
bFinished = AL_TRUE;
break;
}
DataLeft -= ret;
alBufferData(mBufferList[loop], format, data, ret, freq);
++numBuffers;
if ((error = alGetError()) != AL_NO_ERROR)
return false;
if(bFinished)
break;
}
// Queue the buffers on the source
alSourceQueueBuffers(mSource, numBuffers, mBufferList);
if ((error = alGetError()) != AL_NO_ERROR)
return false;
alSourcei(mSource, AL_LOOPING, AL_FALSE);
// We have to update the buffers here, otherwise alxCloseHandles
// thinks we aren't valid (ie, we aren't in a playing or paused
// state).
updateBuffers();
// We don't really want to start playing if we were previously
// paused.
if (state == AL_PAUSED)
alSourcePause(mSource);
return true;
}
void VorbisStreamSource::pause()
{
alSourcePause(mSource);
}
void VorbisStreamSource::unpause()
{
alSourcePlay(mSource);
}7) Modify engine\audio\vorbisStreamSource.cc and replace the following code that appears twice in this file:if(mBufferList[0] != 0) alDeleteBuffers(NUMBUFFERS, mBufferList); for(int i = 0; i < NUMBUFFERS; i++) mBufferList[i] = 0;with the code below:
// Ensure that the refCount on the buffers is zero: alSourceUnqueueBuffers (mSource, NUMBUFFERS, mBufferList); if(mBufferList[0] != 0) alDeleteBuffers(NUMBUFFERS, mBufferList); for(int i = 0; i < NUMBUFFERS; i++) mBufferList[i] = 0;8) Modify engine\audio\vorbisStreamSouce.h and insert the following code after the declaration of the freeStream() function:
virtual F32 getElapsedTime(); virtual F32 getTotalTime(); virtual bool seekToTime(F32 seconds); virtual void pause(); virtual void unpause();9) Modify engine\audio\wavStreamSource.cc and insert the following code:
#include "console/console.h"directly after this line:
#include "audio/wavStreamSource.h"
Insert the following code at the very end of the file:
F32 WavStreamSource::getElapsedTime()
{
Con::warnf( "GetElapsedTime not implemented in WaveStreams yet" );
return -1.f;
}
F32 WavStreamSource::getTotalTime()
{
Con::warnf( "GetTotalTime not implemented in WaveStreams yet" );
return -1.f;
}
bool WavStreamSource::seekToTime(F32 seconds)
{
Con::warnf( "seekToTime not implemented in WaveStreams yet" );
return false;
}
void WavStreamSource::pause()
{
alSourcePause(mSource);
}
void WavStreamSource::unpause()
{
alSourcePlay(mSource);
}10) Modify engine\audio\wavStreamSource.h and insert the following code after the declaration of the freeStream() function:virtual F32 getElapsedTime(); virtual F32 getTotalTime(); virtual bool seekToTime(F32 seconds); virtual void pause(); virtual void unpause();11) Modify engine\platform\platformAudio.h and insert the following code after the declaration of the alxStopAll() function:
F32 alxGetStreamDuration(AUDIOHANDLE handle); F32 alxGetStreamPosition(AUDIOHANDLE handle); bool alxSeekToStreamPosition(AUDIOHANDLE handle, F32 seconds); bool alxIsPaused(AUDIOHANDLE handle); void alxPauseAll(); void alxPause(AUDIOHANDLE handle); void alxUnpauseAll(); void alxUnpause(AUDIOHANDLE handle); F32 alxGetVolume(AUDIOHANDLE handle); bool alxSetVolume(AUDIOHANDLE handle, F32 volume);12) Modify engine\audio\audioBuffer.cpp and find the AudioBuffer::getALBuffer() function, and replace the two lines just before the call to alGenBuffers with:
// Intangir> fix for newest openAL from creative (it returns true, yea right 0 is not a valid buffer) // it MIGHT not work at all for all i know. if (malBuffer && alIsBuffer(malBuffer)) return malBuffer;13) Recompile Torque and you're done!
Manual integration for TGE 1.3
1) Follow the steps outlined in Manual integration for TGE 1.4, except skip steps 4 and 5. Note that the actual TGE 1.3 files included in this resource contain a few more fixes that are NOT described above so even though the implementing the changes manually will successfully add pausing and seeking, it's highly recommended that you instead use the files included in this resource.
Features
* Ability to pause/unpause playing of one or all audio files
* Ability to skip ahead/back to any specified time position while playing an OGG file
* Ability to modify the volume of any single playing audio file dynamically
Supported TorqueScript Functions
bool alxIsPaused(handle);
void alxPause(handle);
void alxPauseAll();
void alxUnpause(handle);
void alxUnpauseAll();
void alxSeekToStreamPosition(handle, seconds);
bool alxSetVolume(handle, volume);
F32 alxGetVolume(handle);
Updates
12/24/2005 - Added bug fix to seekToTime function. The zip file attached has the fix, or you can simply replace this function with the version posted in this resource under the Manual integration for TGE 1.4 section.
03/09/2006 - Merged both TGE 1.3 audio files and TGE 1.4 audio files into one set, so you can now use the same audio files to update TGE 1.3 as you do to update TGE 1.4. Note that this update has also added add some extra functionality to TGE 1.3 audio that is needed for my VMPlayer resource.
7/01/2006 - Added instructions for adding adding this resouce to TSE Milestone 3.5. Also added support for pausing/unpausing of non-streaming audio files (many thanks goes out to Gary Preston for taking the time to post all the changes necessary to add support of non-streaming audio file). Lastly added another fix by Gary Preston where in some rare circumstances unpausing sounds did not work. The fix is included in the latest release but you must also download OpenAl 1.1 for this fix to take effect.
1/07/2007 - Added fix for memory leak when playing streaming OGG files (many thanks goes out to Richard McKinney for this fix!). Also added support to dynamically change the volume on any playing audio file. Previously the Torque audio code only supported volume changes on a per-channel level.
1/07/2007 - Just added some fixes to the Manual Install section of this resource.
Enjoy!
About the author
#2
That why I'm actually planning on releasing another resource for game music that's purely script based that build's off of this resource. It'll support fade in/out and much, much, much more. I don't want to give away anymore details until I'm sure I can implement all the features that I want to. I'm hoping to have it finished in another week, so stay tuned.
12/19/2005 (12:39 pm)
Tim, I'm actually doing the same in my game.That why I'm actually planning on releasing another resource for game music that's purely script based that build's off of this resource. It'll support fade in/out and much, much, much more. I don't want to give away anymore details until I'm sure I can implement all the features that I want to. I'm hoping to have it finished in another week, so stay tuned.
#3
12/19/2005 (4:55 pm)
Robert, you just made my day. Sound is very important to me & what you've done here is brilliant. Very pleased to hear you have more to come.
#4
12/24/2005 (11:22 am)
FYI, I discovered a bug in the seekToTime() function which I've since fixed. If you use this feature you'll want to get this fix. The source files in the zip attached to this resource have the fix, so you can simply replace your old files, or if you like you could simply replace seekToTime() function in the vorbisStreamSource.cc file with the version posted under the Manual Integration section.
#5
12/28/2005 (3:03 pm)
Wow, this is really cool. Looking forward to the fade resource too, Robert.
#6
Anyone who is running TGE 1.3 and wishes to use VMPlayer would need to get the latest files and recompile TGE. Those who are running TGE 1.4 or do not wish to use VMPlayer do not need to update as there are no bug fixes in this latest update.
For those interested, the VMPlayer resource can be downloaded here:
http://www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=9560
03/09/2006 (10:08 am)
I've made another small change to this resource. I've merged both the 1.3 and 1.4 audio files into one single set that can be used to update both TGE 1.4 and TGE 1.3. In doing so, this adds some extra functionality to TGE 1.3 which is required to get my VMPlayer resource to work with TGE 1.3.Anyone who is running TGE 1.3 and wishes to use VMPlayer would need to get the latest files and recompile TGE. Those who are running TGE 1.4 or do not wish to use VMPlayer do not need to update as there are no bug fixes in this latest update.
For those interested, the VMPlayer resource can be downloaded here:
http://www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=9560
#7
03/09/2006 (2:35 pm)
Nice work, Robert!
#8
For those sounds that keep playing after calling alxPauseAll, if I change their profile and add isStreaming=true; the sounds will now pause. Any ideas why non-streaming sounds won't ?
I've only had a quick look through the audio code so I'm not sure whether pausing of none streaming sounds is possible, so this may not be a bug, just a missing feature :P If anyone has any ideas I'd love to hear them, if not you can find me knee deep in the audio code.
04/27/2006 (9:46 am)
Anyone tried pausing non streaming audio? calling alxPauseAll() seems to pause any audio files that have isStreaming=true in the profile, but doesn't pause any others. For those sounds that keep playing after calling alxPauseAll, if I change their profile and add isStreaming=true; the sounds will now pause. Any ideas why non-streaming sounds won't ?
I've only had a quick look through the audio code so I'm not sure whether pausing of none streaming sounds is possible, so this may not be a bug, just a missing feature :P If anyone has any ideas I'd love to hear them, if not you can find me knee deep in the audio code.
#9
04/27/2006 (10:59 am)
Gary, it's been a while since I wrote that code, so I don't have any ideas off the top of my head. However, I'll be happy to take a look at the code on Monday when I get back from my business trip. If you happen to make changes before I get a chance then please post them and I'll update this resource to include them.
#10
As a quick test I changed this method to pause the source stored in the global mSource and all the sounds pause eg:
Without more digging though I'm not sure of the implications of this (although the ->pause() method only calls alSourcePause anyway. However, unpausing is another matter. From the openal docs it states that calling alSourcePlay on a source in the AL_PAUSED state will resume the source from its stored state whilst calling it on a playing source will restart the audio. Well, changing the unpause to a findsource/alsourceplay call unpauses the audio but it starts at the beginning of the sample again.
I'm missing something, gonna spend an hour or two and have a good read though the source/openal docs to see if I can find anything obvious. Failing that I'll do a more detailed look at this tomorrow :)
Another update: The source still has its paused state set prior to the call to alSourcePlay(source); which suggests this may also be a problem in openal. I've done a quick google and turned up a few posts regarding bugs with the windows version of openal and resuming sounds on v1.0. V1.1 doesn't look like it will be a viable solution as sound is compleatly non-functional using that dll and upgrading to make use of the latest sdk might be some work :P
More updates: This refers to the current resume play bug I'm seeing. opensource.creative.com/pipermail/openal-devel/2004-January/000226.html from what I've read elsewhere an update to 1.0 was released that fixed this which would save trying to move over to 1.1.
04/27/2006 (12:20 pm)
I've had a short look through the code so I may still be missing the bigger picture, but from what I've seen so far, it looks like the pause/unpause methods only handle streaming sources egStreamingList::iterator itr = mStreamingList.findImage(handle);
if( !itr )
return;
(*itr)->pause();As a quick test I changed this method to pause the source stored in the global mSource and all the sounds pause eg:
ALuint source = alxFindSource(handle); alSourcePause(source);
Without more digging though I'm not sure of the implications of this (although the ->pause() method only calls alSourcePause anyway. However, unpausing is another matter. From the openal docs it states that calling alSourcePlay on a source in the AL_PAUSED state will resume the source from its stored state whilst calling it on a playing source will restart the audio. Well, changing the unpause to a findsource/alsourceplay call unpauses the audio but it starts at the beginning of the sample again.
I'm missing something, gonna spend an hour or two and have a good read though the source/openal docs to see if I can find anything obvious. Failing that I'll do a more detailed look at this tomorrow :)
Another update: The source still has its paused state set prior to the call to alSourcePlay(source); which suggests this may also be a problem in openal. I've done a quick google and turned up a few posts regarding bugs with the windows version of openal and resuming sounds on v1.0. V1.1 doesn't look like it will be a viable solution as sound is compleatly non-functional using that dll and upgrading to make use of the latest sdk might be some work :P
More updates: This refers to the current resume play bug I'm seeing. opensource.creative.com/pipermail/openal-devel/2004-January/000226.html from what I've read elsewhere an update to 1.0 was released that fixed this which would save trying to move over to 1.1.
#11
Changing the alxpause and and alxunpause routines to the following
I also removed the loopinglist and streaminglist calls in pauseall/unpause all which now looks like:
This will pause/unpause streaming and none streaming sounds.
Now the other problem I encountered is that with the openal32.dll I had installed (earlier version from TGE 1.3) the unpause was not working correctly, rather than alsourceplay resuming a paused sound from the paused location it would restart the sound. This only occurs on windows and in specific instances. Its a bug in the openal dll.
Downloading the latest OpenAl 1.1 windows installer will resolve this bug. However, it brings its own problems, namely none of the sounds worked anymore.
After a fair bit of digging and comparint tge1.3 to 1.4 audio code I isolated it down to the following fix: In audioBuffer.cc AudioBuffer::getALBuffer the line just before alGenBuffers should be changed to
With that fix in place the latest 1.1 install of openAL will play correctly (at least on my SBLive and also integrated hardware which it didn't before) and with 1.1 we get the alSourcePlay resume bug fix :)
I'm gonna finish of checking the differences between tge1.3 and 1.4 audio code and merge things over, but the above should be all thats needed.
Let me know if you find any problems with any of the above.
04/27/2006 (4:23 pm)
In a professor Farnsworth voice: "Good news everybody"Changing the alxpause and and alxunpause routines to the following
void alxPause(AUDIOHANDLE handle)
{
ALuint source = alxFindSource(handle);
alSourcePause(source);
}
void alxUnpause(AUDIOHANDLE handle)
{
ALuint source = alxFindSource(handle);
alSourcePlay(source);
}I also removed the loopinglist and streaminglist calls in pauseall/unpause all which now looks like:
void alxPauseAll()
{
S32 i;
for(i = mNumSources - 1; i >= 0; i--)
if(mHandle[i] != NULL_AUDIOHANDLE)
alxPause(mHandle[i]);
}
void alxUnpauseAll()
{
S32 i;
for(i = mNumSources - 1; i >= 0; i--)
if(mHandle[i] != NULL_AUDIOHANDLE)
alxUnpause(mHandle[i]);
}This will pause/unpause streaming and none streaming sounds.
Now the other problem I encountered is that with the openal32.dll I had installed (earlier version from TGE 1.3) the unpause was not working correctly, rather than alsourceplay resuming a paused sound from the paused location it would restart the sound. This only occurs on windows and in specific instances. Its a bug in the openal dll.
Downloading the latest OpenAl 1.1 windows installer will resolve this bug. However, it brings its own problems, namely none of the sounds worked anymore.
After a fair bit of digging and comparint tge1.3 to 1.4 audio code I isolated it down to the following fix: In audioBuffer.cc AudioBuffer::getALBuffer the line just before alGenBuffers should be changed to
// Intangir> fix for newest openAL from creative (it returns true, yea right 0 is not a valid buffer)
// it MIGHT not work at all for all i know.
if (malBuffer && alIsBuffer(malBuffer))
return malBuffer;With that fix in place the latest 1.1 install of openAL will play correctly (at least on my SBLive and also integrated hardware which it didn't before) and with 1.1 we get the alSourcePlay resume bug fix :)
I'm gonna finish of checking the differences between tge1.3 and 1.4 audio code and merge things over, but the above should be all thats needed.
Let me know if you find any problems with any of the above.
#12
Thanks for taking the time to post your changes!
04/27/2006 (5:31 pm)
That IS good news, Gary. When I get back from my trip I'll look over your changes more closely, and verify it doesn't break anything. Once I'm satisfied I'll merge them into this resource.Thanks for taking the time to post your changes!
#13
06/30/2006 (6:36 pm)
Doesn't work in TSE Milestone 3.5.
#14
This includes support for TSE Milestone 3.5. To install under TSE you must rename all .cc files included in this resource to .cpp, replacing any existing files. Instructions are included now at the top of this resource.
Also included Gary Preston's changes to support non-streaming audio files, as well as that rare issue where unpausing doesn't work correctly (this also requires installing openAl 1.1 or greater as well to fix this issue).
07/01/2006 (11:46 am)
C2, I just posted a new update to this resource.This includes support for TSE Milestone 3.5. To install under TSE you must rename all .cc files included in this resource to .cpp, replacing any existing files. Instructions are included now at the top of this resource.
Also included Gary Preston's changes to support non-streaming audio files, as well as that rare issue where unpausing doesn't work correctly (this also requires installing openAl 1.1 or greater as well to fix this issue).
#15
Here is the changed
07/03/2006 (7:39 am)
for those of you attempting to get this to work with versions of TGE before 1.3 you might find that fading does not work. The issue is in audioFunctions.cc alxGetChannelVolum. For some unknown reason this ConsoleFunction is setup to return a S32.Here is the changed
//--------------------------------------------------------------------------
// Channel Volumes
//--------------------------------------------------------------------------
ConsoleFunction(alxGetChannelVolume, F32, 2, 2, "alxGetChannelVolume(channel_id)")
{
U32 type = dAtoi(argv[1]);
Audio::NumAudioTypes, mAudioTypeVolume[type]);
if(type >= Audio::NumAudioTypes)
{
Con::errorf(ConsoleLogEntry::General, "alxGetChannelVolume: invalid channel '%d'", dAtoi(argv[1]));
return(0.f);
}
return(mAudioTypeVolume[type]);
}
#16
I do have a concern, I noticed that the memory consumed by the game continued to increase every time a song would play and never came back down. I even deleted the virtual player object from memory hoping it would release some memory but it did not.
Does anyone know if there is a way to better manage memory in this resource?
Thx!
- BigPapa
07/14/2006 (9:06 pm)
This was extremely easy to implement. Now I just have to design an interface for users to be able to manage playlists and songs.I do have a concern, I noticed that the memory consumed by the game continued to increase every time a song would play and never came back down. I even deleted the virtual player object from memory hoping it would release some memory but it did not.
Does anyone know if there is a way to better manage memory in this resource?
Thx!
- BigPapa
#18
10/18/2006 (12:16 pm)
I tried it on TGB 1.1.2 and it works perfectly so far (under very limited testing).
#20
10/20/2006 (5:16 am)
Robert, looks like you have a cut-and-paste error in the resource's definition of alxUnPauseAll()...it's different from the version in your zip file (not to mention a syntax error :). 
Torque Owner Tim Heldna
Thank you.
Hey, if you wanted to add to this to make it even better you could add a volume fade control function. We use this in our game so when one music track has finished playing the volume slowly fades out as the next track fades in. This gives a much nicer transition, especially useful if you're using triggers for level music.
Thanks again for contributing.