Mixer::~Mixer() { int i; for (i = 0; i < mNumBuffers; i++) { DeleteSamples(mBuffer[i]); DeleteSamples(mTemp[i]); } delete[] mBuffer; delete[] mTemp; delete[] mInputTrack; delete[] mEnvValues; delete[] mFloatBuffer; delete[] mGains; delete[] mSamplePos; for(i=0; i<mNumInputTracks; i++) { delete mResample[i]; delete[] mSampleQueue[i]; } delete[] mResample; delete[] mSampleQueue; delete[] mQueueStart; delete[] mQueueLen; }
Mixer::~Mixer() { for (int c = 0; c < mNumBuffers; c++) DeleteSamples(mBuffer[c]); delete[]mBuffer; DeleteSamples(mTemp); delete[]mEnvValues; }
// 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"); }
/// Write the summary to disk. Derived classes must call this method /// from their constructors for the summary to be correctly written. /// It uses the derived class's ReadData() to retrieve the data to /// summarize. void AliasBlockFile::WriteSummary() { // Now checked carefully in the DirManager //wxASSERT( !wxFileExists(FILENAME(mFileName.GetFullPath()))); // I would much rather have this code as part of the constructor, but // I can't call virtual functions from the constructor. So we just // need to ensure that every derived class calls this in *its* constructor wxFFile summaryFile(mFileName.GetFullPath(), wxT("wb")); if( !summaryFile.IsOpened() ){ // Never silence the Log w.r.t write errors; they always count // as new errors wxLogError(wxT("Unable to write summary data to file %s"), mFileName.GetFullPath().c_str()); // If we can't write, there's nothing to do. return; } // To build the summary data, call ReadData (implemented by the // derived classes) to get the sample data samplePtr sampleData = NewSamples(mLen, floatSample); this->ReadData(sampleData, floatSample, 0, mLen); void *summaryData = BlockFile::CalcSummary(sampleData, mLen, floatSample); summaryFile.Write(summaryData, mSummaryInfo.totalSummaryBytes); DeleteSamples(sampleData); }
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)); }
bool Sequence::CopyWrite(samplePtr buffer, SeqBlock *b, sampleCount start, sampleCount len) { // We don't ever write to an existing block; to support Undo, // we copy the old block entirely into memory, dereference it, // make the change, and then write the new block to disk. wxASSERT(b); wxASSERT(b->f->GetLength() <= mMaxSamples); wxASSERT(start + len <= b->f->GetLength()); int sampleSize = SAMPLE_SIZE(mSampleFormat); samplePtr newBuffer = NewSamples(mMaxSamples, mSampleFormat); wxASSERT(newBuffer); Read(newBuffer, mSampleFormat, b, 0, b->f->GetLength()); memcpy(newBuffer + start*sampleSize, buffer, len*sampleSize); BlockFile *oldBlockFile = b->f; b->f = mDirManager->NewSimpleBlockFile(newBuffer, b->f->GetLength(), mSampleFormat); mDirManager->Deref(oldBlockFile); DeleteSamples(newBuffer); return true; }
/// Retrieves the minimum, maximum, and maximum RMS of the /// specified sample data in this block. /// /// @param start The offset in this block where the region should begin /// @param len The number of samples to include in the region /// @param *outMin A pointer to where the minimum value for this region /// should be stored /// @param *outMax A pointer to where the maximum value for this region /// should be stored /// @param *outRMS A pointer to where the maximum RMS value for this /// region should be stored. void BlockFile::GetMinMax(sampleCount start, sampleCount len, float *outMin, float *outMax, float *outRMS) { // TODO: actually use summaries samplePtr blockData = NewSamples(len, floatSample); this->ReadData(blockData, floatSample, start, len); float min = FLT_MAX; float max = -FLT_MAX; float sumsq = 0; for( int i = 0; i < len; i++ ) { float sample = ((float*)blockData)[i]; if( sample > max ) max = sample; if( sample < min ) min = sample; sumsq = (sample*sample); } DeleteSamples(blockData); *outMin = min; *outMax = max; *outRMS = sqrt(sumsq/len); }
WaveTrack::~WaveTrack() { if (mAppendBuffer) DeleteSamples(mAppendBuffer); delete mSequence; delete mEnvelope; delete mWaveCache; delete mSpecCache; }
bool Sequence::ConvertToSampleFormat(sampleFormat format) { if (format == mSampleFormat) return true; if (mBlock->Count() == 0) { mSampleFormat = format; return true; } sampleFormat oldFormat = mSampleFormat; mSampleFormat = format; for (unsigned int i = 0; i < mBlock->Count(); i++) { BlockFile *oldBlock = mBlock->Item(i)->f; sampleCount len = mBlock->Item(i)->len; if (!oldBlock->IsAlias()) { BlockFile *newBlock = mDirManager->NewBlockFile(mSummary->totalSummaryBytes); samplePtr buffer1 = NewSamples(len, oldFormat); samplePtr buffer2 = NewSamples(len, mSampleFormat); oldBlock->ReadData(buffer1, oldFormat, 0, len); CopySamples(buffer1, oldFormat, buffer2, mSampleFormat, len); newBlock->WriteData(buffer2, mSampleFormat, len); mBlock->Item(i)->f = newBlock; mDirManager->Deref(oldBlock); UpdateSummaries(buffer2, mBlock->Item(i), len); DeleteSamples(buffer2); DeleteSamples(buffer1); } } return true; }
/// Write the summary to disk, using the derived ReadData() to get the data void ODPCMAliasBlockFile::WriteSummary() { //the mFileName path may change, for example, when the project is saved. //(it moves from /tmp/ to wherever it is saved to. mFileNameMutex.Lock(); //wxFFile is not thread-safe - if any error occurs in opening the file, // it posts a wxlog message which WILL crash // Audacity because it goes into the wx GUI. // For this reason I left the wxFFile method commented out. (mchinen) // wxFFile summaryFile(mFileName.GetFullPath(), wxT("wb")); // ...and we use fopen instead. wxString sFullPath = mFileName.GetFullPath(); char* fileNameChar = new char[strlen(sFullPath.mb_str(wxConvFile)) + 1]; strcpy(fileNameChar, sFullPath.mb_str(wxConvFile)); FILE* summaryFile = fopen(fileNameChar, "wb"); mFileNameMutex.Unlock(); if( !summaryFile) { //.IsOpened() ){ // Never silence the Log w.r.t write errors; they always count //however, this is going to be called from a non-main thread, //and wxLog calls are not thread safe. printf("Unable to write summary data to file: %s", fileNameChar); delete [] fileNameChar; return; } delete [] fileNameChar; // To build the summary data, call ReadData (implemented by the // derived classes) to get the sample data samplePtr sampleData = NewSamples(mLen, floatSample); this->ReadData(sampleData, floatSample, 0, mLen); void *summaryData = CalcSummary(sampleData, mLen, floatSample); //summaryFile.Write(summaryData, mSummaryInfo.totalSummaryBytes); fwrite(summaryData, 1, mSummaryInfo.totalSummaryBytes, summaryFile); fclose(summaryFile); DeleteSamples(sampleData); delete [] (char *) summaryData; // printf("write successful. filename: %s\n", fileNameChar); mSummaryAvailableMutex.Lock(); mSummaryAvailable=true; mSummaryAvailableMutex.Unlock(); }
bool Sequence::ConvertToSampleFormat(sampleFormat format) { if (format == mSampleFormat) return true; if (mBlock->Count() == 0) { mSampleFormat = format; return true; } sampleFormat oldFormat = mSampleFormat; mSampleFormat = format; for (unsigned int i = 0; i < mBlock->Count(); i++) { SeqBlock *b = mBlock->Item(i); BlockFile *oldBlock = b->f; sampleCount len = b->f->GetLength(); if (!oldBlock->IsAlias()) { BlockFile *newBlock; samplePtr buffer1 = NewSamples(len, oldFormat); samplePtr buffer2 = NewSamples(len, mSampleFormat); oldBlock->ReadData(buffer1, oldFormat, 0, len); CopySamples(buffer1, oldFormat, buffer2, mSampleFormat, len); newBlock = mDirManager->NewSimpleBlockFile(buffer2, len, mSampleFormat); mBlock->Item(i)->f = newBlock; mDirManager->Deref(oldBlock); DeleteSamples(buffer2); DeleteSamples(buffer1); } } return true; }
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"); }
bool Sequence::Copy(sampleCount s0, sampleCount s1, Sequence **dest) { *dest = 0; if (s0 >= s1 || s0 >= mNumSamples || s1 < 0) return false; int numBlocks = mBlock->Count(); int b0 = FindBlock(s0); int b1 = FindBlock(s1); if (s1 == mNumSamples) b1 = numBlocks; *dest = new Sequence(mDirManager, mSampleFormat); samplePtr buffer = NewSamples(mMaxSamples, mSampleFormat); int blocklen; // Do the first block if (b0 >= 0 && b0 < numBlocks && s0 != mBlock->Item(b0)->start) { blocklen = (mBlock->Item(b0)->start + mBlock->Item(b0)->f->GetLength() - s0); if (blocklen > (s1 - s0)) blocklen = s1 - s0; Get(buffer, mSampleFormat, s0, blocklen); (*dest)->Append(buffer, mSampleFormat, blocklen); } if (b0 >= 0 && b0 < numBlocks && s0 == mBlock->Item(b0)->start) { b0--; } // If there are blocks in the middle, copy the blockfiles directly for (int b = b0 + 1; b < b1; b++) ((Sequence *)*dest)->AppendBlock(mBlock->Item(b)); // Do the last block if (b1 > b0 && b1 < numBlocks) { blocklen = (s1 - mBlock->Item(b1)->start); Get(buffer, mSampleFormat, mBlock->Item(b1)->start, blocklen); (*dest)->Append(buffer, mSampleFormat, blocklen); } DeleteSamples(buffer); return true; }
/// Write the summary to disk, using the derived ReadData() to get the data /// Here, the decoder ODTask associated with this file must fetch the samples with /// the ODDecodeTask::Decode() method. int ODDecodeBlockFile::WriteODDecodeBlockFile() { // To build the summary data, call ReadData (implemented by the // derived classes) to get the sample data samplePtr sampleData;// = NewSamples(mLen, floatSample); int ret; //use the decoder here. mDecoderMutex.Lock(); if(!mDecoder) { mDecoderMutex.Unlock(); return -1; } //sampleData and mFormat are set by the decoder. ret = mDecoder->Decode(sampleData, mFormat, mAliasStart, mLen, mAliasChannel); mDecoderMutex.Unlock(); if(ret < 0) { printf("ODDecodeBlockFile Decode failure\n"); return ret; //failure } //the summary is also calculated here. mFileNameMutex.Lock(); //TODO: we may need to write a version of WriteSimpleBlockFile that uses threadsafe FILE vs wxFile bool bSuccess = WriteSimpleBlockFile( sampleData, mLen, mFormat, NULL);//summaryData); wxASSERT(bSuccess); // TODO: Handle failure here by alert to user and undo partial op. mFileNameMutex.Unlock(); DeleteSamples(sampleData); // delete [] (char *) summaryData; mDataAvailableMutex.Lock(); mDataAvailable=true; mDataAvailableMutex.Unlock(); 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 int PCMAliasBlockFile::ReadData(samplePtr data, sampleFormat format, sampleCount start, sampleCount len) { SF_INFO info; memset(&info, 0, sizeof(info)); SNDFILE *sf = sf_open(mAliasedFullPath, SFM_READ, &info); if (!sf) return 0; sf_seek(sf, mAliasStart + start, SEEK_SET); samplePtr buffer = NewSamples(len * info.channels, floatSample); int framesRead = 0; if (format == int16Sample && !sf_subtype_more_than_16_bits(info.format)) { // Special case: if the file is in 16-bit (or less) format, // and the calling method wants 16-bit data, go ahead and // read 16-bit data directly. This is a pretty common // case, as most audio files are 16-bit. framesRead = sf_readf_short(sf, (short *)buffer, len); for (int i = 0; i < framesRead; i++) ((short *)data)[i] = ((short *)buffer)[(info.channels * i) + mAliasChannel]; } else { // Otherwise, let libsndfile handle the conversion and // scaling, and pass us normalized data as floats. We can // then convert to whatever format we want. framesRead = sf_readf_float(sf, (float *)buffer, len); float *bufferPtr = &((float *)buffer)[mAliasChannel]; CopySamples((samplePtr)bufferPtr, floatSample, (samplePtr)data, format, framesRead, true, info.channels); } DeleteSamples(buffer); sf_close(sf); return framesRead; }
WaveClip::~WaveClip() { delete mSequence; delete mEnvelope; delete mWaveCache; delete mSpecCache; delete mSpecPxCache; #ifdef EXPERIMENTAL_USE_REALFFTF if(hFFT != NULL) EndFFT(hFFT); if(mWindow != NULL) delete[] mWindow; #endif if (mAppendBuffer) DeleteSamples(mAppendBuffer); mCutLines.DeleteContents(true); mCutLines.Clear(); }
/// Write the summary to disk, using the derived ReadData() to get the data void ODPCMAliasBlockFile::WriteSummary() { //Below from BlockFile.cpp's method. We need to delete the data returned by //CalcSummary, because it uses local info. In the future we might do something //smarter and thread-dependant like a static thread context. wxFFile summaryFile(mFileName.GetFullPath(), wxT("wb")); if( !summaryFile.IsOpened() ){ // Never silence the Log w.r.t write errors; they always count // as new errors //however, this is going to be called from a non-main thread, //and wxLog calls are not thread safe. printf("Unable to write summary data to file %s", mFileName.GetFullPath().c_str()); // If we can't write, there's nothing to do. return; } // To build the summary data, call ReadData (implemented by the // derived classes) to get the sample data samplePtr sampleData = NewSamples(mLen, floatSample); this->ReadData(sampleData, floatSample, 0, mLen); void *summaryData = CalcSummary(sampleData, mLen, floatSample); summaryFile.Write(summaryData, mSummaryInfo.totalSummaryBytes); DeleteSamples(sampleData); delete [] summaryData; //above from BlockFiles.cpps method mSummaryAvailableMutex.Lock(); mSummaryAvailable=true; mSummaryAvailableMutex.Unlock(); }
bool Sequence::AppendAlias(wxString fullPath, sampleCount start, sampleCount len, int channel) { SeqBlock *newBlock = new SeqBlock(); newBlock->start = mNumSamples; newBlock->len = len; newBlock->f = mDirManager->NewBlockFile(mSummary->totalSummaryBytes); newBlock->f->SetAliasedData(fullPath, start, len, channel); samplePtr buffer = NewSamples(len, mSampleFormat); Read(buffer, mSampleFormat, newBlock, 0, len); UpdateSummaries(buffer, newBlock, len); DeleteSamples(buffer); mBlock->Add(newBlock); mNumSamples += newBlock->len; return true; }
/// Write the summary to disk, using the derived ReadData() to get the data /// Here, the decoder ODTask associated with this file must fetch the samples with /// the ODDecodeTask::Decode() method. void ODDecodeBlockFile::WriteODDecodeBlockFile() { // To build the summary data, call ReadData (implemented by the // derived classes) to get the sample data samplePtr sampleData = NewSamples(mLen, floatSample); //use the decoder here. mDecoderMutex.Lock(); if(!mDecoder) { mDecoderMutex.Unlock(); return; } mDecoder->Decode(sampleData, mFormat, mDecodeFileStart, mLen); mDecoderMutex.Unlock(); this->ReadData(sampleData, floatSample, 0, mLen); void *summaryData = CalcSummary(sampleData, mLen, floatSample); //OD TODO: use new write() // summaryFile.Write(summaryData, mSummaryInfo.totalSummaryBytes); WriteSimpleBlockFile( sampleData, mLen, mFormat, summaryData); DeleteSamples(sampleData); delete [] (char *) summaryData; mDataAvailableMutex.Lock(); mDataAvailable=true; mDataAvailableMutex.Unlock(); }
/// Reads the specified data from the aliased file, using libsndfile, /// and converts it to the given sample format. /// Copied from PCMAliasBlockFIle but wxLog calls taken out for thread safety /// /// @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 ODPCMAliasBlockFile::ReadData(samplePtr data, sampleFormat format, sampleCount start, sampleCount len) { mReadDataMutex.Lock(); SF_INFO info; if(!mAliasedFileName.IsOk()){ // intentionally silenced memset(data,0,SAMPLE_SIZE(format)*len); mReadDataMutex.Unlock(); return len; } memset(&info, 0, sizeof(info)); wxString aliasPath = mAliasedFileName.GetFullPath(); //there are thread-unsafe crashes here - not sure why. sf_open may be called on the same file //from different threads, but this seems okay, unless it is implemented strangely.. static ODLock sfMutex; wxFile f; // will be closed when it goes out of scope SNDFILE *sf = NULL; if (f.Open(aliasPath)) { // Even though there is an sf_open() that takes a filename, use the one that // takes a file descriptor since wxWidgets can open a file with a Unicode name and // libsndfile can't (under Windows). ODManager::LockLibSndFileMutex(); sf = sf_open_fd(f.fd(), SFM_READ, &info, FALSE); ODManager::UnlockLibSndFileMutex(); } if (!sf){ memset(data,0,SAMPLE_SIZE(format)*len); mSilentAliasLog=TRUE; mReadDataMutex.Unlock(); return len; } mSilentAliasLog=FALSE; ODManager::LockLibSndFileMutex(); sf_seek(sf, mAliasStart + start, SEEK_SET); ODManager::UnlockLibSndFileMutex(); samplePtr buffer = NewSamples(len * info.channels, floatSample); int framesRead = 0; if (format == int16Sample && !sf_subtype_more_than_16_bits(info.format)) { // Special case: if the file is in 16-bit (or less) format, // and the calling method wants 16-bit data, go ahead and // read 16-bit data directly. This is a pretty common // case, as most audio files are 16-bit. ODManager::LockLibSndFileMutex(); framesRead = sf_readf_short(sf, (short *)buffer, len); ODManager::UnlockLibSndFileMutex(); for (int i = 0; i < framesRead; i++) ((short *)data)[i] = ((short *)buffer)[(info.channels * i) + mAliasChannel]; } else { // Otherwise, let libsndfile handle the conversion and // scaling, and pass us normalized data as floats. We can // then convert to whatever format we want. ODManager::LockLibSndFileMutex(); framesRead = sf_readf_float(sf, (float *)buffer, len); ODManager::UnlockLibSndFileMutex(); float *bufferPtr = &((float *)buffer)[mAliasChannel]; CopySamples((samplePtr)bufferPtr, floatSample, (samplePtr)data, format, framesRead, true, info.channels); } DeleteSamples(buffer); ODManager::LockLibSndFileMutex(); sf_close(sf); ODManager::UnlockLibSndFileMutex(); mReadDataMutex.Unlock(); return framesRead; }
bool EffectNyquist::ProcessOne() { nyx_rval rval; if (GetEffectFlags() & INSERT_EFFECT) { nyx_set_audio_params(mCurTrack[0]->GetRate(), 0); } else { nyx_set_audio_params(mCurTrack[0]->GetRate(), mCurLen); nyx_set_input_audio(StaticGetCallback, (void *)this, mCurNumChannels, mCurLen, mCurTrack[0]->GetRate()); } wxString cmd; if (mDebug) { cmd += wxT("(setf *tracenable* T)\n"); if (mExternal) { cmd += wxT("(setf *breakenable* T)\n"); } } for (unsigned int j = 0; j < mControls.GetCount(); j++) { if (mControls[j].type == NYQ_CTRL_REAL) { // We use Internat::ToString() rather than "%f" here because we // always have to use the dot as decimal separator when giving // numbers to Nyquist, whereas using "%f" will use the user's // decimal separator which may be a comma in some countries. cmd += wxString::Format(wxT("(setf %s %s)\n"), mControls[j].var.c_str(), Internat::ToString(mControls[j].val).c_str()); } else if (mControls[j].type == NYQ_CTRL_INT || mControls[j].type == NYQ_CTRL_CHOICE) { cmd += wxString::Format(wxT("(setf %s %d)\n"), mControls[j].var.c_str(), (int)(mControls[j].val)); } else if (mControls[j].type == NYQ_CTRL_STRING) { wxString str = mControls[j].valStr; str.Replace(wxT("\\"), wxT("\\\\")); str.Replace(wxT("\""), wxT("\\\"")); cmd += wxT("(setf "); // restrict variable names to 7-bit ASCII: cmd += mControls[j].var.c_str(); cmd += wxT(" \""); cmd += str; // unrestricted value will become quoted UTF-8 cmd += wxT("\")\n"); } } if (mIsSal) { wxString str = mCmd; str.Replace(wxT("\\"), wxT("\\\\")); str.Replace(wxT("\""), wxT("\\\"")); // this is tricky: we need SAL to call main so that we can get a // SAL traceback in the event of an error (sal-compile catches the // error and calls sal-error-output), but SAL does not return values. // We will catch the value in a special global aud:result and if no // error occurs, we will grab the value with a LISP expression str += wxT("\nset aud:result = main()\n"); if (mDebug) { // since we're about to evaluate SAL, remove LISP trace enable and // break enable (which stops SAL processing) and turn on SAL stack // trace cmd += wxT("(setf *tracenable* nil)\n"); cmd += wxT("(setf *breakenable* nil)\n"); cmd += wxT("(setf *sal-traceback* t)\n"); } if (mCompiler) { cmd += wxT("(setf *sal-compiler-debug* t)\n"); } cmd += wxT("(setf *sal-call-stack* nil)\n"); // if we do not set this here and an error occurs in main, another // error will be raised when we try to return the value of aud:result // which is unbound cmd += wxT("(setf aud:result nil)\n"); cmd += wxT("(sal-compile-audacity \"") + str + wxT("\" t t nil)\n"); // Capture the value returned by main (saved in aud:result), but // set aud:result to nil so sound results can be evaluated without // retaining audio in memory cmd += wxT("(prog1 aud:result (setf aud:result nil))\n"); } else { cmd += mCmd; } int i; for (i = 0; i < mCurNumChannels; i++) { mCurBuffer[i] = NULL; } rval = nyx_eval_expression(cmd.mb_str(wxConvUTF8)); if (rval == nyx_string) { wxMessageBox(NyquistToWxString(nyx_get_string()), wxT("Nyquist"), wxOK | wxCENTRE, mParent); return true; } if (rval == nyx_double) { wxString str; str.Printf(_("Nyquist returned the value:") + wxString(wxT(" %f")), nyx_get_double()); wxMessageBox(str, wxT("Nyquist"), wxOK | wxCENTRE, mParent); return true; } if (rval == nyx_int) { wxString str; str.Printf(_("Nyquist returned the value:") + wxString(wxT(" %d")), nyx_get_int()); wxMessageBox(str, wxT("Nyquist"), wxOK | wxCENTRE, mParent); return true; } if (rval == nyx_labels) { unsigned int numLabels = nyx_get_num_labels(); unsigned int l; LabelTrack *ltrack = NULL; TrackListIterator iter(mOutputTracks); for (Track *t = iter.First(); t; t = iter.Next()) { if (t->GetKind() == Track::Label) { ltrack = (LabelTrack *)t; break; } } if (!ltrack) { ltrack = mFactory->NewLabelTrack(); this->AddToOutputTracks((Track *)ltrack); } for (l = 0; l < numLabels; l++) { double t0, t1; const char *str; nyx_get_label(l, &t0, &t1, &str); ltrack->AddLabel(t0 + mT0, t1 + mT0, UTF8CTOWX(str)); } return true; } if (rval != nyx_audio) { wxMessageBox(_("Nyquist did not return audio.\n"), wxT("Nyquist"), wxOK | wxCENTRE, mParent); return false; } int outChannels; outChannels = nyx_get_audio_num_channels(); if (outChannels > mCurNumChannels) { wxMessageBox(_("Nyquist returned too many audio channels.\n"), wxT("Nyquist"), wxOK | wxCENTRE, mParent); return false; } double rate = mCurTrack[0]->GetRate(); for (i = 0; i < outChannels; i++) { sampleFormat format = mCurTrack[i]->GetSampleFormat(); if (outChannels == mCurNumChannels) { rate = mCurTrack[i]->GetRate(); } mOutputTrack[i] = mFactory->NewWaveTrack(format, rate); mCurBuffer[i] = NULL; } int success = nyx_get_audio(StaticPutCallback, (void *)this); if (!success) { for(i = 0; i < outChannels; i++) { delete mOutputTrack[i]; mOutputTrack[i] = NULL; } return false; } for (i = 0; i < outChannels; i++) { mOutputTrack[i]->Flush(); if (mCurBuffer[i]) { DeleteSamples(mCurBuffer[i]); } mOutputTime = mOutputTrack[i]->GetEndTime(); } for (i = 0; i < mCurNumChannels; i++) { WaveTrack *out; if (outChannels == mCurNumChannels) { out = mOutputTrack[i]; } else { out = mOutputTrack[0]; } mCurTrack[i]->ClearAndPaste(mT0, mT1, out, false, false); // If we were first in the group adjust non-selected group tracks if (mFirstInGroup) { SyncLockedTracksIterator git(mOutputTracks); Track *t; for (t = git.First(mCurTrack[i]); t; t = git.Next()) { if (!t->GetSelected() && t->IsSyncLockSelected()) { t->SyncLockAdjust(mT1, mT0 + out->GetEndTime()); } } } // Only the first channel can be first in its group mFirstInGroup = false; } for (i = 0; i < outChannels; i++) { delete mOutputTrack[i]; mOutputTrack[i] = NULL; } return true; }
bool Sequence::Paste(sampleCount s, const Sequence *src) { if (s < 0) s = 0; if (s >= mNumSamples) s = mNumSamples; // Quick check to make sure that it doesn't overflow if (((double)mNumSamples) + ((double)src->mNumSamples) > wxLL(9223372036854775807)) return false; BlockArray *srcBlock = src->mBlock; sampleCount addedLen = src->mNumSamples; unsigned int srcNumBlocks = srcBlock->Count(); int sampleSize = SAMPLE_SIZE(mSampleFormat); if (addedLen == 0 || srcNumBlocks == 0) return true; unsigned int b = FindBlock(s); unsigned int numBlocks = mBlock->Count(); if (numBlocks == 0 || (s == mNumSamples && mBlock->Item(numBlocks-1)->f->GetLength() >= mMinSamples)) { // Special case: this track is currently empty, or it's safe to append // onto the end because the current last block is longer than the // minimum size for (unsigned int i = 0; i < srcNumBlocks; i++) AppendBlock(srcBlock->Item(i)); return ConsistencyCheck(wxT("Paste branch one")); } if (b >= 0 && b < numBlocks && mBlock->Item(b)->f->GetLength() + addedLen < mMaxSamples) { // Special case: we can fit all of the new samples inside of // one block! samplePtr buffer = NewSamples(mMaxSamples, mSampleFormat); int splitPoint = s - mBlock->Item(b)->start; Read(buffer, mSampleFormat, mBlock->Item(b), 0, splitPoint); src->Get(buffer + splitPoint*sampleSize, mSampleFormat, 0, addedLen); Read(buffer + (splitPoint + addedLen)*sampleSize, mSampleFormat, mBlock->Item(b), splitPoint, mBlock->Item(b)->f->GetLength() - splitPoint); SeqBlock *largerBlock = new SeqBlock(); largerBlock->start = mBlock->Item(b)->start; int largerBlockLen = mBlock->Item(b)->f->GetLength() + addedLen; if (largerBlockLen > mMaxSamples) largerBlockLen = mMaxSamples; // Prevent overruns, per NGS report for UmixIt. largerBlock->f = mDirManager->NewSimpleBlockFile(buffer, largerBlockLen, mSampleFormat); mDirManager->Deref(mBlock->Item(b)->f); delete mBlock->Item(b); mBlock->Item(b) = largerBlock; for (unsigned int i = b + 1; i < numBlocks; i++) mBlock->Item(i)->start += addedLen; mNumSamples += addedLen; DeleteSamples(buffer); return ConsistencyCheck(wxT("Paste branch two")); } // Case two: if we are inserting four or fewer blocks, // it's simplest to just lump all the data together // into one big block along with the split block, // then resplit it all unsigned int i; BlockArray *newBlock = new BlockArray(); newBlock->Alloc(numBlocks + srcNumBlocks + 2); int newNumBlocks = 0; for (i = 0; i < b; i++) { newBlock->Add(mBlock->Item(i)); newNumBlocks++; } SeqBlock *splitBlock = mBlock->Item(b); sampleCount splitLen = mBlock->Item(b)->f->GetLength(); int splitPoint = s - splitBlock->start; if (srcNumBlocks <= 4) { sampleCount sum = splitLen + addedLen; samplePtr sumBuffer = NewSamples(sum, mSampleFormat); Read(sumBuffer, mSampleFormat, splitBlock, 0, splitPoint); src->Get(sumBuffer + splitPoint * sampleSize, mSampleFormat, 0, addedLen); Read(sumBuffer + (splitPoint + addedLen) * sampleSize, mSampleFormat, splitBlock, splitPoint, splitBlock->f->GetLength() - splitPoint); BlockArray *split = Blockify(sumBuffer, sum); for (i = 0; i < split->Count(); i++) { split->Item(i)->start += splitBlock->start; newBlock->Add(split->Item(i)); newNumBlocks++; } delete split; DeleteSamples(sumBuffer); } else { // The final case is that we're inserting at least five blocks. // We divide these into three groups: the first two get merged // with the first half of the split block, the middle ones get // copied in as is, and the last two get merged with the last // half of the split block. sampleCount srcFirstTwoLen = srcBlock->Item(0)->f->GetLength() + srcBlock->Item(1)->f->GetLength(); sampleCount leftLen = splitPoint + srcFirstTwoLen; samplePtr leftBuffer = NewSamples(leftLen, mSampleFormat); Read(leftBuffer, mSampleFormat, splitBlock, 0, splitPoint); src->Get(leftBuffer + splitPoint*sampleSize, mSampleFormat, 0, srcFirstTwoLen); BlockArray *split = Blockify(leftBuffer, leftLen); for (i = 0; i < split->Count(); i++) { split->Item(i)->start += splitBlock->start; newBlock->Add(split->Item(i)); newNumBlocks++; } delete split; DeleteSamples(leftBuffer); for (i = 2; i < srcNumBlocks - 2; i++) { SeqBlock *insertBlock = new SeqBlock(); insertBlock->start = srcBlock->Item(i)->start + s; insertBlock->f = mDirManager->CopyBlockFile(srcBlock->Item(i)->f); if (!insertBlock->f) { // TODO error: Could not paste! (Out of disk space?) return false; } newBlock->Add(insertBlock); newNumBlocks++; } sampleCount srcLastTwoLen = srcBlock->Item(srcNumBlocks - 2)->f->GetLength() + srcBlock->Item(srcNumBlocks - 1)->f->GetLength(); sampleCount rightSplit = splitBlock->f->GetLength() - splitPoint; sampleCount rightLen = rightSplit + srcLastTwoLen; samplePtr rightBuffer = NewSamples(rightLen, mSampleFormat); sampleCount lastStart = srcBlock->Item(srcNumBlocks - 2)->start; src->Get(rightBuffer, mSampleFormat, lastStart, srcLastTwoLen); Read(rightBuffer + srcLastTwoLen * sampleSize, mSampleFormat, splitBlock, splitPoint, rightSplit); sampleCount pos = s + lastStart; split = Blockify(rightBuffer, rightLen); for (i = 0; i < split->Count(); i++) { split->Item(i)->start += pos; newBlock->Add(split->Item(i)); newNumBlocks++; } delete split; DeleteSamples(rightBuffer); } mDirManager->Deref(splitBlock->f); delete splitBlock; // Copy remaining blocks to new block array and // swap the new block array in for the old for (i = b + 1; i < numBlocks; i++) { mBlock->Item(i)->start += addedLen; newBlock->Add(mBlock->Item(i)); newNumBlocks++; } delete mBlock; mBlock = newBlock; mNumSamples += addedLen; return ConsistencyCheck(wxT("Paste branch three")); }
void ComputeLegacySummaryInfo(wxFileName fileName, int summaryLen, sampleFormat format, SummaryInfo *info, bool noRMS, float *min, float *max, float *rms) { int fields = 3; /* min, max, rms */ if (noRMS) fields = 2; info->fields = fields; info->format = format; info->bytesPerFrame = SAMPLE_SIZE(info->format) * fields; info->totalSummaryBytes = summaryLen; info->offset64K = 20; /* legacy header tag len */ info->frames64K = (summaryLen-20) / (info->bytesPerFrame * 256); info->offset256 = info->offset64K + (info->frames64K * info->bytesPerFrame); info->frames256 = (summaryLen - 20 - (info->frames64K * info->bytesPerFrame)) / info->bytesPerFrame; // // Compute the min, max, and RMS of the block from the // 64K summary data // float *summary = new float[info->frames64K * fields]; samplePtr data = NewSamples(info->frames64K * fields, info->format); wxFFile summaryFile; if( !summaryFile.Open(fileName.GetFullPath(), "rb") ) { delete[] data; return; } summaryFile.Seek(info->offset64K); int read = summaryFile.Read(data, info->frames64K * info->bytesPerFrame); int count = read / info->bytesPerFrame; CopySamples(data, info->format, (samplePtr)summary, floatSample, count); (*min) = FLT_MAX; (*max) = FLT_MIN; float sumsq = 0; for(int i=0; i<count; i++) { if (summary[fields*i] < (*min)) (*min) = summary[fields*i]; if (summary[fields*i+1] > (*max)) (*max) = summary[fields*i+1]; if (fields >= 3) sumsq += summary[fields*i+2]*summary[fields*i+2]; } if (fields >= 3) (*rms) = sqrt(sumsq / count); else (*rms) = 0; DeleteSamples(data); delete[] summary; }
// Given a project and a list of aliased files that should no // longer be external dependencies (selected by the user), replace // all of those alias block files with disk block files. void RemoveDependencies(AudacityProject *project, AliasedFileArray *aliasedFiles) { DirManager *dirManager = project->GetDirManager(); ProgressDialog *progress = new ProgressDialog(_("Removing Dependencies"), _("Copying audio data into project...")); int updateResult = eProgressSuccess; // Hash aliasedFiles based on their full paths and // count total number of bytes to process. AliasedFileHash aliasedFileHash; wxLongLong totalBytesToProcess = 0; unsigned int i; for (i = 0; i < aliasedFiles->GetCount(); i++) { totalBytesToProcess += aliasedFiles->Item(i).mByteCount; wxString fileNameStr = aliasedFiles->Item(i).mFileName.GetFullPath(); aliasedFileHash[fileNameStr] = &aliasedFiles->Item(i); } BlockArray blocks; GetAllSeqBlocks(project, &blocks); const sampleFormat format = project->GetDefaultFormat(); ReplacedBlockFileHash blockFileHash; wxLongLong completedBytes = 0; for (i = 0; i < blocks.GetCount(); i++) { BlockFile *f = blocks[i]->f; if (f->IsAlias() && (blockFileHash.count(f) == 0)) { // f is an alias block we have not yet processed. AliasBlockFile *aliasBlockFile = (AliasBlockFile *)f; wxFileName fileName = aliasBlockFile->GetAliasedFileName(); wxString fileNameStr = fileName.GetFullPath(); if (aliasedFileHash.count(fileNameStr) == 0) // This aliased file was not selected to be replaced. Skip it. continue; // Convert it from an aliased file to an actual file in the project. unsigned int len = aliasBlockFile->GetLength(); samplePtr buffer = NewSamples(len, format); f->ReadData(buffer, format, 0, len); BlockFile *newBlockFile = dirManager->NewSimpleBlockFile(buffer, len, format); DeleteSamples(buffer); // Update our hash so we know what block files we've done blockFileHash[f] = newBlockFile; // Update the progress bar completedBytes += SAMPLE_SIZE(format) * len; updateResult = progress->Update(completedBytes, totalBytesToProcess); if (updateResult != eProgressSuccess) break; } } // Above, we created a SimpleBlockFile contained in our project // to go with each AliasBlockFile that we wanted to migrate. // However, that didn't actually change any references to these // blockfiles in the Sequences, so we do that next... ReplaceBlockFiles(project, blockFileHash); // Subtract one from reference count of new block files; they're // now all referenced the proper number of times by the Sequences ReplacedBlockFileHash::iterator it; for( it = blockFileHash.begin(); it != blockFileHash.end(); ++it ) { BlockFile *f = it->second; dirManager->Deref(f); } delete progress; }
bool Sequence::Delete(sampleCount start, sampleCount len) { if (len == 0) return true; if (len < 0 || start < 0 || start >= mNumSamples) return false; //TODO: add a ref-deref mechanism to SeqBlock/BlockArray so we don't have to make this a critical section. //On-demand threads iterate over the mBlocks and the GUI thread deletes them, so for now put a mutex here over //both functions, LockDeleteUpdateMutex(); unsigned int numBlocks = mBlock->Count(); unsigned int newNumBlocks = 0; unsigned int b0 = FindBlock(start); unsigned int b1 = FindBlock(start + len - 1); int sampleSize = SAMPLE_SIZE(mSampleFormat); // Special case: if the samples to delete are all within a single // block and the resulting length is not too small, perform the // deletion within this block: if (b0 == b1 && mBlock->Item(b0)->f->GetLength() - len >= mMinSamples) { SeqBlock *b = mBlock->Item(b0); sampleCount pos = start - b->start; sampleCount newLen = b->f->GetLength() - len; samplePtr buffer = NewSamples(newLen, mSampleFormat); Read(buffer, mSampleFormat, b, 0, pos); Read(buffer + (pos * sampleSize), mSampleFormat, b, pos + len, newLen - pos); SeqBlock *newBlock = new SeqBlock(); newBlock->start = b->start; newBlock->f = mDirManager->NewSimpleBlockFile(buffer, newLen, mSampleFormat); mBlock->Item(b0) = newBlock; for (unsigned int j = b0 + 1; j < numBlocks; j++) mBlock->Item(j)->start -= len; DeleteSamples(buffer); mDirManager->Deref(b->f); delete b; mNumSamples -= len; UnlockDeleteUpdateMutex(); return ConsistencyCheck(wxT("Delete - branch one")); } // Create a new array of blocks BlockArray *newBlock = new BlockArray(); newBlock->Alloc(numBlocks - (b1 - b0) + 2); // Copy the blocks before the deletion point over to // the new array unsigned int i; for (i = 0; i < b0; i++) { newBlock->Add(mBlock->Item(i)); newNumBlocks++; } // First grab the samples in block b0 before the deletion point // into preBuffer. If this is enough samples for its own block, // or if this would be the first block in the array, write it out. // Otherwise combine it with the previous block (splitting them // 50/50 if necessary). SeqBlock *preBlock = mBlock->Item(b0); sampleCount preBufferLen = start - preBlock->start; if (preBufferLen) { if (preBufferLen >= mMinSamples || b0 == 0) { SeqBlock *insBlock = new SeqBlock(); insBlock->start = preBlock->start; samplePtr preBuffer = NewSamples(preBufferLen, mSampleFormat); Read(preBuffer, mSampleFormat, preBlock, 0, preBufferLen); insBlock->f = mDirManager->NewSimpleBlockFile(preBuffer, preBufferLen, mSampleFormat); DeleteSamples(preBuffer); newBlock->Add(insBlock); newNumBlocks++; if (b0 != b1) { mDirManager->Deref(preBlock->f); delete preBlock; } } else { SeqBlock *prepreBlock = mBlock->Item(b0 - 1); sampleCount prepreLen = prepreBlock->f->GetLength(); sampleCount sum = prepreLen + preBufferLen; samplePtr sumBuffer = NewSamples(sum, mSampleFormat); Read(sumBuffer, mSampleFormat, prepreBlock, 0, prepreLen); Read(sumBuffer + prepreLen*sampleSize, mSampleFormat, preBlock, 0, preBufferLen); BlockArray *split = Blockify(sumBuffer, sum); split->Item(0)->start += prepreBlock->start; newBlock->Item(b0 - 1) = split->Item(0); for (i = 1; i < split->Count(); i++) { split->Item(i)->start += prepreBlock->start; newBlock->Add(split->Item(i)); newNumBlocks++; } delete split; DeleteSamples(sumBuffer); mDirManager->Deref(prepreBlock->f); delete prepreBlock; if (b0 != b1) { mDirManager->Deref(preBlock->f); delete preBlock; } } } else { // The sample where we begin deletion happens to fall // right on the beginning of a block. if (b0 != b1) { mDirManager->Deref(mBlock->Item(b0)->f); delete mBlock->Item(b0); } } // Next, delete blocks strictly between b0 and b1 for (i = b0 + 1; i < b1; i++) { mDirManager->Deref(mBlock->Item(i)->f); delete mBlock->Item(i); } // Now, symmetrically, grab the samples in block b1 after the // deletion point into postBuffer. If this is enough samples // for its own block, or if this would be the last block in // the array, write it out. Otherwise combine it with the // subsequent block (splitting them 50/50 if necessary). SeqBlock *postBlock = mBlock->Item(b1); sampleCount postBufferLen = (postBlock->start + postBlock->f->GetLength()) - (start + len); if (postBufferLen) { if (postBufferLen >= mMinSamples || b1 == numBlocks - 1) { SeqBlock *insBlock = new SeqBlock(); insBlock->start = start; samplePtr postBuffer = NewSamples(postBufferLen, mSampleFormat); sampleCount pos = (start + len) - postBlock->start; Read(postBuffer, mSampleFormat, postBlock, pos, postBufferLen); insBlock->f = mDirManager->NewSimpleBlockFile(postBuffer, postBufferLen, mSampleFormat); DeleteSamples(postBuffer); newBlock->Add(insBlock); newNumBlocks++; mDirManager->Deref(postBlock->f); delete postBlock; } else { SeqBlock *postpostBlock = mBlock->Item(b1 + 1); sampleCount postpostLen = postpostBlock->f->GetLength(); sampleCount sum = postpostLen + postBufferLen; samplePtr sumBuffer = NewSamples(sum, mSampleFormat); sampleCount pos = (start + len) - postBlock->start; Read(sumBuffer, mSampleFormat, postBlock, pos, postBufferLen); Read(sumBuffer + (postBufferLen * sampleSize), mSampleFormat, postpostBlock, 0, postpostLen); BlockArray *split = Blockify(sumBuffer, sum); for (i = 0; i < split->Count(); i++) { split->Item(i)->start += start; newBlock->Add(split->Item(i)); newNumBlocks++; } delete split; b1++; DeleteSamples(sumBuffer); mDirManager->Deref(postpostBlock->f); delete postpostBlock; mDirManager->Deref(postBlock->f); delete postBlock; } } else { // The sample where we begin deletion happens to fall // right on the end of a block. mDirManager->Deref(mBlock->Item(b1)->f); delete mBlock->Item(b1); } // Copy the remaining blocks over from the old array for (i = b1 + 1; i < numBlocks; i++) { mBlock->Item(i)->start -= len; newBlock->Add(mBlock->Item(i)); newNumBlocks++; } // Substitute our new array for the old one delete mBlock; mBlock = newBlock; // Update total number of samples and do a consistency check. mNumSamples -= len; UnlockDeleteUpdateMutex(); return ConsistencyCheck(wxT("Delete - branch two")); }
bool Sequence::Append(samplePtr buffer, sampleFormat format, sampleCount len, XMLWriter* blockFileLog /*=NULL*/) { // Quick check to make sure that it doesn't overflow if (((double)mNumSamples) + ((double)len) > wxLL(9223372036854775807)) return false; samplePtr temp = NULL; if (format != mSampleFormat) { temp = NewSamples(mMaxSamples, mSampleFormat); wxASSERT(temp); } // If the last block is not full, we need to add samples to it int numBlocks = mBlock->Count(); if (numBlocks > 0 && mBlock->Item(numBlocks - 1)->f->GetLength() < mMinSamples) { SeqBlock *lastBlock = mBlock->Item(numBlocks - 1); sampleCount addLen; if (lastBlock->f->GetLength() + len < mMaxSamples) addLen = len; else addLen = GetIdealBlockSize() - lastBlock->f->GetLength(); SeqBlock *newLastBlock = new SeqBlock(); samplePtr buffer2 = NewSamples((lastBlock->f->GetLength() + addLen), mSampleFormat); Read(buffer2, mSampleFormat, lastBlock, 0, lastBlock->f->GetLength()); CopySamples(buffer, format, buffer2 + lastBlock->f->GetLength() * SAMPLE_SIZE(mSampleFormat), mSampleFormat, addLen); newLastBlock->start = lastBlock->start; int newLastBlockLen = lastBlock->f->GetLength() + addLen; newLastBlock->f = mDirManager->NewSimpleBlockFile(buffer2, newLastBlockLen, mSampleFormat, blockFileLog != NULL); if (blockFileLog) ((SimpleBlockFile*)newLastBlock->f)->SaveXML(*blockFileLog); DeleteSamples(buffer2); mDirManager->Deref(lastBlock->f); delete lastBlock; mBlock->Item(numBlocks - 1) = newLastBlock; len -= addLen; mNumSamples += addLen; buffer += addLen * SAMPLE_SIZE(format); } // Append the rest as new blocks while (len) { sampleCount idealSamples = GetIdealBlockSize(); sampleCount l = (len > idealSamples ? idealSamples : len); SeqBlock *w = new SeqBlock(); w->start = mNumSamples; if (format == mSampleFormat) { w->f = mDirManager->NewSimpleBlockFile(buffer, l, mSampleFormat, blockFileLog != NULL); } else { CopySamples(buffer, format, temp, mSampleFormat, l); w->f = mDirManager->NewSimpleBlockFile(temp, l, mSampleFormat, blockFileLog != NULL); } if (blockFileLog) ((SimpleBlockFile*)w->f)->SaveXML(*blockFileLog); mBlock->Add(w); buffer += l * SAMPLE_SIZE(format); mNumSamples += l; len -= l; } if (format != mSampleFormat) DeleteSamples(temp); // JKC: During generate we use Append again and again. // If generating a long sequence this test would give O(n^2) // performance - not good! #ifdef VERY_SLOW_CHECKING ConsistencyCheck(wxT("Append")); #endif 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 BlockFile::ReadData(void *data, sampleFormat format, sampleCount start, sampleCount len) { int i; if (mType == BLOCK_TYPE_ALIAS) { SF_INFO info; SNDFILE *sf = sf_open(mAliasFullPath, SFM_READ, &info); if (!sf) return 0; sf_seek(sf, mStart + start, SEEK_SET); samplePtr buffer = NewSamples(len * info.channels, floatSample); int framesRead = 0; switch(format) { case int16Sample: framesRead = sf_readf_short(sf, (short *)buffer, len); for (i = 0; i < framesRead; i++) ((short *)data)[i] = ((short *)buffer)[(info.channels * i) + mChannel]; break; case floatSample: framesRead = sf_readf_float(sf, (float *)buffer, len); for (i = 0; i < framesRead; i++) ((float *)data)[i] = ((float *)buffer)[(info.channels * i) + mChannel]; break; default: framesRead = sf_readf_float(sf, (float *)buffer, len); for (i = 0; i < framesRead; i++) ((float *)buffer)[i] = ((float *)buffer)[(info.channels * i) + mChannel]; CopySamples((samplePtr)buffer, floatSample, (samplePtr)data, format, framesRead); } DeleteSamples(buffer); sf_close(sf); return framesRead; } else { wxFFile file; int read; if (!file.Open((const wxChar *) mFullPath, "rb")) return 0; file.Seek(mSummaryLen + start * SAMPLE_SIZE(mSampleFormat), wxFromStart); if (format == mSampleFormat) { int bytes = len * SAMPLE_SIZE(mSampleFormat); read = (int)file.Read(data, (size_t)bytes); read /= SAMPLE_SIZE(mSampleFormat); } else { samplePtr buffer = NewSamples(len, mSampleFormat); int srcBytes = len * SAMPLE_SIZE(mSampleFormat); read = (int)file.Read(buffer, (size_t)srcBytes); read /= SAMPLE_SIZE(mSampleFormat); CopySamples(buffer, mSampleFormat, (samplePtr)data, format, read); DeleteSamples(buffer); } file.Close(); return read; } }
bool Sequence::Append(samplePtr buffer, sampleFormat format, sampleCount len) { samplePtr temp = NULL; if (format != mSampleFormat) { temp = NewSamples(mMaxSamples, mSampleFormat); wxASSERT(temp); } // If the last block is not full, we need to add samples to it int numBlocks = mBlock->Count(); if (numBlocks > 0 && mBlock->Item(numBlocks - 1)->len < mMinSamples) { SeqBlock *lastBlock = mBlock->Item(numBlocks - 1); sampleCount addLen; if (lastBlock->len + len < mMaxSamples) addLen = len; else addLen = GetIdealBlockSize() - lastBlock->len; SeqBlock *newLastBlock = NewInitedSeqBlock(); samplePtr buffer2 = NewSamples((lastBlock->len + addLen), mSampleFormat); Read(buffer2, mSampleFormat, lastBlock, 0, lastBlock->len); if (format == mSampleFormat) memcpy(buffer2 + lastBlock->len * SAMPLE_SIZE(format), buffer, addLen * SAMPLE_SIZE(format)); else { CopySamples(buffer, format, temp, mSampleFormat, addLen); memcpy(buffer2 + lastBlock->len * SAMPLE_SIZE(format), temp, addLen * SAMPLE_SIZE(format)); } newLastBlock->start = lastBlock->start; newLastBlock->len = lastBlock->len + addLen; FirstWrite(buffer2, newLastBlock, lastBlock->len + addLen); DeleteSamples(buffer2); mDirManager->Deref(lastBlock->f); delete lastBlock; mBlock->Item(numBlocks - 1) = newLastBlock; len -= addLen; mNumSamples += addLen; buffer += addLen * SAMPLE_SIZE(format); } // Append the rest as new blocks while (len) { sampleCount idealSamples = GetIdealBlockSize(); sampleCount l = (len > idealSamples ? idealSamples : len); SeqBlock *w = new SeqBlock(); w->f = mDirManager->NewBlockFile(mSummary->totalSummaryBytes); w->start = mNumSamples; w->len = l; if (format == mSampleFormat) FirstWrite(buffer, w, l); else { CopySamples(buffer, format, temp, mSampleFormat, l); FirstWrite(temp, w, l); } mBlock->Add(w); buffer += l * SAMPLE_SIZE(format); mNumSamples += l; len -= l; } if (format != mSampleFormat) DeleteSamples(temp); ConsistencyCheck("Append"); return true; }
bool ImportPCM(wxWindow * parent, wxString fName, WaveTrack ** channels[], int *numChannels, DirManager * dirManager) { SF_INFO info; SNDFILE *fp; sampleFormat format; fp = sf_open_read(OSFILENAME(fName), &info); if (!fp) { char str[1000]; sf_error_str((SNDFILE *)NULL, str, 1000); wxMessageBox(LAT1CTOWX(str)); return false; } wxString progressStr; wxString formatName = sf_header_name(info.format & SF_FORMAT_TYPEMASK); progressStr.Printf(_("Importing %s File..."), formatName.c_str()); *numChannels = info.channels; *channels = new WaveTrack*[*numChannels]; if (info.pcmbitwidth > 16) format = floatSample; else format = int16Sample; int c; for(c=0; c<*numChannels; c++) { (*channels)[c] = new WaveTrack(dirManager, format, info.samplerate); (*channels)[c]->SetName(TrackNameFromFileName(fName)); (*channels)[c]->SetChannel(Track::MonoChannel); } if (*numChannels == 2) { (*channels)[0]->SetChannel(Track::LeftChannel); (*channels)[1]->SetChannel(Track::RightChannel); (*channels)[0]->SetLinked(true); (*channels)[1]->SetTeamed(true); } sampleCount fileTotalFrames = (sampleCount)info.frames; sampleCount maxBlockSize = (*channels)[0]->GetMaxBlockSize(); wxString copyEdit = gPrefs->Read(wxT("/FileFormats/CopyOrEditUncompressedData"), wxT("edit")); // Fall back to "edit" if it doesn't match anything else bool doEdit = true; if (copyEdit.IsSameAs(wxT("copy"), false)) doEdit = false; if (doEdit) { wxLogDebug(wxT("Importing PCM...ImportPCM \n")); // If this mode has been selected, we form the tracks as // aliases to the files we're editing, i.e. ("foo.wav", 12000-18000) // instead of actually making fresh copies of the samples. bool cancelling = false; GetActiveProject()->ProgressShow(_("Import"), progressStr); for (sampleCount i = 0; i < fileTotalFrames; i += maxBlockSize) { sampleCount blockLen = maxBlockSize; if (i + blockLen > fileTotalFrames) blockLen = fileTotalFrames - i; for(c=0; c<*numChannels; c++) (*channels)[c]->AppendAlias(fName, i, blockLen, c); cancelling = !GetActiveProject()->ProgressUpdate((int)((i*1000.0)/fileTotalFrames)); if (cancelling) i = fileTotalFrames; } GetActiveProject()->ProgressHide(); //printf(_("Time elapsed: %d\n"), wxGetElapsedTime()); if (cancelling) { for(c=0; c<*numChannels; c++) delete (*channels)[c]; delete[] (*channels); *channels = NULL; return false; } return true; } // Otherwise, we're in the "copy" mode, where we read in the actual // samples from the file and store our own local copy of the // samples in the tracks. samplePtr srcbuffer = NewSamples(maxBlockSize * (*numChannels), format); samplePtr buffer = NewSamples(maxBlockSize, format); sampleCount framescompleted = 0; bool cancelling = false; GetActiveProject->ProgressShow(_("Import"), progressStr); long block; do { block = maxBlockSize; if (format == int16Sample) block = sf_readf_short(fp, (short *)srcbuffer, block); else block = sf_readf_float(fp, (float *)srcbuffer, block); if (block) { for(c=0; c<(*numChannels); c++) { if (format==int16Sample) { if (info.pcmbitwidth == 8) { for(int j=0; j<block; j++) ((short *)buffer)[j] = ((short *)srcbuffer)[(*numChannels)*j+c] << 8; } else { for(int j=0; j<block; j++) ((short *)buffer)[j] = ((short *)srcbuffer)[(*numChannels)*j+c]; } } else for(int j=0; j<block; j++) ((float *)buffer)[j] = ((float *)srcbuffer)[(*numChannels)*j+c]; (*channels)[c]->Append(buffer, format, block); } framescompleted += block; } int progressvalue = (framescompleted > fileTotalFrames) ? fileTotalFrames : framescompleted; cancelling = !GetActiveProject()->ProgressUpdate((int)((progressvalue*1000.0)/fileTotalFrames)); if (cancelling) block = 0; } while (block > 0); GetActiveProject()->ProgressHide(); sf_close(fp); //printf("Time elapsed: %d\n", wxGetElapsedTime()); DeleteSamples(srcbuffer); DeleteSamples(buffer); if (cancelling) { for(c=0; c<*numChannels; c++) delete (*channels)[c]; delete[] (*channels); *channels = NULL; return false; } return true; }