bool WaveTrack::Get(samplePtr buffer, sampleFormat format, longSampleCount start, sampleCount len) { longSampleCount startTime = (longSampleCount)floor(mOffset*mRate + 0.5); longSampleCount endTime = startTime + mSequence->GetNumSamples(); if (start+len < startTime || start>=endTime) { ClearSamples(buffer, format, 0, len); return true; } sampleCount s0 = (sampleCount)(start - startTime); sampleCount soffset = 0; sampleCount getlen = len; if (s0 < 0) { soffset = -s0; getlen -= soffset; s0 = 0; } if (s0+getlen > mSequence->GetNumSamples()) getlen = mSequence->GetNumSamples() - s0; if (!mSequence->Get(buffer + soffset*SAMPLE_SIZE(format), format, s0, getlen)) { ClearSamples(buffer, format, 0, len); return false; } ClearSamples(buffer, format, 0, soffset); ClearSamples(buffer, format, soffset+getlen, len-(soffset+getlen)); return true; }
void Mixer::GetSamples(WaveTrack *src, int s0, int slen) { // Retrieves samples from a track, even outside of the range which // contains samples. (Fills in extra space with zeros.) // Puts samples in mTemp if (slen > mTempBufferSize) { mTempBufferSize = slen; DeleteSamples(mTemp); mTemp = NewSamples(mTempBufferSize, mFormat); } int soffset = 0; int getlen = slen; if (s0 < 0) { soffset = -s0; getlen -= soffset; s0 = 0; } if (s0+getlen > src->GetNumSamples()) { getlen = src->GetNumSamples() - s0; } src->Get(mTemp + soffset*SAMPLE_SIZE(mFormat), mFormat, (sampleCount)s0, (sampleCount)getlen); ClearSamples(mTemp, mFormat, 0, soffset); ClearSamples(mTemp, mFormat, soffset+getlen, slen-(soffset+getlen)); }
size_t SilentBlockFile::ReadData(samplePtr data, sampleFormat format, size_t WXUNUSED(start), size_t len, bool) const { ClearSamples(data, format, 0, len); return len; }
int SilentBlockFile::ReadData(samplePtr data, sampleFormat format, sampleCount start, sampleCount len) { ClearSamples(data, format, 0, len); return len; }
// Pass NULL to set silence bool Sequence::Set(samplePtr buffer, sampleFormat format, sampleCount start, sampleCount len) { if (start < 0 || start > mNumSamples || start+len > mNumSamples) return false; samplePtr temp = NULL; if (format != mSampleFormat) { temp = NewSamples(mMaxSamples, mSampleFormat); wxASSERT(temp); } samplePtr silence = NULL; if (!buffer) { silence = NewSamples(mMaxSamples, format); wxASSERT(silence); ClearSamples(silence, format, 0, mMaxSamples); } int b = FindBlock(start); while (len) { int blen = mBlock->Item(b)->start + mBlock->Item(b)->len - start; if (blen > len) blen = len; if (buffer) { if (format == mSampleFormat) CopyWrite(buffer, mBlock->Item(b), start - mBlock->Item(b)->start, blen); else { CopySamples(buffer, format, temp, mSampleFormat, blen); CopyWrite(temp, mBlock->Item(b), start - mBlock->Item(b)->start, blen); } buffer += (blen * SAMPLE_SIZE(format)); } else CopyWrite(silence, mBlock->Item(b), start - mBlock->Item(b)->start, blen); len -= blen; start += blen; b++; } if (!buffer) DeleteSamples(silence); if (format != mSampleFormat) DeleteSamples(temp); return ConsistencyCheck("Set"); }
bool WaveTrack::Get(samplePtr buffer, sampleFormat format, longSampleCount start, sampleCount len) { // Simple optimization: When this buffer is completely contained within one clip, // don't clear anything (because we never won't have to). Otherwise, just clear // everything to be on the safe side. WaveClipList::Node* it; bool doClear = true; for (it=GetClipIterator(); it; it=it->GetNext()) { WaveClip *clip = it->GetData(); if (start >= clip->GetStartSample() && start+len <= clip->GetEndSample()) { doClear = false; break; } } if (doClear) ClearSamples(buffer, format, 0, len); for (it=GetClipIterator(); it; it=it->GetNext()) { WaveClip *clip = it->GetData(); longSampleCount clipStart = clip->GetStartSample(); longSampleCount clipEnd = clip->GetEndSample(); if (clipEnd > start && clipStart < start+len) { // Clip sample region and Get/Put sample region overlap sampleCount samplesToCopy = start+len - clipStart; if (samplesToCopy > clip->GetNumSamples()) samplesToCopy = clip->GetNumSamples(); longSampleCount inclipDelta = 0; longSampleCount startDelta = clipStart - start; if (startDelta < 0) { inclipDelta = -startDelta; // make positive value samplesToCopy -= inclipDelta; startDelta = 0; } if (!clip->GetSamples((samplePtr)(((char*)buffer)+startDelta*SAMPLE_SIZE(format)), format, inclipDelta, samplesToCopy)) { wxASSERT(false); // should always work return false; } } } return true; }
/// Returns the 64K summary data block /// Fill with zeroes and return false if data are unavailable for any reason. bool ODDecodeBlockFile::Read64K(float *buffer, size_t start, size_t len) { if(IsSummaryAvailable()) { return SimpleBlockFile::Read64K(buffer,start,len); } else { ClearSamples((samplePtr)buffer, floatSample, 0, len); return false; } }
/// Returns the 64K summary data block. /// Fill with zeroes and return false if data are unavailable for any reason. bool ODPCMAliasBlockFile::Read64K(float *buffer, size_t start, size_t len) { if(IsSummaryAvailable()) { return PCMAliasBlockFile::Read64K(buffer,start,len); } else { //return nothing - it hasn't been calculated yet ClearSamples((samplePtr)buffer, floatSample, 0, len); return false; } }
/// Returns the 256 byte summary data block. /// Fill with zeroes and return false if data are unavailable for any reason. bool ODPCMAliasBlockFile::Read256(float *buffer, size_t start, size_t len) { if(IsSummaryAvailable()) { return PCMAliasBlockFile::Read256(buffer,start,len); } else { //return nothing. ClearSamples((samplePtr)buffer, floatSample, 0, len); return false; } }
bool Sequence::InsertSilence(sampleCount s0, sampleCount len) { // Create a new track containing as much silence as we // need to insert, and then call Paste to do the insertion Sequence *sTrack = new Sequence(mDirManager, mSampleFormat); sampleCount idealSamples = GetIdealBlockSize(); // Allocate a zeroed buffer samplePtr buffer = NewSamples(idealSamples, mSampleFormat); ClearSamples(buffer, mSampleFormat, 0, idealSamples); sampleCount pos = 0; BlockFile *firstBlockFile = NULL; while (len) { sampleCount l = (len > idealSamples ? idealSamples : len); SeqBlock *w = new SeqBlock(); w->start = pos; w->len = l; w->min = float(0.0); w->max = float(0.0); w->rms = float(0.0); if (pos == 0 || len == l) { w->f = mDirManager->NewBlockFile(mSummary->totalSummaryBytes); firstBlockFile = w->f; FirstWrite(buffer, w, l); } else { w->f = mDirManager->CopyBlockFile(firstBlockFile); if (!w->f) { // TODO set error message return false; } } sTrack->mBlock->Add(w); pos += l; len -= l; } sTrack->mNumSamples = pos; Paste(s0, sTrack); delete sTrack; DeleteSamples(buffer); return ConsistencyCheck("InsertSilence"); }
/// Reads the specified data from the aliased file, using libsndfile, /// and converts it to the given sample format. /// /// @param data The buffer to read the sample data into. /// @param format The format to convert the data into /// @param start The offset within the block to begin reading /// @param len The number of samples to read int ODDecodeBlockFile::ReadData(samplePtr data, sampleFormat format, sampleCount start, sampleCount len) { int ret; LockRead(); if(IsSummaryAvailable()) ret= SimpleBlockFile::ReadData(data,format,start,len); else { //we should do an ODRequest to start processing the data here, and wait till it finishes. and just do a SimpleBlockFIle //ReadData. ClearSamples(data, format, 0, len); ret= len; } UnlockRead(); return ret; }
/// Reads the specified data from the aliased file, using libsndfile, /// and converts it to the given sample format. /// /// @param data The buffer to read the sample data into. /// @param format The format to convert the data into /// @param start The offset within the block to begin reading /// @param len The number of samples to read size_t ODDecodeBlockFile::ReadData(samplePtr data, sampleFormat format, size_t start, size_t len, bool mayThrow) const { auto locker = LockForRead(); if(IsSummaryAvailable()) return SimpleBlockFile::ReadData(data, format, start, len, mayThrow); else { if (mayThrow) throw NotYetAvailableException{ mAudioFileName }; //we should do an ODRequest to start processing the data here, and wait till it finishes. and just do a SimpleBlockFile //ReadData. ClearSamples(data, format, 0, len); return 0; } }
size_t RingBuffer::Clear(sampleFormat format, size_t samplesToClear) { samplesToClear = std::min( samplesToClear, AvailForPut() ); size_t cleared = 0; auto pos = mEnd; while(samplesToClear) { auto block = std::min( samplesToClear, mBufferSize - pos ); ClearSamples(mBuffer.ptr(), format, pos, block); pos = (pos + block) % mBufferSize; samplesToClear -= block; cleared += block; } mEnd = pos; return cleared; }
bool Sequence::Read(samplePtr buffer, sampleFormat format, SeqBlock * b, sampleCount start, sampleCount len) const { wxASSERT(b); wxASSERT(start >= 0); wxASSERT(start + len <= b->f->GetLength()); BlockFile *f = b->f; int result = f->ReadData(buffer, format, start, len); if (result != len) { wxLogError(wxT("Expected to read %d samples, got %d samples.\n"), len, result); if (result < 0) result = 0; ClearSamples(buffer, format, result, len-result); } return true; }
// Pass NULL to set silence bool Sequence::Set(samplePtr buffer, sampleFormat format, sampleCount start, sampleCount len) { if (start < 0 || start > mNumSamples || start+len > mNumSamples) return false; samplePtr temp = NULL; if (format != mSampleFormat) { temp = NewSamples(mMaxSamples, mSampleFormat); wxASSERT(temp); } samplePtr silence = NULL; if (!buffer) { silence = NewSamples(mMaxSamples, format); wxASSERT(silence); ClearSamples(silence, format, 0, mMaxSamples); } int b = FindBlock(start); while (len) { int blen = mBlock->Item(b)->start + mBlock->Item(b)->f->GetLength() - start; if (blen > len) blen = len; if (buffer) { if (format == mSampleFormat) CopyWrite(buffer, mBlock->Item(b), start - mBlock->Item(b)->start, blen); else { CopySamples(buffer, format, temp, mSampleFormat, blen); CopyWrite(temp, mBlock->Item(b), start - mBlock->Item(b)->start, blen); } buffer += (blen * SAMPLE_SIZE(format)); } else { // If it's a full block of silence if (start == mBlock->Item(b)->start && blen == mBlock->Item(b)->f->GetLength()) { mDirManager->Deref(mBlock->Item(b)->f); mBlock->Item(b)->f = new SilentBlockFile(blen); } else { // Otherwise write silence just to the portion of the block CopyWrite(silence, mBlock->Item(b), start - mBlock->Item(b)->start, blen); } } len -= blen; start += blen; b++; } if (!buffer) DeleteSamples(silence); if (format != mSampleFormat) DeleteSamples(temp); return ConsistencyCheck(wxT("Set")); }
int audacityAudioCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ) { int numOutChannels = gAudioIO->mNumOutChannels; int numInChannels = gAudioIO->mNumInChannels; int minIndex = 0, minID = 0; unsigned int i; // // Copy from our pool of output buffers to PortAudio's output buffer // if (outputBuffer && numOutChannels > 0) { for(i=0; i<gAudioIO->mNumOutBuffers; i++) { if (gAudioIO->mOutBuffer[i].ID>0 && (minID==0 || gAudioIO->mOutBuffer[i].ID < minID)) { minID = gAudioIO->mOutBuffer[i].ID; minIndex = i; } } if (minID > 0) { AudioIOBuffer *b = &gAudioIO->mOutBuffer[minIndex]; sampleCount len = b->len; memcpy(outputBuffer, b->data, len * numOutChannels * SAMPLE_SIZE(gAudioIO->GetFormat())); // Fill rest of buffer with silence if (len < (sampleCount) framesPerBuffer) ClearSamples((samplePtr)outputBuffer, gAudioIO->GetFormat(), len*numOutChannels, (framesPerBuffer-len)*numOutChannels); b->ID = 0; } else { // we had a buffer underrun! // play silence ClearSamples((samplePtr)outputBuffer, gAudioIO->GetFormat(), 0, framesPerBuffer * numOutChannels); // increase number of output buffers to prevent another underrun! if (gAudioIO->mNumOutBuffers < gAudioIO->mMaxBuffers) gAudioIO->mNumOutBuffers++; } } // // Copy from PortAudio's input buffer to one of our input buffers. // if (inputBuffer && numInChannels > 0) { bool found = false; for(i=0; i<gAudioIO->mNumInBuffers; i++) { if (gAudioIO->mInBuffer[i].ID == 0) { int len = framesPerBuffer; int sampleSize = SAMPLE_SIZE(gAudioIO->GetFormat()); AudioIOBuffer *b = &gAudioIO->mInBuffer[i]; memcpy(b->data, inputBuffer, len * numInChannels * sampleSize); b->len = len; b->ID = gAudioIO->mInID; gAudioIO->mInID++; found = true; int checksum = 0; for(int k=0; k<len*numInChannels*sampleSize; k++) checksum += ((char *)inputBuffer)[k]; if (checksum == gAudioIO->mLastChecksum) { gAudioIO->mRepeats++; gAudioIO->mRepeatPoint = gAudioIO->mT; } gAudioIO->mLastChecksum = checksum; break; } } if (!found) { // we had a buffer underrun! gAudioIO->mInUnderruns++; } } return 0; }