void BufferedAudioSource::close() { if(!isLoadedInMemory()) { BufferedAudioSourceThread::getInstance()->removeSource(this); } }
void BufferedAudioSource::prime() { if(!isLoadedInMemory()) { // if this is the first time source is added, trigger to read data immediately if (BufferedAudioSourceThread::getInstance()->addSource(this)) { BufferedAudioSourceThread::getInstance()->readMore(); } } }
void BufferedAudioSource::flush() { if(!isLoadedInMemory()) { BufferedAudioSourceThread::getInstance()->removeSource(this); { RScopedLock l(&mLock); mBuffer.clear(); } } }
void BufferedAudioSource::setPosition(double seconds) { seconds = seconds < 0 ? 0.0f : seconds; seconds = seconds > getLength() ? getLength() : seconds; RScopedLock l(&mLock); Int64 frames = (Int64)(seconds * getSampleRate()); if(!isLoadedInMemory()) { mBuffer.clear(); setDecoderPosition(frames); BufferedAudioSourceThread::getInstance()->readMore(); } }
Int64 ExtAudioFileAudioSource::decodeData(float* buffer, UInt32 numFrames) { RPRINT("decoding data\n"); UInt32 numChannels = getNumChannels(); OSStatus err = noErr; mReadBuffer.resize(numChannels * numFrames); // Set up the buffers setUpBuffers(&mReadBuffer[0], numChannels, numFrames); // Read the data out of our file, filling our output buffer UInt32 framesRead = numFrames; if(!isLoadedInMemory()) { RScopedLock l(&mDecodeLock); err = ExtAudioFileRead (mAudioFile, &framesRead, mpBufferList); } else { err = ExtAudioFileRead (mAudioFile, &framesRead, mpBufferList); } if(err || framesRead == 0) { mEOF = true; RPRINT("done decoding data\n"); return 0; } // The data is expected to be interlaced for(UInt32 j = 0; j < numChannels; ++j) { float *pTemp = &mReadBuffer[j * numFrames]; float *pOut = &buffer[j]; for(UInt32 i = j; i < framesRead; i++) { *pOut = *pTemp++; pOut += numChannels; } } RPRINT("done decoding data\n"); return framesRead; }
Int64 BufferedAudioSource::readFrames(float* buffer, UInt32 numChannels, UInt32 numFrames, AudioSourceState& state) { RScopedLock l(&mLock); Int64 framesRead = numFrames; int framesAvailable = mBuffer.size() / getNumChannels() - state.mCurrentFrame; // For disk-streaming sources we calculate available frames using the whole buffer if(!isLoadedInMemory()) { framesAvailable = mBuffer.size() / getNumChannels(); } Int64 loopEndFrame = convertSecondsToSamples(state.mLoopEnd); Int64 totalFrames = convertSecondsToSamples(getLength()); bool needToLoop = state.mLooping && ((state.mCurrentFrame >= loopEndFrame && loopEndFrame > 0) || (framesAvailable == 0 && mEOF)); if(framesAvailable > 0 && !needToLoop) { // Make sure we don't read passed the end loop frame if(state.mLooping && loopEndFrame > 0 && loopEndFrame > state.mCurrentFrame) framesRead = (std::min)(framesRead, loopEndFrame-state.mCurrentFrame); if(framesAvailable < framesRead) framesRead = framesAvailable; int sourceChannels = getNumChannels(); int frameOffset = state.mCurrentFrame; // For disk-streaming sources we always start at the beginning of the buffer if(!isLoadedInMemory()) frameOffset = 0; for(UInt32 j = 0; j < numChannels; ++j) { float *in = NULL; if(sourceChannels == 1) in = mBuffer.getData(0, frameOffset); else in = mBuffer.getData(j, frameOffset); for(UInt32 i = 0; i < framesRead; ++i) { *(buffer++) = *in; in += sourceChannels; } } state.mCurrentFrame += framesRead; if(!isLoadedInMemory()) { mBuffer.erase(0, framesRead); framesAvailable = mBuffer.size() / getNumChannels(); UInt32 minimumFrames = getSampleRate() * SECONDS_TO_BUFFER / 2; if(framesAvailable <= minimumFrames) { BufferedAudioSourceThread::getInstance()->readMore(); } } } else { framesRead = ERR_BUFFERING; if(needToLoop) { setPosition(state.mLoopStart); state.mCurrentFrame = convertSecondsToSamples(state.mLoopStart); // Now that we rewinded, read new data if preloaded if(isLoadedInMemory()) { return readFrames(buffer, numChannels, numFrames, state); } } if(mEOF) { return 0; // signal that we are done } else if(!isLoadedInMemory()) { BufferedAudioSourceThread::getInstance()->readMore(); } } return framesRead; }
Int64 BufferedAudioSource::readFrames(float* buffer, UInt32 numChannels, UInt32 numFrames, AudioSourceState& state) { mLock.lock(); Int64 framesRead = numFrames; int framesAvailable = mBuffer.size() / getNumChannels() - state.mCurrentFrame; // For disk-streaming sources we calculate available frames using the whole buffer if(!isLoadedInMemory()) framesAvailable = mBuffer.size() / getNumChannels(); mLock.unlock(); Int64 loopEndFrame = convertSecondsToSamples(state.mLoopEnd); Int64 totalFrames = convertSecondsToSamples(getLength()); bool needToLoop = state.mLooping && ((state.mCurrentFrame >= loopEndFrame && loopEndFrame > 0) || (framesAvailable == 0 && mEOF)); if(framesAvailable > 0 && !needToLoop) { RScopedLock l(&mLock); if(framesAvailable < numFrames) framesRead = framesAvailable; int sourceChannels = getNumChannels(); int frameOffset = state.mCurrentFrame; // For disk-streaming sources we always start at the beginning of the buffer if(!isLoadedInMemory()) frameOffset = 0; for(UInt32 j = 0; j < numChannels; ++j) { float *in = NULL; if(sourceChannels == 1) in = mBuffer.getData(0, frameOffset); else in = mBuffer.getData(j, frameOffset); for(UInt32 i = 0; i < framesRead; ++i) { *(buffer++) = *in; in += sourceChannels; } } state.mCurrentFrame += framesRead; if(!isLoadedInMemory()) { mBuffer.erase(0, framesRead); framesAvailable = mBuffer.size() / getNumChannels(); UInt32 minimumFrames = getSampleRate() / 3; // 1/3 of a second if(framesAvailable <= minimumFrames) { BufferedAudioSourceThread::getInstance()->readMore(); } } } else { framesRead = ERR_BUFFERING; if(needToLoop) { setPosition(state.mLoopStart); state.mCurrentFrame = convertSecondsToSamples(state.mLoopStart); } Int64 totalFrames = convertSecondsToSamples(getLength()); if(state.mCurrentFrame >= totalFrames) { if(!isLoadedInMemory()) BufferedAudioSourceThread::getInstance()->removeSource(this); return 0; // signal that we are done } else if(!isLoadedInMemory()) BufferedAudioSourceThread::getInstance()->readMore(); } return framesRead; }