Logo Search packages:      
Sourcecode: warzone2100 version File versions

audio.c

/*
      This file is part of Warzone 2100.
      Copyright (C) 1999-2004  Eidos Interactive
      Copyright (C) 2005-2007  Warzone Resurrection Project

      Warzone 2100 is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published by
      the Free Software Foundation; either version 2 of the License, or
      (at your option) any later version.

      Warzone 2100 is distributed in the hope that it will be useful,
      but WITHOUT ANY WARRANTY; without even the implied warranty of
      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
      GNU General Public License for more details.

      You should have received a copy of the GNU General Public License
      along with Warzone 2100; if not, write to the Free Software
      Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "lib/framework/frame.h"
#include "lib/framework/frameresource.h"
#include "lib/gamelib/gtime.h"
#include "lib/ivis_common/pietypes.h"

#include "tracklib.h"
#include "aud.h"
#include "audio_id.h"

// defines
#define NO_SAMPLE                   - 2
#define MAX_SAME_SAMPLES            2

// global variables
static AUDIO_SAMPLE *g_psSampleList = NULL;
static AUDIO_SAMPLE *g_psSampleQueue = NULL;
static BOOL             g_bAudioEnabled = false;
static BOOL             g_bAudioPaused = false;
static AUDIO_SAMPLE g_sPreviousSample;

/** Counts the number of samples in the SampleQueue
 *  \return the number of samples in the SampleQueue
 */
unsigned int audio_GetSampleQueueCount()
{
      //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      AUDIO_SAMPLE      *psSample = NULL;
      unsigned int      count=0;
      //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

      // loop through SampleQueue to count how many we have.
      psSample = g_psSampleQueue;
      while ( psSample != NULL )
      {
            count++;
            psSample = psSample->psNext;
      }

      return count;
}

/** Counts the number of samples in the SampleList
 *  \return the number of samples in the SampleList
 */
unsigned int audio_GetSampleListCount()
{
      //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      AUDIO_SAMPLE *psSample = NULL;
      unsigned int count = 0;
      //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

      // loop through SampleList to count how many we have.
      psSample = g_psSampleList;
      while (psSample != NULL)
      {
            ++count;
            psSample = psSample->psNext;
      }

      return count;
}
//*
// =======================================================================================================================
// =======================================================================================================================
//
BOOL audio_Disabled( void )
{
      return !g_bAudioEnabled;
}

//*
// =======================================================================================================================
// =======================================================================================================================
//
BOOL audio_Init( AUDIO_CALLBACK pStopTrackCallback )
{
      // init audio system
      g_sPreviousSample.iTrack = NO_SAMPLE;
      g_sPreviousSample.x = SAMPLE_COORD_INVALID;
      g_sPreviousSample.y = SAMPLE_COORD_INVALID;
      g_sPreviousSample.z = SAMPLE_COORD_INVALID;
      g_bAudioEnabled = sound_Init();
      if (g_bAudioEnabled)
      {
            sound_SetStoppedCallback( pStopTrackCallback );
      }
      return g_bAudioEnabled;
}

//*
// =======================================================================================================================
// =======================================================================================================================
//
BOOL audio_Shutdown( void )
{
      //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      AUDIO_SAMPLE      *psSample = NULL, *psSampleTemp = NULL;
      BOOL              bOK;
      //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

      // if audio not enabled return true to carry on game without audio
      if ( g_bAudioEnabled == false )
      {
            return true;
      }

      sound_StopAll();
      bOK = sound_Shutdown();

      // empty sample list
      psSample = g_psSampleList;
      while ( psSample != NULL )
      {
            psSampleTemp = psSample->psNext;
            free(psSample);
            psSample = psSampleTemp;
      }

      // empty sample queue
      psSample = g_psSampleQueue;
      while ( psSample != NULL )
      {
            psSampleTemp = psSample->psNext;
            free(psSample);
            psSample = psSampleTemp;
      }

      // free sample heap
      g_psSampleList = NULL;
      g_psSampleQueue = NULL;

      return bOK;
}

