コード例 #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
ファイル: ScienFilter.cpp プロジェクト: MartynShaw/audacity
bool EffectScienFilter::Init()
{
   int selcount = 0;
   double rate = 0.0;

   TrackListOfKindIterator iter(Track::Wave, mTracks);
   WaveTrack *t = (WaveTrack *) iter.First();

   mNyquist = (t ? t->GetRate() : GetActiveProject()->GetRate()) / 2.0;

   while (t)
   {
      if (t->GetSelected() && t->GetKind() == Track::Wave)
      {
         if (selcount == 0)
         {
            rate = t->GetRate();
         }
         else
         {
            if (t->GetRate() != rate)
            {
               wxMessageBox(_("To apply a filter, all selected tracks must have the same sample rate."));
               return false;
            }
         }
         selcount++;
      }
      t = (WaveTrack *) iter.Next();
   }

   return true;
}
コード例 #3
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);
   }
}
コード例 #4
0
ファイル: Menus.cpp プロジェクト: andreipaga/audacity
void AudacityProject::OnPlotSpectrum(wxCommandEvent & event)
{
   int selcount = 0;
   WaveTrack *selt = NULL;
   TrackListIterator iter(mTracks);
   VTrack *t = iter.First();
   while (t) {
      if (t->GetSelected())
         selcount++;
      if (t->GetKind() == VTrack::Wave)
         selt = (WaveTrack *) t;
      t = iter.Next();
   }
   if (selcount != 1) {
      wxMessageBox(_("Please select a single track first.\n"));
      return;
   }

   /* This shouldn't be possible, since the menu is grayed out.
    * But we'll check just in case it does happen, to prevent
    * the crash that would result. */

   if (!selt) {
      wxMessageBox(_("Please select a track first.\n"));
      return;
   }


   sampleCount s0 = (sampleCount) ((mViewInfo.sel0 - selt->GetOffset())
                                   * selt->GetRate());
   sampleCount s1 = (sampleCount) ((mViewInfo.sel1 - selt->GetOffset())
                                   * selt->GetRate());
   sampleCount slen = s1 - s0;

   if (slen > 1048576)
      slen = 1048576;

   float *data = new float[slen];
   sampleType *data_sample = new sampleType[slen];

   if (s0 >= selt->GetNumSamples() || s0 + slen > selt->GetNumSamples()) {
      wxMessageBox(_("Not enough samples selected.\n"));
      delete[]data;
      delete[]data_sample;
      return;
   }

   selt->Get(data_sample, s0, slen);

   for (sampleCount i = 0; i < slen; i++)
      data[i] = data_sample[i] / 32767.;

   gFreqWindow->Plot(slen, data, selt->GetRate());
   gFreqWindow->Show(true);
   gFreqWindow->Raise();

   delete[]data;
   delete[]data_sample;
}
コード例 #5
0
ファイル: Noise.cpp プロジェクト: ruthmagnus/audacity
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;
}
コード例 #6
0
ファイル: Repeat.cpp プロジェクト: ruthmagnus/audacity
bool EffectRepeat::PromptUser()
{
   //
   // Figure out the maximum number of times the selection
   // could be repeated without overflowing any track
   //
   int maxCount = -1;
   TrackListIterator iter(mWaveTracks);
   WaveTrack *track = (WaveTrack *) iter.First();
   while (track) {
      sampleCount trackLen = 
         (sampleCount)((track->GetEndTime() - track->GetStartTime()) * 
                       track->GetRate());
      sampleCount selectionLen = (sampleCount)((mT1 - mT0) * track->GetRate());
      int availSamples = 2147483647 - trackLen;
      int count = availSamples / selectionLen;
      if (maxCount == -1 || count < maxCount)
         maxCount = count;

      track = (WaveTrack *) iter.Next();
   }
   
   if (maxCount <= 1) {
      wxMessageBox(_("Tracks are too long to repeat the selection."),
                   _("Repeat"), wxOK | wxCENTRE, mParent);
      return false;
   }

   RepeatDialog dlog(this, mParent);
   dlog.repeatCount = repeatCount;
   dlog.selectionTimeSecs = mT1 - mT0;
   dlog.maxCount = maxCount;
   dlog.TransferDataToWindow();

   dlog.CentreOnParent();

   dlog.ShowModal();

  if (dlog.GetReturnCode() == wxID_CANCEL)
      return false;

   repeatCount = dlog.repeatCount;
   if (repeatCount > maxCount)
      repeatCount = maxCount;
   if (repeatCount < 1)
      repeatCount = 1;

   return true;
}
コード例 #7
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();
}
コード例 #8
0
ファイル: VSTEffect.cpp プロジェクト: ruthmagnus/audacity
bool VSTEffect::Init()
{
   if (!mAEffect) {
      Load();
   }

   if (!mAEffect) {
      return false;
   }

   mBlockSize = 0;

   TrackListIterator iter(mOutputTracks);
   WaveTrack *left = (WaveTrack *) iter.First();
   while (left) {
      sampleCount lstart;
      sampleCount llen;

      GetSamples(left, &lstart, &llen);
      
      if (left->GetLinked()) {
         WaveTrack *right = (WaveTrack *) iter.Next();
         sampleCount rstart;
         sampleCount rlen;

         GetSamples(right, &rstart, &rlen);         

         if (left->GetRate() != right->GetRate()) {
            wxMessageBox(_("Both channels of a stereo track must be the same sample rate."));
            return false;
         }

         if (llen != rlen) {
            wxMessageBox(_("Both channels of a stereo track must be the same length."));
            return false;
         }
      }
      
      left = (WaveTrack *) iter.Next();
   }

   return true;
}
コード例 #9
0
ファイル: VampEffect.cpp プロジェクト: tuanmasterit/audacity
bool VampEffect::Init()
{
   Vamp::HostExt::PluginLoader *loader =
      Vamp::HostExt::PluginLoader::getInstance();
   
   delete mPlugin;
   mPlugin = 0;

   TrackListIterator iter(mWaveTracks);
   WaveTrack *left = (WaveTrack *)iter.First();

   mRate = 0.0;

   while (left) {

      if (mRate == 0.0) mRate = left->GetRate();
      
      if (left->GetLinked()) {

         WaveTrack *right = (WaveTrack *)iter.Next();
         
         if (left->GetRate() != right->GetRate()) {
            wxMessageBox(_("Sorry, Vamp Plug-ins cannot be run on stereo tracks where the individual channels of the track do not match."));
            return false;
         }
      }
      
      left = (WaveTrack *)iter.Next();
   }

   if (mRate <= 0.0) mRate = mProjectRate;

   mPlugin = loader->loadPlugin
      (mKey, mRate, Vamp::HostExt::PluginLoader::ADAPT_ALL);

   if (!mPlugin) {
      wxMessageBox(_("Sorry, failed to load Vamp Plug-in."));
      return false;
   }

   return true;
}
コード例 #10
0
ファイル: Mix.cpp プロジェクト: Kirushanr/audacity
sampleCount Mixer::Process(int maxToProcess)
{
   if (mT >= mT1)
      return 0;
   
   int i, j;
   sampleCount out;
   sampleCount maxOut = 0;
   int *channelFlags = new int[mNumChannels];

   mMaxOut = maxToProcess;

   Clear();
   for(i=0; i<mNumInputTracks; i++) {
      WaveTrack *track = mInputTrack[i];
      for(j=0; j<mNumChannels; j++)
         channelFlags[j] = 0;

      switch(track->GetChannel()) {
      case Track::MonoChannel:
      default:
         for(j=0; j<mNumChannels; j++)
            channelFlags[j] = 1;
         break;
      case Track::LeftChannel:
         channelFlags[0] = 1;
         break;
      case Track::RightChannel:
         if (mNumChannels >= 2)
            channelFlags[1] = 1;
         else
            channelFlags[0] = 1;
         break;
      }

      if (mTimeTrack ||
          track->GetRate() != mRate)
         out = MixVariableRates(channelFlags, track,
                                &mSamplePos[i], mSampleQueue[i],
                                &mQueueStart[i], &mQueueLen[i], mSRC[i]);
      else
         out = MixSameRate(channelFlags, track, &mSamplePos[i]);

      if (out > maxOut)
         maxOut = out;
   }

   mT += (maxOut / mRate);

   delete [] channelFlags; 

   return maxOut;
}
コード例 #11
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;
}
コード例 #12
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;
}
コード例 #13
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;
}
コード例 #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
ファイル: Equalization.cpp プロジェクト: ruthmagnus/audacity
bool EffectEqualization::PromptUser()
{
   TrackListIterator iter(mWaveTracks);
   WaveTrack *t = (WaveTrack *) iter.First();
   float hiFreq = ((float)(t->GetRate())/2.);

   EqualizationDialog dlog(this, ((double)loFreqI), hiFreq, mFilterFunc, windowSize,
			   mParent, -1, _("Equalization"));

   dlog.CentreOnParent();
   dlog.ShowModal();
   
   if (!dlog.GetReturnCode())
      return false;

   return true;
}
コード例 #16
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));
   }
}
コード例 #17
0
ファイル: ToneGen.cpp プロジェクト: Kirushanr/audacity
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;
}
コード例 #18
0
ファイル: Silence.cpp プロジェクト: andreipaga/audacity
bool EffectSilence::Process()
{
   if (length <= 0.0)
      length = sDefaultGenerateLen;

   TrackListIterator iter(mWaveTracks);
   WaveTrack *track = (WaveTrack *)iter.First();
   while (track) {
      WaveTrack *tmp = mFactory->NewWaveTrack(track->GetSampleFormat(), track->GetRate());
      tmp->InsertSilence(0.0, length);
      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;
}
コード例 #19
0
ファイル: DtmfGen.cpp プロジェクト: tuanmasterit/audacity
bool EffectDtmf::GenerateTrack(WaveTrack *tmp,
                               const WaveTrack &track,
                               int ntrack)
{
   bool bGoodResult = true;

   // all dtmf sequence durations in samples from seconds
   numSamplesSequence = (sampleCount)(mDuration * track.GetRate() + 0.5);
   numSamplesTone = (sampleCount)(dtmfTone * track.GetRate() + 0.5);
   numSamplesSilence = (sampleCount)(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;

   sampleCount i = 0;
   sampleCount 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) && bGoodResult) {
      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 && bGoodResult; 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, dtmfAmplitude);
            tmp->Append((samplePtr)data, floatSample, block);
            //Update the Progress meter
            if (TrackProgress(ntrack, (double)(i+j) / numSamplesSequence))
               bGoodResult = false;
         }
         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 && bGoodResult; 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);
            //Update the Progress meter
            if (TrackProgress(ntrack, (double)(i+j) / numSamplesSequence))
               bGoodResult = false;
         }
         i += numSamplesSilence;
      }
      // flip flag
      isTone=!isTone;

   } // finished the whole dtmf sequence

   delete[] data;
   return bGoodResult;
}
コード例 #20
0
bool Generator::Process()
{
   if (GetDuration() < 0.0)
      return false;


   // Set up mOutputTracks.
   // This effect needs Track::All for sync-lock grouping.
   this->CopyInputTracks(Track::All);

   // Iterate over the tracks
   bool bGoodResult = true;
   int ntrack = 0;
   TrackListIterator iter(mOutputTracks);
   Track* t = iter.First();

   while (t != NULL)
   {
      if (t->GetKind() == Track::Wave && t->GetSelected()) {
         WaveTrack* track = (WaveTrack*)t;

         bool editClipCanMove;
         gPrefs->Read(wxT("/GUI/EditClipCanMove"), &editClipCanMove, true);

         //if we can't move clips, and we're generating into an empty space,
         //make sure there's room.
         if (!editClipCanMove &&
             track->IsEmpty(mT0, mT1+1.0/track->GetRate()) &&
             !track->IsEmpty(mT0, mT0+GetDuration()-(mT1-mT0)-1.0/track->GetRate()))
         {
            wxMessageBox(
                  _("There is not enough room available to generate the audio"),
                  _("Error"), wxICON_STOP);
            Failure();
            return false;
         }

         if (GetDuration() > 0.0)
         {
            AudacityProject *p = GetActiveProject();
            // Create a temporary track
            std::unique_ptr<WaveTrack> tmp(
               mFactory->NewWaveTrack(track->GetSampleFormat(),
               track->GetRate())
            );
            BeforeTrack(*track);
            BeforeGenerate();

            // Fill it with data
            if (!GenerateTrack(&*tmp, *track, ntrack))
               bGoodResult = false;
            else {
               // Transfer the data from the temporary track to the actual one
               tmp->Flush();
               SetTimeWarper(new StepTimeWarper(mT0+GetDuration(), GetDuration()-(mT1-mT0)));
               bGoodResult = track->ClearAndPaste(p->GetSel0(), p->GetSel1(), &*tmp, true,
                     false, GetTimeWarper());
            }

            if (!bGoodResult) {
               Failure();
               return false;
            }
         }
         else
         {
            // If the duration is zero, there's no need to actually
            // generate anything
            track->Clear(mT0, mT1);
         }

         ntrack++;
      }
      else if (t->IsSyncLockSelected()) {
         t->SyncLockAdjust(mT1, mT0 + GetDuration());
      }
      // Move on to the next track
      t = iter.Next();
   }

   Success();

   this->ReplaceProcessedTracks(bGoodResult);

   mT1 = mT0 + GetDuration(); // Update selection.

   return true;
}
コード例 #21
0
//------------------------- Processing methods -------------------------
bool EffectSineSweepGenerator::Process()
{
   // taken `as is` from Audacity`s Generator.cpp to resolve
   // a vc++ linking problem...
   
   if (mDuration < 0.0)
      return false;

   BeforeGenerate();

   // Set up mOutputTracks. This effect needs Track::All for grouping
   this->CopyInputTracks(Track::All);

   // Iterate over the tracks
   bool bGoodResult = true;
   int ntrack = 0;
   TrackListIterator iter(mOutputTracks);
   Track* t = iter.First();

   while (t != NULL)
   {
      if (t->GetKind() == Track::Wave && t->GetSelected()) 
      {
         WaveTrack* track = (WaveTrack*)t;
         
         bool editClipCanMove = true;
         //gPrefs->Read(wxT("/GUI/EditClipCanMove"), &editClipCanMove, true);

         //if we can't move clips, and we're generating into an empty space,
         //make sure there's room.
         if (!editClipCanMove &&
             track->IsEmpty(mT0, mT1+1.0/track->GetRate()) &&
             !track->IsEmpty(mT0, mT0+mDuration-(mT1-mT0)-1.0/track->GetRate()))
         {
             wxMessageBox(_("There is not enough room available to generate the audio"),
                          _("Error"), wxICON_STOP);   
            Failure();
            return false;
         }

         if (mDuration > 0.0)
         {
            // Create a temporary track
            WaveTrack *tmp = mFactory->NewWaveTrack(track->GetSampleFormat(),
                                                    track->GetRate());
            //BeforeTrack(*track);

            // Fill it with data
            if (!GenerateTrack(tmp, *track, ntrack))
               bGoodResult = false;
            else 
            {
               // Transfer the data from the temporary track to the actual one
               tmp->Flush();
               SetTimeWarper(new AFStepTimeWarper(mT0+mDuration, mDuration-(mT1-mT0)));
               bGoodResult = track->ClearAndPaste(mT0, mT1, tmp, true,
                     false, GetTimeWarper());
               delete tmp;
            }

            if (!bGoodResult) 
            {
               Failure();
               return false;
            }
         }
         else
         {
            // If the duration is zero, there's no need to actually
            // generate anything
            track->Clear(mT0, mT1);
         }

         ntrack++;
      }
      else if (t->IsSyncLockSelected()) 
      {
         t->SyncLockAdjust(mT1, mT0 + mDuration);
      }
      // Move on to the next track
      t = iter.Next();
   }

   Success();

   this->ReplaceProcessedTracks(bGoodResult);

   mT1 = mT0 + mDuration; // Update selection.

   return true;
}
コード例 #22
0
ファイル: Mix.cpp プロジェクト: andreipaga/audacity
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;
}
コード例 #23
0
ファイル: ToneGen.cpp プロジェクト: tuanmasterit/audacity
void EffectToneGen::BeforeTrack(const WaveTrack &track)
{
   mSample = 0;
   mCurRate = track.GetRate();
}
コード例 #24
0
//This 'calibrates' the voicekey to noise
void VoiceKey::CalibrateNoise(WaveTrack & t, sampleCount start, sampleCount len) {
    //To calibrate the noise, we need to scan the sample block just like in the voicekey and
    //calculate the mean and standard deviation of the test statistics.
    //Then, we set the BaselineThreshold to be one

    wxBusyCursor busy;

    //initialize some sample statistics: sums of X and X^2

    double sumerg, sumerg2;
    double sumsc, sumsc2;
    double sumdc, sumdc2;
    double erg, sc, dc;
    // sampleFormat a1=0;
    //   sampleFormat a2=0;
    //   sampleFormat z1=0;
    //   sampleFormat z2=0;              // keeps track of initial and final samples of window to enable updating formulae
    int atrend=0;                             // equals sgn(a2-a1); Keeps track of trend at start of window
    int ztrend=0;                             // equals sgn(z2-z1); Keeps track of trend at end of window

    //Now, change the millisecond-based parameters into sample-based parameters
    //(This depends on WaveTrack t)
    double rate = t.GetRate();
    unsigned int WindowSizeInt = (unsigned int)(rate  * mWindowSize);
    //   unsigned int SignalWindowSizeInt = (unsigned int)(rate  * mSignalWindowSize);


    //Get the first test statistics

    //Calibrate all of the statistic, because they might be
    //changed later.

    //   if(mUseEnergy)
    erg = TestEnergy(t, start, WindowSizeInt);

    //   if(mUseSignChanges)
    sc = TestSignChanges(t,start, WindowSizeInt);

    //   if(mUseDirectionChanges)
    dc = TestDirectionChanges(t,start,WindowSizeInt);

    //Calculate initial values for the trend trackers--------------------//
    //Get((samplePtr)a1, floatSample, start,  1);
    // t.Get((samplePtr)a2, floatSample, start+1, 1);
    // t.Get((samplePtr)z1, floatSample, start+WindowSizeInt-1, 1);
    // t.Get((samplePtr)z2, floatSample, start+WindowSizeInt, 1);
    atrend = -1;//sgn(a2-a1);
    ztrend = -1;// sgn(z2-z1);
    //-------------------------------------------------------------------//


    sumerg =0.0;
    sumerg2 = 0.0;
    sumsc =0.0;
    sumsc2 = 0.0;
    sumdc =0.0;
    sumdc2 =0.0;


    //	int n = len - WindowSizeInt;        //This is how many samples we have
    int samplesleft = len - WindowSizeInt;
    int i;
    int blocksize;
    int samples=0;

    for(i = start; samplesleft >=10 ; i += (WindowSizeInt -1), samplesleft -= (WindowSizeInt -1) )
    {
        //Take samples chunk-by-chunk.
        //Normally, this should be in WindowSizeInt chunks, but at the end (if there are more than 10
        //samples left) take a chunk that eats the rest of the samples.

        samples++;          //Increment the number of samples we have
        if(samplesleft < (int)WindowSizeInt)
        {
            blocksize = samplesleft;
        }
        else
        {
            blocksize = WindowSizeInt;
        }

        erg = TestEnergy(t, i, blocksize);
        sumerg +=(double)erg;
        sumerg2 += pow((double)erg,2);

        sc = TestSignChanges(t,i, blocksize);
        sumsc += (double)sc;
        sumsc2 += pow((double)sc,2);


        dc = TestDirectionChanges(t,i,blocksize);
        sumdc += (double)dc;
        sumdc2 += pow((double)dc,2);



    }

    mEnergyMean = sumerg / samples;
    mEnergySD =  sqrt(sumerg2/samples - mEnergyMean*mEnergyMean);

    mSignChangesMean = sumsc / samples;
    mSignChangesSD = sqrt(sumsc2 / samples - mSignChangesMean * mSignChangesMean);

    mDirectionChangesMean = sumdc / samples;
    mDirectionChangesSD =sqrt(sumdc2 / samples - mDirectionChangesMean * mDirectionChangesMean) ;





    wxString text =   wxString::Format(_("Calibration Results\n"));
    /* i18n-hint: %1.4f is replaced by a number.  sd stands for 'Standard Deviations'*/
    text +=           wxString::Format(_("Energy                  -- mean: %1.4f  sd: (%1.4f)\n"),mEnergyMean,mEnergySD);
    text+=            wxString::Format(_("Sign Changes        -- mean: %1.4f  sd: (%1.4f)\n"),mSignChangesMean,mSignChangesSD);
    text+=            wxString::Format(_("Direction Changes  -- mean: %1.4f  sd: (%1.4f)\n"),mDirectionChangesMean,mDirectionChangesSD);
    wxMessageDialog  * stats =  new wxMessageDialog(NULL, text,
            wxT("Calibration Complete"),
            wxOK | wxICON_INFORMATION,
            wxPoint(-1,-1));
    stats->ShowModal();
    delete stats;

    AdjustThreshold(mThresholdAdjustment);
}
コード例 #25
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;
}
コード例 #26
0
ファイル: VoiceKey.cpp プロジェクト: henricj/audacity
//Move forward to find an ON region.
sampleCount VoiceKey::OnForward (WaveTrack & t, sampleCount start, sampleCount len)
{

   if((mWindowSize) >= (len + 10).as_double() ){

      /* i18n-hint: Voice key is an experimental/incomplete feature that
         is used to navigate in vocal recordings, to move forwards and
         backwards by words.  So 'key' is being used in the sense of an index.
         This error message means that you've selected too short
         a region of audio to be able to use this feature.*/
      wxMessageBox(_("Selection is too small to use voice key."));
      return start;
   }
   else {

      //Change the millisecond-based parameters into sample-based parameters
      double rate = t.GetRate();                                                     //Translates seconds to samples
      size_t WindowSizeInt = (rate  * mWindowSize);               //Size of window to examine
      size_t SignalWindowSizeInt = (rate  * mSignalWindowSize);   //This much signal is necessary to trip key

      auto samplesleft = len - WindowSizeInt;   //Indexes the number of samples remaining in the selection
      auto lastsubthresholdsample = start;          //start this off at the selection start
      // keeps track of the sample number of the last sample to not exceed the threshold

      int blockruns=0;                         //keeps track of the number of consecutive above-threshold blocks


      //This loop goes through the selection a block at a time.  If a long enough run
      //of above-threshold blocks occur, we return to the last sub-threshold block and
      //go through one sample at a time.
      //If there are fewer than 10 samples leftover, don't bother.

      for(auto i = start; samplesleft >= 10;
          i += (WindowSizeInt - 1) , samplesleft -= (WindowSizeInt - 1)) {

         //Set blocksize so that it is the right size
         const auto blocksize = limitSampleBufferSize( WindowSizeInt, samplesleft);

         //Test whether we are above threshold (the number of stats)
         if(AboveThreshold(t,i,blocksize))
            {
               blockruns++;                   //Hit
            } else {
               blockruns=0;                   //Miss--start over
               lastsubthresholdsample = i;
            }

         //If the blockrun is long enough, break out of the loop early:
         if(blockruns > mSignalWindowSize/mWindowSize)
            break;

      }

      //Now, if we broke out early (samplesleft > 10), go back to the lastsubthresholdsample and look more carefully
      if(samplesleft > 10) {


         //Calculate how many to scan through--we only have to go through (at most)
         //the first window + 1 samples--but we need another window samples to draw from.
         size_t remaining = 2*WindowSizeInt+1;

         //To speed things up, create a local buffer to store things in, to avoid the costly t.Get();
         //Only go through the first SignalWindowSizeInt samples, and choose the first that trips the key.
         float *buffer = new float[remaining];
         t.Get((samplePtr)buffer, floatSample, lastsubthresholdsample, remaining);



         //Initialize these trend markers atrend and ztrend.  They keep track of the
         //up/down trends at the start and end of the evaluation window.
         int atrend = sgn(buffer[1]-buffer[0]);
         int ztrend = sgn(buffer[WindowSizeInt+1]-buffer[WindowSizeInt]);


         double erg=0;
         double  sc=0;
         double  dc=0;

         //Get initial test statistic values.
         if(mUseEnergy)
            erg = TestEnergy(t, lastsubthresholdsample, WindowSizeInt);

         if(mUseSignChangesLow || mUseSignChangesHigh)
            sc  = TestSignChanges(t,lastsubthresholdsample, WindowSizeInt);

         if(mUseDirectionChangesLow || mUseDirectionChangesHigh)
            dc  = TestDirectionChanges(t,lastsubthresholdsample,WindowSizeInt);


         //Now, go through the sound again, sample by sample.
         wxASSERT(WindowSizeInt < SignalWindowSizeInt);
         size_t i;
         for(i = 0; i + WindowSizeInt < SignalWindowSizeInt; i++) {

            int tests = 0;
            int testThreshold = 0;
            //Update the test statistics
            if(mUseEnergy)
               {
                  TestEnergyUpdate(erg, WindowSizeInt,buffer[i],buffer[i+WindowSizeInt+1]);
                  tests += (int)(erg>mThresholdEnergy);
                  testThreshold++;
               }
            if(mUseSignChangesLow)
               {
                  TestSignChangesUpdate(sc,WindowSizeInt,buffer[i],buffer[i+1],buffer[i+WindowSizeInt],buffer[i+WindowSizeInt+1]);
                  tests += (int)(sc < mThresholdSignChangesLower);
                  testThreshold++;
               }

            if(mUseSignChangesHigh)
               {
                  TestSignChangesUpdate(sc,WindowSizeInt,buffer[i],buffer[i+1],buffer[i+WindowSizeInt],buffer[i+WindowSizeInt+1]);
                  tests += (int)(sc > mThresholdSignChangesUpper);
                  testThreshold++;
               }

            if(mUseDirectionChangesLow)
               {
                  TestDirectionChangesUpdate(dc,WindowSizeInt,atrend,buffer[i],buffer[i+1],ztrend,buffer[i+WindowSizeInt],buffer[i+WindowSizeInt+1]);
                  tests += (int)(dc < mThresholdDirectionChangesLower);
                  testThreshold++;
               }

            if(mUseDirectionChangesHigh)
               {
                  TestDirectionChangesUpdate(dc,WindowSizeInt,atrend,buffer[i],buffer[i+1],ztrend,buffer[i+WindowSizeInt],buffer[i+WindowSizeInt+1]);
                  tests += (int)(dc > mThresholdDirectionChangesUpper);
                  testThreshold++;
               }



            if(tests >= testThreshold)
               {	//Finish off on the first hit
                  break;
               }
         }

         //When we get here, i+lastsubthresholdsample is the best guess for where the word starts
         delete [] buffer;
         return i + lastsubthresholdsample;
      }
      else {
         //If we failed to find anything, return the start position
         return start ;
      }
   }
}
コード例 #27
0
ファイル: VoiceKey.cpp プロジェクト: henricj/audacity
//This 'calibrates' the voicekey to noise
void VoiceKey::CalibrateNoise(WaveTrack & t, sampleCount start, sampleCount len)
{
   //To calibrate the noise, we need to scan the sample block just like in the voicekey and
   //calculate the mean and standard deviation of the test statistics.
   //Then, we set the BaselineThreshold to be one

   wxBusyCursor busy;

   //initialize some sample statistics: sums of X and X^2

   double sumerg, sumerg2;
   double sumsc, sumsc2;
   double sumdc, sumdc2;
   double erg, sc, dc;
   //Now, change the millisecond-based parameters into sample-based parameters
   //(This depends on WaveTrack t)
   double rate = t.GetRate();
   unsigned int WindowSizeInt = (unsigned int)(rate  * mWindowSize);
   //   unsigned int SignalWindowSizeInt = (unsigned int)(rate  * mSignalWindowSize);


   //Get the first test statistics

   //Calibrate all of the statistic, because they might be
   //changed later.

   //   if(mUseEnergy)
   erg = TestEnergy(t, start, WindowSizeInt);

   //   if(mUseSignChanges)
   sc = TestSignChanges(t,start, WindowSizeInt);

   //   if(mUseDirectionChanges)
   dc = TestDirectionChanges(t,start,WindowSizeInt);

   sumerg =0.0;
   sumerg2 = 0.0;
   sumsc =0.0;
   sumsc2 = 0.0;
   sumdc =0.0;
   sumdc2 =0.0;


   //	int n = len - WindowSizeInt;        //This is how many samples we have
   auto samplesleft = len - WindowSizeInt;
   int samples=0;

   for(auto i = start; samplesleft >= 10;
       i += (WindowSizeInt - 1), samplesleft -= (WindowSizeInt -1) ) {
         //Take samples chunk-by-chunk.
         //Normally, this should be in WindowSizeInt chunks, but at the end (if there are more than 10
         //samples left) take a chunk that eats the rest of the samples.

         samples++;          //Increment the number of samples we have
         const auto blocksize = limitSampleBufferSize( WindowSizeInt, samplesleft);

         erg = TestEnergy(t, i, blocksize);
         sumerg +=(double)erg;
         sumerg2 += pow((double)erg,2);

         sc = TestSignChanges(t,i, blocksize);
         sumsc += (double)sc;
         sumsc2 += pow((double)sc,2);


         dc = TestDirectionChanges(t,i,blocksize);
         sumdc += (double)dc;
         sumdc2 += pow((double)dc,2);
      }

   mEnergyMean = sumerg / samples;
   mEnergySD =  sqrt(sumerg2/samples - mEnergyMean*mEnergyMean);

   mSignChangesMean = sumsc / samples;
   mSignChangesSD = sqrt(sumsc2 / samples - mSignChangesMean * mSignChangesMean);

   mDirectionChangesMean = sumdc / samples;
   mDirectionChangesSD =sqrt(sumdc2 / samples - mDirectionChangesMean * mDirectionChangesMean) ;

   wxString text =   wxString::Format(_("Calibration Results\n"));
   /* i18n-hint: %1.4f is replaced by a number.  sd stands for 'Standard Deviations'*/
   text +=           wxString::Format(_("Energy                  -- mean: %1.4f  sd: (%1.4f)\n"),mEnergyMean,mEnergySD);
   text+=            wxString::Format(_("Sign Changes        -- mean: %1.4f  sd: (%1.4f)\n"),mSignChangesMean,mSignChangesSD);
   text += wxString::Format(_("Direction Changes  -- mean: %1.4f  sd: (%1.4f)\n"), mDirectionChangesMean, mDirectionChangesSD);
   wxMessageDialog{ NULL, text,
      wxT("Calibration Complete"),
      wxOK | wxICON_INFORMATION,
      wxPoint(-1, -1) }
   .ShowModal();

   AdjustThreshold(mThresholdAdjustment);
}
コード例 #28
0
ファイル: Noise.cpp プロジェクト: ruthmagnus/audacity
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;
}
コード例 #29
0
ファイル: VSTEffect.cpp プロジェクト: ruthmagnus/audacity
bool VSTEffect::Process()
{
   CopyInputTracks();
   bool bGoodResult = true;

   mInBuffer = NULL;
   mOutBuffer = NULL;

   TrackListIterator iter(mOutputTracks);
   int count = 0;
   bool clear = false;
   WaveTrack *left = (WaveTrack *) iter.First();
   while (left) {
      WaveTrack *right;
      sampleCount len;
      sampleCount lstart;
      sampleCount rstart;

      GetSamples(left, &lstart, &len);

      mChannels = 1;

      right = NULL;
      rstart = 0;
      if (left->GetLinked() && mInputs > 1) {
         right = (WaveTrack *) iter.Next();         
         GetSamples(right, &rstart, &len);
         clear = false;
         mChannels = 2;
      }

      if (mBlockSize == 0) {
         mBlockSize = left->GetMaxBlockSize() * 2;

         // Some VST effects (Antress Modern is an example), do not like
         // overly large block sizes.  Unfortunately, I have not found a
         // way to determine if the effect has a maximum it will support,
         // so just limit to small value for now.  This will increase
         // processing time and, it's a shame, because most plugins seem
         // to be able to handle much larger sizes.
         if (mBlockSize > 8192) { // The Antress limit
            mBlockSize = 8192;
         }

         mInBuffer = new float *[mInputs];
         for (int i = 0; i < mInputs; i++) {
            mInBuffer[i] = new float[mBlockSize];
         }

         mOutBuffer = new float *[mOutputs];
         for (int i = 0; i < mOutputs; i++) {
            mOutBuffer[i] = new float[mBlockSize];
         }

         // Turn the power off
         callDispatcher(effMainsChanged, 0, 0, NULL, 0.0);

         // Set processing parameters
         callDispatcher(effSetSampleRate, 0, 0, NULL, left->GetRate());
         callDispatcher(effSetBlockSize, 0, mBlockSize, NULL, 0.0);
      }

      // Clear unused input buffers
      if (!right && !clear) {
         for (int i = 1; i < mInputs; i++) {
            for (int j = 0; j < mBlockSize; j++) {
               mInBuffer[i][j] = 0.0;
            }
         }
         clear = true;
      }

      bGoodResult = ProcessStereo(count, left, right, lstart, rstart, len);
      if (!bGoodResult) {
         break;
      }

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

   if (mOutBuffer) {
      for (int i = 0; i < mOutputs; i++) {
         delete mOutBuffer[i];
      }
      delete [] mOutBuffer;
      mOutBuffer = NULL;
   }

   if (mInBuffer) {
      for (int i = 0; i < mInputs; i++) {
         delete mInBuffer[i];
      }
      delete [] mInBuffer;
      mInBuffer = NULL;
   }

   ReplaceProcessedTracks(bGoodResult); 
   return bGoodResult;
}
コード例 #30
0
ファイル: Mix.cpp プロジェクト: ruthmagnus/audacity
sampleCount Mixer::Process(int maxToProcess)
{
   if (mT >= mT1)
      return 0;
   
   int i, j;
   sampleCount out;
   sampleCount maxOut = 0;
   int *channelFlags = new int[mNumChannels];

   mMaxOut = maxToProcess;

   Clear();
   for(i=0; i<mNumInputTracks; i++) {
      WaveTrack *track = mInputTrack[i];
      for(j=0; j<mNumChannels; j++)
         channelFlags[j] = 0;

      if( mMixerSpec ) {
         //ignore left and right when downmixing is not required
         for( j = 0; j < mNumChannels; j++ )
            channelFlags[ j ] = mMixerSpec->mMap[ i ][ j ] ? 1 : 0;
      }
      else {
         switch(track->GetChannel()) {
         case Track::MonoChannel:
         default:
            for(j=0; j<mNumChannels; j++)
               channelFlags[j] = 1;
            break;
         case Track::LeftChannel:
            channelFlags[0] = 1;
            break;
         case Track::RightChannel:
            if (mNumChannels >= 2)
               channelFlags[1] = 1;
            else
               channelFlags[0] = 1;
            break;
         }
      }

      if (mTimeTrack ||
          track->GetRate() != mRate)
         out = MixVariableRates(channelFlags, track,
                                &mSamplePos[i], mSampleQueue[i],
                                &mQueueStart[i], &mQueueLen[i], mSRC[i]);
      else
         out = MixSameRate(channelFlags, track, &mSamplePos[i]);

      if (out > maxOut)
         maxOut = out;
   }
   out = mInterleaved ? maxOut * mNumChannels : maxOut;
   for(int c=0; c<mNumBuffers; c++)
      CopySamples(mTemp[c], floatSample, mBuffer[c], mFormat, out);

   mT += (maxOut / mRate);

   delete [] channelFlags; 

   return maxOut;
}