/ClassMaster2014/barahon/Transcend_0.3_UnixSource/Transcend/game/SoundPlayer.cpp
C++ | 494 lines | 268 code | 159 blank | 67 comment | 37 complexity | b169d63622709b9f9c116117b07eba3c MD5 | raw file
Possible License(s): BSD-3-Clause
- /*
- * Modification History
- *
- * 2004-July-17 Jason Rohrer
- * Created.
- *
- * 2004-July-21 Jason Rohrer
- * Changed to use a callback to reduce latency.
- *
- * 2004-August-9 Jason Rohrer
- * Added a limit on the number of simultaneous sounds.
- *
- * 2004-August-12 Jason Rohrer
- * Parameterized the sample rate.
- *
- * 2004-August-13 Jason Rohrer
- * Added Mutex to protect members that are accessed by multiple threads.
- *
- * 2004-August-14 Jason Rohrer
- * Changed to fade sounds out before dropping them.
- *
- * 2004-August-15 Jason Rohrer
- * Added a function for getting the sample rate.
- * Added volume modifier parameter to playSoundNow function.
- *
- * 2004-August-20 Jason Rohrer
- * Added priority flags.
- *
- * 2004-August-23 Jason Rohrer
- * Added music.
- *
- * 2004-August-25 Jason Rohrer
- * Added lock in setMusicPlayer function.
- * Added function for setting music loudness.
- *
- * 2004-August-31 Jason Rohrer
- * Added function for removing filters.
- */
- #include "SoundPlayer.h"
- #include "MusicPlayer.h"
- #include <stdio.h>
- // callback passed into portaudio
- static int portaudioCallback( void *inputBuffer, void *outputBuffer,
- unsigned long framesPerBuffer,
- PaTimestamp outTime, void *userData ) {
- SoundPlayer *player = (SoundPlayer *)userData;
- player->getSamples( outputBuffer, framesPerBuffer );
- return 0;
- }
- /**
- * Class that wraps SoundSamples in a PlayableSound.
- */
- class SamplesPlayableSound : public PlayableSound {
- public:
- /**
- * Constructs a playable sound.
- *
- * @param inSamples the samples to play.
- * Must be destroyed by caller.
- */
- SamplesPlayableSound( SoundSamples *inSamples );
-
- ~SamplesPlayableSound();
-
- // implements the PlayableSound interface
- virtual SoundSamples *getMoreSamples( unsigned long inNumSamples );
- virtual PlayableSound *copy();
-
- protected:
- SoundSamples *mRemainingSamples;
- };
- SamplesPlayableSound::SamplesPlayableSound( SoundSamples *inSamples )
- : mRemainingSamples( new SoundSamples( inSamples ) ) {
- }
- SamplesPlayableSound::~SamplesPlayableSound() {
- delete mRemainingSamples;
- }
- SoundSamples *SamplesPlayableSound::getMoreSamples(
- unsigned long inNumSamples ) {
- SoundSamples *returnSamples = new SoundSamples( mRemainingSamples,
- inNumSamples );
- mRemainingSamples->trim( returnSamples->mSampleCount );
- return returnSamples;
- }
- PlayableSound *SamplesPlayableSound::copy() {
- return new SamplesPlayableSound( mRemainingSamples );
- }
- SoundPlayer::SoundPlayer( int inSampleRate,
- int inMaxSimultaneousRealtimeSounds,
- void *inMusicPlayer,
- double inMusicLoudness )
- : mLock( new MutexLock() ),
- mSampleRate( inSampleRate ),
- mMaxSimultaneousRealtimeSounds( inMaxSimultaneousRealtimeSounds ),
- mMusicPlayer( inMusicPlayer ),
- mMusicLoudness( inMusicLoudness ),
- mRealtimeSounds( new SimpleVector<PlayableSound *>() ),
- mPriorityFlags( new SimpleVector<char>() ),
- mSoundLoudnessModifiers( new SimpleVector<double>() ),
- mSoundDroppedFlags( new SimpleVector<char>() ),
- mFilterChain( new SimpleVector<SoundFilter *>() ) {
- PaError error = Pa_Initialize();
- if( error == paNoError ) {
-
- error = Pa_OpenStream(
- &mAudioStream,
- paNoDevice,// default input device
- 0, // no input
- paFloat32, // 32 bit floating point input
- NULL,
- Pa_GetDefaultOutputDeviceID(),
- 2, // stereo output
- paFloat32, // 32 bit floating point output
- NULL,
- mSampleRate,
- 1024, // frames per buffer
- 0, // number of buffers, if zero then use default minimum
- paClipOff, // we won't output out of range samples so
- // don't bother clipping them
- portaudioCallback,
- (void *)this ); // pass self-pointer to callback function
-
- if( error == paNoError ) {
- error = Pa_StartStream( mAudioStream );
-
- if( error == paNoError ) {
- mAudioInitialized = true;
- }
- else {
- fprintf( stderr, "Error starting audio stream\n" );
- Pa_CloseStream( mAudioStream );
- }
- }
- else {
- fprintf( stderr, "Error opening audio stream\n" );
- Pa_Terminate();
- }
- }
- else {
- fprintf( stderr, "Error initializing audio framework\n" );
- }
-
- if( error != paNoError ) {
- fprintf( stderr, "Error number: %d\n", error );
- fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( error ) );
- mAudioInitialized = false;
- }
- }
- SoundPlayer::~SoundPlayer() {
- if( mAudioInitialized ) {
- PaError error = Pa_StopStream( mAudioStream );
- if( error == paNoError ) {
- error = Pa_CloseStream( mAudioStream );
- if( error != paNoError ) {
- fprintf( stderr, "Error closingaudio stream\n" );
- }
- }
- else {
- fprintf( stderr, "Error stopping audio stream\n" );
- }
- Pa_Terminate();
-
- if( error != paNoError ) {
- fprintf( stderr, "Error number: %d\n", error);
- fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( error) );
- }
- }
- delete mLock;
-
- int i;
-
- int numSounds = mRealtimeSounds->size();
- for( i=0; i<numSounds; i++ ) {
- delete *( mRealtimeSounds->getElement( i ) );
- }
- delete mRealtimeSounds;
- delete mPriorityFlags;
- delete mSoundLoudnessModifiers;
- delete mSoundDroppedFlags;
-
- int numFilters = mFilterChain->size();
- for( i=0; i<numFilters; i++ ) {
- delete *( mFilterChain->getElement( i ) );
- }
- delete mFilterChain;
- }
- void SoundPlayer::setMusicPlayer( void *inMusicPlayer ) {
- mLock->lock();
- mMusicPlayer = inMusicPlayer;
- mLock->unlock();
- }
- void SoundPlayer::setMusicLoudness( double inMusicLoudness ) {
- mLock->lock();
- mMusicLoudness = inMusicLoudness;
- mLock->unlock();
- }
-
- void SoundPlayer::getSamples( void *outputBuffer,
- unsigned long inFramesInBuffer ) {
- SoundSamples *mixingBuffer = new SoundSamples( inFramesInBuffer );
- unsigned long bufferLength = inFramesInBuffer;
-
- mLock->lock();
- // add each pending realtime sound to the buffer
- int i = 0;
-
- // we may be removing sounds from the buffer as we use them up
- // i is adjusted inside the while loop
- while( i<mRealtimeSounds->size() ) {
-
- PlayableSound *realtimeSound = *( mRealtimeSounds->getElement( i ) );
- double loudnessModifier =
- *( mSoundLoudnessModifiers->getElement( i ) );
- SoundSamples *samples = realtimeSound->getMoreSamples( bufferLength );
- unsigned long mixLength = samples->mSampleCount;
- char shouldDrop = *( mSoundDroppedFlags->getElement( i ) );
- // fade out if we should drop
- float fadeFactor = 1;
- unsigned long maxJ = mixLength - 1;
- for( unsigned long j=0; j<mixLength; j++ ) {
- mixingBuffer->mLeftChannel[j] +=
- loudnessModifier * fadeFactor * samples->mLeftChannel[j];
- mixingBuffer->mRightChannel[j] +=
- loudnessModifier * fadeFactor * samples->mRightChannel[j];
- if( shouldDrop ) {
- fadeFactor = ( maxJ - j ) / (float)maxJ;
- }
- }
- delete samples;
-
-
- if( mixLength < bufferLength || shouldDrop ) {
- // we have used up all samples of this sound or
- // it is flagged to be dropped
- delete realtimeSound;
- mRealtimeSounds->deleteElement( i );
- mPriorityFlags->deleteElement( i );
- mSoundLoudnessModifiers->deleteElement( i );
- mSoundDroppedFlags->deleteElement( i );
-
- // don't increment i, since the next element drops into the current
- // index
- }
- else {
- // increment i to move on to the next sound
- i++;
- }
- }
- if( mMusicPlayer != NULL ) {
- // cast out of void *
- MusicPlayer *player = (MusicPlayer *)mMusicPlayer;
- // mix in the music
- SoundSamples *musicSamples =
- player->getMoreMusic( inFramesInBuffer );
- for( unsigned long j=0; j<inFramesInBuffer; j++ ) {
- mixingBuffer->mLeftChannel[j] +=
- musicSamples->mLeftChannel[j] * mMusicLoudness;
- mixingBuffer->mRightChannel[j] +=
- musicSamples->mRightChannel[j] * mMusicLoudness;
- }
- delete musicSamples;
- }
-
-
- // filter the samples
- int numFilters = mFilterChain->size();
- SoundSamples *filteredSamples = new SoundSamples( mixingBuffer );
- delete mixingBuffer;
-
- for( i=0; i<numFilters; i++ ) {
- SoundFilter *filter = *( mFilterChain->getElement( i ) );
-
- SoundSamples *nextOutput = filter->filterSamples( filteredSamples );
- delete filteredSamples;
- filteredSamples = nextOutput;
- }
- mLock->unlock();
-
-
- float *samples = (float *)outputBuffer;
- unsigned long numSamples = 2 * bufferLength;
- unsigned long j;
- unsigned long frameNumber = 0;
- for( j=0; j<numSamples; j+=2 ) {
- samples[j] = filteredSamples->mLeftChannel[frameNumber];
- samples[j+1] = filteredSamples->mRightChannel[frameNumber];
- frameNumber++;
- }
-
- delete filteredSamples;
- }
- void SoundPlayer::checkForExcessSounds() {
-
- int numSounds = mRealtimeSounds->size();
- if( numSounds > mMaxSimultaneousRealtimeSounds ) {
- // flag the oldest unflagged, low-priority sound
-
- // skip sounds that are already flagged or are priority sounds
- int i=0;
- while( i<numSounds &&
- ( *( mSoundDroppedFlags->getElement( i ) ) ||
- *( mPriorityFlags->getElement( i ) ) ) ) {
- i++;
- }
- if( i<numSounds ) {
- *( mSoundDroppedFlags->getElement( i ) ) = true;
- }
- else {
- // else all low-priority sounds are already flagged
- // try again, ignoring priority flags
- i=0;
- while( i<numSounds && *( mSoundDroppedFlags->getElement( i ) ) ) {
- i++;
- }
- if( i<numSounds ) {
- *( mSoundDroppedFlags->getElement( i ) ) = true;
- }
- // else all sounds are already flagged
-
- }
-
- }
- }
- void SoundPlayer::playSoundNow( SoundSamples *inSamples,
- char inPriorityFlag,
- double inLoudnessModifier ) {
- mLock->lock();
-
- mRealtimeSounds->push_back( new SamplesPlayableSound( inSamples ) );
- mPriorityFlags->push_back( inPriorityFlag );
- mSoundLoudnessModifiers->push_back( inLoudnessModifier );
- mSoundDroppedFlags->push_back( false );
- checkForExcessSounds();
-
- mLock->unlock();
- }
- void SoundPlayer::playSoundNow( PlayableSound *inSound,
- char inPriorityFlag,
- double inLoudnessModifier ) {
- mLock->lock();
-
- mRealtimeSounds->push_back( inSound->copy() );
- mPriorityFlags->push_back( inPriorityFlag );
- mSoundLoudnessModifiers->push_back( inLoudnessModifier );
- mSoundDroppedFlags->push_back( false );
- checkForExcessSounds();
- mLock->unlock();
- }
-
- void SoundPlayer::addMoreMusic( SoundSamples *inSamples ) {
- }
- void SoundPlayer::addFilter( SoundFilter *inFilter ) {
- mLock->lock();
-
- mFilterChain->push_back( inFilter );
- mLock->unlock();
- }
- void SoundPlayer::removeAllFilters() {
- mLock->lock();
- int numFilters = mFilterChain->size();
- for( int i=0; i<numFilters; i++ ) {
- delete *( mFilterChain->getElement( i ) );
- }
- mFilterChain->deleteAll();
- mLock->unlock();
- }
- unsigned long SoundPlayer::getSampleRate() {
- return mSampleRate;
- }