//*
// =======================================================================================================================
// =======================================================================================================================
//
BOOL audio_GetPreviousQueueTrackPos( SDWORD *iX, SDWORD *iY, SDWORD *iZ )
{
      if (g_sPreviousSample.x == SAMPLE_COORD_INVALID
       || g_sPreviousSample.y == SAMPLE_COORD_INVALID
       || g_sPreviousSample.z == SAMPLE_COORD_INVALID)
      {
            return false;
      }

      *iX = g_sPreviousSample.x;
      *iY = g_sPreviousSample.y;
      *iZ = g_sPreviousSample.z;

      return true;
}

//*
// =======================================================================================================================
// =======================================================================================================================
//
static void audio_AddSampleToHead( AUDIO_SAMPLE **ppsSampleList, AUDIO_SAMPLE *psSample )
{
      psSample->psNext = ( *ppsSampleList );
      psSample->psPrev = NULL;
      if ( (*ppsSampleList) != NULL )
      {
            ( *ppsSampleList )->psPrev = psSample;
      }
      ( *ppsSampleList ) = psSample;
}

//*
// =======================================================================================================================
// =======================================================================================================================
//
static void audio_AddSampleToTail( AUDIO_SAMPLE **ppsSampleList, AUDIO_SAMPLE *psSample )
{
      //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      AUDIO_SAMPLE      *psSampleTail = NULL;
      //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

      if ( (*ppsSampleList) == NULL )
      {
            ( *ppsSampleList ) = psSample;
            return;
      }

      psSampleTail = ( *ppsSampleList );
      while ( psSampleTail->psNext != NULL )
      {
            psSampleTail = psSampleTail->psNext;
      }

      psSampleTail->psNext = psSample;
      psSample->psPrev = psSampleTail;
      psSample->psNext = NULL;
}

//*
//
// audio_RemoveSample Removes sample from list but doesn't free its memory

//*
// =======================================================================================================================
// =======================================================================================================================
//
static void audio_RemoveSample( AUDIO_SAMPLE **ppsSampleList, AUDIO_SAMPLE *psSample )
{
      if ( psSample == NULL )
      {
            return;
      }

      if ( psSample == (*ppsSampleList) )
      {
            // first sample in list
            ( *ppsSampleList ) = psSample->psNext;
      }

      if ( psSample->psPrev != NULL )
      {
            psSample->psPrev->psNext = psSample->psNext;
      }

      if ( psSample->psNext != NULL )
      {
            psSample->psNext->psPrev = psSample->psPrev;
      }

      // set sample pointers NULL for safety
      psSample->psPrev = NULL;
      psSample->psNext = NULL;
}

//*
// =======================================================================================================================
// =======================================================================================================================
//
static BOOL audio_CheckSameQueueTracksPlaying( SDWORD iTrack )
{
      //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      SDWORD                  iCount;
      AUDIO_SAMPLE      *psSample = NULL;
      BOOL              bOK = true;
      //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

      // return if audio not enabled
      if ( g_bAudioEnabled == false || g_bAudioPaused == true )
      {
            return true;
      }

      iCount = 0;

      // loop through queue sounds and check whether too many already in it
      psSample = g_psSampleQueue;
      while ( psSample != NULL )
      {
            if ( psSample->iTrack == iTrack )
            {
                  iCount++;
            }

            if ( iCount > MAX_SAME_SAMPLES )
            {
                  bOK = false;
                  break;
            }

            psSample = psSample->psNext;
      }

      return bOK;
}

