コード例 #1
0
void FreqWindow::GetAudio()
{
   int selcount = 0;
   int i;
   bool warning = false;
   //wxLogDebug(wxT("Entering FreqWindow::GetAudio()"));
   TrackListIterator iter(p->GetTracks());
   Track *t = iter.First();
   while (t) {
      if (t->GetSelected() && t->GetKind() == Track::Wave) {
         WaveTrack *track = (WaveTrack *)t;
         if (selcount==0) {
            mRate = track->GetRate();
            sampleCount start, end;
            start = track->TimeToLongSamples(p->mViewInfo.sel0);
            end = track->TimeToLongSamples(p->mViewInfo.sel1);
            mDataLen = (sampleCount)(end - start);
            if (mDataLen > 10485760) {
               warning = true;
               mDataLen = 10485760;
            }
            if (mBuffer) {
               delete [] mBuffer;
            }
            mBuffer = new float[mDataLen];
            track->Get((samplePtr)mBuffer, floatSample, start, mDataLen);
         }
         else {
            if (track->GetRate() != mRate) {
               wxMessageBox(_("To plot the spectrum, all selected tracks must be the same sample rate."));
               delete[] mBuffer;
               mBuffer = NULL;
               return;
            }
            sampleCount start;
            start = track->TimeToLongSamples(p->mViewInfo.sel0);
            float *buffer2 = new float[mDataLen];
            track->Get((samplePtr)buffer2, floatSample, start, mDataLen);
            for(i=0; i<mDataLen; i++)
               mBuffer[i] += buffer2[i];
            delete[] buffer2;
         }
         selcount++;
      }
      t = iter.Next();
   }
   
   if (selcount == 0)
      return;

   if (warning) {
      wxString msg;
      msg.Printf(_("Too much audio was selected.  Only the first %.1f seconds of audio will be analyzed."),
                          (mDataLen / mRate));
      //wxLogDebug(wxT("About to show length warning message"));
      wxMessageBox(msg);
      //wxLogDebug(wxT("Length warning message done"));
   }
   //wxLogDebug(wxT("Leaving FreqWindow::GetAudio()"));
}
コード例 #2
0
ファイル: ClickRemoval.cpp プロジェクト: Kirushanr/audacity
bool EffectClickRemoval::Process()
{
   this->CopyInputTracks(); // Set up mOutputTracks.
   bool bGoodResult = true;

   SelectedTrackListOfKindIterator iter(Track::Wave, mOutputTracks);
   WaveTrack *track = (WaveTrack *) iter.First();
   int count = 0;
   while (track) {
      double trackStart = track->GetStartTime();
      double trackEnd = track->GetEndTime();
      double t0 = mT0 < trackStart? trackStart: mT0;
      double t1 = mT1 > trackEnd? trackEnd: mT1;

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

         if (!ProcessOne(count, track, start, len))
         {
            bGoodResult = false;
            break;
         }
      }

      track = (WaveTrack *) iter.Next();
      count++;
   }
   this->ReplaceProcessedTracks(bGoodResult); 
   return bGoodResult;
}
コード例 #3
0
ファイル: Equalization.cpp プロジェクト: ruthmagnus/audacity
bool EffectEqualization::Process()
{
   TrackListIterator iter(mWaveTracks);
   WaveTrack *track = (WaveTrack *) iter.First();
   int count = 0;
   while (track) {
      double trackStart = track->GetStartTime();
      double trackEnd = track->GetEndTime();
      double t0 = mT0 < trackStart? trackStart: mT0;
      double t1 = mT1 > trackEnd? trackEnd: mT1;

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

         if (!ProcessOne(count, track, start, len))
            return false;
      }

      track = (WaveTrack *) iter.Next();
      count++;
   }

   return true;
}
コード例 #4
0
void FreqWindow::GetAudio()
{
   mData.reset();
   mDataLen = 0;

   int selcount = 0;
   bool warning = false;
   TrackListIterator iter(p->GetTracks());
   Track *t = iter.First();
   while (t) {
      if (t->GetSelected() && t->GetKind() == Track::Wave) {
         WaveTrack *track = (WaveTrack *)t;
         if (selcount==0) {
            mRate = track->GetRate();
            auto start = track->TimeToLongSamples(p->mViewInfo.selectedRegion.t0());
            auto end = track->TimeToLongSamples(p->mViewInfo.selectedRegion.t1());
            auto dataLen = end - start;
            if (dataLen > 10485760) {
               warning = true;
               mDataLen = 10485760;
            }
            else
               // dataLen is not more than 10 * 2 ^ 20
               mDataLen = dataLen.as_size_t();
            mData = Floats{ mDataLen };
            // Don't allow throw for bad reads
            track->Get((samplePtr)mData.get(), floatSample, start, mDataLen,
                       fillZero, false);
         }
         else {
            if (track->GetRate() != mRate) {
               AudacityMessageBox(_("To plot the spectrum, all selected tracks must be the same sample rate."));
               mData.reset();
               mDataLen = 0;
               return;
            }
            auto start = track->TimeToLongSamples(p->mViewInfo.selectedRegion.t0());
            Floats buffer2{ mDataLen };
            // Again, stop exceptions
            track->Get((samplePtr)buffer2.get(), floatSample, start, mDataLen,
                       fillZero, false);
            for (size_t i = 0; i < mDataLen; i++)
               mData[i] += buffer2[i];
         }
         selcount++;
      }
      t = iter.Next();
   }

   if (selcount == 0)
      return;

   if (warning) {
      wxString msg;
      msg.Printf(_("Too much audio was selected.  Only the first %.1f seconds of audio will be analyzed."),
                          (mDataLen / mRate));
      AudacityMessageBox(msg);
   }
}
コード例 #5
0
ファイル: Repeat.cpp プロジェクト: ruthmagnus/audacity
bool EffectRepeat::Process()
{
   this->CopyInputWaveTracks(); // Set up mOutputWaveTracks.
   bool bGoodResult = true;

   TrackListIterator iter(mOutputWaveTracks);
   WaveTrack *track = (WaveTrack *) iter.First();
   int nTrack = 0;
	double maxDestLen = 0.0; // used to change selection to generated bit
   while ((track != NULL) && bGoodResult) {
      double trackStart = track->GetStartTime();
      double trackEnd = track->GetEndTime();
      double t0 = mT0 < trackStart? trackStart: mT0;
      double t1 = mT1 > trackEnd? trackEnd: mT1;

      if (t1 <= t0)
         continue;

      sampleCount start = track->TimeToLongSamples(t0);
      sampleCount end = track->TimeToLongSamples(t1);
      sampleCount len = (sampleCount)(end - start);
      double tLen = track->LongSamplesToTime(len);
      double tc = t0 + tLen;

      if (len <= 0)
         continue;

      Track *dest;
      track->Copy(t0, t1, &dest);
      for(int j=0; j<repeatCount; j++)
      {
         if (!track->Paste(tc, dest) || 
               TrackProgress(nTrack, j / repeatCount)) // TrackProgress returns true on Cancel.
         {
            bGoodResult = false;
            break;
         }
         tc += tLen;
      }
      if (tc > maxDestLen)
         maxDestLen = tc;
      delete dest;

      track = (WaveTrack *) iter.Next();
      nTrack++;
   }

   if (bGoodResult)
   {
      // Change selection to just the generated bits.
      mT0 = mT1;
	   mT1 = maxDestLen;
   }

   this->ReplaceProcessedWaveTracks(bGoodResult); 
   return bGoodResult;
}
コード例 #6
0
bool EffectNoiseRemoval::Process()
{
   if (!mDoProfile && !mHasProfile)
      CleanSpeechMayReadNoisegate();
   
   // If we still don't have a profile we have a problem.
   // This should only happen in CleanSpeech.
   if(!mDoProfile && !mHasProfile) {
      wxMessageBox(
        _("Attempt to run Noise Removal without a noise profile.\n"));
      return false;
   }

   Initialize();

   // This same code will both remove noise and profile it,
   // depending on 'mDoProfile'
   this->CopyInputWaveTracks(); // Set up mOutputWaveTracks.
   bool bGoodResult = true;

   TrackListIterator iter(mOutputWaveTracks);
   WaveTrack *track = (WaveTrack *) iter.First();
   int count = 0;
   while (track) {
      double trackStart = track->GetStartTime();
      double trackEnd = track->GetEndTime();
      double t0 = mT0 < trackStart? trackStart: mT0;
      double t1 = mT1 > trackEnd? trackEnd: mT1;

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

         if (!ProcessOne(count, track, start, len)) {
            Cleanup();
            bGoodResult = false;
            break;
         }
      }
      track = (WaveTrack *) iter.Next();
      count++;
   }

   if (bGoodResult && mDoProfile) {
      CleanSpeechMayWriteNoiseGate();
      mHasProfile = true;
      mDoProfile = false;
   }

   if (bGoodResult)
      Cleanup();
   this->ReplaceProcessedWaveTracks(bGoodResult); 
   return bGoodResult;
}
コード例 #7
0
ファイル: FindClipping.cpp プロジェクト: PhilSee/audacity
bool EffectFindClipping::Process()
{
   LabelTrack *l = NULL;
   Track *original = NULL;

   TrackListOfKindIterator iter(Track::Label, mTracks);
   for (Track *t = iter.First(); t; t = iter.Next()) {
      if (t->GetName() == wxT("Clipping")) {
         l = (LabelTrack *) t;
         // copy LabelTrack here, so it can be undone on cancel
         l->Copy(l->GetStartTime(), l->GetEndTime(), &original);
         original->SetOffset(l->GetStartTime());
         original->SetName(wxT("Clipping"));
         break;
      }
   }

   if (!l) {
      l = mFactory->NewLabelTrack();
      l->SetName(_("Clipping"));
      mTracks->Add((Track *) l);
   }

   int count = 0;

   // JC: Only process selected tracks.
   SelectedTrackListOfKindIterator waves(Track::Wave, mTracks);
   WaveTrack *t = (WaveTrack *) waves.First();
   while (t) {
      double trackStart = t->GetStartTime();
      double trackEnd = t->GetEndTime();
      double t0 = mT0 < trackStart ? trackStart : mT0;
      double t1 = mT1 > trackEnd ? trackEnd : mT1;

      if (t1 > t0) {
         sampleCount start = t->TimeToLongSamples(t0);
         sampleCount end = t->TimeToLongSamples(t1);
         sampleCount len = (sampleCount)(end - start);

         if (!ProcessOne(l, count, t, start, len)) {
            //put it back how it was
            mTracks->Remove((Track *) l);
            if(original) {
               mTracks->Add((Track *) original);
            }
            return false;
         }
      }

      count++;
      t = (WaveTrack *) waves.Next();
   }

   return true;
}
コード例 #8
0
bool EffectSoundTouch::Process()
{
   // Assumes that mSoundTouch has already been initialized
   // by the subclass for subclass-specific parameters.

   //Iterate over each track
   TrackListIterator iter(mWaveTracks);
   WaveTrack* leftTrack = (WaveTrack*)(iter.First());
   WaveTrack* rightTrack = NULL;
   mCurTrackNum = 0;
	m_maxNewLength = 0.0;
   while (leftTrack) {
      //Get start and end times from track
      double trackStart = leftTrack->GetStartTime();
      double trackEnd = leftTrack->GetEndTime();

      //Set the current bounds to whichever left marker is
      //greater and whichever right marker is less:
      mCurT0 = mT0 < trackStart? trackStart: mT0;
      mCurT1 = mT1 > trackEnd? trackEnd: mT1;

      // Process only if the right marker is to the right of the left marker
      if (mCurT1 > mCurT0) {

         //Transform the marker timepoints to samples
         longSampleCount start = leftTrack->TimeToLongSamples(mCurT0);
         longSampleCount end = leftTrack->TimeToLongSamples(mCurT1);
         
         rightTrack = NULL; 
         if (leftTrack->GetLinked()) {
            rightTrack = (WaveTrack*)(iter.Next());
            mSoundTouch->setChannels(2);
            if (!ProcessStereo(leftTrack, rightTrack, start, end))
               return false;
            mCurTrackNum++; // Increment for rightTrack, too.
         } else {
            mSoundTouch->setChannels(1);
            //ProcessOne() (implemented below) processes a single track
            if (!ProcessOne(leftTrack, start, end))
               return false;
         }
      }
      
      //Iterate to the next track
      leftTrack = (WaveTrack*)(iter.Next());
      mCurTrackNum++;
   }

   delete mSoundTouch;
   mSoundTouch = NULL;

	mT1 = mT0 + m_maxNewLength; // Update selection.
   return true;
}
コード例 #9
0
ファイル: PopClick.cpp プロジェクト: AaronFae/VimProject
bool EffectPopClickRemoval::Process()
{
   TrackListIterator iter(mWaveTracks);
   WaveTrack *track = (WaveTrack *) iter.First();
   int count = 0;
   while (track) {
      double trackStart = track->GetStartTime();
      double trackEnd = track->GetEndTime();
      double t0 = mT0 < trackStart? trackStart: mT0;
      double t1 = mT1 > trackEnd? trackEnd: mT1;
      double deltat = t1 - t0;
      double tpre;
      double pretime;
      double rate = track->GetRate();
      int max_matrix_size = 1500;

      pretime = 3*deltat;
      if (pretime * rate > max_matrix_size)
         pretime = max_matrix_size / rate;
      tpre = t0 - pretime;
      tpre = tpre < trackStart? trackStart: tpre;
      tpre = tpre > t0? t0: tpre;

      if (t1 - t0 > 1) {
         ::wxMessageBox(_("Cannot remove a pop or click longer than "
                          "one second."));
      }
      else if (t1 > t0) {
         if ((t0 - tpre) * rate < 20)
            ::wxMessageBox(_("Cannot remove a pop or click at the very "
                             "beginning of a track."));
         else {
            longSampleCount pre = track->TimeToLongSamples(tpre);
            longSampleCount start = track->TimeToLongSamples(t0);
            longSampleCount end = track->TimeToLongSamples(t1);
            sampleCount preLen = (sampleCount)(start - pre);
            sampleCount postLen = (sampleCount)(end - start);
            
            if (!ProcessOne(count, track, pre, preLen, postLen))
               return false;
         }
      }

      track = (WaveTrack *) iter.Next();
      count++;
   }

   return true;
}
コード例 #10
0
ファイル: ChangeSpeed.cpp プロジェクト: ruthmagnus/audacity
bool EffectChangeSpeed::Process()
{
	// Similar to EffectSoundTouch::Process()

   //Iterate over each track
   this->CopyInputWaveTracks(); // Set up m_pOutputWaveTracks.
   bool bGoodResult = true;

   TrackListIterator iter(m_pOutputWaveTracks);
   WaveTrack* pOutWaveTrack = (WaveTrack*)(iter.First());
   mCurTrackNum = 0;
	m_maxNewLength = 0.0;
   while (pOutWaveTrack != NULL)
   {
      //Get start and end times from track
      mCurT0 = pOutWaveTrack->GetStartTime();
      mCurT1 = pOutWaveTrack->GetEndTime();

      //Set the current bounds to whichever left marker is
      //greater and whichever right marker is less:
      mCurT0 = wxMax(mT0, mCurT0);
      mCurT1 = wxMin(mT1, mCurT1);

      // Process only if the right marker is to the right of the left marker
      if (mCurT1 > mCurT0) {

         //Transform the marker timepoints to samples
         longSampleCount start = pOutWaveTrack->TimeToLongSamples(mCurT0);
         longSampleCount end = pOutWaveTrack->TimeToLongSamples(mCurT1);

         //ProcessOne() (implemented below) processes a single track
         if (!ProcessOne(pOutWaveTrack, start, end))
         {
            bGoodResult = false;
            break;
         }
      }
      
      //Iterate to the next track
      pOutWaveTrack = (WaveTrack*)(iter.Next());
      mCurTrackNum++;
   }

   this->ReplaceProcessedWaveTracks(bGoodResult); 

// mT1 = mT0 + m_maxNewLength; // Update selection.

   return bGoodResult;
}
コード例 #11
0
bool EffectTwoPassSimpleMono::ProcessPass()
{
   //Iterate over each track
   SelectedTrackListOfKindIterator iter(Track::Wave, mOutputTracks);
   WaveTrack *track = (WaveTrack *) iter.First();
   mCurTrackNum = 0;
   while (track) {
      //Get start and end times from track
      double trackStart = track->GetStartTime();
      double trackEnd = track->GetEndTime();

      //Set the current bounds to whichever left marker is
      //greater and whichever right marker is less:
      mCurT0 = mT0 < trackStart? trackStart: mT0;
      mCurT1 = mT1 > trackEnd? trackEnd: mT1;

      // Process only if the right marker is to the right of the left marker
      if (mCurT1 > mCurT0) {

         //Transform the marker timepoints to samples
         sampleCount start = track->TimeToLongSamples(mCurT0);
         sampleCount end = track->TimeToLongSamples(mCurT1);
         
         //Get the track rate and samples
         mCurRate = track->GetRate();
         mCurChannel = track->GetChannel();

         //NewTrackPass1/2() returns true by default
         bool ret;
         if (mPass == 0)
            ret = NewTrackPass1();
         else
            ret = NewTrackPass2();
         if (!ret)
            return false;

         //ProcessOne() (implemented below) processes a single track
         if (!ProcessOne(track, start, end))
            return false;
      }
      
      //Iterate to the next track
      track = (WaveTrack *) iter.Next();
      mCurTrackNum++;
   }

   return true;
}
コード例 #12
0
ファイル: SimpleMono.cpp プロジェクト: ruthmagnus/audacity
bool EffectSimpleMono::Process()
{
   //Iterate over each track
   this->CopyInputWaveTracks(); // Set up mOutputWaveTracks.
   bool bGoodResult = true;

   TrackListIterator iter(mOutputWaveTracks);
   WaveTrack* pOutWaveTrack = (WaveTrack*)(iter.First());
   mCurTrackNum = 0;
   while (pOutWaveTrack != NULL)
   {
      //Get start and end times from track
      double trackStart = pOutWaveTrack->GetStartTime();
      double trackEnd = pOutWaveTrack->GetEndTime();

      //Set the current bounds to whichever left marker is
      //greater and whichever right marker is less:
      mCurT0 = mT0 < trackStart? trackStart: mT0;
      mCurT1 = mT1 > trackEnd? trackEnd: mT1;

      // Process only if the right marker is to the right of the left marker
      if (mCurT1 > mCurT0) {

         //Transform the marker timepoints to samples
         longSampleCount start = pOutWaveTrack->TimeToLongSamples(mCurT0);
         longSampleCount end = pOutWaveTrack->TimeToLongSamples(mCurT1);
         
         //Get the track rate and samples
         mCurRate = pOutWaveTrack->GetRate();
         mCurChannel = pOutWaveTrack->GetChannel();

         //NewTrackSimpleMono() will returns true by default
         //ProcessOne() processes a single track
         if (!NewTrackSimpleMono() || !ProcessOne(pOutWaveTrack, start, end))
         {
            bGoodResult = false;
            break;
         }
      }
      
      //Iterate to the next track
      pOutWaveTrack = (WaveTrack*)(iter.Next());
      mCurTrackNum++;
   }

   this->ReplaceProcessedWaveTracks(bGoodResult); 
   return bGoodResult;
}
コード例 #13
0
bool BlockGenerator::GenerateTrack(WaveTrack *tmp,
                                   const WaveTrack &track,
                                   int ntrack)
{
   bool bGoodResult = true;
   numSamples = track.TimeToLongSamples(GetDuration());
   sampleCount i = 0;
   float *data = new float[tmp->GetMaxBlockSize()];
   sampleCount block = 0;

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

      GenerateBlock(data, track, block);

      // Add the generated data to the temporary track
      tmp->Append((samplePtr)data, floatSample, block);
      i += block;

      // Update the progress meter
      if (TrackProgress(ntrack, (double)i / numSamples))
         bGoodResult = false;
   }
   delete[] data;
   return bGoodResult;
}
コード例 #14
0
bool EffectSoundTouch::Process()
{
   //Assumes that mSoundTouch has already been initialized
   //by the subclass

   //Iterate over each track
   TrackListIterator iter(mWaveTracks);
   WaveTrack *track = (WaveTrack *) iter.First();
   mCurTrackNum = 0;
	m_maxNewLength = 0.0;
   while (track) {
      //Get start and end times from track
      double trackStart = track->GetStartTime();
      double trackEnd = track->GetEndTime();

      //Set the current bounds to whichever left marker is
      //greater and whichever right marker is less:
      mCurT0 = mT0 < trackStart? trackStart: mT0;
      mCurT1 = mT1 > trackEnd? trackEnd: mT1;

      // Process only if the right marker is to the right of the left marker
      if (mCurT1 > mCurT0) {

         //Transform the marker timepoints to samples
         longSampleCount start = track->TimeToLongSamples(mCurT0);
         longSampleCount end = track->TimeToLongSamples(mCurT1);
         
         //Get the track rate and samples
         mCurRate = track->GetRate();
         mCurChannel = track->GetChannel();

         //ProcessOne() (implemented below) processes a single track
         if (!ProcessOne(track, start, end))
            return false;
      }
      
      //Iterate to the next track
      track = (WaveTrack *) iter.Next();
      mCurTrackNum++;
   }

   delete mSoundTouch;
   mSoundTouch = NULL;

	mT1 = mT0 + m_maxNewLength; // Update selection.
   return true;
}
コード例 #15
0
ファイル: ChangePitch.cpp プロジェクト: MindFy/audacity
// Deduce m_FromFrequency from the samples at the beginning of
// the selection. Then set some other params accordingly.
void EffectChangePitch::DeduceFrequencies()
{
   // As a neat trick, attempt to get the frequency of the note at the
   // beginning of the selection.
   SelectedTrackListOfKindIterator iter(Track::Wave, inputTracks());
   WaveTrack *track = (WaveTrack *) iter.First();
   if (track) {
      double rate = track->GetRate();

      // Auto-size window -- high sample rates require larger windowSize.
      // Aim for around 2048 samples at 44.1 kHz (good down to about 100 Hz).
      // To detect single notes, analysis period should be about 0.2 seconds.
      // windowSize must be a power of 2.
      const size_t windowSize =
         // windowSize < 256 too inaccurate
         std::max(256, wxRound(pow(2.0, floor((log(rate / 20.0)/log(2.0)) + 0.5))));

      // we want about 0.2 seconds to catch the first note.
      // number of windows rounded to nearest integer >= 1.
      const unsigned numWindows =
         std::max(1, wxRound((double)(rate / (5.0f * windowSize))));

      double trackStart = track->GetStartTime();
      double t0 = mT0 < trackStart? trackStart: mT0;
      auto start = track->TimeToLongSamples(t0);

      auto analyzeSize = windowSize * numWindows;
      Floats buffer{ analyzeSize };

      Floats freq{ windowSize / 2 };
      Floats freqa{ windowSize / 2, true };

      track->Get((samplePtr) buffer.get(), floatSample, start, analyzeSize);
      for(unsigned i = 0; i < numWindows; i++) {
         ComputeSpectrum(buffer.get() + i * windowSize, windowSize,
                         windowSize, rate, freq.get(), true);
         for(size_t j = 0; j < windowSize / 2; j++)
            freqa[j] += freq[j];
      }
      size_t argmax = 0;
      for(size_t j = 1; j < windowSize / 2; j++)
         if (freqa[j] > freqa[argmax])
            argmax = j;

      auto lag = (windowSize / 2 - 1) - argmax;
      m_dStartFrequency = rate / lag;
   }

   double dFromMIDInote = FreqToMIDInote(m_dStartFrequency);
   double dToMIDInote = dFromMIDInote + m_dSemitonesChange;
   m_nFromPitch = PitchIndex(dFromMIDInote);
   m_nFromOctave = PitchOctave(dFromMIDInote);
   m_nToPitch = PitchIndex(dToMIDInote);
   m_nToOctave = PitchOctave(dToMIDInote);

   m_FromFrequency = m_dStartFrequency;
   Calc_PercentChange();
   Calc_ToFrequency();
}
コード例 #16
0
ファイル: NoiseRemoval.cpp プロジェクト: ruthmagnus/audacity
bool EffectNoiseRemoval::Process()
{
   if (doProfile) {
      for(int i=0; i<windowSize; i++) {
         sum[i] = float(0.0);
         sumsq[i] = float(0.0);
         profileCount[i] = 0;
      }
   }

   TrackListIterator iter(mWaveTracks);
   WaveTrack *track = (WaveTrack *) iter.First();
   int count = 0;
   while (track) {
      double trackStart = track->GetStartTime();
      double trackEnd = track->GetEndTime();
      double t0 = mT0 < trackStart? trackStart: mT0;
      double t1 = mT1 > trackEnd? trackEnd: mT1;

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

         if (!ProcessOne(count, track, start, len))
            return false;
      }

      track = (WaveTrack *) iter.Next();
      count++;
   }

   if (doProfile) {
      for(int i=0; i<=windowSize/2; i++) {
         //float stddev = sqrt(sumsq[i] - (sum[i]*sum[i])/profileCount[i])
         //                               / profileCount[i];
         noiseGate[i] = sum[i] / profileCount[i]; // average
      }
      
      hasProfile = true;
   }

   return true;
}
コード例 #17
0
ファイル: NoiseRemoval.cpp プロジェクト: GYGit/Audacity
bool EffectNoiseRemoval::Process()
{
   Initialize();

   // This same code will both remove noise and profile it,
   // depending on 'mDoProfile'
   this->CopyInputTracks(); // Set up mOutputTracks.
   bool bGoodResult = true;

   SelectedTrackListOfKindIterator iter(Track::Wave, mOutputTracks);
   WaveTrack *track = (WaveTrack *) iter.First();
   int count = 0;
   while (track) {
      double trackStart = track->GetStartTime();
      double trackEnd = track->GetEndTime();
      double t0 = mT0 < trackStart? trackStart: mT0;
      double t1 = mT1 > trackEnd? trackEnd: mT1;

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

         if (!ProcessOne(count, track, start, len)) {
            Cleanup();
            bGoodResult = false;
            break;
         }
      }
      track = (WaveTrack *) iter.Next();
      count++;
   }

   if (bGoodResult && mDoProfile) {
      mHasProfile = true;
      mDoProfile = false;
   }

   if (bGoodResult)
      Cleanup();
   this->ReplaceProcessedTracks(bGoodResult);
   return bGoodResult;
}
コード例 #18
0
ファイル: ChangeSpeed.cpp プロジェクト: andreipaga/audacity
bool EffectChangeSpeed::Process()
{
	// Similar to EffectSoundTouch::Process()

   //Iterate over each track
   TrackListIterator iter(mWaveTracks);
   WaveTrack *track = (WaveTrack *) iter.First();
   mCurTrackNum = 0;
	m_maxNewLength = 0.0;
	double curT0;
	double curT1;
   while (track) {
      //Get start and end times from track
      double trackStart = track->GetStartTime();
      double trackEnd = track->GetEndTime();

      //Set the current bounds to whichever left marker is
      //greater and whichever right marker is less:
      curT0 = mT0 < trackStart? trackStart: mT0;
      curT1 = mT1 > trackEnd? trackEnd: mT1;

      // Process only if the right marker is to the right of the left marker
      if (curT1 > curT0) {

         //Transform the marker timepoints to samples
         longSampleCount start = track->TimeToLongSamples(curT0);
         longSampleCount end = track->TimeToLongSamples(curT1);

         //ProcessOne() (implemented below) processes a single track
         if (!ProcessOne(track, start, end))
            return false;
      }
      
      //Iterate to the next track
      track = (WaveTrack *) iter.Next();
      mCurTrackNum++;
   }

	mT1 = mT0 + m_maxNewLength; // Update selection.
   return true;
}
コード例 #19
0
bool EffectReverse::Process()
{
   //Track::All is needed because Reverse should move the labels too
   this->CopyInputTracks(Track::All); // Set up mOutputTracks.
   bool bGoodResult = true;

   TrackListIterator iter(mOutputTracks);
   Track *t = iter.First();
   int count = 0;
   while (t) {
      if (t->GetKind() == Track::Wave &&
            (t->GetSelected() || t->IsSyncLockSelected()))
      {
         WaveTrack *track = (WaveTrack*)t;

         if (mT1 > mT0) {
            sampleCount start = track->TimeToLongSamples(mT0);
            sampleCount end = track->TimeToLongSamples(mT1);
            sampleCount len = (sampleCount)(end - start);

            if (!ProcessOneWave(count, track, start, len))
            {
               bGoodResult = false;
               break;
            }
         }
      }
      else if (t->GetKind() == Track::Label &&
            (t->GetSelected() || t->IsSyncLockSelected()))
      {
         LabelTrack *track = (LabelTrack*)t;
         track->ChangeLabelsOnReverse(mT0, mT1);
      }
      t = iter.Next();
      count++;
   }

   this->ReplaceProcessedTracks(bGoodResult); 
   return bGoodResult;
}
コード例 #20
0
ファイル: ChangePitch.cpp プロジェクト: ruthmagnus/audacity
// DeduceFrequencies is Dominic's extremely cool trick (Vaughan sez so!) 
// to set deduce m_FromFrequency from the samples at the beginning of 
// the selection. Then we set some other params accordingly.
void EffectChangePitch::DeduceFrequencies()
{
   // As a neat trick, attempt to get the frequency of the note at the
   // beginning of the selection.
   SelectedTrackListOfKindIterator iter(Track::Wave, mTracks);
   WaveTrack *track = (WaveTrack *) iter.First();
   if (track) {
      const int windowSize = 1024;
      const int analyzeSize = 8192;
      const int numWindows = analyzeSize / windowSize;
      double trackStart = track->GetStartTime();
      double t0 = mT0 < trackStart? trackStart: mT0;
      sampleCount start = track->TimeToLongSamples(t0);
      double rate = track->GetRate();
      float buffer[analyzeSize];
      float freq[windowSize/2];
      float freqa[windowSize/2];
      int i, j, argmax;
      int lag;

      for(j=0; j<windowSize/2; j++)
         freqa[j] = 0;

      track->Get((samplePtr) buffer, floatSample, start, analyzeSize);
      for(i=0; i<numWindows; i++) {
         ComputeSpectrum(buffer+i*windowSize, windowSize,
                         windowSize, rate, freq, true);
         for(j=0; j<windowSize/2; j++)
            freqa[j] += freq[j];
      }
      argmax=0;
      for(j=1; j<windowSize/2; j++)
         if (freqa[j] > freqa[argmax])
            argmax = j;
      lag = (windowSize/2 - 1) - argmax;
      m_FromFrequency = rate / lag;
      m_ToFrequency = (m_FromFrequency * (100.0 + m_PercentChange)) / 100.0;

      // Now we can set the pitch control values. 
      m_FromPitchIndex = PitchIndex(FreqToMIDInoteNumber(m_FromFrequency));
      m_bWantPitchDown = (m_ToFrequency < m_FromFrequency);
      m_ToPitchIndex = PitchIndex(FreqToMIDInoteNumber(m_ToFrequency));
   }
}
コード例 #21
0
ファイル: Repair.cpp プロジェクト: GYGit/Audacity
bool EffectRepair::Process()
{
   //v This may be too much copying for EffectRepair. To support Cancel, may be able to copy much less.
   //  But for now, Cancel isn't supported without this.
   this->CopyInputTracks(); // Set up mOutputTracks. //v This may be too much copying for EffectRepair.
   bool bGoodResult = true;

   SelectedTrackListOfKindIterator iter(Track::Wave, mOutputTracks);
   WaveTrack *track = (WaveTrack *) iter.First();
   int count = 0;
   while (track) {
      double trackStart = track->GetStartTime();
      double trackEnd = track->GetEndTime();
      double repair_t0 = mT0;
      double repair_t1 = mT1;
      repair_t0 = (repair_t0 < trackStart? trackStart: repair_t0);
      repair_t1 = (repair_t1 > trackEnd? trackEnd: repair_t1);
      if (repair_t0 < repair_t1) {  // selection is within track audio
         double rate = track->GetRate();
         double repair_deltat = repair_t1 - repair_t0;

         double spacing = repair_deltat * 2;

         if (spacing < 128. / rate)
            spacing = 128. / rate;

         double t0 = repair_t0 - spacing;
         double t1 = repair_t1 + spacing;

         t0 = t0 < trackStart? trackStart: t0;
         t1 = t1 > trackEnd? trackEnd: t1;

         repair_t0 = (repair_t0 < t0? t0: repair_t0);
         repair_t1 = (repair_t1 > t1? t1: repair_t1);

         sampleCount s0 = track->TimeToLongSamples(t0);
         sampleCount repair0 = track->TimeToLongSamples(repair_t0);
         sampleCount repair1 = track->TimeToLongSamples(repair_t1);
         sampleCount s1 = track->TimeToLongSamples(t1);

         sampleCount repairStart = (sampleCount)(repair0 - s0);
         sampleCount repairLen = (sampleCount)(repair1 - repair0);
         sampleCount len = (sampleCount)(s1 - s0);

         if (repairLen > 128) {
            ::wxMessageBox(_("The Repair effect is intended to be used on very short sections of damaged audio (up to 128 samples).\n\nZoom in and select a tiny fraction of a second to repair."));
            bGoodResult = false;
            break;
         }

         if (s0 == repair0 && s1 == repair1) {
            ::wxMessageBox(_("Repair works by using audio data outside the selection region.\n\nPlease select a region that has audio touching at least one side of it.\n\nThe more surrounding audio, the better it performs."));
   ///            The Repair effect needs some data to go on.\n\nPlease select an area to repair with some audio on at least one side (the more the better)."));
            bGoodResult = false;
            break;
         }

         if (!ProcessOne(count, track,
                         s0, len, repairStart, repairLen)) {
            bGoodResult = false;
            break;
         }
      }

      track = (WaveTrack *) iter.Next();
      count++;
   }

   this->ReplaceProcessedTracks(bGoodResult);
   return bGoodResult;
}
コード例 #22
0
bool EffectChangeSpeed::Process()
{
   // Similar to EffectSoundTouch::Process()

   // Iterate over each track.
   // Track::All is needed because this effect needs to introduce 
   // silence in the sync-lock group tracks to keep sync
   this->CopyInputTracks(Track::All); // Set up mOutputTracks.
   bool bGoodResult = true;

   TrackListIterator iter(mOutputTracks);
   Track* t;
   mCurTrackNum = 0;
   mMaxNewLength = 0.0;

   mFactor = 100.0 / (100.0 + mPercentChange);

   t = iter.First();
   while (t != NULL)
   {
      if (t->GetKind() == Track::Label) {
         if (t->GetSelected() || t->IsSyncLockSelected())
         {
            if (!ProcessLabelTrack(t)) {
               bGoodResult = false;
               break;
            }
         }
      }
      else if (t->GetKind() == Track::Wave && t->GetSelected())
      {
         WaveTrack *pOutWaveTrack = (WaveTrack*)t;
         //Get start and end times from track
         mCurT0 = pOutWaveTrack->GetStartTime();
         mCurT1 = pOutWaveTrack->GetEndTime();

         //Set the current bounds to whichever left marker is
         //greater and whichever right marker is less:
         mCurT0 = wxMax(mT0, mCurT0);
         mCurT1 = wxMin(mT1, mCurT1);

         // Process only if the right marker is to the right of the left marker
         if (mCurT1 > mCurT0) {
            //Transform the marker timepoints to samples
            sampleCount start = pOutWaveTrack->TimeToLongSamples(mCurT0);
            sampleCount end = pOutWaveTrack->TimeToLongSamples(mCurT1);

            //ProcessOne() (implemented below) processes a single track
            if (!ProcessOne(pOutWaveTrack, start, end))
            {
               bGoodResult = false;
               break;
            }
         }
         mCurTrackNum++;
      }
      else if (t->IsSyncLockSelected())
      {
         t->SyncLockAdjust(mT1, mT0 + (mT1 - mT0) * mFactor);
      }

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

   if (bGoodResult)
      ReplaceProcessedTracks(bGoodResult);

   mT1 = mT0 + mMaxNewLength; // Update selection.

   return bGoodResult;
}
コード例 #23
0
ファイル: NoiseRemoval.cpp プロジェクト: andreipaga/audacity
bool EffectNoiseRemoval::Process()
{
	// If we are creating a profile, we don't care whether we have
	// one already.  We just prepare the counters.
   if (mDoProfile) {
      for(int i=0; i<windowSize; i++) {
         sum[i] = float(0.0);
         sumsq[i] = float(0.0);
         profileCount[i] = 0;
      }
   }
	else
	{
		// We need a profile.
      if( !mHasProfile )
      {
         CleanSpeechMayReadNoisegate();
      }
   
	   // If we still don't have a profile we have a problem.
      if( !mHasProfile)
      {
         wxMessageBox( _("Attempt to run Noise Removal without a noise profile\n.") );
         return false;
      }
	}

	// This same code will both remove noise and
	// profile it, depending on 'mDoProfile'
   TrackListIterator iter(mWaveTracks);
   WaveTrack *track = (WaveTrack *) iter.First();
   int count = 0;
   while (track) {
      double trackStart = track->GetStartTime();
      double trackEnd = track->GetEndTime();
      double t0 = mT0 < trackStart? trackStart: mT0;
      double t1 = mT1 > trackEnd? trackEnd: mT1;

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

         if (!ProcessOne(count, track, start, len)){
            return false;
	      }
      }
      track = (WaveTrack *) iter.Next();
      count++;
   }

   if (mDoProfile) {
      for(int i=0; i<=windowSize/2; i++) {
         //float stddev = sqrt(sumsq[i] - (sum[i]*sum[i])/profileCount[i])
         //                               / profileCount[i];
         mNoiseGate[i] = sum[i] / profileCount[i]; // average
      }
		CleanSpeechMayWriteNoiseGate();
      mHasProfile = true;
      mDoProfile = false;
   }
   return true;
}
コード例 #24
0
ファイル: TruncSilence.cpp プロジェクト: ruthmagnus/audacity
bool EffectTruncSilence::Process()
{
   TrackListIterator iter(mWaveTracks);
   WaveTrack *t;
   double t0 = mT0;
   double t1 = mT1;
   int tndx; 
   int tcount = 0;

   // Init using first track
   t = (WaveTrack *) iter.First();
   double rate = t->GetRate();
   sampleCount blockLen = t->GetMaxBlockSize();

   // Get the left and right bounds for all tracks
   while (t) {
      // Make sure all tracks have the same sample rate
      if (rate != t->GetRate()) {
         wxMessageBox(_("All tracks must have the same sample rate"), _("Truncate Silence"));
         return false;
      }

      // Count the tracks
      tcount++;

      // Set the current bounds to whichever left marker is
      // greater and whichever right marker is less
      t0 = wxMax(mT0, t->GetStartTime());
      t1 = wxMin(mT1, t->GetEndTime());

      // Use the smallest block size of all the tracks
      blockLen = wxMin(blockLen, t->GetMaxBlockSize());

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

   // Transform the marker timepoints to samples
   t = (WaveTrack *) iter.First();
   longSampleCount start = t->TimeToLongSamples(t0);
   longSampleCount end = t->TimeToLongSamples(t1);

   // Bigger buffers reduce 'reset'
   blockLen *= 8;

   // Allocate buffers
   float **buffer = new float*[tcount];
   for (tndx = 0; tndx < tcount; tndx++) {
      buffer[tndx] = new float[blockLen];
   }

   // Set thresholds
   // We have a lower bound on the amount of silence we chop out at a time
   // to avoid chopping up low frequency sounds.  We're good down to 10Hz
   // if we use 100ms.
   const float minTruncMs = 1.0f;
   double truncDbSilenceThreshold = Enums::Db2Signal[mTruncDbChoiceIndex];
   int truncLongestAllowedSilentSamples = 
      int((wxMax( mTruncLongestAllowedSilentMs, minTruncMs) * rate) / 1000.0);

   

   // Figure out number of frames for ramping
   int quarterSecondFrames = int((rate * QUARTER_SECOND_MS) / 1000.0);
   int rampInFrames = (truncLongestAllowedSilentSamples / 4);
   if (rampInFrames > quarterSecondFrames) {
      rampInFrames = quarterSecondFrames;
   }

   // Start processing
   this->CopyInputWaveTracks(); // Set up mOutputWaveTracks.
   TrackListIterator iterOut(mOutputWaveTracks);

   longSampleCount index = start;
   longSampleCount outTrackOffset = start;
   bool cancelled = false;
   while (index < end) {

      // Limit size of current block if we've reached the end
      sampleCount limit = blockLen;
      if ((index + blockLen) > end) {
         limit = end - index; 
      }

      // Fill the buffers
      tndx = 0;
      t = (WaveTrack *) iter.First();
      while (t) {
         t->Get((samplePtr)buffer[tndx++], floatSample, index, blockLen);
         t = (WaveTrack *) iter.Next();
      }

      // Reset
      bool ignoringFrames = false;
      sampleCount consecutiveSilentFrames = 0;
      sampleCount truncIndex = 0;

      // Look for silences in current block
      for (sampleCount i = 0; i < limit; i++) {

         // Is current frame in all tracks below threshold
         bool below = true;
         for (tndx = 0; tndx < tcount; tndx++) {
            if (fabs(buffer[tndx][i]) >= truncDbSilenceThreshold) {
               below = false;
               break;
            }
         }

         // Count frame if it's below threshold
         if (below) {
            consecutiveSilentFrames++;

            // Ignore this frame (equivalent to cutting it)
            // otherwise, keep sample to be part of allowed silence
            if (consecutiveSilentFrames > truncLongestAllowedSilentSamples) {
               ignoringFrames = true;
               continue;
            }
         }
         else {
            if (ignoringFrames == true) {
               sampleCount curOffset = i - rampInFrames;
               truncIndex -= rampInFrames; // backup into ignored frames

               for (tndx = 0; tndx < tcount; tndx++) {
                  sampleCount trunci = truncIndex;
                  for (int fr = 0; fr < rampInFrames; fr++) {
                     buffer[tndx][trunci++] = buffer[tndx][curOffset + fr];
                  }
                  if(((trunci - rampInFrames) - mBlendFrameCount) >= 0) {
                     BlendFrames(buffer[tndx], mBlendFrameCount,
                             ((trunci - rampInFrames) - mBlendFrameCount), 
                             ((i - rampInFrames) - mBlendFrameCount));
                  }
               }
               truncIndex += rampInFrames;
            }
            consecutiveSilentFrames = 0;
            ignoringFrames = false;
         }

         // Can get here either because > dbThreshold
         // or silence duration isn't longer than allowed
         for (tndx = 0; tndx < tcount; tndx++) {
            buffer[tndx][truncIndex] = buffer[tndx][i];
         }
         truncIndex++;
      }

      // Update tracks if any samples were removed
      if (truncIndex < limit) {

         // Put updated sample back into output tracks.
         tndx = 0;
         t = (WaveTrack *) iterOut.First();
         while (t) {
            t->Set((samplePtr)buffer[tndx++], floatSample, outTrackOffset, truncIndex);
            t = (WaveTrack *) iterOut.Next();
         }
      }

      // Maintain output index
      outTrackOffset += truncIndex;

      // Update progress and bail if user cancelled
      cancelled = TrackProgress(0, ((double)index / (double)end));
      if (cancelled) {
         break;
      }

      // Bump to next block
      index += limit;
   }

   // Remove stale data at end of output tracks.
   if (!cancelled && (outTrackOffset < end)) {
      t = (WaveTrack *) iterOut.First();
      while (t) {
         t->Clear(outTrackOffset / rate, t1);
         t = (WaveTrack *) iterOut.Next();
      }
      t1 = outTrackOffset / rate;
   }

   // Free buffers
   for (tndx = 0; tndx < tcount; tndx++) {
      delete [] buffer[tndx];
   }
   delete [] buffer;

   mT0 = t0;
   mT1 = t1;

   this->ReplaceProcessedWaveTracks(!cancelled); 
   return !cancelled;
}
コード例 #25
0
ファイル: SBSMSEffect.cpp プロジェクト: QuincyPYoung/audacity
bool EffectSBSMS::Process()
{
   bool bGoodResult = true;

   //Iterate over each track
   //Track::All is needed because this effect needs to introduce silence in the group tracks to keep sync
   this->CopyInputTracks(Track::All); // Set up mOutputTracks.
   TrackListIterator iter(mOutputTracks);
   Track* t;
   mCurTrackNum = 0;

   double maxDuration = 0.0;

   // Must sync if selection length will change
   bool mustSync = (rateStart != rateEnd);
   Slide rateSlide(rateSlideType,rateStart,rateEnd);
   Slide pitchSlide(pitchSlideType,pitchStart,pitchEnd);
   mTotalStretch = rateSlide.getTotalStretch();

   t = iter.First();
   while (t != NULL) {
      if (t->GetKind() == Track::Label &&
            (t->GetSelected() || (mustSync && t->IsSyncLockSelected())) )
      {
         if (!ProcessLabelTrack(t)) {
            bGoodResult = false;
            break;
         }
      }
      else if (t->GetKind() == Track::Wave && t->GetSelected() )
      {
         WaveTrack* leftTrack = (WaveTrack*)t;

         //Get start and end times from track
         mCurT0 = leftTrack->GetStartTime();
         mCurT1 = leftTrack->GetEndTime();

         //Set the current bounds to whichever left marker is
         //greater and whichever right marker is less
         mCurT0 = wxMax(mT0, mCurT0);
         mCurT1 = wxMin(mT1, mCurT1);

         // Process only if the right marker is to the right of the left marker
         if (mCurT1 > mCurT0) {
            sampleCount start;
            sampleCount end;
            start = leftTrack->TimeToLongSamples(mCurT0);
            end = leftTrack->TimeToLongSamples(mCurT1);

            WaveTrack* rightTrack = NULL;
            if (leftTrack->GetLinked()) {
               double t;
               rightTrack = (WaveTrack*)(iter.Next());

               //Adjust bounds by the right tracks markers
               t = rightTrack->GetStartTime();
               t = wxMax(mT0, t);
               mCurT0 = wxMin(mCurT0, t);
               t = rightTrack->GetEndTime();
               t = wxMin(mT1, t);
               mCurT1 = wxMax(mCurT1, t);

               //Transform the marker timepoints to samples
               start = leftTrack->TimeToLongSamples(mCurT0);
               end = leftTrack->TimeToLongSamples(mCurT1);

               mCurTrackNum++; // Increment for rightTrack, too.
            }
            sampleCount trackStart = leftTrack->TimeToLongSamples(leftTrack->GetStartTime());
            sampleCount trackEnd = leftTrack->TimeToLongSamples(leftTrack->GetEndTime());

            // SBSMS has a fixed sample rate - we just convert to its sample rate and then convert back
            float srTrack = leftTrack->GetRate();
            float srProcess = bLinkRatePitch?srTrack:44100.0;

            // the resampler needs a callback to supply its samples
            ResampleBuf rb;
            sampleCount maxBlockSize = leftTrack->GetMaxBlockSize();
            rb.blockSize = maxBlockSize;
            rb.buf = (audio*)calloc(rb.blockSize,sizeof(audio));
            rb.leftTrack = leftTrack;
            rb.rightTrack = rightTrack?rightTrack:leftTrack;
            rb.leftBuffer = (float*)calloc(maxBlockSize,sizeof(float));
            rb.rightBuffer = (float*)calloc(maxBlockSize,sizeof(float));

            // Samples in selection
            sampleCount samplesIn = end-start;

            // Samples for SBSMS to process after resampling
            sampleCount samplesToProcess = (sampleCount) ((float)samplesIn*(srProcess/srTrack));

            SlideType outSlideType;
            SBSMSResampleCB outResampleCB;

            sampleCount processPresamples = 0;
            sampleCount trackPresamples = 0;

            if(bLinkRatePitch) {
              rb.bPitch = true;
              outSlideType = rateSlideType;
              outResampleCB = resampleCB;
              rb.offset = start;
              rb.end = end;
              rb.iface = new SBSMSInterfaceSliding(&rateSlide,&pitchSlide,
                                                       bPitchReferenceInput,
                                                       samplesToProcess,0,
                                                       NULL);
               
             
            } else {
              rb.bPitch = false;
              outSlideType = (srProcess==srTrack?SlideIdentity:SlideConstant);
              outResampleCB = postResampleCB;
              rb.ratio = srProcess/srTrack;
              rb.quality = new SBSMSQuality(&SBSMSQualityStandard);
              rb.resampler = new Resampler(resampleCB, &rb, srProcess==srTrack?SlideIdentity:SlideConstant);
              rb.sbsms = new SBSMS(rightTrack?2:1,rb.quality,true);
              rb.SBSMSBlockSize = rb.sbsms->getInputFrameSize();
              rb.SBSMSBuf = (audio*)calloc(rb.SBSMSBlockSize,sizeof(audio));

              processPresamples = wxMin(rb.quality->getMaxPresamples(),
                                        (long)((float)(start-trackStart)*(srProcess/srTrack)));
              trackPresamples = wxMin(start-trackStart,
                                      (long)((float)(processPresamples)*(srTrack/srProcess)));
              rb.offset = start - trackPresamples;
              rb.end = trackEnd;
              rb.iface = new SBSMSEffectInterface(rb.resampler,
                                                      &rateSlide,&pitchSlide,
                                                      bPitchReferenceInput,
                                                      samplesToProcess,processPresamples,
                                                      rb.quality);
            }
            
            Resampler resampler(outResampleCB,&rb,outSlideType);

            audio outBuf[SBSMSOutBlockSize];
            float outBufLeft[2*SBSMSOutBlockSize];
            float outBufRight[2*SBSMSOutBlockSize];

            // Samples in output after SBSMS
            sampleCount samplesToOutput = rb.iface->getSamplesToOutput();

            // Samples in output after resampling back
            sampleCount samplesOut = (sampleCount) ((float)samplesToOutput * (srTrack/srProcess));

            // Duration in track time
            double duration =  (mCurT1-mCurT0) * mTotalStretch;

            if(duration > maxDuration)
               maxDuration = duration;

            TimeWarper *warper = createTimeWarper(mCurT0,mCurT1,maxDuration,rateStart,rateEnd,rateSlideType);
            SetTimeWarper(warper);

            rb.outputLeftTrack = mFactory->NewWaveTrack(leftTrack->GetSampleFormat(),
                                                        leftTrack->GetRate());
            if(rightTrack)
               rb.outputRightTrack = mFactory->NewWaveTrack(rightTrack->GetSampleFormat(),
                                                            rightTrack->GetRate());
            long pos = 0;
            long outputCount = -1;

            // process
            while(pos<samplesOut && outputCount) {
               long frames;
               if(pos+SBSMSOutBlockSize>samplesOut) {
                  frames = samplesOut - pos;
               } else {
                  frames = SBSMSOutBlockSize;
               }
               outputCount = resampler.read(outBuf,frames);
               for(int i = 0; i < outputCount; i++) {
                  outBufLeft[i] = outBuf[i][0];
                  if(rightTrack)
                     outBufRight[i] = outBuf[i][1];
               }
               pos += outputCount;
               rb.outputLeftTrack->Append((samplePtr)outBufLeft, floatSample, outputCount);
               if(rightTrack)
                  rb.outputRightTrack->Append((samplePtr)outBufRight, floatSample, outputCount);

               double frac = (double)pos/(double)samplesOut;
               int nWhichTrack = mCurTrackNum;
               if(rightTrack) {
                  nWhichTrack = 2*(mCurTrackNum/2);
                  if (frac < 0.5)
                     frac *= 2.0; // Show twice as far for each track, because we're doing 2 at once.
                  else {
                     nWhichTrack++;
                     frac -= 0.5;
                     frac *= 2.0; // Show twice as far for each track, because we're doing 2 at once.
                  }
               }
               if (TrackProgress(nWhichTrack, frac))
                  return false;
            }
            rb.outputLeftTrack->Flush();
            if(rightTrack)
               rb.outputRightTrack->Flush();

            bool bResult =
               leftTrack->ClearAndPaste(mCurT0, mCurT1, rb.outputLeftTrack,
                                          true, false, GetTimeWarper());
            wxASSERT(bResult); // TO DO: Actually handle this.
            wxUnusedVar(bResult);

            if(rightTrack)
            {
               bResult =
                  rightTrack->ClearAndPaste(mCurT0, mCurT1, rb.outputRightTrack,
                                             true, false, GetTimeWarper());
               wxASSERT(bResult); // TO DO: Actually handle this.
            }
         }
         mCurTrackNum++;
      }
      else if (mustSync && t->IsSyncLockSelected())
      {
         t->SyncLockAdjust(mCurT1, mCurT0 + (mCurT1 - mCurT0) * mTotalStretch);
      }
      //Iterate to the next track
      t = iter.Next();
   }

   if (bGoodResult)
      ReplaceProcessedTracks(bGoodResult);

   // Update selection
   mT0 = mCurT0;
   mT1 = mCurT0 + maxDuration;

   return bGoodResult;
}
コード例 #26
0
ファイル: Contrast.cpp プロジェクト: MindFy/audacity
bool ContrastDialog::GetDB(float &dB)
{
   float rms = float(0.0);
   int numberSelecteTracks = 0;

   // For stereo tracks: sqrt((mean(L)+mean(R))/2)
   bool isStereo = false;
   double meanSq = 0.0;

   AudacityProject *p = GetActiveProject();
   SelectedTrackListOfKindIterator iter(Track::Wave, p->GetTracks());
   WaveTrack *t = (WaveTrack *) iter.First();
   while (t) {
      numberSelecteTracks++;
      if (numberSelecteTracks > 1 && !isStereo) {
         AudacityMessageDialog m(NULL, _("You can only measure one track at a time."), _("Error"), wxOK);
         m.ShowModal();
         return false;
      }
      isStereo = t->GetLinked();

      wxASSERT(mT0 <= mT1);

      // Ignore whitespace beyond ends of track.
      if(mT0 < t->GetStartTime())
         mT0 = t->GetStartTime();
      if(mT1 > t->GetEndTime())
         mT1 = t->GetEndTime();

      auto SelT0 = t->TimeToLongSamples(mT0);
      auto SelT1 = t->TimeToLongSamples(mT1);

      if(SelT0 > SelT1)
      {
         AudacityMessageDialog m(NULL, _("Invalid audio selection.\nPlease ensure that audio is selected."), _("Error"), wxOK);
         m.ShowModal();
         return false;
      }

      if(SelT0 == SelT1)
      {
         AudacityMessageDialog m(NULL, _("Nothing to measure.\nPlease select a section of a track."), _("Error"), wxOK);
         m.ShowModal();
         return false;
      }

      // Don't throw in this analysis dialog
      rms = ((WaveTrack *)t)->GetRMS(mT0, mT1, false);
      meanSq += rms * rms;
      t = (WaveTrack *) iter.Next();
   }
   // TODO: This works for stereo, provided the audio clips are in both channels.
   // We should really count gaps between clips as silence.
   rms = (meanSq > 0.0)? sqrt(meanSq/(double)numberSelecteTracks) : 0.0;

   if(numberSelecteTracks == 0) {
      AudacityMessageDialog m(NULL, _("Please select an audio track."), _("Error"), wxOK);
      m.ShowModal();
      return false;
   }
   // Gives warning C4056, Overflow in floating-point constant arithmetic
   // -INFINITY is intentional here.
   // Looks like we are stuck with this warning, as 
   // #pragma warning( disable : 4056)
   // even around the whole function does not disable it successfully.

   dB = (rms == 0.0)? -INFINITY : LINEAR_TO_DB(rms);
   return true;
}
コード例 #27
0
bool EffectTruncSilence::Process()
{
   SelectedTrackListOfKindIterator iter(Track::Wave, mTracks);
   WaveTrack *t;
   double t0 = mT0;
   double t1 = mT1;
   int tndx; 
   int tcount = 0;
   int fr;

   // Init using first track
   t = (WaveTrack *) iter.First();
   double rate = t->GetRate();
   sampleCount blockLen = t->GetMaxBlockSize();

   // Get the left and right bounds for all tracks
   while (t) {
      // Make sure all tracks have the same sample rate
      if (rate != t->GetRate()) {
         wxMessageBox(_("All tracks must have the same sample rate"), _("Truncate Silence"));
         return false;
      }

      // Count the tracks
      tcount++;

      // Set the current bounds to whichever left marker is
      // greater and whichever right marker is less
      t0 = wxMax(mT0, t->GetStartTime());
      t1 = wxMin(mT1, t->GetEndTime());

      // Use the smallest block size of all the tracks
      blockLen = wxMin(blockLen, t->GetMaxBlockSize());

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

   // Just a sanity check, really it should be much higher
   if(blockLen < 4*mBlendFrameCount)
      blockLen = 4*mBlendFrameCount;

   // Transform the marker timepoints to samples
   t = (WaveTrack *) iter.First();
   sampleCount start = t->TimeToLongSamples(t0);
   sampleCount end = t->TimeToLongSamples(t1);

   // Bigger buffers reduce 'reset'
   //blockLen *= 8;
   // Stress-test the logic for cutting samples through block endpoints
   //blockLen /= 8;

   // Set thresholds
   // We have a lower bound on the amount of silence we chop out at a time
   // to avoid chopping up low frequency sounds.  We're good down to 10Hz
   // if we use 100ms.
   const float minTruncMs = 1.0f;
   double truncDbSilenceThreshold = Enums::Db2Signal[mTruncDbChoiceIndex];
   int truncInitialAllowedSilentSamples = 
      int((wxMax( mTruncInitialAllowedSilentMs, minTruncMs) * rate) / 1000.0);
   int truncLongestAllowedSilentSamples = 
      int((wxMax( mTruncLongestAllowedSilentMs, minTruncMs) * rate) / 1000.0);

   // Require at least 4 samples for lengths
   if(truncInitialAllowedSilentSamples < 4)
      truncInitialAllowedSilentSamples = 4;
   if(truncLongestAllowedSilentSamples < 4)
      truncLongestAllowedSilentSamples = 4;

   // If the cross-fade is longer than the minimum length,
   // then limit the cross-fade length to the minimum length
   // This allows us to have reasonable cross-fade by default
   // and still allow for 1ms minimum lengths
   if(truncInitialAllowedSilentSamples < mBlendFrameCount)
      mBlendFrameCount = truncInitialAllowedSilentSamples;
   if(truncLongestAllowedSilentSamples < mBlendFrameCount)
      mBlendFrameCount = truncLongestAllowedSilentSamples;

   // For sake of efficiency, don't let blockLen be less than double the longest silent samples
   // up until a sane limit of 1Meg samples
   while((blockLen > 0) && (blockLen < truncLongestAllowedSilentSamples*2) && (blockLen < 1048576)) {
      blockLen *= 2;
   }
    // Don't allow either value to be more than half of the block length
   if(truncLongestAllowedSilentSamples > blockLen/2)
      truncLongestAllowedSilentSamples = blockLen/2;
   if(truncInitialAllowedSilentSamples > truncLongestAllowedSilentSamples)
      truncInitialAllowedSilentSamples = truncLongestAllowedSilentSamples;

   // We use the 'longest' variable as additive to the 'initial' variable
   truncLongestAllowedSilentSamples -= truncInitialAllowedSilentSamples;

   // Perform the crossfade half-way through the minimum removed silence duration
   int rampInFrames = (truncInitialAllowedSilentSamples + mBlendFrameCount) / 2;
   if(rampInFrames > truncInitialAllowedSilentSamples)
      rampInFrames = truncInitialAllowedSilentSamples;

   // Allocate buffers
   float **buffer = new float*[tcount];
   for (tndx = 0; tndx < tcount; tndx++) {
      buffer[tndx] = new float[blockLen];
   }

   // Start processing
   //Track::All is needed because this effect has clear functionality
   this->CopyInputTracks(Track::All); // Set up mOutputTracks.
   SelectedTrackListOfKindIterator iterOut(Track::Wave, mOutputTracks);

   sampleCount index = start;
   sampleCount outTrackOffset = start;
   bool cancelled = false;
   // Reset
   bool ignoringFrames = false;
   bool truncToMinimum = true;  // Ignore the initial samples until we get above the noise floor
   sampleCount consecutiveSilentFrames = 0;
   sampleCount truncIndex = 0;
   sampleCount i = 0;
   sampleCount keep;

   while (index < end) {

      // Limit size of current block if we've reached the end
      sampleCount count = blockLen-i;
      if ((index + count) > end) {
         count = end - index; 
      }

      // Fill the buffers
      tndx = 0;
      t = (WaveTrack *) iter.First();
      while (t) {
         t->Get((samplePtr)(buffer[tndx++]+i), floatSample, index, count);
         t = (WaveTrack *) iter.Next();
      }

      // Shift over to account for samples remaining from prior block
      sampleCount limit = count+i;

      // Look for silences in current block
      for ( ; i < limit; i++) {

         // Is current frame in all tracks below threshold
         bool below = true;
         for (tndx = 0; tndx < tcount; tndx++) {
            if (fabs(buffer[tndx][i]) >= truncDbSilenceThreshold) {
               below = false;
               break;
            }
         }
         // Make sure we cross-fade and output the last silence
         // so we get a smooth transition into whatever follows the selected region
         // Also set the 'truncToMinimum' flag so that the last silence is truncated to the minimum amount
         if(below && ((index+i+1) == end)) {
            below = false;
            truncToMinimum = true;
         }

         // Count frame if it's below threshold
         if (below) {
            consecutiveSilentFrames++;

            // Ignore this frame (equivalent to cutting it)
            // otherwise, keep sample to be part of allowed silence
            if (consecutiveSilentFrames > truncInitialAllowedSilentSamples) {
               ignoringFrames = true;
               continue;
            }
         }
         else {
            if (ignoringFrames == true) {
               // Scale the consectiveSilentFrames so we keep a silence duration
               // which is proportional to the original silence up to the limit
               keep = consecutiveSilentFrames - truncInitialAllowedSilentSamples;
               keep /= mSilenceCompressRatio;

               // The first and last samples always get truncated to the minimum amount
               if(truncToMinimum == true)
                  keep = 0;
               if(keep > truncLongestAllowedSilentSamples)
                  keep = truncLongestAllowedSilentSamples;
               if(keep < 0)
                  keep = 0;

               // Compute the location of the cross-fade to be halfway through the silence
               // with restriction to the samples we still have available to use
               rampInFrames = (truncInitialAllowedSilentSamples - keep + mBlendFrameCount) / 2;
               if(rampInFrames > truncInitialAllowedSilentSamples)
                  rampInFrames = truncInitialAllowedSilentSamples;
               if(rampInFrames < mBlendFrameCount)
                  rampInFrames = mBlendFrameCount;

               // Include the cross-fade samples in the count to make the loop logic easier
               keep += rampInFrames;
               truncIndex -= rampInFrames;

               // back up for cross-fade
               sampleCount curOffset = i - keep;

               if(curOffset < 0) {
                  // This should never happen, but just in case...
                  keep += curOffset - rampInFrames;
                  if(keep < mBlendFrameCount)
                     keep = mBlendFrameCount;
                  curOffset = 0;
               }
               if(truncIndex < 0) {
                  // This should never happen, but just in case...
                  truncIndex = 0;
               }

               for (tndx = 0; tndx < tcount; tndx++) {
                  // Cross fade the cut point
                  for (fr = 0; fr < mBlendFrameCount; fr++) {
                     buffer[tndx][truncIndex+fr] = ((mBlendFrameCount-fr)*buffer[tndx][truncIndex+fr] + fr*buffer[tndx][curOffset + fr]) / mBlendFrameCount;
                  }
                  // Append the 'keep' samples, if any
                  for ( ; fr < keep; fr++) {
                     buffer[tndx][truncIndex+fr] = buffer[tndx][curOffset + fr];
                  }
               }
               truncIndex += keep;
            }
            consecutiveSilentFrames = 0;
            ignoringFrames = false;
            truncToMinimum = false;
         }

         // Can get here either because > dbThreshold
         // or silence duration isn't longer than allowed
         for (tndx = 0; tndx < tcount; tndx++) {
            buffer[tndx][truncIndex] = buffer[tndx][i];
         }
         truncIndex++;
      }

      // Update tracks if any samples were removed, now or before
      if (outTrackOffset + truncIndex != index + limit) {
         // Put updated sample back into output tracks.
         tndx = 0;
         t = (WaveTrack *) iterOut.First();
         while (t) {
            t->Set((samplePtr)buffer[tndx++], floatSample, outTrackOffset, truncIndex);
            t = (WaveTrack *) iterOut.Next();
         }
      }

      // If currently in a silent section, retain samples for the next pass
      if(ignoringFrames) {
         keep = consecutiveSilentFrames - truncInitialAllowedSilentSamples;
         if(keep > (truncLongestAllowedSilentSamples+mBlendFrameCount))
            keep = truncLongestAllowedSilentSamples+mBlendFrameCount;
         for (tndx = 0; tndx < tcount; tndx++) {
            for(fr = 0; fr < truncInitialAllowedSilentSamples; fr++) {
               buffer[tndx][fr] = buffer[tndx][truncIndex-truncInitialAllowedSilentSamples+fr];
            }
            for(fr = 0; fr < keep; fr++) {
               buffer[tndx][truncInitialAllowedSilentSamples+fr] = buffer[tndx][i-keep+fr];
            }
         }
         // Update the output index, less what we are retaining for next time
         outTrackOffset += truncIndex - truncInitialAllowedSilentSamples;
         // Append the following buffer to the existing data
         i = consecutiveSilentFrames = truncInitialAllowedSilentSamples + keep;
         truncIndex = truncInitialAllowedSilentSamples;
      } else {
         // Maintain output index
         outTrackOffset += truncIndex;
         // Reset the buffer pointers to the beginning
         i = 0;
         truncIndex = 0;
         consecutiveSilentFrames = 0;
      }

      // Update progress and bail if user cancelled
      cancelled = TrackProgress(0, ((double)index / (double)end));
      if (cancelled) {
         break;
      }

      // Bump to next block
      index += count;
   }

   AudacityProject *p = GetActiveProject();
   if (!p)
      return false;

   // Remove stale data at end of output tracks.
   if (!cancelled && (outTrackOffset < end)) {
      t = (WaveTrack *) iterOut.First();
      if( p->IsSticky() )
         t->Clear(outTrackOffset / rate, t1, mOutputTracks);
      else
         while(t) {
            t->Clear(outTrackOffset / rate, t1, mOutputTracks);
            t = (WaveTrack *) iterOut.Next();
         }         

      t1 = outTrackOffset / rate;
   }

   // Free buffers
   for (tndx = 0; tndx < tcount; tndx++) {
      delete [] buffer[tndx];
   }
   delete [] buffer;

   mT0 = t0;
   mT1 = t1;

   this->ReplaceProcessedTracks(!cancelled); 
   return !cancelled;
}
コード例 #28
0
ファイル: ChangePitch.cpp プロジェクト: Avi2011class/audacity
// Deduce m_FromFrequency from the samples at the beginning of
// the selection. Then set some other params accordingly.
void EffectChangePitch::DeduceFrequencies()
{
   // As a neat trick, attempt to get the frequency of the note at the
   // beginning of the selection.
   SelectedTrackListOfKindIterator iter(Track::Wave, mTracks);
   WaveTrack *track = (WaveTrack *) iter.First();
   if (track) {
      double rate = track->GetRate();

      // Auto-size window -- high sample rates require larger windowSize.
      // Aim for around 2048 samples at 44.1 kHz (good down to about 100 Hz).
      // To detect single notes, analysis period should be about 0.2 seconds.
      // windowSize must be a power of 2.
      int windowSize = wxRound(pow(2.0, floor((log(rate / 20.0)/log(2.0)) + 0.5)));
      // windowSize < 256 too inaccurate
      windowSize = (windowSize > 256)? windowSize : 256;

      // we want about 0.2 seconds to catch the first note.
      // number of windows rounded to nearest integer >= 1.
      int numWindows = wxRound((double)(rate / (5.0f * windowSize)));
      numWindows = (numWindows > 0)? numWindows : 1;

      double trackStart = track->GetStartTime();
      double t0 = mT0 < trackStart? trackStart: mT0;
      sampleCount start = track->TimeToLongSamples(t0);

      int analyzeSize = windowSize * numWindows;
      float * buffer;
      buffer = new float[analyzeSize];

      float * freq;
      freq = new float[windowSize/2];

      float * freqa;
      freqa = new float[windowSize/2];

      int i, j, argmax;
      int lag;

      for(j=0; j<windowSize/2; j++)
         freqa[j] = 0;

      track->Get((samplePtr) buffer, floatSample, start, analyzeSize);
      for(i=0; i<numWindows; i++) {
         ComputeSpectrum(buffer+i*windowSize, windowSize,
                         windowSize, rate, freq, true);
         for(j=0; j<windowSize/2; j++)
            freqa[j] += freq[j];
      }
      argmax=0;
      for(j=1; j<windowSize/2; j++)
         if (freqa[j] > freqa[argmax])
            argmax = j;

      delete [] freq;
      delete [] freqa;
      delete [] buffer;

      lag = (windowSize/2 - 1) - argmax;
      m_dStartFrequency = rate / lag;
   }

   double dFromMIDInote = FreqToMIDInote(m_dStartFrequency);
   double dToMIDInote = dFromMIDInote + m_dSemitonesChange;
   m_nFromPitch = PitchIndex(dFromMIDInote);
   m_nFromOctave = PitchOctave(dFromMIDInote);
   m_nToPitch = PitchIndex(dToMIDInote);
   m_nToOctave = PitchOctave(dToMIDInote);

   m_FromFrequency = m_dStartFrequency;
   Calc_PercentChange();
   Calc_ToFrequency();
}
コード例 #29
0
ファイル: Contrast.cpp プロジェクト: disinteger1/audacity
bool ContrastDialog::GetDB(float &dB)
{
   float rms = float(0.0);
   int numberSelecteTracks = 0;

   // For stereo tracks: sqrt((mean(L)+mean(R))/2)
   bool isStereo = false;
   double meanSq = 0.0;

   AudacityProject *p = GetActiveProject();
   SelectedTrackListOfKindIterator iter(Track::Wave, p->GetTracks());
   WaveTrack *t = (WaveTrack *) iter.First();
   while (t) {
      numberSelecteTracks++;
      if (numberSelecteTracks > 1 && !isStereo) {
         wxMessageDialog m(NULL, _("You can only measure one track at a time."), _("Error"), wxOK);
         m.ShowModal();
         return false;
      }
      isStereo = t->GetLinked();

      wxASSERT(mT0 <= mT1);

      // Ignore whitespace beyond ends of track.
      if(mT0 < t->GetStartTime())
         mT0 = t->GetStartTime();
      if(mT1 > t->GetEndTime())
         mT1 = t->GetEndTime();

      sampleCount SelT0 = t->TimeToLongSamples(mT0);
      sampleCount SelT1 = t->TimeToLongSamples(mT1);

      if(SelT0 > SelT1)
      {
         wxMessageDialog m(NULL, _("Invalid audio selection.\nPlease ensure that audio is selected."), _("Error"), wxOK);
         m.ShowModal();
         return false;
      }

      if(SelT0 == SelT1)
      {
         wxMessageDialog m(NULL, _("Nothing to measure.\nPlease select a section of a track."), _("Error"), wxOK);
         m.ShowModal();
         return false;
      }

      ((WaveTrack *)t)->GetRMS(&rms, mT0, mT1);
      meanSq += rms * rms;
      t = (WaveTrack *) iter.Next();
   }
   // TODO: This works for stereo, provided the audio clips are in both channels.
   // We should really count gaps between clips as silence.
   rms = (meanSq > 0.0)? sqrt(meanSq/(double)numberSelecteTracks) : 0.0;

   if(numberSelecteTracks == 0) {
      wxMessageDialog m(NULL, _("Please select an audio track."), _("Error"), wxOK);
      m.ShowModal();
      return false;
   }

   dB = (rms == 0.0)? -INFINITY : LINEAR_TO_DB(rms);
   return true;
}
コード例 #30
0
ファイル: ChangeSpeed.cpp プロジェクト: ruthmagnus/audacity
bool EffectChangeSpeed::Process()
{
	// Similar to EffectSoundTouch::Process()

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

   TrackListIterator iter(mOutputWaveTracks);
   WaveTrack* pOutWaveTrack = (WaveTrack*)(iter.First());
   mCurTrackNum = 0;
	m_maxNewLength = 0.0;
	
   //Get start and end times from track
   mCurT0 = pOutWaveTrack->GetStartTime();
   mCurT1 = pOutWaveTrack->GetEndTime();

   //Set the current bounds to whichever left marker is
   //greater and whichever right marker is less:
   mCurT0 = wxMax(mT0, mCurT0);
   mCurT1 = wxMin(mT1, mCurT1);

   double len = pOutWaveTrack->GetEndTime() - pOutWaveTrack->GetStartTime();
   
   while (pOutWaveTrack != NULL)
   {
      //Get start and end times from track
      mCurT0 = pOutWaveTrack->GetStartTime();
      mCurT1 = pOutWaveTrack->GetEndTime();

      //Set the current bounds to whichever left marker is
      //greater and whichever right marker is less:
      mCurT0 = wxMax(mT0, mCurT0);
      mCurT1 = wxMin(mT1, mCurT1);

      // Process only if the right marker is to the right of the left marker
      if (mCurT1 > mCurT0) {       
         //Transform the marker timepoints to samples
         sampleCount start = pOutWaveTrack->TimeToLongSamples(mCurT0);
         sampleCount end = pOutWaveTrack->TimeToLongSamples(mCurT1);

         //ProcessOne() (implemented below) processes a single track
         if (!ProcessOne(pOutWaveTrack, start, end))
         {
            bGoodResult = false;
            break;
         }
      }
      
      //Iterate to the next track
      pOutWaveTrack = (WaveTrack*)(iter.Next());
      mCurTrackNum++;
   }

   this->ReplaceProcessedWaveTracks(bGoodResult); 

#ifdef EXPERIMENTAL_FULL_LINKING
   AudacityProject *p = (AudacityProject*)mParent;
   if( p && p->IsSticky() ){
      pOutWaveTrack = (WaveTrack*)(iter.First());
      double newLen = pOutWaveTrack->GetEndTime() - pOutWaveTrack->GetStartTime();
      double timeAdded = newLen-len;
      double sel = mCurT1-mCurT0;
      double percent = (sel/(timeAdded+sel))*100 - 100;
      if ( !(HandleGroupChangeSpeed(percent, mCurT0, mCurT1)) ) bGoodResult = false;
   }
#endif

// mT1 = mT0 + m_maxNewLength; // Update selection.

   return bGoodResult;
}