Example #1
0
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;
}
Example #2
0
Mixer::~Mixer()
{
   for (int c = 0; c < mNumBuffers; c++)
      DeleteSamples(mBuffer[c]);
   delete[]mBuffer;
   DeleteSamples(mTemp);
   delete[]mEnvValues;
}
Example #3
0
// 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");
}
Example #4
0
/// 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);
}
Example #5
0
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));
}
Example #6
0
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;
}
Example #7
0
/// 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);
}
Example #8
0
WaveTrack::~WaveTrack()
{
   if (mAppendBuffer)
      DeleteSamples(mAppendBuffer);
   delete mSequence;
   delete mEnvelope;
   delete mWaveCache;
   delete mSpecCache;
}
Example #9
0
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();
}
Example #11
0
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;
}
Example #12
0
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");
}
Example #13
0
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;
}
Example #15
0
/// 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;
}
Example #16
0
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();
}
Example #18
0
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;
}
Example #19
0
/// 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;
}
Example #21
0
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;
}
Example #22
0
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"));
}
Example #23
0
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;   
}
Example #24
0
// 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;
}
Example #25
0
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"));
}
Example #26
0
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;
}
Example #27
0
// 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"));
}
Example #28
0
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;
   }
}
Example #29
0
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;
}
Example #30
0
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;
}