//*
// =======================================================================================================================
// =======================================================================================================================
//
static AUDIO_SAMPLE *audio_QueueSample( SDWORD iTrack )
{
      //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      AUDIO_SAMPLE      *psSample = NULL;
      //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

      // return if audio not enabled
      if ( g_bAudioEnabled == false || g_bAudioPaused == true)
      {
            return NULL;
      }

      ASSERT( sound_CheckTrack(iTrack) == true, "audio_QueueSample: track %i outside limits\n", iTrack );

      // reject track if too many of same ID already in queue
      if ( audio_CheckSameQueueTracksPlaying(iTrack) == false )
      {
            return NULL;
      }

      psSample = calloc(1, sizeof(AUDIO_SAMPLE));
      if ( psSample == NULL )
      {
            debug(LOG_ERROR, "audio_QueueSample: Out of memory");
            return NULL;
      }

      psSample->iTrack = iTrack;
      psSample->x = SAMPLE_COORD_INVALID;
      psSample->y = SAMPLE_COORD_INVALID;
      psSample->z = SAMPLE_COORD_INVALID;
      psSample->bFinishedPlaying = false;

      // add to queue
      audio_AddSampleToTail( &g_psSampleQueue, psSample );

      return psSample;
}

//*
// =======================================================================================================================
// =======================================================================================================================
//
void audio_QueueTrack( SDWORD iTrack )
{
      //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      AUDIO_SAMPLE      *psSample = NULL;
      //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

      // return if audio not enabled
      if ( g_bAudioEnabled == false || g_bAudioPaused == true)
      {
            return;
      }

      psSample = audio_QueueSample( iTrack );
}

//*
//
//
// * audio_QueueTrackMinDelay Will only play track if iMinDelay has elapsed since
// * track last finished
//

//*
// =======================================================================================================================
// =======================================================================================================================
//
void audio_QueueTrackMinDelay( SDWORD iTrack, UDWORD iMinDelay )
{
      //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      AUDIO_SAMPLE      *psSample;
      UDWORD                  iDelay;
      //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

      // return if audio not enabled
      if ( g_bAudioEnabled == false || g_bAudioPaused == true )
      {
            return;
      }

      // Determine if at least iMinDelay time has passed since the last time this track was played
      iDelay = sound_GetGameTime() - sound_GetTrackTimeLastFinished( iTrack );
      if ( !(iDelay > iMinDelay) )
      {
            return;
      }

      // Construct an audio sample from requested track
      psSample = audio_QueueSample( iTrack );
      if ( psSample == NULL )
      {
            return;
      }

      // Set last finished tracktime to current time to prevent parallel playing of this track
      sound_SetTrackTimeLastFinished( iTrack, sound_GetGameTime() );
}

//*
// =======================================================================================================================
// =======================================================================================================================
//
void audio_QueueTrackMinDelayPos( SDWORD iTrack, UDWORD iMinDelay, SDWORD iX, SDWORD iY, SDWORD iZ )
{
      //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      AUDIO_SAMPLE      *psSample;
      UDWORD                  iDelay;
      //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

      // return if audio not enabled
      if ( g_bAudioEnabled == false || g_bAudioPaused == true )
      {
            return;
      }

      // Determine if at least iMinDelay time has passed since the last time this track was played
      iDelay = sound_GetGameTime() - sound_GetTrackTimeLastFinished( iTrack );
      if ( iDelay > iMinDelay )
      {
            return;
      }

      // Construct an audio sample from requested track
      psSample = audio_QueueSample( iTrack );
      if ( psSample == NULL )
      {
            return;
      }

      psSample->x = iX;
      psSample->y = iY;
      psSample->z = iZ;

      // Set last finished tracktime to current time to prevent parallel playing of this track
      sound_SetTrackTimeLastFinished( iTrack, sound_GetGameTime() );
}

//*
// =======================================================================================================================
// =======================================================================================================================
//
void audio_QueueTrackPos( SDWORD iTrack, SDWORD iX, SDWORD iY, SDWORD iZ )
{
      //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      AUDIO_SAMPLE      *psSample;
      //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

      // return if audio not enabled
      if ( g_bAudioEnabled == false || g_bAudioPaused == true )
      {
            return;
      }

      // Construct an audio sample from requested track
      psSample = audio_QueueSample( iTrack );
      if ( psSample == NULL )
      {
            return;
      }

      psSample->x = iX;
      psSample->y = iY;
      psSample->z = iZ;
}

