Beispiel #1
0
bool EffectNoise::Process()
{
   if (noiseDuration <= 0.0)
      noiseDuration = sDefaultGenerateLen;

   //Iterate over each track
   TrackListIterator iter(mWaveTracks);
   WaveTrack *track = (WaveTrack *)iter.First();
   while (track) {
      WaveTrack *tmp = mFactory->NewWaveTrack(track->GetSampleFormat(), track->GetRate());
      numSamples = (longSampleCount)(noiseDuration * track->GetRate() + 0.5);
      longSampleCount i = 0;
      float *data = new float[tmp->GetMaxBlockSize()];
      sampleCount block;

      while(i < numSamples) {
         block = tmp->GetBestBlockSize(i);
         if (block > (numSamples - i))
             block = numSamples - i;

         MakeNoise(data, block, track->GetRate(), noiseAmplitude);

         tmp->Append((samplePtr)data, floatSample, block);
         i += block;
      }
      delete[] data;

      tmp->Flush();
      track->Clear(mT0, mT1);
      track->Paste(mT0, tmp);
      delete tmp;

      //Iterate to the next track
      track = (WaveTrack *)iter.Next();
   }

   /*
      save last used values
      save duration unless value was got from selection, so we save only
      when user explicitely setup a value
   */
   if (mT1 == mT0)
      gPrefs->Write(wxT("/CsPresets/NoiseGen_Duration"), noiseDuration);

   gPrefs->Write(wxT("/CsPresets/NoiseGen_Type"), noiseType);
   gPrefs->Write(wxT("/CsPresets/NoiseGen_Amp"), noiseAmplitude);

   mT1 = mT0 + noiseDuration; // Update selection.

   return true;
}
Beispiel #2
0
bool EffectToneGen::Process()
{
   if (length <= 0.0)
      length = sDefaultGenerateLen;

   //Iterate over each track
   TrackListIterator iter(mWaveTracks);
   WaveTrack *track = (WaveTrack *)iter.First();
   while (track) {
      mSample = 0;
      WaveTrack *tmp = mFactory->NewWaveTrack(track->GetSampleFormat());
      mCurRate = track->GetRate();
      tmp->SetRate(mCurRate);
      longSampleCount numSamples =
         (longSampleCount)(length * mCurRate + 0.5);
      longSampleCount i = 0;
      float *data = new float[tmp->GetMaxBlockSize()];
      sampleCount block;

      while(i < numSamples) {
         block = tmp->GetBestBlockSize(i);
         if (block > (numSamples - i))
             block = numSamples - i;
         MakeTone(data, block);
         tmp->Append((samplePtr)data, floatSample, block);
         i += block;
      }
      delete[] data;

      tmp->Flush();
      track->Clear(mT0, mT1);
      track->Paste(mT0, tmp);
      delete tmp;
      
      //Iterate to the next track
      track = (WaveTrack *)iter.Next();
   }

	mT1 = mT0 + length; // Update selection.

   return true;
}
// ProcessOne() takes a track, transforms it to bunch of buffer-blocks,
// and calls libsamplerate code on these blocks.
bool EffectChangeSpeed::ProcessOne(WaveTrack * track,
                           sampleCount start, sampleCount end)
{
   if (track == NULL)
      return false;

   // initialization, per examples of Mixer::Mixer and
   // EffectSoundTouch::ProcessOne

   WaveTrack * outputTrack = mFactory->NewWaveTrack(track->GetSampleFormat(),
                                                    track->GetRate());

   //Get the length of the selection (as double). len is
   //used simple to calculate a progress meter, so it is easier
   //to make it a double now than it is to do it later 
   double len = (double)(end - start);

   // Initiate processing buffers, most likely shorter than 
   // the length of the selection being processed.
   sampleCount inBufferSize = track->GetMaxBlockSize();

   float * inBuffer = new float[inBufferSize];

   sampleCount outBufferSize = 
      (sampleCount)((mFactor * inBufferSize) + 10);
   float * outBuffer = new float[outBufferSize]; 

   // Set up the resampling stuff for this track.
   Resample resample(true, mFactor, mFactor);

   //Go through the track one buffer at a time. samplePos counts which
   //sample the current buffer starts at.
   bool bResult = true;
   sampleCount blockSize;
   sampleCount samplePos = start;
   while (samplePos < end) {
      //Get a blockSize of samples (smaller than the size of the buffer)
      blockSize = track->GetBestBlockSize(samplePos);

      //Adjust the block size if it is the final block in the track
      if (samplePos + blockSize > end)
         blockSize = end - samplePos;

      //Get the samples from the track and put them in the buffer
      track->Get((samplePtr) inBuffer, floatSample, samplePos, blockSize);

      int inUsed;
      int outgen = resample.Process(mFactor,
                                    inBuffer,
                                    blockSize,
                                    ((samplePos + blockSize) >= end),
                                    &inUsed,
                                    outBuffer,
                                    outBufferSize);
      if (outgen < 0) {
         bResult = false;
         break;
      }

      if (outgen > 0)
         outputTrack->Append((samplePtr)outBuffer, floatSample, 
                             outgen);

      // Increment samplePos
      samplePos += inUsed;

      // Update the Progress meter
      if (TrackProgress(mCurTrackNum, (samplePos - start) / len)) {
         bResult = false;
         break;
      }
   }

   // Flush the output WaveTrack (since it's buffered, too)
   outputTrack->Flush();

   // Clean up the buffers
   delete [] inBuffer;
   delete [] outBuffer;

   // Take the output track and insert it in place of the original
   // sample data
   double newLength = outputTrack->GetEndTime(); 
   if (bResult) 
   {
      SetTimeWarper(new LinearTimeWarper(mCurT0, mCurT0, mCurT1, mCurT0 + newLength));
      bResult = track->ClearAndPaste(mCurT0, mCurT1, outputTrack, true, false, GetTimeWarper());
   }

   if (newLength > mMaxNewLength) 
      mMaxNewLength = newLength; 

   // Delete the outputTrack now that its data is inserted in place
   delete outputTrack;

   return bResult;
}
Beispiel #4
0
bool QuickMix(TrackList *tracks, DirManager *dirManager,
              double rate, sampleFormat format)
{
   WaveTrack **waveArray;
   VTrack *t;
   int numWaves = 0;
   int numLeft = 0;
   int numRight = 0;
   int numMono = 0;
   bool mono = false;
   int w;

   TrackListIterator iter(tracks);

   t = iter.First();
   while (t) {
      if (t->GetSelected() && t->GetKind() == VTrack::Wave) {
         numWaves++;
         switch (t->GetChannel()) {
         case VTrack::MonoChannel:
            numLeft++;
            numRight++;
            numMono++;
            break;
         case VTrack::LeftChannel:
            numLeft++;
            break;
         case VTrack::RightChannel:
            numRight++;
            break;
         }
      }
      t = iter.Next();
   }

   if (numMono == numWaves || numLeft == numWaves || numRight == numWaves)
      mono = true;

   double totalTime = 0.0;

   waveArray = new WaveTrack *[numWaves];
   w = 0;
   t = iter.First();
   while (t) {
      if (t->GetSelected() && t->GetKind() == VTrack::Wave) {
         waveArray[w++] = (WaveTrack *) t;
         if (t->GetMaxLen() > totalTime)
            totalTime = t->GetMaxLen();
      }
      t = iter.Next();
   }

   WaveTrack *mixLeft = new WaveTrack(dirManager);
   mixLeft->SetSampleFormat(format);
   mixLeft->SetRate(rate);
   mixLeft->SetChannel(VTrack::MonoChannel);
   mixLeft->SetName(_("Mix"));
   WaveTrack *mixRight = 0;
   if (!mono) {
      mixRight = new WaveTrack(dirManager);
      mixRight->SetSampleFormat(format);
      mixRight->SetRate(rate);
      mixRight->SetName(_("Mix"));
      mixLeft->SetChannel(VTrack::LeftChannel);
      mixRight->SetChannel(VTrack::RightChannel);
      mixLeft->SetLinked(true);
   }

   int maxBlockLen = mixLeft->GetIdealBlockSize();
   double maxBlockTime = maxBlockLen / mixLeft->GetRate();

   Mixer *mixer = new Mixer(mono ? 1 : 2, maxBlockLen, false,
                            rate, format);

   wxProgressDialog *progress = NULL;
   wxYield();
   wxStartTimer();
   wxBusyCursor busy;

   double tt = 0.0;
   while (tt < totalTime) {

      double blockTime = maxBlockTime;
      if (tt + blockTime > totalTime)
         blockTime = totalTime - tt;
      int blockLen = int (blockTime * mixLeft->GetRate());

      mixer->Clear();

      for (int i = 0; i < numWaves; i++) {
         if (mono)
            mixer->MixMono(waveArray[i], tt, tt + blockTime);
         else {
            switch (waveArray[i]->GetChannel()) {
            case VTrack::LeftChannel:
               mixer->MixLeft(waveArray[i], tt, tt + blockTime);
               break;
            case VTrack::RightChannel:
               mixer->MixRight(waveArray[i], tt, tt + blockTime);
               break;
            case VTrack::MonoChannel:
               mixer->MixMono(waveArray[i], tt, tt + blockTime);
               break;
            }
         }
      }

      if (mono) {
         samplePtr buffer = mixer->GetBuffer();
         mixLeft->Append(buffer, format, blockLen);
      } else {
         samplePtr buffer;
         buffer = mixer->GetBuffer(0);
         mixLeft->Append(buffer, format, blockLen);
         buffer = mixer->GetBuffer(1);
         mixRight->Append(buffer, format, blockLen);
      }

      tt += blockTime;

      if (!progress && wxGetElapsedTime(false) > 500) {
         progress =
             new wxProgressDialog(_("Quick Mix"), _("Mixing tracks"), 1000);
      }
      if (progress) {
         int progressvalue = int (1000 * (tt / totalTime));
         progress->Update(progressvalue);
      }
   }

   tracks->Add(mixLeft);
   if (!mono)
      tracks->Add(mixRight);

   delete progress;

   int elapsedMS = wxGetElapsedTime();
   double elapsedTime = elapsedMS * 0.001;
   double maxTracks = totalTime / (elapsedTime / numWaves);

#ifdef __WXGTK__
   printf(_("      Tracks: %d\n"), numWaves);
   printf(_("  Mix length: %f sec\n"), totalTime);
   printf(_("Elapsed time: %f sec\n"), elapsedTime);
   printf(_("Max number of tracks to mix in real time: %f\n"), maxTracks);
#endif

   delete waveArray;
   delete mixer;

   return true;
}
Beispiel #5
0
bool EffectNoise::Process()
{
   if (noiseDuration <= 0.0)
      noiseDuration = sDefaultGenerateLen;

   //Iterate over each track
   int ntrack = 0;
   this->CopyInputWaveTracks(); // Set up mOutputWaveTracks.
   bool bGoodResult = true;

   TrackListIterator iter(mOutputWaveTracks);
   WaveTrack *track = (WaveTrack *)iter.First();
   while (track) {
      WaveTrack *tmp = mFactory->NewWaveTrack(track->GetSampleFormat(), track->GetRate());
      numSamples = (longSampleCount)(noiseDuration * track->GetRate() + 0.5);
      longSampleCount i = 0;
      float *data = new float[tmp->GetMaxBlockSize()];
      sampleCount block;

      while ((i < numSamples) && bGoodResult) {
         block = tmp->GetBestBlockSize(i);
         if (block > (numSamples - i))
             block = numSamples - i;

         MakeNoise(data, block, track->GetRate(), noiseAmplitude);

         tmp->Append((samplePtr)data, floatSample, block);
         i += block;

         //Update the Progress meter
         if (TrackProgress(ntrack, (double)i / numSamples))
            bGoodResult = false;
      }
      delete[] data;

      tmp->Flush();
      track->Clear(mT0, mT1);
      track->Paste(mT0, tmp);
      delete tmp;

      if (!bGoodResult)
         break;

      //Iterate to the next track
      ntrack++;
      track = (WaveTrack *)iter.Next();
   }

   if (bGoodResult)
   {
      /*
         save last used values
         save duration unless value was got from selection, so we save only
         when user explicitely setup a value
      */
      if (mT1 == mT0)
         gPrefs->Write(wxT("/CsPresets/NoiseGen_Duration"), noiseDuration);

      gPrefs->Write(wxT("/CsPresets/NoiseGen_Type"), noiseType);
      gPrefs->Write(wxT("/CsPresets/NoiseGen_Amp"), noiseAmplitude);

      mT1 = mT0 + noiseDuration; // Update selection.
   }

   this->ReplaceProcessedWaveTracks(bGoodResult); 
   return bGoodResult;
}
Beispiel #6
0
bool MixAndRender(TrackList *tracks, TrackFactory *trackFactory,
                  double rate, sampleFormat format,
                  double startTime, double endTime,
                  WaveTrack **newLeft, WaveTrack **newRight)
{
   // This function was formerly known as "Quick Mix".  It takes one or
   // more tracks as input; of all tracks that are selected, it mixes
   // them together, applying any envelopes, amplitude gain, panning,
   // and real-time effects in the process.  The resulting pair of
   // tracks (stereo) are "rendered" and have no effects, gain, panning,
   // or envelopes.

   WaveTrack **waveArray;
   Track *t;
   int numWaves = 0;
   int numMono = 0;
   bool mono = false;
   int w;

   TrackListIterator iter(tracks);

   t = iter.First();
   while (t) {
      if (t->GetSelected() && t->GetKind() == Track::Wave) {
         numWaves++;
         float pan = ((WaveTrack*)t)->GetPan();
         if (t->GetChannel() == Track::MonoChannel && pan == 0)
            numMono++;
      }
      t = iter.Next();
   }

   if (numMono == numWaves)
      mono = true;

   double totalTime = 0.0;

   waveArray = new WaveTrack *[numWaves];
   w = 0;
   t = iter.First();
   while (t) {
      if (t->GetSelected() && t->GetKind() == Track::Wave) {
         waveArray[w++] = (WaveTrack *) t;
         if (t->GetEndTime() > totalTime)
            totalTime = t->GetEndTime();
      }
      t = iter.Next();
   }

   WaveTrack *mixLeft = trackFactory->NewWaveTrack(format, rate);
   mixLeft->SetName(_("Mix"));
   WaveTrack *mixRight = 0;
   if (mono) {
      mixLeft->SetChannel(Track::MonoChannel);
   }
   else {
      mixRight = trackFactory->NewWaveTrack(format, rate);
      mixRight->SetName(_("Mix"));
      mixLeft->SetChannel(Track::LeftChannel);
      mixRight->SetChannel(Track::RightChannel);
      mixLeft->SetLinked(true);
      mixRight->SetTeamed(true);
   }

   int maxBlockLen = mixLeft->GetIdealBlockSize();

   if (startTime == endTime) {
      startTime = 0.0;
      endTime = totalTime;
   }

   Mixer *mixer = new Mixer(numWaves, waveArray, tracks->GetTimeTrack(),
                            startTime, endTime, mono ? 1 : 2, maxBlockLen, false,
                            rate, format);

   wxYield();
   GetActiveProject()->ProgressShow(_NoAcc("&Mix and Render"),
                                    _("Mixing and rendering tracks"));
   wxBusyCursor busy;
   
   bool cancelling = false;
   while(!cancelling) {
      sampleCount blockLen = mixer->Process(maxBlockLen);

      if (blockLen == 0)
         break;

      if (mono) {
         samplePtr buffer = mixer->GetBuffer();
         mixLeft->Append(buffer, format, blockLen);
      }
      else {
         samplePtr buffer;
         buffer = mixer->GetBuffer(0);
         mixLeft->Append(buffer, format, blockLen);
         buffer = mixer->GetBuffer(1);
         mixRight->Append(buffer, format, blockLen);
      }

      int progressvalue = int (1000 * (mixer->MixGetCurrentTime() / totalTime));
      cancelling = !GetActiveProject()->ProgressUpdate(progressvalue);
   }

   GetActiveProject()->ProgressHide();

   mixLeft->Flush();
   *newLeft = mixLeft;
   if (!mono) {
      mixRight->Flush();
      *newRight = mixRight;
   }

#if 0
   int elapsedMS = wxGetElapsedTime();
   double elapsedTime = elapsedMS * 0.001;
   double maxTracks = totalTime / (elapsedTime / numWaves);

   // Note: these shouldn't be translated - they're for debugging
   // and profiling only.
   printf("      Tracks: %d\n", numWaves);
   printf("  Mix length: %f sec\n", totalTime);
   printf("Elapsed time: %f sec\n", elapsedTime);
   printf("Max number of tracks to mix in real time: %f\n", maxTracks);
#endif

   delete[] waveArray;
   delete mixer;

   return true;
}
//ProcessOne() takes a track, transforms it to bunch of buffer-blocks,
//and executes ProcessSoundTouch on these blocks
bool EffectSoundTouch::ProcessOne(WaveTrack *track,
                                  longSampleCount start, longSampleCount end)
{
   WaveTrack *outputTrack;
   longSampleCount s;

   mSoundTouch->setSampleRate((unsigned int)(track->GetRate()+0.5));
   
   outputTrack = mFactory->NewWaveTrack(track->GetSampleFormat());

   //Get the length of the buffer (as double). len is
   //used simple to calculate a progress meter, so it is easier
   //to make it a double now than it is to do it later 
   double len = (double)(end - start);

   //Initiate a processing buffer.  This buffer will (most likely)
   //be shorter than the length of the track being processed.
   float *buffer = new float[track->GetMaxBlockSize()];

   //Go through the track one buffer at a time. s counts which
   //sample the current buffer starts at.
   s = start;
   while (s < end) {
      //Get a block of samples (smaller than the size of the buffer)
      sampleCount block = track->GetBestBlockSize(s);

      //Adjust the block size if it is the final block in the track
      if (s + block > end)
         block = end - s;

      //Get the samples from the track and put them in the buffer
      track->Get((samplePtr) buffer, floatSample, s, block);

      //Add samples to SoundTouch
      mSoundTouch->putSamples(buffer, block);

      //Get back samples from SoundTouch
      unsigned int outputCount = mSoundTouch->numSamples();
      if (outputCount > 0) {
         float *buffer2 = new float[outputCount];
         mSoundTouch->receiveSamples(buffer2, outputCount);
         outputTrack->Append((samplePtr)buffer2, floatSample, outputCount);
         delete[] buffer2;
      }

      //Increment s one blockfull of samples
      s += block;

      //Update the Progress meter
      if (TrackProgress(mCurTrackNum, (s - start) / len))
         return false;
   }

   // Tell SoundTouch to finish processing any remaining samples
   mSoundTouch->flush();

   unsigned int outputCount = mSoundTouch->numSamples();
   if (outputCount > 0) {
      float *buffer2 = new float[outputCount];
      mSoundTouch->receiveSamples(buffer2, outputCount);
      outputTrack->Append((samplePtr)buffer2, floatSample, outputCount);
      delete[] buffer2;
   }

   // Flush the output WaveTrack (since it's buffered, too)
   outputTrack->Flush();

   // Clean up the buffer
   delete[]buffer;

   // Take the output track and insert it in place of the original
   // sample data

   track->Clear(mT0, mT1);
   track->Paste(mT0, outputTrack);

	double newLength = outputTrack->GetEndTime(); 
	if (newLength > m_maxNewLength) 
		m_maxNewLength = newLength; 

   // Delete the outputTrack now that its data is inserted in place
   delete outputTrack;

   //Return true because the effect processing succeeded.
   return true;
}
Beispiel #8
0
bool EffectPaulstretch::ProcessOne(WaveTrack *track,double t0,double t1,int count)
{
   int stretch_buf_size = GetBufferSize(track->GetRate());
   double amount = this->mAmount;

   sampleCount start = track->TimeToLongSamples(t0);
   sampleCount end = track->TimeToLongSamples(t1);
   sampleCount len = (sampleCount)(end - start);

   int minDuration = stretch_buf_size * 2 + 1;
   if (len < minDuration){   //error because the selection is too short

      float maxTimeRes = log(len) / log(2.0);
      maxTimeRes = pow(2.0, floor(maxTimeRes) + 0.5);
      maxTimeRes = maxTimeRes / track->GetRate();

      if (this->IsPreviewing()) {
         double defaultPreviewLen;
         gPrefs->Read(wxT("/AudioIO/EffectsPreviewLen"), &defaultPreviewLen, 6.0);

         /* i18n-hint: 'Time Resolution' is the name of a control in the Paulstretch effect.*/
         if ((minDuration / mProjectRate) < defaultPreviewLen) {
            ::wxMessageBox (wxString::Format(_("Audio selection too short to preview.\n\n"
                                               "Try increasing the audio selection to at least %.1f seconds,\n"
                                               "or reducing the 'Time Resolution' to less than %.1f seconds."),
                                             (minDuration / track->GetRate()) + 0.05, // round up to 1/10 s.
                                             floor(maxTimeRes * 10.0) / 10.0),
                            GetName(), wxOK | wxICON_EXCLAMATION);
         }
         else {
            /* i18n-hint: 'Time Resolution' is the name of a control in the Paulstretch effect.*/
            ::wxMessageBox (wxString::Format(_("Unable to Preview.\n\n"
                                               "For the current audio selection, the maximum\n"
                                               "'Time Resolution' is %.1f seconds."),
                                             floor(maxTimeRes * 10.0) / 10.0),
                            GetName(), wxOK | wxICON_EXCLAMATION);
         }
      }
      else {
         /* i18n-hint: 'Time Resolution' is the name of a control in the Paulstretch effect.*/
         ::wxMessageBox (wxString::Format(_("The 'Time Resolution' is too long for the selection.\n\n"
                                            "Try increasing the audio selection to at least %.1f seconds,\n"
                                            "or reducing the 'Time Resolution' to less than %.1f seconds."),
                                          (minDuration / track->GetRate()) + 0.05, // round up to 1/10 s.
                                          floor(maxTimeRes * 10.0) / 10.0),
                         GetName(), wxOK | wxICON_EXCLAMATION);
      }

      return false;
   }


   double adjust_amount=(double)len/((double)len-((double)stretch_buf_size*2.0));
   amount=1.0+(amount-1.0)*adjust_amount;

   WaveTrack * outputTrack = mFactory->NewWaveTrack(track->GetSampleFormat(),track->GetRate());

   PaulStretch *stretch=new PaulStretch(amount,stretch_buf_size,track->GetRate());

   sampleCount nget=stretch->get_nsamples_for_fill();

   int bufsize=stretch->poolsize;
   float *buffer0=new float[bufsize];
   float *bufferptr0=buffer0;
   sampleCount outs=0;
   bool first_time=true;

   int fade_len=100;
   if (fade_len>(bufsize/2-1)) fade_len=bufsize/2-1;
   float *fade_track_smps=new float[fade_len];
   sampleCount s=0;
   bool cancelled=false;

   while (s<len){
      track->Get((samplePtr)bufferptr0,floatSample,start+s,nget);
      stretch->process(buffer0,nget);

      if (first_time) {
         stretch->process(buffer0,0);
      };

      outs+=stretch->out_bufsize;
      s+=nget;

      if (first_time){//blend the the start of the selection
         track->Get((samplePtr)fade_track_smps,floatSample,start,fade_len);
         first_time=false;
         for (int i=0;i<fade_len;i++){
            float fi=(float)i/(float)fade_len;
            stretch->out_buf[i]=stretch->out_buf[i]*fi+(1.0-fi)*fade_track_smps[i];
         };
      };
      if (s>=len){//blend the end of the selection
         track->Get((samplePtr)fade_track_smps,floatSample,end-fade_len,fade_len);
         for (int i=0;i<fade_len;i++){
            float fi=(float)i/(float)fade_len;
            int i2=bufsize/2-1-i;
            stretch->out_buf[i2]=stretch->out_buf[i2]*fi+(1.0-fi)*fade_track_smps[fade_len-1-i];
         };
      };

      outputTrack->Append((samplePtr)stretch->out_buf,floatSample,stretch->out_bufsize);

      nget=stretch->get_nsamples();
      if (TrackProgress(count, (s / (double) len))) {
         cancelled=true;
         break;
      };
   };

   delete [] fade_track_smps;
   outputTrack->Flush();

   track->Clear(t0,t1);
   bool success = track->Paste(t0,outputTrack);
   if (!cancelled && success){
      m_t1 = mT0 + outputTrack->GetEndTime();
   }

   delete stretch;
   delete []buffer0;

   delete outputTrack;
   return !cancelled;
};
bool EffectPaulstretch::ProcessOne(WaveTrack *track,double t0,double t1,int count){

   int stretch_buf_size;//must be power of 2 (because Audacity's fft requires it)
   if (time_resolution<0.001) time_resolution=0.001f;
   {
      float tmp=track->GetRate()*time_resolution*0.5;
      tmp=log(tmp)/log(2.0);
      tmp=pow(2.0,floor(tmp+0.5));
      stretch_buf_size=(int)tmp;
   };
   if (stretch_buf_size<128) stretch_buf_size=128;
   double amount=this->amount;
   if (amount<1.0) amount=1.0;

   sampleCount start = track->TimeToLongSamples(t0);
   sampleCount end = track->TimeToLongSamples(t1);
   sampleCount len = (sampleCount)(end - start);

   m_t1=mT1;

   if (len<=(stretch_buf_size*2+1)){//error because the selection is too short
      /* i18n-hint: This is an effect error message, for the effect named Paulstretch.
       * Time Resolution is a parameter of the effect, the translation should match
       */
      ::wxMessageBox(_("Error in Paulstretch:\nThe selection is too short.\n It must be much longer than the Time Resolution."));
      return false;
   };


   double adjust_amount=(double)len/((double)len-((double)stretch_buf_size*2.0));
   amount=1.0+(amount-1.0)*adjust_amount;

   WaveTrack * outputTrack = mFactory->NewWaveTrack(track->GetSampleFormat(),track->GetRate());

   PaulStretch *stretch=new PaulStretch(amount,stretch_buf_size,track->GetRate());

   sampleCount nget=stretch->get_nsamples_for_fill();

   int bufsize=stretch->poolsize;
   float *buffer0=new float[bufsize];
   float *bufferptr0=buffer0;
   sampleCount outs=0;
   bool first_time=true;

   int fade_len=100;
   if (fade_len>(bufsize/2-1)) fade_len=bufsize/2-1;
   float *fade_track_smps=new float[fade_len];
   sampleCount s=0;
   bool cancelled=false;

   while (s<len){
      track->Get((samplePtr)bufferptr0,floatSample,start+s,nget);
      stretch->process(buffer0,nget);

      if (first_time) {
         stretch->process(buffer0,0);
      };

      outs+=stretch->out_bufsize;
      s+=nget;

      if (first_time){//blend the the start of the selection
         track->Get((samplePtr)fade_track_smps,floatSample,start,fade_len);
         first_time=false;
         for (int i=0;i<fade_len;i++){
            float fi=(float)i/(float)fade_len;
            stretch->out_buf[i]=stretch->out_buf[i]*fi+(1.0-fi)*fade_track_smps[i];
         };
      };
      if (s>=len){//blend the end of the selection
         track->Get((samplePtr)fade_track_smps,floatSample,end-fade_len,fade_len);
         for (int i=0;i<fade_len;i++){
            float fi=(float)i/(float)fade_len;
            int i2=bufsize/2-1-i;
            stretch->out_buf[i2]=stretch->out_buf[i2]*fi+(1.0-fi)*fade_track_smps[fade_len-1-i];
         };
      };

      outputTrack->Append((samplePtr)stretch->out_buf,floatSample,stretch->out_bufsize);

      nget=stretch->get_nsamples();
      if (TrackProgress(count, (s / (double) len))) {
         cancelled=true;
         break;
      };
   };

   delete [] fade_track_smps; 
   outputTrack->Flush();



   track->Clear(t0,t1);
   track->Paste(t0,outputTrack);
   if (!cancelled){
      double flen=t1-t0;
      if (s>0) m_t1=t0+flen*(double)outs/(double)(s);
   };


   delete stretch;
   delete []buffer0;

   delete outputTrack;
   return !cancelled;
};
Beispiel #10
0
//TODO-MB: wouldn't it make more sense to delete the time track after 'mix and render'?
bool MixAndRender(TrackList *tracks, TrackFactory *trackFactory,
                  double rate, sampleFormat format,
                  double startTime, double endTime,
                  WaveTrack **newLeft, WaveTrack **newRight)
{
   // This function was formerly known as "Quick Mix".
   WaveTrack **waveArray;
   Track *t;
   int numWaves = 0; /* number of wave tracks in the selection */
   int numMono = 0;  /* number of mono, centre-panned wave tracks in selection*/
   bool mono = false;   /* flag if output can be mono without loosing anything*/
   bool oneinput = false;  /* flag set to true if there is only one input track
                              (mono or stereo) */
   int w;

   TrackListIterator iter(tracks);
   SelectedTrackListOfKindIterator usefulIter(Track::Wave, tracks);
   // this only iterates tracks which are relevant to this function, i.e.
   // selected WaveTracks. The tracklist is (confusingly) the list of all
   // tracks in the project

   t = iter.First();
   while (t) {
      if (t->GetSelected() && t->GetKind() == Track::Wave) {
         numWaves++;
         float pan = ((WaveTrack*)t)->GetPan();
         if (t->GetChannel() == Track::MonoChannel && pan == 0)
            numMono++;
      }
      t = iter.Next();
   }

   if (numMono == numWaves)
      mono = true;

   /* the next loop will do two things at once:
    * 1. build an array of all the wave tracks were are trying to process
    * 2. determine when the set of WaveTracks starts and ends, in case we
    *    need to work out for ourselves when to start and stop rendering.
    */

   double mixStartTime = 0.0;    /* start time of first track to start */
   bool gotstart = false;  // flag indicates we have found a start time
   double mixEndTime = 0.0;   /* end time of last track to end */
   double tstart, tend;    // start and end times for one track.

   waveArray = new WaveTrack *[numWaves];
   w = 0;
   t = iter.First();

   while (t) {
      if (t->GetSelected() && t->GetKind() == Track::Wave) {
         waveArray[w++] = (WaveTrack *) t;
         tstart = t->GetStartTime();
         tend = t->GetEndTime();
         if (tend > mixEndTime)
            mixEndTime = tend;
         // try and get the start time. If the track is empty we will get 0,
         // which is ambiguous because it could just mean the track starts at
         // the beginning of the project, as well as empty track. The give-away
         // is that an empty track also ends at zero.

         if (tstart != tend) {
            // we don't get empty tracks here
            if (!gotstart) {
               // no previous start, use this one unconditionally
               mixStartTime = tstart;
               gotstart = true;
            } else if (tstart < mixStartTime)
               mixStartTime = tstart;  // have a start, only make it smaller
         }  // end if start and end are different
      }  // end if track is a selected WaveTrack.
      /** @TODO: could we not use a SelectedTrackListOfKindIterator here? */
      t = iter.Next();
   }

   /* create the destination track (new track) */
   if ((numWaves == 1) || ((numWaves == 2) && (usefulIter.First()->GetLink() != NULL)))
      oneinput = true;
   // only one input track (either 1 mono or one linked stereo pair)

   WaveTrack *mixLeft = trackFactory->NewWaveTrack(format, rate);
   if (oneinput)
      mixLeft->SetName(usefulIter.First()->GetName()); /* set name of output track to be the same as the sole input track */
   else
      mixLeft->SetName(_("Mix"));
   mixLeft->SetOffset(mixStartTime);
   WaveTrack *mixRight = 0;
   if (mono) {
      mixLeft->SetChannel(Track::MonoChannel);
   }
   else {
      mixRight = trackFactory->NewWaveTrack(format, rate);
      if (oneinput) {
         if (usefulIter.First()->GetLink() != NULL)   // we have linked track
            mixLeft->SetName(usefulIter.First()->GetLink()->GetName()); /* set name to match input track's right channel!*/
         else
            mixLeft->SetName(usefulIter.First()->GetName());   /* set name to that of sole input channel */
      }
      else
         mixRight->SetName(_("Mix"));
      mixLeft->SetChannel(Track::LeftChannel);
      mixRight->SetChannel(Track::RightChannel);
      mixRight->SetOffset(mixStartTime);
      mixLeft->SetLinked(true);
   }



   int maxBlockLen = mixLeft->GetIdealBlockSize();

   // If the caller didn't specify a time range, use the whole range in which
   // any input track had clips in it.
   if (startTime == endTime) {
      startTime = mixStartTime;
      endTime = mixEndTime;
   }

   Mixer *mixer = new Mixer(numWaves, waveArray,
                            Mixer::WarpOptions(tracks->GetTimeTrack()),
                            startTime, endTime, mono ? 1 : 2, maxBlockLen, false,
                            rate, format);

   ::wxSafeYield();
   ProgressDialog *progress = new ProgressDialog(_("Mix and Render"),
                                                 _("Mixing and rendering tracks"));

   int updateResult = eProgressSuccess;
   while(updateResult == eProgressSuccess) {
      sampleCount blockLen = mixer->Process(maxBlockLen);

      if (blockLen == 0)
         break;

      if (mono) {
         samplePtr buffer = mixer->GetBuffer();
         mixLeft->Append(buffer, format, blockLen);
      }
      else {
         samplePtr buffer;
         buffer = mixer->GetBuffer(0);
         mixLeft->Append(buffer, format, blockLen);
         buffer = mixer->GetBuffer(1);
         mixRight->Append(buffer, format, blockLen);
      }

      updateResult = progress->Update(mixer->MixGetCurrentTime() - startTime, endTime - startTime);
   }

   delete progress;

   mixLeft->Flush();
   if (!mono)
      mixRight->Flush();
   if (updateResult == eProgressCancelled || updateResult == eProgressFailed)
   {
      delete mixLeft;
      if (!mono)
         delete mixRight;
   } else {
      *newLeft = mixLeft;
      if (!mono)
         *newRight = mixRight;

#if 0
   int elapsedMS = wxGetElapsedTime();
   double elapsedTime = elapsedMS * 0.001;
   double maxTracks = totalTime / (elapsedTime / numWaves);

   // Note: these shouldn't be translated - they're for debugging
   // and profiling only.
   printf("      Tracks: %d\n", numWaves);
   printf("  Mix length: %f sec\n", totalTime);
   printf("Elapsed time: %f sec\n", elapsedTime);
   printf("Max number of tracks to mix in real time: %f\n", maxTracks);
#endif
   }

   delete[] waveArray;
   delete mixer;

   return (updateResult == eProgressSuccess || updateResult == eProgressStopped);
}
Beispiel #11
0
bool EffectDtmf::Process()
{
   if (dtmfDuration <= 0.0)
      return false;

   //Iterate over each track
   TrackListIterator iter(mWaveTracks);
   WaveTrack *track = (WaveTrack *)iter.First();
   while (track) {
      // new tmp track, to fill with dtmf sequence
      // we will build the track by adding a tone, then a silence, next tone, and so on...
      WaveTrack *tmp = mFactory->NewWaveTrack(track->GetSampleFormat(), track->GetRate());

      // all dtmf sequence durations in samples from seconds
      numSamplesSequence = (longSampleCount)(dtmfDuration * track->GetRate() + 0.5);
      numSamplesTone = (longSampleCount)(dtmfTone * track->GetRate() + 0.5);
      numSamplesSilence = (longSampleCount)(dtmfSilence * track->GetRate() + 0.5);

      // recalculate the sum, and spread the difference - due to approximations.
      // Since diff should be in the order of "some" samples, a division (resulting in zero)
      // is not sufficient, so we add the additional remaining samples in each tone/silence block,
      // at least until available.
      int diff = numSamplesSequence - (dtmfNTones*numSamplesTone) - (dtmfNTones-1)*numSamplesSilence;
      if (diff>dtmfNTones) {
         // in this case, both these values would change, so it makes sense to recalculate diff
         // otherwise just keep the value we already have

         // should always be the case that dtmfNTones>1, as if 0, we don't even start processing,
         // and with 1 there is no difference to spread (no silence slot)...
         wxASSERT(dtmfNTones > 1);
         numSamplesTone += (diff/(dtmfNTones));
         numSamplesSilence += (diff/(dtmfNTones-1));
         diff = numSamplesSequence - (dtmfNTones*numSamplesTone) - (dtmfNTones-1)*numSamplesSilence;
      }
      // this var will be used as extra samples distributor
      int extra=0;

      longSampleCount i = 0;
      longSampleCount j = 0;
      int n=0; // pointer to string in dtmfString
      sampleCount block;
      bool isTone = true;
      float *data = new float[tmp->GetMaxBlockSize()];

      // for the whole dtmf sequence, we will be generating either tone or silence
      // according to a bool value, and this might be done in small chunks of size
      // 'block', as a single tone might sometimes be larger than the block
      // tone and silence generally have different duration, thus two generation blocks
      //
      // Note: to overcome a 'clicking' noise introduced by the abrupt transition from/to
      // silence, I added a fade in/out of 1/250th of a second (4ms). This can still be
      // tweaked but gives excellent results at 44.1kHz: I haven't tried other freqs.
      // A problem might be if the tone duration is very short (<10ms)... (?)
      //
      // One more problem is to deal with the approximations done when calculating the duration 
      // of both tone and silence: in some cases the final sum might not be same as the initial
      // duration. So, to overcome this, we had a redistribution block up, and now we will spread
      // the remaining samples in every bin in order to achieve the full duration: test case was
      // to generate an 11 tone DTMF sequence, in 4 seconds, and with DutyCycle=75%: after generation
      // you ended up with 3.999s or in other units: 3 seconds and 44097 samples.
      //
      while(i < numSamplesSequence) {
         if (isTone)
         // generate tone
         {
            // the statement takes care of extracting one sample from the diff bin and
            // adding it into the tone block until depletion
            extra=(diff-- > 0?1:0);
            for(j=0; j < numSamplesTone+extra; j+=block) {
               block = tmp->GetBestBlockSize(j);
               if (block > (numSamplesTone+extra - j))
                   block = numSamplesTone+extra - j;

               // generate the tone and append
               MakeDtmfTone(data, block, track->GetRate(), dtmfString[n], j, numSamplesTone);
               tmp->Append((samplePtr)data, floatSample, block);
            }
            i += numSamplesTone;
            n++;
            if(n>=dtmfNTones)break;
         }
         else
         // generate silence
         {
            // the statement takes care of extracting one sample from the diff bin and
            // adding it into the silence block until depletion
            extra=(diff-- > 0?1:0);
            for(j=0; j < numSamplesSilence+extra; j+=block) {
               block = tmp->GetBestBlockSize(j);
               if (block > (numSamplesSilence+extra - j))
                   block = numSamplesSilence+extra - j;

               // generate silence and append
               memset(data, 0, sizeof(float)*block);
               tmp->Append((samplePtr)data, floatSample, block);
            }
            i += numSamplesSilence;
         }
         // flip flag
         isTone=!isTone;
      } // finished the whole dtmf sequence

      delete[] data;

      tmp->Flush();
      track->Clear(mT0, mT1);
      track->Paste(mT0, tmp);
      delete tmp;

      //Iterate to the next track
      track = (WaveTrack *)iter.Next();
   }

   /*
      save last used values
      save duration unless value was got from selection, so we save only
      when user explicitely setup a value
   */
   if (mT1 == mT0)
      gPrefs->Write(wxT("/CsPresets/DtmfGen_SequenceDuration"), dtmfDuration);

   gPrefs->Write(wxT("/CsPresets/DtmfGen_String"), dtmfString);
   gPrefs->Write(wxT("/CsPresets/DtmfGen_DutyCycle"), dtmfDutyCycle);

   // Update selection: this is not accurate if my calculations are wrong.
   // To validate, once the effect is done, unselect, and select all, then
   // see what the selection length is being reported (in sec,ms,samples)
   mT1 = mT0 + dtmfDuration;

   return true;
}