void LLAudioEngine::setMasterGain(const F32 gain) { mMasterGain = gain; F32 internal_gain = getMuted() ? 0.f : gain; if (internal_gain != mInternalGain) { mInternalGain = internal_gain; setInternalGain(mInternalGain); } }
void LLAudioEngine::setMasterGain(const F32 gain) { mMasterGain = gain; setInternalGain(gain); }
void LLAudioEngine::idle(F32 max_decode_time) { if (max_decode_time <= 0.f) { max_decode_time = default_max_decode_time; } // "Update" all of our audio sources, clean up dead ones. // Primarily does position updating, cleanup of unused audio sources. // Also does regeneration of the current priority of each audio source. if (getMuted()) { setInternalGain(0.f); } else { setInternalGain(getMasterGain()); } S32 i; for (i = 0; i < MAX_BUFFERS; i++) { if (mBuffers[i]) { mBuffers[i]->mInUse = FALSE; } } F32 max_priority = -1.f; LLAudioSource *max_sourcep = NULL; // Maximum priority source without a channel source_map::iterator iter; for (iter = mAllSources.begin(); iter != mAllSources.end();) { LLAudioSource *sourcep = iter->second; // Update this source sourcep->update(); sourcep->updatePriority(); if (sourcep->isDone()) { // The source is done playing, clean it up. delete sourcep; mAllSources.erase(iter++); continue; } if (!sourcep->getChannel() && sourcep->getCurrentBuffer()) { // We could potentially play this sound if its priority is high enough. if (sourcep->getPriority() > max_priority) { max_priority = sourcep->getPriority(); max_sourcep = sourcep; } } // Move on to the next source iter++; } // Now, do priority-based organization of audio sources. // All channels used, check priorities. // Find channel with lowest priority if (max_sourcep) { LLAudioChannel *channelp = getFreeChannel(max_priority); if (channelp) { //llinfos << "Replacing source in channel due to priority!" << llendl; max_sourcep->setChannel(channelp); channelp->setSource(max_sourcep); if (max_sourcep->isSyncSlave()) { // A sync slave, it doesn't start playing until it's synced up with the master. // Flag this channel as waiting for sync, and return true. channelp->setWaiting(TRUE); } else { channelp->setWaiting(FALSE); channelp->play(); } } } // Do this BEFORE we update the channels // Update the channels to sync up with any changes that the source made, // such as changing what sound was playing. updateChannels(); // Update queued sounds (switch to next queued data if the current has finished playing) for (iter = mAllSources.begin(); iter != mAllSources.end(); ++iter) { // This is lame, instead of this I could actually iterate through all the sources // attached to each channel, since only those with active channels // can have anything interesting happen with their queue? (Maybe not true) LLAudioSource *sourcep = iter->second; if (!sourcep->mQueuedDatap) { // Nothing queued, so we don't care. continue; } LLAudioChannel *channelp = sourcep->getChannel(); if (!channelp) { // This sound isn't playing, so we just process move the queue sourcep->mCurrentDatap = sourcep->mQueuedDatap; sourcep->mQueuedDatap = NULL; // Reset the timer so the source doesn't die. sourcep->mAgeTimer.reset(); // Make sure we have the buffer set up if we just decoded the data if (sourcep->mCurrentDatap) { updateBufferForData(sourcep->mCurrentDatap); } // Actually play the associated data. sourcep->setupChannel(); channelp = sourcep->getChannel(); if (channelp) { channelp->updateBuffer(); sourcep->getChannel()->play(); } continue; } else { // Check to see if the current sound is done playing, or looped. if (!channelp->isPlaying()) { sourcep->mCurrentDatap = sourcep->mQueuedDatap; sourcep->mQueuedDatap = NULL; // Reset the timer so the source doesn't die. sourcep->mAgeTimer.reset(); // Make sure we have the buffer set up if we just decoded the data if (sourcep->mCurrentDatap) { updateBufferForData(sourcep->mCurrentDatap); } // Actually play the associated data. sourcep->setupChannel(); channelp->updateBuffer(); sourcep->getChannel()->play(); } else if (sourcep->isLoop()) { // It's a loop, we need to check and see if we're done with it. if (channelp->mLoopedThisFrame) { sourcep->mCurrentDatap = sourcep->mQueuedDatap; sourcep->mQueuedDatap = NULL; // Actually, should do a time sync so if we're a loop master/slave // we don't drift away. sourcep->setupChannel(); sourcep->getChannel()->play(); } } } } // Lame, update the channels AGAIN. // Update the channels to sync up with any changes that the source made, // such as changing what sound was playing. updateChannels(); // Hack! For now, just use a global sync master; LLAudioSource *sync_masterp = NULL; LLAudioChannel *master_channelp = NULL; F32 max_sm_priority = -1.f; for (iter = mAllSources.begin(); iter != mAllSources.end(); ++iter) { LLAudioSource *sourcep = iter->second; if (sourcep->isSyncMaster()) { if (sourcep->getPriority() > max_sm_priority) { sync_masterp = sourcep; master_channelp = sync_masterp->getChannel(); max_sm_priority = sourcep->getPriority(); } } } if (master_channelp && master_channelp->mLoopedThisFrame) { // Synchronize loop slaves with their masters // Update queued sounds (switch to next queued data if the current has finished playing) for (iter = mAllSources.begin(); iter != mAllSources.end(); ++iter) { LLAudioSource *sourcep = iter->second; if (!sourcep->isSyncSlave()) { // Not a loop slave, we don't need to do anything continue; } LLAudioChannel *channelp = sourcep->getChannel(); if (!channelp) { // Not playing, don't need to bother. continue; } if (!channelp->isPlaying()) { // Now we need to check if our loop master has just looped, and // start playback if that's the case. if (sync_masterp->getChannel()) { channelp->playSynced(master_channelp); channelp->setWaiting(FALSE); } } } } // Sync up everything that the audio engine needs done. commitDeferredChanges(); // Flush unused buffers that are stale enough for (i = 0; i < MAX_BUFFERS; i++) { if (mBuffers[i]) { if (!mBuffers[i]->mInUse && mBuffers[i]->mLastUseTimer.getElapsedTimeF32() > 30.f) { //llinfos << "Flushing unused buffer!" << llendl; mBuffers[i]->mAudioDatap->mBufferp = NULL; delete mBuffers[i]; mBuffers[i] = NULL; } } } // Clear all of the looped flags for the channels for (i = 0; i < MAX_CHANNELS; i++) { if (mChannels[i]) { mChannels[i]->mLoopedThisFrame = FALSE; } } // Decode audio files gAudioDecodeMgrp->processQueue(max_decode_time); // Call this every frame, just in case we somehow // missed picking it up in all the places that can add // or request new data. startNextTransfer(); }