//*
// =======================================================================================================================
// =======================================================================================================================
//
static void audio_UpdateQueue( void )
{
      //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      AUDIO_SAMPLE      *psSample;
      //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

      // return if audio not enabled
      if ( g_bAudioEnabled == false || g_bAudioPaused == true )
      {
            return;
      }

      if (sound_QueueSamplePlaying() == true)
      {
            return;
      }

      // check queue for members
      if ( g_psSampleQueue == NULL )
      {
            return;
      }

      // remove queue head
      psSample = g_psSampleQueue;
      audio_RemoveSample( &g_psSampleQueue, psSample );

      // add sample to list if able to play
      if ( !sound_Play2DTrack(psSample, true) )
      {
            debug( LOG_NEVER, "audio_UpdateQueue: couldn't play sample\n" );
            free(psSample);
            return;
      }

      audio_AddSampleToHead( &g_psSampleList, psSample );

      // update last queue sound coords
      if ( psSample->x != SAMPLE_COORD_INVALID && psSample->y != SAMPLE_COORD_INVALID
        && psSample->z != SAMPLE_COORD_INVALID )
      {
            g_sPreviousSample.x = psSample->x;
            g_sPreviousSample.y = psSample->y;
            g_sPreviousSample.z = psSample->z;
      }
}

//*
// =======================================================================================================================
// =======================================================================================================================
//
void audio_Update( void )
{
      //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      Vector3i          vecPlayer;
      SDWORD                  iA;
      AUDIO_SAMPLE      *psSample, *psSampleTemp;
      //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

      // if audio not enabled return true to carry on game without audio
      if ( g_bAudioEnabled == false )
      {
            return;
      }

      audio_UpdateQueue();

      // get player position
      audio_Get3DPlayerPos(&vecPlayer.x, &vecPlayer.y, &vecPlayer.z);

      sound_SetPlayerPos( vecPlayer.x, vecPlayer.y, vecPlayer.z );
      audio_Get3DPlayerRotAboutVerticalAxis( &iA );
      sound_SetPlayerOrientation( 0, 0, iA );

      // loop through 3D sounds and remove if finished or update position
      psSample = g_psSampleList;
      while ( psSample != NULL )
      {
            // remove finished samples from list
            if ( psSample->bFinishedPlaying == true )
            {
                  audio_RemoveSample( &g_psSampleList, psSample );
                  psSampleTemp = psSample->psNext;
                  free(psSample);
                  psSample = psSampleTemp;
            }

            // check looping sound callbacks for finished condition
            else
            {
                  if ( psSample->psObj != NULL )
                  {
                        if ( audio_ObjectDead(psSample->psObj)
                         || (psSample->pCallback != NULL && psSample->pCallback(psSample->psObj) == false) )
                        {
                              sound_StopTrack( psSample );
                              psSample->psObj = NULL;
                        }
                        else
                        {
                              // update sample position
                              {
                                    audio_GetObjectPos( psSample->psObj, &psSample->x, &psSample->y, &psSample->z );
#ifndef WZ_NOSOUND
                                    sound_SetObjectPosition(psSample);
#endif
                              }
                        }
                  }
                  // next sample
                  psSample = psSample->psNext;
            }
      }

      sound_Update();
      return;
}


/** Retrieves loaded audio files and retrieves a TRACK from them on which some values are set and returns their respective ID numbers
 *  \param fileName the filename of the track
 *  \param loop whether the track should be looped until explicitly stopped
 *  \param volume the volume this track should be played on (range is 0-100)
 *  \param audibleRadius the radius from the source of sound where it can be heard
 *  \return a non-zero value when succesfull or audio is disabled, zero when the file is not found or no more tracks can be loaded (i.e. the limit is reached)
 */
unsigned int audio_SetTrackVals(const char* fileName, BOOL loop, unsigned int volume, unsigned int audibleRadius)
{
      // if audio not enabled return a random non-zero value to carry on game without audio
      if ( g_bAudioEnabled == false )
      {
            return 1;
      }

      return sound_SetTrackVals(fileName, loop, volume, audibleRadius);
}

//*
//
//
// * audio_CheckSame3DTracksPlaying Reject samples if too many already playing in
// * same area
//

//*
// =======================================================================================================================
// =======================================================================================================================
//
static BOOL audio_CheckSame3DTracksPlaying( SDWORD iTrack, SDWORD iX, SDWORD iY, SDWORD iZ )
{
      //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      SDWORD                  iCount, iDx, iDy, iDz, iDistSq, iMaxDistSq, iRad;
      AUDIO_SAMPLE      *psSample = NULL;
      BOOL              bOK = true;
      //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

      // return if audio not enabled
      if ( g_bAudioEnabled == false || g_bAudioPaused == true )
      {
            return true;
      }

      iCount = 0;

      // loop through 3D sounds and check whether too many already in earshot
      psSample = g_psSampleList;
      while ( psSample != NULL )
      {
            if ( psSample->iTrack == iTrack )
            {
                  iDx = iX - psSample->x;
                  iDy = iY - psSample->y;
                  iDz = iZ - psSample->z;
                  iDistSq = ( iDx * iDx ) + ( iDy * iDy ) + ( iDz * iDz );
                  iRad = sound_GetTrackAudibleRadius( iTrack );
                  iMaxDistSq = iRad * iRad;
                  if ( iDistSq < iMaxDistSq )
                  {
                        iCount++;
                  }

                  if ( iCount > MAX_SAME_SAMPLES )
                  {
                        bOK = false;
                        break;
                  }
            }

            psSample = psSample->psNext;
      }

      return bOK;
}

//*
// =======================================================================================================================
// =======================================================================================================================
//
static BOOL audio_Play3DTrack( SDWORD iX, SDWORD iY, SDWORD iZ, int iTrack, void *psObj, AUDIO_CALLBACK pUserCallback )
{
      //~~~~~~~~~~~~~~~~~~~~~~
      AUDIO_SAMPLE      *psSample;
      //~~~~~~~~~~~~~~~~~~~~~~

      // if audio not enabled return true to carry on game without audio
      if ( g_bAudioEnabled == false || g_bAudioPaused == true)
      {
            return false;
      }

      if ( audio_CheckSame3DTracksPlaying(iTrack, iX, iY, iZ) == false )
      {
            return false;
      }

      psSample = malloc(sizeof(AUDIO_SAMPLE));
      if ( psSample == NULL )
      {
            debug(LOG_ERROR, "audio_Play3DTrack: Out of memory");
            return false;
      }

      // setup sample
      memset( psSample, 0, sizeof(AUDIO_SAMPLE) );                                  // [check] -Q
      psSample->iTrack = iTrack;
      psSample->x = iX;
      psSample->y = iY;
      psSample->z = iZ;
      psSample->bFinishedPlaying = false;
      psSample->psObj = psObj;
      psSample->pCallback = pUserCallback;

      // add sample to list if able to play
      if ( !sound_Play3DTrack(psSample) )
      {
            debug( LOG_NEVER, "audio_Play3DTrack: couldn't play sample\n" );
            free(psSample);
            return false;
      }

      audio_AddSampleToHead( &g_psSampleList, psSample );
      return true;
}

//*
// =======================================================================================================================
// =======================================================================================================================
//
BOOL audio_PlayStaticTrack( SDWORD iMapX, SDWORD iMapY, int iTrack )
{
      //~~~~~~~~~~~~~~~
      SDWORD      iX, iY, iZ;
      //~~~~~~~~~~~~~~~

      // if audio not enabled return true to carry on game without audio
      if ( g_bAudioEnabled == false )
      {
            return false;
      }

      audio_GetStaticPos( iMapX, iMapY, &iX, &iY, &iZ );
      return audio_Play3DTrack( iX, iY, iZ, iTrack, NULL, NULL );
}

//*
// =======================================================================================================================
// =======================================================================================================================
//
BOOL audio_PlayObjStaticTrack( void *psObj, int iTrack )
{
      //~~~~~~~~~~~~~~~
      SDWORD      iX, iY, iZ;
      //~~~~~~~~~~~~~~~

      // if audio not enabled return true to carry on game without audio
      if ( g_bAudioEnabled == false )
      {
            return false;
      }

      audio_GetObjectPos( psObj, &iX, &iY, &iZ );
      return audio_Play3DTrack( iX, iY, iZ, iTrack, psObj, NULL );
}

//*
// =======================================================================================================================
// =======================================================================================================================
//
BOOL audio_PlayObjStaticTrackCallback( void *psObj, int iTrack, AUDIO_CALLBACK pUserCallback )
{
      //~~~~~~~~~~~~~~~
      SDWORD      iX, iY, iZ;
      //~~~~~~~~~~~~~~~

      // if audio not enabled return true to carry on game without audio
      if ( g_bAudioEnabled == false )
      {
            return false;
      }

      audio_GetObjectPos( psObj, &iX, &iY, &iZ );
      return audio_Play3DTrack( iX, iY, iZ, iTrack, psObj, pUserCallback );
}

//*
// =======================================================================================================================
// =======================================================================================================================
//
BOOL audio_PlayObjDynamicTrack( void *psObj, int iTrack, AUDIO_CALLBACK pUserCallback )
{
      //~~~~~~~~~~~~~~~
      SDWORD      iX, iY, iZ;
      //~~~~~~~~~~~~~~~

      // if audio not enabled return true to carry on game without audio
      if ( g_bAudioEnabled == false )
      {
            return false;
      }

      audio_GetObjectPos( psObj, &iX, &iY, &iZ );
      return audio_Play3DTrack( iX, iY, iZ, iTrack, psObj, pUserCallback );
}

/** Plays the given audio file as a stream and reports back when it has finished
 *  playing.
 *  \param fileName the (OggVorbis) file to play from
 *  \param volume the volume to use while playing this file (in the range of
 *         0.0 - 1.0)
 *  \param onFinished a callback function to invoke when playing of this stream
 *         has been finished. You can use NULL to specifiy no callback function.
 *  \param user_data a pointer to contain some user data to pass along to the
 *         finished callback.
 *  \return a pointer to the currently playing stream when the stream is playing
 *          (and as such the callback will be invoked some time in the future),
 *          NULL when the stream didn't start playing (and the callback won't be
 *          invoked).
 *  \note The returned pointer will become invalid/dangling immediately after
 *        the \c onFinished callback is invoked.
 *  \note You must _never_ manually free() the memory used by the returned
 *        pointer.
 */
AUDIO_STREAM* audio_PlayStream(const char* fileName, float volume, void (*onFinished)(void*), void* user_data)
{
      PHYSFS_file* fileHandle;
      AUDIO_STREAM* stream;

      // If audio is not enabled return false to indicate that the given callback
      // will not be invoked.
      if (g_bAudioEnabled == false)
      {
            return NULL;
      }

      // Open up the file
      fileHandle = PHYSFS_openRead(fileName);
      if (fileHandle == NULL)
      {
            debug(LOG_ERROR, "sound_LoadTrackFromFile: PHYSFS_openRead(\"%s\") failed with error: %s\n", fileName, PHYSFS_getLastError());
            return NULL;
      }

      stream = sound_PlayStream(fileHandle, volume, onFinished, user_data);
      if (stream == NULL)
      {
            PHYSFS_close(fileHandle);
            return NULL;
      }

      return stream;
}

//*
// =======================================================================================================================
// =======================================================================================================================
//
void audio_StopObjTrack( void *psObj, int iTrack )
{
      //~~~~~~~~~~~~~~~~~~~~~~
      AUDIO_SAMPLE      *psSample;
      //~~~~~~~~~~~~~~~~~~~~~~

      // return if audio not enabled
      if ( g_bAudioEnabled == false)
      {
            return;
      }

      // find sample
      psSample = g_psSampleList;
      while ( psSample != NULL )
      {
            // If track has been found stop it and return
            if ( psSample->psObj == psObj && psSample->iTrack == iTrack )
            {
                  sound_StopTrack(psSample);
                  return;
            }

            // get next sample from linked list
            psSample = psSample->psNext;
      }
}

//*
//
// audio_PlayTrack Play immediate 2D FX track

//*
// =======================================================================================================================
// =======================================================================================================================
//
void audio_PlayTrack( int iTrack )
{
      //~~~~~~~~~~~~~~~~~~~~~~
      AUDIO_SAMPLE      *psSample;
      //~~~~~~~~~~~~~~~~~~~~~~

      // return if audio not enabled
      if ( g_bAudioEnabled == false || g_bAudioPaused == true)
      {
            return;
      }

      // Allocate a sample
      psSample = malloc(sizeof(AUDIO_SAMPLE));
      if ( psSample == NULL )
      {
            debug(LOG_ERROR, "audio_PlayTrack: Out of memory");
            return;
      }

      // setup/initialize sample
      psSample->iTrack = iTrack;
      psSample->bFinishedPlaying = false;

      // Zero callback stuff since we don't need/want it
      psSample->pCallback = NULL;
      psSample->psObj = NULL;

      /* iSample, psPrev, and psNext will be initialized by the
       * following functions, and x, y and z will be completely
       * ignored so we don't need to bother about it
       */

      // add sample to list if able to play
      if ( !sound_Play2DTrack(psSample, false) )
      {
            debug( LOG_NEVER, "audio_PlayTrack: couldn't play sample\n" );
            free(psSample);
            return;
      }

      audio_AddSampleToHead( &g_psSampleList, psSample );
}

//*
// =======================================================================================================================
// =======================================================================================================================
//
void audio_PauseAll( void )
{
      // return if audio not enabled
      if ( g_bAudioEnabled == false )
      {
            return;
      }

      g_bAudioPaused = true;
      sound_PauseAll();
}

//*
// =======================================================================================================================
// =======================================================================================================================
//
void audio_ResumeAll( void )
{
      // return if audio not enabled
      if ( g_bAudioEnabled == false )
      {
            return;
      }

      g_bAudioPaused = false;
      sound_ResumeAll();
}

//*
// =======================================================================================================================
// =======================================================================================================================
//
void audio_StopAll( void )
{
      //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      AUDIO_SAMPLE* psSample;
      //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

      // return if audio not enabled
      if ( g_bAudioEnabled == false )
      {
            return;
      }

      //
      // * empty list - audio_Update will free samples because callbacks have to come in first
      //
      for (psSample = g_psSampleList; psSample != NULL; psSample = psSample->psNext)
      {
            // Stop this sound sample
            sound_StopTrack(psSample);

            // HACK:
            // Make sure to set psObj to NULL, since sometimes it becomes
            // invalidated, i.e. dangling, before audio_Update() gets the
            // chance to clean it up.
            //
            // Meaning at this place in the code audio_ObjectDead(psObj)
            // would indicate that psObj is still valid and will remain
            // such. While in reality, before audio_Update() can get the
            // chance to check again, this pointer will have become
            // dangling.
            //
            // NOTE: This would always happen when audio_StopAll() had been
            // invoked by stageThreeShutDown().
            psSample->psObj = NULL;
      }

      // empty sample queue
      psSample = g_psSampleQueue;
      while ( psSample != NULL )
      {
            AUDIO_SAMPLE* psSampleTemp = psSample;

            // Advance the sample iterator (before invalidating it)
            psSample = psSample->psNext;

            // Destroy the sample
            free(psSampleTemp);
      }

      g_psSampleQueue = NULL;
}

//*
// =======================================================================================================================
// =======================================================================================================================
//
SDWORD audio_GetTrackID( const char *fileName )
{
      //~~~~~~~~~~~~~
      TRACK *psTrack;
      //~~~~~~~~~~~~~

      // return if audio not enabled
      if ( g_bAudioEnabled == false )
      {
            return SAMPLE_NOT_FOUND;
      }

      if (fileName == NULL || strlen(fileName) == 0)
      {
            debug(LOG_ERROR, "audio_GetTrackID: fileName is %s", (fileName == NULL) ? "a NULL pointer" : "empty");
            return SAMPLE_NOT_FOUND;
      }

      psTrack = (TRACK*)resGetData( "WAV", fileName );
      if ( psTrack == NULL )
      {
            return SAMPLE_NOT_FOUND;
      }

      return sound_GetTrackID( psTrack );
}

/** Loop through the list of playing and queued audio samples, and destroy any
 *  of them that refer to the given object.
 *  \param psObj pointer to the object for which we must destroy all of its
 *               outstanding audio samples.
 */
void audio_RemoveObj(const void* psObj)
{
      unsigned int count = 0;

      // loop through queued sounds and check if a sample needs to be removed
      AUDIO_SAMPLE *psSample = g_psSampleQueue;
      while (psSample != NULL)
      {
            if (psSample->psObj == psObj)
            {
                  // The current audio sample seems to refer to an object
                  // that is about to be destroyed. So destroy this
                  // sample as well.
                  AUDIO_SAMPLE* toRemove = psSample;

                  // Make sure to keep our linked list iterator valid
                  psSample = psSample->psNext;

                  debug(LOG_MEMORY, "audio_RemoveObj: callback %p sample %d\n",toRemove->pCallback,toRemove->iTrack);
                  // Remove sound from global active list
                  sound_RemoveActiveSample( toRemove ); //remove from global active list.

                  // Perform the actual task of destroying this sample
                  audio_RemoveSample(&g_psSampleQueue, toRemove);
                  free(toRemove);

                  // Increment the deletion count
                  ++count;
            }
            else
            {
                  psSample = psSample->psNext;
            }
      }

      if (count)
            debug(LOG_MEMORY, "audio_RemoveObj: BASE_OBJECT* 0x%p was found %u times in the audio sample queue", psObj, count);

      // Reset the deletion count
      count = 0;

      // loop through list of currently playing sounds and check if a sample needs to be removed
      psSample = g_psSampleList;
      while (psSample != NULL)
      {
            if (psSample->psObj == psObj)
            {
                  // The current audio sample seems to refer to an object
                  // that is about to be destroyed. So destroy this
                  // sample as well.
                  AUDIO_SAMPLE* toRemove = psSample;

                  // Make sure to keep our linked list iterator valid
                  psSample = psSample->psNext;

                  debug(LOG_MEMORY, "audio_RemoveObj: callback %p sample %d\n",toRemove->pCallback,toRemove->iTrack);
                  // Stop this sound sample
                  sound_RemoveActiveSample( toRemove ); //remove from global active list.

                  // Perform the actual task of destroying this sample
                  audio_RemoveSample(&g_psSampleList, toRemove);
                  free(toRemove);

                  // Increment the deletion count
                  ++count;
            }
            else
            {
                  psSample = psSample->psNext;
            }
      }

      if (count)
            debug(LOG_MEMORY, "audio_RemoveObj: ***Warning! psOBJ %p was found %u times in the list of playing audio samples", psObj, count);
}

Generated by  Doxygen 1.6.0   Back to index