Beispiel #1
0
size_t EffectBassTreble::InstanceProcess(EffectBassTrebleState & data,
                                              float **inBlock,
                                              float **outBlock,
                                              size_t blockLen)
{
   float *ibuf = inBlock[0];
   float *obuf = outBlock[0];

   // Set value to ensure correct rounding
   double oldBass = DB_TO_LINEAR(mBass);
   double oldTreble = DB_TO_LINEAR(mTreble);

   data.gain = DB_TO_LINEAR(mGain);

   // Compute coefficents of the low shelf biquand IIR filter
   if (data.bass != oldBass)
      Coefficents(data.hzBass, data.slope, mBass, data.samplerate, kBass,
                  data.a0Bass, data.a1Bass, data.a2Bass,
                  data.b0Bass, data.b1Bass, data.b2Bass);

   // Compute coefficents of the high shelf biquand IIR filter
   if (data.treble != oldTreble)
      Coefficents(data.hzTreble, data.slope, mTreble, data.samplerate, kTreble,
                  data.a0Treble, data.a1Treble, data.a2Treble,
                  data.b0Treble, data.b1Treble, data.b2Treble);

   for (decltype(blockLen) i = 0; i < blockLen; i++) {
      obuf[i] = DoFilter(data, ibuf[i]) * data.gain;
   }

   return blockLen;
}
Beispiel #2
0
bool EffectCompressor::NewTrackPass1()
{
   mThreshold = DB_TO_LINEAR(mThresholdDB);
   mNoiseFloor = DB_TO_LINEAR(mNoiseFloorDB);
   mNoiseCounter = 100;

   mAttackInverseFactor = exp(log(mThreshold) / (mCurRate * mAttackTime + 0.5));
   mAttackFactor = 1.0 / mAttackInverseFactor;
   mDecayFactor = exp(log(mThreshold) / (mCurRate * mDecayTime + 0.5));

   if(mRatio > 1)
      mCompression = 1.0-1.0/mRatio;
   else
      mCompression = 0.0;

   mLastLevel = mThreshold;

   if (mCircle)
      delete[] mCircle;
   mCircleSize = 100;
   mCircle = new double[mCircleSize];
   for(int j=0; j<mCircleSize; j++) {
      mCircle[j] = 0.0;
   }
   mCirclePos = 0;
   mRMSSum = 0.0;

   return true;
}
Beispiel #3
0
void EffectDistortion::Leveller()
{
   double noiseFloor = DB_TO_LINEAR(mParams.mNoiseFloor);
   int numPasses = mParams.mRepeats;
   double fractionalPass = mParams.mParam1 / 100.0;

   const int numPoints = 6;
   const double gainFactors[numPoints] = { 0.80, 1.00, 1.20, 1.20, 1.00, 0.80 };
   double gainLimits[numPoints] = { 0.0001, 0.0, 0.1, 0.3, 0.5, 1.0 };
   double addOnValues[numPoints];

   gainLimits[1] = noiseFloor;
   /* In the original Leveller effect, behaviour was undefined for threshold > 20 dB.
    * If we want to support > 20 dB we need to scale the points to keep them non-decreasing.
    * 
    * if (noiseFloor > gainLimits[2]) {
    *    for (int i = 3; i < numPoints; i++) {
    *    gainLimits[i] = noiseFloor + ((1 - noiseFloor)*((gainLimits[i] - 0.1) / 0.9));
    * }
    * gainLimits[2] = noiseFloor;
    * }
    */

   // Calculate add-on values
   addOnValues[0] = 0.0;
   for (int i = 0; i < numPoints-1; i++) {
      addOnValues[i+1] = addOnValues[i] + (gainLimits[i] * (gainFactors[i] - gainFactors[1 + i]));
   }

   // Positive half of table.
   // The original effect increased the 'strength' of the effect by
   // repeated passes over the audio data.
   // Here we model that more efficiently by repeated passes over a linear table.
   for (int n = STEPS; n < TABLESIZE; n++) {
      mTable[n] = ((double) (n - STEPS) / (double) STEPS);
      for (int i = 0; i < numPasses; i++) {
         // Find the highest index for gain adjustment
         int index = numPoints - 1;
         for (int i = index; i >= 0 && mTable[n] < gainLimits[i]; i--) {
            index = i;
         }
         // the whole number of 'repeats'
         mTable[n] = (mTable[n] * gainFactors[index]) + addOnValues[index];
      }
      // Extrapolate for fine adjustment.
      // tiny fractions are not worth the processing time
      if (fractionalPass > 0.001) {
         int index = numPoints - 1;
         for (int i = index; i >= 0 && mTable[n] < gainLimits[i]; i--) {
            index = i;
         }
         mTable[n] += fractionalPass * ((mTable[n] * (gainFactors[index] - 1)) + addOnValues[index]);
      }
   }
   CopyHalfTable();
}
Beispiel #4
0
EffectAmplify::EffectAmplify()
{
   mAmp = DEF_Amp;
   mRatio = DB_TO_LINEAR(mAmp);
   mRatioClip = 0.0;
   mCanClip = false;
   mPeak = 0.0;

   SetLinearEffectFlag(true);
}
Beispiel #5
0
bool EffectDistortion::TransferDataFromWindow()
{
   if (!mUIParent->Validate() || !mUIParent->TransferDataFromWindow())
   {
      return false;
   }

   mThreshold = DB_TO_LINEAR(mParams.mThreshold_dB);

   return true;
}
Beispiel #6
0
void EffectAmplify::OnAmpSlider(wxCommandEvent & evt)
{
   double dB = evt.GetInt() / SCL_Amp;
   mRatio = DB_TO_LINEAR(TrapDouble(dB, MIN_Amp, MAX_Amp));

   double dB2 = (evt.GetInt() - 1) / SCL_Amp;
   double ratio2 = DB_TO_LINEAR(TrapDouble(dB2, MIN_Amp, MAX_Amp));

   if (!mClip->GetValue() && mRatio * mPeak > 1.0 && ratio2 * mPeak < 1.0)
   {
      mRatio = 1.0 / mPeak;
   }

   mAmp = LINEAR_TO_DB(mRatio);
   mAmpT->GetValidator()->TransferToWindow();

   mNewPeak = LINEAR_TO_DB(mRatio * mPeak);
   mNewPeakT->GetValidator()->TransferToWindow();

   CheckClip();
}
Beispiel #7
0
void EffectDistortion::ExponentialTable()
{
   double amount = std::min(0.999, DB_TO_LINEAR(-1 * mParams.mParam1));   // avoid divide by zero

   for (int n = STEPS; n < TABLESIZE; n++) {
      double linVal = n/(float)STEPS;
      double scale = -1.0 / (1.0 - amount);   // unity gain at 0dB
      double curve = std::exp((linVal - 1) * std::log(amount));
      mTable[n] = scale * (curve -1);
   }
   CopyHalfTable();
}
Beispiel #8
0
size_t EffectPhaser::InstanceProcess(EffectPhaserState & data, float **inBlock, float **outBlock, size_t blockLen)
{
   float *ibuf = inBlock[0];
   float *obuf = outBlock[0];

   for (int j = data.laststages; j < mStages; j++)
   {
      data.old[j] = 0;
   }
   data.laststages = mStages;

   data.lfoskip = mFreq * 2 * M_PI / data.samplerate;
   data.phase = mPhase * M_PI / 180;
   data.outgain = DB_TO_LINEAR(mOutGain);

   for (decltype(blockLen) i = 0; i < blockLen; i++)
   {
      double in = ibuf[i];

      double m = in + data.fbout * mFeedback / 101;  // Feedback must be less than 100% to avoid infinite gain.

      if (((data.skipcount++) % lfoskipsamples) == 0)
      {
         //compute sine between 0 and 1
         data.gain =
            (1.0 +
             cos(data.skipcount.as_double() * data.lfoskip
                 + data.phase)) / 2.0;

         // change lfo shape
         data.gain = expm1(data.gain * phaserlfoshape) / expm1(phaserlfoshape);

         // attenuate the lfo
         data.gain = 1.0 - data.gain / 255.0 * mDepth;
      }

      // phasing routine
      for (int j = 0; j < mStages; j++)
      {
         double tmp = data.old[j];
         data.old[j] = data.gain * tmp + m;
         m = tmp - data.gain * data.old[j];
      }
      data.fbout = m;

      obuf[i] = (float) (data.outgain * (m * mDryWet + in * (255 - mDryWet)) / 255);
   }

   return blockLen;
}
Beispiel #9
0
void EffectAmplify::OnPeakText(wxCommandEvent & WXUNUSED(evt))
{
   if (!mNewPeakT->GetValidator()->TransferFromWindow())
   {
      EnableApply(false);
      return;
   }

   if (mNewPeak == 0.0)
      mRatio = mRatioClip;
   else
      mRatio = DB_TO_LINEAR(mNewPeak) / mPeak;

   double ampInit = LINEAR_TO_DB(mRatio);
   mAmp = TrapDouble(ampInit, MIN_Amp, MAX_Amp);
   if (mAmp != ampInit)
      mRatio = DB_TO_LINEAR(mAmp);

   mAmpT->GetValidator()->TransferToWindow();

   mAmpS->SetValue((int) (mAmp * SCL_Amp + 0.5f));

   CheckClip();
}
Beispiel #10
0
bool EffectCompressor::NewTrackPass1()
{
   mThreshold = DB_TO_LINEAR(mThresholdDB);
   mNoiseFloor = DB_TO_LINEAR(mNoiseFloorDB);
   mNoiseCounter = 100;

   mAttackInverseFactor = exp(log(mThreshold) / (mCurRate * mAttackTime + 0.5));
   mAttackFactor = 1.0 / mAttackInverseFactor;
   mDecayFactor = exp(log(mThreshold) / (mCurRate * mDecayTime + 0.5));

   if(mRatio > 1)
      mCompression = 1.0-1.0/mRatio;
   else
      mCompression = 0.0;

   mLastLevel = mThreshold;

   mCircleSize = 100;
   mCircle.reinit( mCircleSize, true );
   mCirclePos = 0;
   mRMSSum = 0.0;

   return true;
}
static void
gst_rg_volume_update_gain (GstRgVolume * self)
{
  gdouble target_gain, result_gain, result_volume;
  gboolean target_gain_changed, result_gain_changed;

  gst_rg_volume_determine_gain (self, &target_gain, &result_gain);

  result_volume = DB_TO_LINEAR (result_gain);

  /* Ensure that the result volume is within the range that the volume element
   * can handle.  Currently, the limit is 10. (+20 dB), which should not be
   * restrictive. */
  if (G_UNLIKELY (result_volume > self->max_volume)) {
    GST_INFO_OBJECT (self,
        "cannot handle result gain of %" GAIN_FORMAT " (%0.6f), adjusting",
        result_gain, result_volume);

    result_volume = self->max_volume;
    result_gain = LINEAR_TO_DB (result_volume);
  }

  /* Direct comparison is OK in this case. */
  if (target_gain == result_gain) {
    GST_INFO_OBJECT (self,
        "result gain is %" GAIN_FORMAT " (%0.6f), matching target",
        result_gain, result_volume);
  } else {
    GST_INFO_OBJECT (self,
        "result gain is %" GAIN_FORMAT " (%0.6f), target is %" GAIN_FORMAT,
        result_gain, result_volume, target_gain);
  }

  target_gain_changed = (self->target_gain != target_gain);
  result_gain_changed = (self->result_gain != result_gain);

  self->target_gain = target_gain;
  self->result_gain = result_gain;

  g_object_set (self->volume_element, "volume", result_volume, NULL);

  if (target_gain_changed)
    g_object_notify ((GObject *) self, "target-gain");
  if (result_gain_changed)
    g_object_notify ((GObject *) self, "result-gain");
}
Beispiel #12
0
bool EffectDistortion::LoadFactoryPreset(int id)
{
   if (id < 0 || id >= (int) WXSIZEOF(FactoryPresets))
   {
      return false;
   }

   mParams = FactoryPresets[id].params;
   mThreshold = DB_TO_LINEAR(mParams.mThreshold_dB);

   if (mUIDialog)
   {
      TransferDataToWindow();
   }

   return true;
}
Beispiel #13
0
size_t EffectWahwah::InstanceProcess(EffectWahwahState & data, float **inBlock, float **outBlock, size_t blockLen)
{
   float *ibuf = inBlock[0];
   float *obuf = outBlock[0];
   double frequency, omega, sn, cs, alpha;
   double in, out;

   data.lfoskip = mFreq * 2 * M_PI / data.samplerate;
   data.depth = mDepth / 100.0;
   data.freqofs = mFreqOfs / 100.0;

   data.phase = mPhase * M_PI / 180.0;
   data.outgain = DB_TO_LINEAR(mOutGain);

   for (decltype(blockLen) i = 0; i < blockLen; i++)
   {
      in = (double) ibuf[i];

      if ((data.skipcount++) % lfoskipsamples == 0)
      {
         frequency = (1 + cos(data.skipcount * data.lfoskip + data.phase)) / 2;
         frequency = frequency * data.depth * (1 - data.freqofs) + data.freqofs;
         frequency = exp((frequency - 1) * 6);
         omega = M_PI * frequency;
         sn = sin(omega);
         cs = cos(omega);
         alpha = sn / (2 * mRes);
         data.b0 = (1 - cs) / 2;
         data.b1 = 1 - cs;
         data.b2 = (1 - cs) / 2;
         data.a0 = 1 + alpha;
         data.a1 = -2 * cs;
         data.a2 = 1 - alpha;
      };
      out = (data.b0 * in + data.b1 * data.xn1 + data.b2 * data.xn2 - data.a1 * data.yn1 - data.a2 * data.yn2) / data.a0;
      data.xn2 = data.xn1;
      data.xn1 = in;
      data.yn2 = data.yn1;
      data.yn1 = out;
      out *= data.outgain;

      obuf[i] = (float) out;
   }

   return blockLen;
}
AUDMAudioFilterNormalize::AUDMAudioFilterNormalize(AUDMAudioFilter * instream,GAINparam *param):AUDMAudioFilter (instream)
{
  float db_out;
    // nothing special here...
  switch(param->mode)
  {
    case ADM_NO_GAIN: _ratio=1;_scanned=1;printf("[Gain] Gain of 1.0\n");break; 
    case ADM_GAIN_AUTOMATIC: _ratio=1;_scanned=0;printf("[Gain] Automatic gain\n");break;
    case ADM_GAIN_MANUAL: 
                _scanned=1;
                db_out =  param->gain10/10.0; // Dbout is in 10*DB (!)
                _ratio = DB_TO_LINEAR(db_out);
                printf("[Gain] %f db (p=%d)\n", (float)(param->gain10)/10.,param->gain10);
                printf("[Gain] Linear ratio of : %03.3f\n", _ratio);
  }
    _previous->rewind();
};
Beispiel #15
0
void EffectAmplify::OnAmpText(wxCommandEvent & WXUNUSED(evt))
{
   if (!mAmpT->GetValidator()->TransferFromWindow())
   {
      EnableApply(false);
      return;
   }

   mRatio = DB_TO_LINEAR(TrapDouble(mAmp * SCL_Amp, MIN_Amp * SCL_Amp, MAX_Amp * SCL_Amp) / SCL_Amp);

   mAmpS->SetValue((int) (LINEAR_TO_DB(mRatio) * SCL_Amp + 0.5));

   mNewPeak = LINEAR_TO_DB(mRatio * mPeak);
   mNewPeakT->GetValidator()->TransferToWindow();

   CheckClip();
}
Beispiel #16
0
bool EffectAmplify::TransferDataFromWindow()
{
   if (!mUIParent->Validate() || !mUIParent->TransferDataFromWindow())
   {
      return false;
   }

   mRatio = DB_TO_LINEAR(TrapDouble(mAmp * SCL_Amp, MIN_Amp * SCL_Amp, MAX_Amp * SCL_Amp) / SCL_Amp);

   mCanClip = mClip->GetValue();

   if (!mCanClip && mRatio * mPeak > 1.0)
   {
      mRatio = 1.0 / mPeak;
   }

   return true;
}
bool SetTrackAudioCommand::ApplyInner(const CommandContext & context, Track * t )
{
   static_cast<void>(context);
   auto wt = dynamic_cast<WaveTrack *>(t);
   auto pt = dynamic_cast<PlayableTrack *>(t);

   if( wt && bHasGain )
      wt->SetGain(DB_TO_LINEAR(mGain));
   if( wt && bHasPan )
      wt->SetPan(mPan/100.0);

   // These ones don't make sense on the second channel of a stereo track.
   if( !bIsSecondChannel ){
      if( pt && bHasSolo )
         pt->SetSolo(bSolo);
      if( pt && bHasMute )
         pt->SetMute(bMute);
   }
   return true;
}
Beispiel #18
0
void EffectWahwah::InstanceInit(EffectWahwahState & data, float sampleRate)
{
   data.samplerate = sampleRate;
   data.lfoskip = mFreq * 2 * M_PI / sampleRate;
   data.skipcount = 0;
   data.xn1 = 0;
   data.xn2 = 0;
   data.yn1 = 0;
   data.yn2 = 0;
   data.b0 = 0;
   data.b1 = 0;
   data.b2 = 0;
   data.a0 = 0;
   data.a1 = 0;
   data.a2 = 0;

   data.depth = mDepth / 100.0;
   data.freqofs = mFreqOfs / 100.0;
   data.phase = mPhase * M_PI / 180.0;
   data.outgain = DB_TO_LINEAR(mOutGain);
}
Beispiel #19
0
bool EffectAmplify::TransferDataToWindow()
{
   // limit range of gain
   double dBInit = LINEAR_TO_DB(mRatio);
   double dB = TrapDouble(dBInit, MIN_Amp, MAX_Amp);
   if (dB != dBInit)
      mRatio = DB_TO_LINEAR(dB);

   mAmp = LINEAR_TO_DB(mRatio);
   mAmpT->GetValidator()->TransferToWindow();

   mAmpS->SetValue((int) (mAmp * SCL_Amp + 0.5f));

   mNewPeak = LINEAR_TO_DB(mRatio * mPeak);
   mNewPeakT->GetValidator()->TransferToWindow();

   mClip->SetValue(mCanClip);

   CheckClip();

   return true;
}
Beispiel #20
0
EffectDistortion::EffectDistortion()
{
   wxASSERT(kNumTableTypes == WXSIZEOF(kTableTypeStrings));

   mParams.mTableChoiceIndx = DEF_TableTypeIndx;
   mParams.mDCBlock = DEF_DCBlock;
   mParams.mThreshold_dB = DEF_Threshold_dB;
   mThreshold = DB_TO_LINEAR(mParams.mThreshold_dB);
   mParams.mNoiseFloor = DEF_NoiseFloor;
   mParams.mParam1 = DEF_Param1;
   mParams.mParam2 = DEF_Param2;
   mParams.mRepeats = DEF_Repeats;
   mMakeupGain = 1.0;
   mbSavedFilterState = DEF_DCBlock;

   for (int i = 0; i < kNumTableTypes; i++)
   {
      mTableTypes.Add(wxGetTranslation(kTableTypeStrings[i]));
   }

   SetLinearEffectFlag(false);
}
Beispiel #21
0
void EffectBassTreble::InstanceInit(EffectBassTrebleState & data, float sampleRate)
{
   data.samplerate = sampleRate;
   data.slope = 0.4f;   // same slope for both filters
   data.hzBass = 250.0f;   // could be tunable in a more advanced version
   data.hzTreble = 4000.0f;   // could be tunable in a more advanced version

   data.a0Bass = 1;
   data.a1Bass = 0;
   data.a2Bass = 0;
   data.b0Bass = 0;
   data.b1Bass = 0;
   data.b2Bass = 0;

   data.a0Treble = 1;
   data.a1Treble = 0;
   data.a2Treble = 0;
   data.b0Treble = 0;
   data.b1Treble = 0;
   data.b2Treble = 0;

   data.xn1Bass = 0;
   data.xn2Bass = 0;
   data.yn1Bass = 0;
   data.yn2Bass = 0;

   data.xn1Treble = 0;
   data.xn2Treble = 0;
   data.yn1Treble = 0;
   data.yn2Treble = 0;

   data.bass = -1;
   data.treble = -1;
   data.gain = DB_TO_LINEAR(mGain);

}
//
// For normalize, we scan the input stream
// to check for maximum value
//___________________________________________
uint8_t AUDMAudioFilterNormalize::preprocess(void)
{

    int16_t *ptr;
    uint32_t scanned = 0, ch = 0;
    AUD_Status status;
    _ratio = 0;

    uint32_t percent=0;
    uint32_t current=0,llength=0;
    float max[_wavHeader.channels];
    _previous->rewind();
    DolbySkip(1);
    printf("\n Seeking for maximum value, that can take a while\n");

    llength=_length ;
    

      for(int i=0;i<_wavHeader.channels;i++) max[i]=0;
      while (1)
      {
          int ready=_previous->fill(AUD_PROCESS_BUFFER_SIZE>>2,_incomingBuffer,&status);
          if(!ready)
          {
            if(status==AUD_END_OF_STREAM) 
            {
              break; 
            }
           else 
            {
              printf("Unknown cause : %d\n",status);
              ADM_assert(0); 
            }
          }
          ADM_assert(!(ready %_wavHeader.channels));
          
          int index=0;
          float current;
          
        //  printf("*\n");
          int sample= ready /_wavHeader.channels;
          for(int j=0;j<sample;j++)
            for(int chan=0;chan<_wavHeader.channels;chan++)
          {
            current=fabs(_incomingBuffer[index++]);
            if(current>max[chan]) max[chan]=current;
          }
          scanned+=ready;
      }
      
      
      

    _previous->rewind();
    float mx=0;
    for(int chan=0;chan<_wavHeader.channels;chan++)
    {
        if(max[chan]>mx) mx=max[chan];
        printf("[Normalize] maximum found for channel %d : %f\n", chan,max[chan]);
    }
    printf("[Normalize] Using : %0.4f as max value \n", mx);
    double db_in, db_out=-3;

    if (mx>0.001)
      db_in = LINEAR_TO_DB(mx);
    else
      db_in = -20; // We consider -20 DB to be noise

    printf("--> %2.2f db / %2.2f \n", db_in, db_out);

    // search ratio
    _ratio=1;

    float db_delta=db_out-db_in;
    printf("[Normalize]Gain %f dB\n",db_delta);
    _ratio = DB_TO_LINEAR(db_delta);
    printf("\n Using ratio of : %f\n", _ratio);

    _scanned = 1;
    DolbySkip(0);
    _previous->rewind();
    return 1;
}
// this currently does an exponential fade
bool EffectAutoDuck::ApplyDuckFade(int trackNumber, WaveTrack* t,
                                   double t0, double t1)
{
   bool cancel = false;

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

   float *buf = new float[kBufSize];
   sampleCount pos = start;

   int fadeDownSamples = t->TimeToLongSamples(
      mOuterFadeDownLen + mInnerFadeDownLen);
   if (fadeDownSamples < 1)
      fadeDownSamples = 1;

   int fadeUpSamples = t->TimeToLongSamples(
      mOuterFadeUpLen + mInnerFadeUpLen);
   if (fadeUpSamples < 1)
      fadeUpSamples = 1;

   float fadeDownStep = mDuckAmountDb / fadeDownSamples;
   float fadeUpStep = mDuckAmountDb / fadeUpSamples;

   while (pos < end)
   {
      sampleCount len = end - pos;
      if (len > kBufSize)
         len = kBufSize;

      t->Get((samplePtr)buf, floatSample, pos, len);

      for (sampleCount i = pos; i < pos + len; i++)
      {
         float gainDown = fadeDownStep * (i - start);
         float gainUp = fadeUpStep * (end - i);;

         float gain;
         if (gainDown > gainUp)
            gain = gainDown;
         else
            gain = gainUp;
         if (gain < mDuckAmountDb)
            gain = mDuckAmountDb;

         buf[i - pos] *= DB_TO_LINEAR(gain);
      }

      t->Set((samplePtr)buf, floatSample, pos, len);

      pos += len;

      float curTime = t->LongSamplesToTime(pos);
      float fractionFinished = (curTime - mT0) / (mT1 - mT0);
      if (TotalProgress( (trackNumber + 1 + fractionFinished) /
                         (GetNumWaveTracks() + 1) ))
      {
         cancel = true;
         break;
      }
   }

   delete[] buf;
   return cancel;
}
bool EffectAutoDuck::Process()
{
   sampleCount i;

   if (GetNumWaveTracks() == 0 || !mControlTrack)
      return false;

   bool cancel = false;

   sampleCount start =
      mControlTrack->TimeToLongSamples(mT0 + mOuterFadeDownLen);
   sampleCount end =
      mControlTrack->TimeToLongSamples(mT1 - mOuterFadeUpLen);

   if (end <= start)
      return false;

   // the minimum number of samples we have to wait until the maximum
   // pause has been exceeded
   double maxPause = mMaximumPause;

   // We don't fade in until we have time enough to actually fade out again
   if (maxPause < mOuterFadeDownLen + mOuterFadeUpLen)
      maxPause = mOuterFadeDownLen + mOuterFadeUpLen;

   sampleCount minSamplesPause =
      mControlTrack->TimeToLongSamples(maxPause);

   double threshold = DB_TO_LINEAR(mThresholdDb);

   // adjust the threshold so we can compare it to the rmsSum value
   threshold = threshold * threshold * kRMSWindowSize;

   int rmsPos = 0;
   float rmsSum = 0;
   float *rmsWindow = new float[kRMSWindowSize];
   for (i = 0; i < kRMSWindowSize; i++)
      rmsWindow[i] = 0;

   float *buf = new float[kBufSize];

   bool inDuckRegion = false;

   // initialize the following two variables to prevent compiler warning
   double duckRegionStart = 0;
   sampleCount curSamplesPause = 0;

   // to make the progress bar appear more natural, we first look for all
   // duck regions and apply them all at once afterwards
   AutoDuckRegionArray regions;
   sampleCount pos = start;

   while (pos < end)
   {
      sampleCount len = end - pos;
      if (len > kBufSize)
         len = kBufSize;

      mControlTrack->Get((samplePtr)buf, floatSample, pos, (sampleCount)len);

      for (i = pos; i < pos + len; i++)
      {
         rmsSum -= rmsWindow[rmsPos];
         rmsWindow[rmsPos] = buf[i - pos] * buf[i - pos];
         rmsSum += rmsWindow[rmsPos];
         rmsPos = (rmsPos + 1) % kRMSWindowSize;

         bool thresholdExceeded = rmsSum > threshold;

         if (thresholdExceeded)
         {
            // everytime the threshold is exceeded, reset our count for
            // the number of pause samples
            curSamplesPause = 0;

            if (!inDuckRegion)
            {
               // the threshold has been exceeded for the first time, so
               // let the duck region begin here
               inDuckRegion = true;
               duckRegionStart = mControlTrack->LongSamplesToTime(i);
            }
         }

         if (!thresholdExceeded && inDuckRegion)
         {
            // the threshold has not been exceeded and we are in a duck
            // region, but only fade in if the maximum pause has been
            // exceeded
            curSamplesPause += 1;

            if (curSamplesPause >= minSamplesPause)
            {
               // do the actual duck fade and reset all values
               double duckRegionEnd =
                  mControlTrack->LongSamplesToTime(i - curSamplesPause);

               regions.Add(AutoDuckRegion(
                              duckRegionStart - mOuterFadeDownLen,
                              duckRegionEnd + mOuterFadeUpLen));

               inDuckRegion = false;
            }
         }
      }

      pos += len;

      if (TotalProgress( ((double)(pos-start)) / (end-start) /
                         (GetNumWaveTracks() + 1) ))
      {
         cancel = true;
         break;
      }
   }

   // apply last duck fade, if any
   if (inDuckRegion)
   {
      double duckRegionEnd =
         mControlTrack->LongSamplesToTime(end - curSamplesPause);
      regions.Add(AutoDuckRegion(
                     duckRegionStart - mOuterFadeDownLen,
                     duckRegionEnd + mOuterFadeUpLen));
   }

   delete[] buf;
   delete[] rmsWindow;

   if (!cancel)
   {
      CopyInputTracks(); // Set up mOutputTracks.
      SelectedTrackListOfKindIterator iter(Track::Wave, mOutputTracks);
      Track *iterTrack = iter.First();

      int trackNumber = 0;

      while (iterTrack)
      {
         wxASSERT(iterTrack->GetKind() == Track::Wave);

         WaveTrack* t = (WaveTrack*)iterTrack;

         for (i = 0; i < (int)regions.GetCount(); i++)
         {
            const AutoDuckRegion& region = regions[i];
            if (ApplyDuckFade(trackNumber, t, region.t0, region.t1))
            {
               cancel = true;
               break;
            }
         }

         if (cancel)
            break;

         iterTrack = iter.Next();
         trackNumber++;
      }
   }

   ReplaceProcessedTracks(!cancel);
   return !cancel;
}
Beispiel #25
0
void EffectDistortion::PopulateOrExchange(ShuttleGui & S)
{
   S.AddSpace(0, 5);
   S.StartVerticalLay();
   {
      S.StartMultiColumn(4, wxCENTER);
      {
         mTypeChoiceCtrl = S.Id(ID_Type).AddChoice(_("Distortion type:"), wxT(""), &mTableTypes);
         mTypeChoiceCtrl->SetValidator(wxGenericValidator(&mParams.mTableChoiceIndx));
         S.SetSizeHints(-1, -1);

         mDCBlockCheckBox = S.Id(ID_DCBlock).AddCheckBox(_("DC blocking filter"),
                                       DEF_DCBlock ? wxT("true") : wxT("false"));
      }
      S.EndMultiColumn();
      S.AddSpace(0, 10);


      S.StartStatic(_("Threshold controls"));
      {
         S.StartMultiColumn(4, wxEXPAND);
         S.SetStretchyCol(2);
         {
            // Allow space for first Column
            S.AddSpace(250,0); S.AddSpace(0,0); S.AddSpace(0,0); S.AddSpace(0,0); 

            // Upper threshold control
            mThresholdTxt = S.AddVariableText(defaultLabel[0], false, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT);
            FloatingPointValidator<double> vldThreshold(2, &mParams.mThreshold_dB);
            vldThreshold.SetRange(MIN_Threshold_dB, MAX_Threshold_dB);
            mThresholdT = S.Id(ID_Threshold).AddTextBox(wxT(""), wxT(""), 10);
            mThresholdT->SetName(defaultLabel[0]);
            mThresholdT->SetValidator(vldThreshold);

            S.SetStyle(wxSL_HORIZONTAL);
            double maxLin = DB_TO_LINEAR(MAX_Threshold_dB) * SCL_Threshold_dB;
            double minLin = DB_TO_LINEAR(MIN_Threshold_dB) * SCL_Threshold_dB;
            mThresholdS = S.Id(ID_Threshold).AddSlider(wxT(""), 0, maxLin, minLin);
            mThresholdS->SetName(defaultLabel[0]);
            S.AddSpace(20, 0);

            // Noise floor control
            mNoiseFloorTxt = S.AddVariableText(defaultLabel[1], false, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT);
            FloatingPointValidator<double> vldfloor(2, &mParams.mNoiseFloor);
            vldfloor.SetRange(MIN_NoiseFloor, MAX_NoiseFloor);
            mNoiseFloorT = S.Id(ID_NoiseFloor).AddTextBox(wxT(""), wxT(""), 10);
            mNoiseFloorT->SetName(defaultLabel[1]);
            mNoiseFloorT->SetValidator(vldfloor);

            S.SetStyle(wxSL_HORIZONTAL);
            mNoiseFloorS = S.Id(ID_NoiseFloor).AddSlider(wxT(""), 0, MAX_NoiseFloor, MIN_NoiseFloor);
            mNoiseFloorS->SetName(defaultLabel[1]);
            S.AddSpace(20, 0);
         }
         S.EndMultiColumn();
      }
      S.EndStatic();

      S.StartStatic(_("Parameter controls"));
      {
         S.StartMultiColumn(4, wxEXPAND);
         S.SetStretchyCol(2);
         {
            // Allow space for first Column
            S.AddSpace(250,0); S.AddSpace(0,0); S.AddSpace(0,0); S.AddSpace(0,0); 

            // Parameter1 control
            mParam1Txt = S.AddVariableText(defaultLabel[2], false, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT);
            FloatingPointValidator<double> vldparam1(2, &mParams.mParam1);
            vldparam1.SetRange(MIN_Param1, MAX_Param1);
            mParam1T = S.Id(ID_Param1).AddTextBox(wxT(""), wxT(""), 10);
            mParam1T->SetName(defaultLabel[2]);
            mParam1T->SetValidator(vldparam1);

            S.SetStyle(wxSL_HORIZONTAL);
            mParam1S = S.Id(ID_Param1).AddSlider(wxT(""), 0, MAX_Param1, MIN_Param1);
            mParam1S->SetName(defaultLabel[2]);
            S.AddSpace(20, 0);

            // Parameter2 control
            mParam2Txt = S.AddVariableText(defaultLabel[3], false, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT);
            FloatingPointValidator<double> vldParam2(2, &mParams.mParam2);
            vldParam2.SetRange(MIN_Param2, MAX_Param2);
            mParam2T = S.Id(ID_Param2).AddTextBox(wxT(""), wxT(""), 10);
            mParam2T->SetName(defaultLabel[3]);
            mParam2T->SetValidator(vldParam2);

            S.SetStyle(wxSL_HORIZONTAL);
            mParam2S = S.Id(ID_Param2).AddSlider(wxT(""), 0, MAX_Param2, MIN_Param2);
            mParam2S->SetName(defaultLabel[3]);
            S.AddSpace(20, 0);

            // Repeats control
            mRepeatsTxt = S.AddVariableText(defaultLabel[4], false, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT);
            IntegerValidator<int>vldRepeats(&mParams.mRepeats);
            vldRepeats.SetRange(MIN_Repeats, MAX_Repeats);
            mRepeatsT = S.Id(ID_Repeats).AddTextBox(wxT(""), wxT(""), 10);
            mRepeatsT->SetName(defaultLabel[4]);
            mRepeatsT->SetValidator(vldRepeats);

            S.SetStyle(wxSL_HORIZONTAL);
            mRepeatsS = S.Id(ID_Repeats).AddSlider(wxT(""), DEF_Repeats, MAX_Repeats, MIN_Repeats);
            mRepeatsS->SetName(defaultLabel[4]);
            S.AddSpace(20, 0);
         }
         S.EndMultiColumn();
      }
      S.EndStatic();
   }
   S.EndVerticalLay();

   return;
}
Beispiel #26
0
void EffectDistortion::OnThresholdText(wxCommandEvent& /*evt*/)
{
   mThresholdT->GetValidator()->TransferFromWindow();
   mThreshold = DB_TO_LINEAR(mParams.mThreshold_dB);
   mThresholdS->SetValue((int) (mThreshold * SCL_Threshold_dB + 0.5));
}
Beispiel #27
0
void EffectDistortion::UpdateControl(control id, bool enabled, wxString name)
{
   wxString suffix = _(" (Not Used):");
   switch (id)
   {
      case ID_Threshold:
         /* i18n-hint: Control range. */
         if (enabled) suffix = _(" (-100 to 0 dB):");
         name += suffix;

         // Logarithmic slider is set indirectly
         mThreshold = DB_TO_LINEAR(mParams.mThreshold_dB);
         mThresholdS->SetValue((int) (mThreshold * SCL_Threshold_dB + 0.5));

         mThresholdTxt->SetLabel(name);
         mThresholdS->SetName(name);
         mThresholdT->SetName(name);
         mThresholdS->Enable(enabled);
         mThresholdT->Enable(enabled);
         break;
      case ID_NoiseFloor:
         /* i18n-hint: Control range. */
         if (enabled) suffix = _(" (-80 to -20 dB):");
         name += suffix;

         mNoiseFloorTxt->SetLabel(name);
         mNoiseFloorS->SetName(name);
         mNoiseFloorT->SetName(name);
         mNoiseFloorS->Enable(enabled);
         mNoiseFloorT->Enable(enabled);
         break;
      case ID_Param1:
         /* i18n-hint: Control range. */
         if (enabled) suffix = _(" (0 to 100):");
         name += suffix;

         mParam1Txt->SetLabel(name);
         mParam1S->SetName(name);
         mParam1T->SetName(name);
         mParam1S->Enable(enabled);
         mParam1T->Enable(enabled);
         break;
      case ID_Param2:
         /* i18n-hint: Control range. */
         if (enabled) suffix = _(" (0 to 100):");
         name += suffix;

         mParam2Txt->SetLabel(name);
         mParam2S->SetName(name);
         mParam2T->SetName(name);
         mParam2S->Enable(enabled);
         mParam2T->Enable(enabled);
         break;
      case ID_Repeats:
         /* i18n-hint: Control range. */
         if (enabled) suffix = _(" (0 to 5):");
         name += suffix;

         mRepeatsTxt->SetLabel(name);
         mRepeatsS->SetName(name);
         mRepeatsT->SetName(name);
         mRepeatsS->Enable(enabled);
         mRepeatsT->Enable(enabled);
         break;
      case ID_DCBlock:
         if (enabled) {
            mDCBlockCheckBox->SetValue(mbSavedFilterState);
            mParams.mDCBlock = mbSavedFilterState;
         }
         else {
            mDCBlockCheckBox->SetValue(false);
            mParams.mDCBlock = false;
         }

         mDCBlockCheckBox->Enable(enabled);
         break;
      default: break;
   }
}
Beispiel #28
0
bool EffectTruncSilence::Analyze(RegionList& silenceList,
                                 RegionList& trackSilences,
                                 const WaveTrack *wt,
                                 sampleCount* silentFrame,
                                 sampleCount* index,
                                 int whichTrack,
                                 double* inputLength /*= NULL*/,
                                 double* minInputLength /*= NULL*/)
{
   // Smallest silent region to detect in frames
   auto minSilenceFrames = sampleCount(std::max( mInitialAllowedSilence, DEF_MinTruncMs) * wt->GetRate());

   double truncDbSilenceThreshold = DB_TO_LINEAR( mThresholdDB );
   auto blockLen = wt->GetMaxBlockSize();
   auto start = wt->TimeToLongSamples(mT0);
   auto end = wt->TimeToLongSamples(mT1);
   sampleCount outLength = 0;

   double previewLength;
   gPrefs->Read(wxT("/AudioIO/EffectsPreviewLen"), &previewLength, 6.0);
   // Minimum required length in samples.
   const sampleCount previewLen( previewLength * wt->GetRate() );

   // Keep position in overall silences list for optimization
   RegionList::iterator rit(silenceList.begin());

   // Allocate buffer
   Floats buffer{ blockLen };

   // Loop through current track
   while (*index < end) {
      if (inputLength && ((outLength >= previewLen) || (*index - start > wt->TimeToLongSamples(*minInputLength)))) {
         *inputLength = std::min<double>(*inputLength, *minInputLength);
         if (outLength >= previewLen) {
            *minInputLength = *inputLength;
         }
         return true;
      }

      if (!inputLength) {
         // Show progress dialog, test for cancellation
         bool cancelled = TotalProgress(
               detectFrac * (whichTrack +
                             (*index - start).as_double() /
                             (end - start).as_double()) /
                             (double)GetNumWaveTracks());
         if (cancelled)
            return false;
      }

      // Optimization: if not in a silent region skip ahead to the next one

      double curTime = wt->LongSamplesToTime(*index);
      for ( ; rit != silenceList.end(); ++rit) {
         // Find the first silent region ending after current time
         if (rit->end >= curTime) {
            break;
         }
      }

      if (rit == silenceList.end()) {
         // No more regions -- no need to process the rest of the track
         if (inputLength) {
            // Add available samples up to previewLength.
            auto remainingTrackSamples = wt->TimeToLongSamples(wt->GetEndTime()) - *index;
            auto requiredTrackSamples = previewLen - outLength;
            outLength += (remainingTrackSamples > requiredTrackSamples)? requiredTrackSamples : remainingTrackSamples;
         }

         break;
      }
      else if (rit->start > curTime) {
         // End current silent region, skip ahead
         if (*silentFrame >= minSilenceFrames)  {
            trackSilences.push_back(Region(
               wt->LongSamplesToTime(*index - *silentFrame),
               wt->LongSamplesToTime(*index)
            ));
         }
         *silentFrame = 0;
         auto newIndex = wt->TimeToLongSamples(rit->start);
         if (inputLength) {
            auto requiredTrackSamples = previewLen - outLength;
            // Add non-silent sample to outLength
            outLength += ((newIndex - *index) > requiredTrackSamples)? requiredTrackSamples : newIndex - *index;
         }

         *index = newIndex;
      }
      // End of optimization

      // Limit size of current block if we've reached the end
      auto count = limitSampleBufferSize( blockLen, end - *index );

      // Fill buffer
      wt->Get((samplePtr)(buffer.get()), floatSample, *index, count);

      // Look for silenceList in current block
      for (decltype(count) i = 0; i < count; ++i) {
         if (inputLength && ((outLength >= previewLen) || (outLength > wt->TimeToLongSamples(*minInputLength)))) {
            *inputLength = wt->LongSamplesToTime(*index + i) - wt->LongSamplesToTime(start);
            break;
         }

         if (fabs(buffer[i]) < truncDbSilenceThreshold) {
            (*silentFrame)++;
         }
         else {
            sampleCount allowed = 0;
            if (*silentFrame >= minSilenceFrames) {
               if (inputLength) {
                  switch (mActionIndex) {
                     case kTruncate:
                        outLength += wt->TimeToLongSamples(mTruncLongestAllowedSilence);
                        break;
                     case kCompress:
                        allowed = wt->TimeToLongSamples(mInitialAllowedSilence);
                        outLength += sampleCount(
                           allowed.as_double() +
                              (*silentFrame - allowed).as_double()
                                 * mSilenceCompressPercent / 100.0
                        );
                        break;
                     // default: // Not currently used.
                  }
               }

               // Record the silent region
               trackSilences.push_back(Region(
                  wt->LongSamplesToTime(*index + i - *silentFrame),
                  wt->LongSamplesToTime(*index + i)
               ));
            }
            else if (inputLength) {   // included as part of non-silence
               outLength += *silentFrame;
            }
            *silentFrame = 0;
            if (inputLength) {
                ++outLength;   // Add non-silent sample to outLength
            }
         }
      }
      // Next block
      *index += count;
   }

   if (inputLength) {
      *inputLength = std::min<double>(*inputLength, *minInputLength);
      if (outLength >= previewLen) {
         *minInputLength = *inputLength;
      }
   }

   return true;
}
Beispiel #29
0
static double
gst_opus_dec_get_r128_volume (gint16 r128_gain)
{
  return DB_TO_LINEAR (gst_opus_dec_get_r128_gain (r128_gain));
}
Beispiel #30
0
bool EffectScienFilter::CalcFilter()
{
   // Set up the coefficients in all the biquads
   float fNorm = mCutoff / mNyquist;
   if (fNorm >= 0.9999)
      fNorm = 0.9999F;
   float fC = tan (PI * fNorm / 2);
   float fDCPoleDistSqr = 1.0F;
   float fZPoleX, fZPoleY;
   float fZZeroX, fZZeroY;
   float beta = cos (fNorm*PI);
   switch (mFilterType)
   {
   case kButterworth:     // Butterworth
      if ((mOrder & 1) == 0)
      {
         // Even order
         for (int iPair = 0; iPair < mOrder/2; iPair++)
         {
            float fSPoleX = fC * cos (PI - (iPair + 0.5) * PI / mOrder);
            float fSPoleY = fC * sin (PI - (iPair + 0.5) * PI / mOrder);
            BilinTransform (fSPoleX, fSPoleY, &fZPoleX, &fZPoleY);
            mpBiquad[iPair].fNumerCoeffs [0] = 1;
            if (mFilterSubtype == kLowPass)		// LOWPASS
               mpBiquad[iPair].fNumerCoeffs [1] = 2;
            else
               mpBiquad[iPair].fNumerCoeffs [1] = -2;
            mpBiquad[iPair].fNumerCoeffs [2] = 1;
            mpBiquad[iPair].fDenomCoeffs [0] = -2 * fZPoleX;
            mpBiquad[iPair].fDenomCoeffs [1] = square(fZPoleX) + square(fZPoleY);
            if (mFilterSubtype == kLowPass)		// LOWPASS
               fDCPoleDistSqr *= Calc2D_DistSqr (1, 0, fZPoleX, fZPoleY);
            else
               fDCPoleDistSqr *= Calc2D_DistSqr (-1, 0, fZPoleX, fZPoleY);		// distance from Nyquist
         }
      }
      else
      {
         // Odd order - first do the 1st-order section
         float fSPoleX = -fC;
         float fSPoleY = 0;
         BilinTransform (fSPoleX, fSPoleY, &fZPoleX, &fZPoleY);
         mpBiquad[0].fNumerCoeffs [0] = 1;
         if (mFilterSubtype == kLowPass)		// LOWPASS
            mpBiquad[0].fNumerCoeffs [1] = 1;
         else
            mpBiquad[0].fNumerCoeffs [1] = -1;
         mpBiquad[0].fNumerCoeffs [2] = 0;
         mpBiquad[0].fDenomCoeffs [0] = -fZPoleX;
         mpBiquad[0].fDenomCoeffs [1] = 0;
         if (mFilterSubtype == kLowPass)		// LOWPASS
            fDCPoleDistSqr = 1 - fZPoleX;
         else
            fDCPoleDistSqr = fZPoleX + 1;    // dist from Nyquist
         for (int iPair = 1; iPair <= mOrder/2; iPair++)
         {
            float fSPoleX = fC * cos (PI - iPair * PI / mOrder);
            float fSPoleY = fC * sin (PI - iPair * PI / mOrder);
            BilinTransform (fSPoleX, fSPoleY, &fZPoleX, &fZPoleY);
            mpBiquad[iPair].fNumerCoeffs [0] = 1;
            if (mFilterSubtype == kLowPass)		// LOWPASS
               mpBiquad[iPair].fNumerCoeffs [1] = 2;
            else
               mpBiquad[iPair].fNumerCoeffs [1] = -2;
            mpBiquad[iPair].fNumerCoeffs [2] = 1;
            mpBiquad[iPair].fDenomCoeffs [0] = -2 * fZPoleX;
            mpBiquad[iPair].fDenomCoeffs [1] = square(fZPoleX) + square(fZPoleY);
            if (mFilterSubtype == kLowPass)		// LOWPASS
               fDCPoleDistSqr *= Calc2D_DistSqr (1, 0, fZPoleX, fZPoleY);
            else
               fDCPoleDistSqr *= Calc2D_DistSqr (-1, 0, fZPoleX, fZPoleY);		// distance from Nyquist
         }
      }
      mpBiquad[0].fNumerCoeffs [0] *= fDCPoleDistSqr / (1 << mOrder);	// mult by DC dist from poles, divide by dist from zeroes
      mpBiquad[0].fNumerCoeffs [1] *= fDCPoleDistSqr / (1 << mOrder);
      mpBiquad[0].fNumerCoeffs [2] *= fDCPoleDistSqr / (1 << mOrder);
      break;

   case kChebyshevTypeI:     // Chebyshev Type 1
      double eps; eps = sqrt (pow (10.0, wxMax(0.001, mRipple) / 10.0) - 1);
      double a; a = log (1 / eps + sqrt(1 / square(eps) + 1)) / mOrder;
      // Assume even order to start
      for (int iPair = 0; iPair < mOrder/2; iPair++)
      {
         float fSPoleX = -fC * sinh (a) * sin ((2*iPair + 1) * PI / (2 * mOrder));
         float fSPoleY = fC * cosh (a) * cos ((2*iPair + 1) * PI / (2 * mOrder));
         BilinTransform (fSPoleX, fSPoleY, &fZPoleX, &fZPoleY);
         if (mFilterSubtype == kLowPass)		// LOWPASS
         {
            fZZeroX = -1;
            fDCPoleDistSqr = Calc2D_DistSqr (1, 0, fZPoleX, fZPoleY);
            fDCPoleDistSqr /= 2*2;  // dist from zero at Nyquist
         }
         else
         {
            // Highpass - do the digital LP->HP transform on the poles and zeroes
            ComplexDiv (beta - fZPoleX, -fZPoleY, 1 - beta * fZPoleX, -beta * fZPoleY, &fZPoleX, &fZPoleY);
            fZZeroX = 1;
            fDCPoleDistSqr = Calc2D_DistSqr (-1, 0, fZPoleX, fZPoleY);		// distance from Nyquist
            fDCPoleDistSqr /= 2*2;  // dist from zero at Nyquist
         }
         mpBiquad[iPair].fNumerCoeffs [0] = fDCPoleDistSqr;
         mpBiquad[iPair].fNumerCoeffs [1] = -2 * fZZeroX * fDCPoleDistSqr;
         mpBiquad[iPair].fNumerCoeffs [2] = fDCPoleDistSqr;
         mpBiquad[iPair].fDenomCoeffs [0] = -2 * fZPoleX;
         mpBiquad[iPair].fDenomCoeffs [1] = square(fZPoleX) + square(fZPoleY);
      }
      if ((mOrder & 1) == 0)
      {
         float fTemp = DB_TO_LINEAR(-wxMax(0.001, mRipple));      // at DC the response is down R dB (for even-order)
         mpBiquad[0].fNumerCoeffs [0] *= fTemp;
         mpBiquad[0].fNumerCoeffs [1] *= fTemp;
         mpBiquad[0].fNumerCoeffs [2] *= fTemp;
      }
      else
      {
         // Odd order - now do the 1st-order section
         float fSPoleX = -fC * sinh (a);
         float fSPoleY = 0;
         BilinTransform (fSPoleX, fSPoleY, &fZPoleX, &fZPoleY);
         if (mFilterSubtype == kLowPass)		// LOWPASS
         {
            fZZeroX = -1;
            fDCPoleDistSqr = sqrt(Calc2D_DistSqr (1, 0, fZPoleX, fZPoleY));
            fDCPoleDistSqr /= 2;  // dist from zero at Nyquist
         }
         else
         {
            // Highpass - do the digital LP->HP transform on the poles and zeroes
            ComplexDiv (beta - fZPoleX, -fZPoleY, 1 - beta * fZPoleX, -beta * fZPoleY, &fZPoleX, &fZPoleY);
            fZZeroX = 1;
            fDCPoleDistSqr = sqrt(Calc2D_DistSqr (-1, 0, fZPoleX, fZPoleY));		// distance from Nyquist
            fDCPoleDistSqr /= 2;  // dist from zero at Nyquist
         }
         mpBiquad[(mOrder-1)/2].fNumerCoeffs [0] = fDCPoleDistSqr;
         mpBiquad[(mOrder-1)/2].fNumerCoeffs [1] = -fZZeroX * fDCPoleDistSqr;
         mpBiquad[(mOrder-1)/2].fNumerCoeffs [2] = 0;
         mpBiquad[(mOrder-1)/2].fDenomCoeffs [0] = -fZPoleX;
         mpBiquad[(mOrder-1)/2].fDenomCoeffs [1] = 0;
      }
      break;

   case kChebyshevTypeII:     // Chebyshev Type 2
      float fSZeroX, fSZeroY;
      float fSPoleX, fSPoleY;
      eps = DB_TO_LINEAR(-wxMax(0.001, mStopbandRipple));
      a = log (1 / eps + sqrt(1 / square(eps) + 1)) / mOrder;

      // Assume even order
      for (int iPair = 0; iPair < mOrder/2; iPair++)
      {
         ComplexDiv (fC, 0, -sinh (a) * sin ((2*iPair + 1) * PI / (2 * mOrder)),
            cosh (a) * cos ((2*iPair + 1) * PI / (2 * mOrder)),
            &fSPoleX, &fSPoleY);
         BilinTransform (fSPoleX, fSPoleY, &fZPoleX, &fZPoleY);
         fSZeroX = 0;
         fSZeroY = fC / cos (((2 * iPair) + 1) * PI / (2 * mOrder));
         BilinTransform (fSZeroX, fSZeroY, &fZZeroX, &fZZeroY);

         if (mFilterSubtype == kLowPass)		// LOWPASS
         {
            fDCPoleDistSqr = Calc2D_DistSqr (1, 0, fZPoleX, fZPoleY);
            fDCPoleDistSqr /= Calc2D_DistSqr (1, 0, fZZeroX, fZZeroY);
         }
         else
         {
            // Highpass - do the digital LP->HP transform on the poles and zeroes
            ComplexDiv (beta - fZPoleX, -fZPoleY, 1 - beta * fZPoleX, -beta * fZPoleY, &fZPoleX, &fZPoleY);
            ComplexDiv (beta - fZZeroX, -fZZeroY, 1 - beta * fZZeroX, -beta * fZZeroY, &fZZeroX, &fZZeroY);
            fDCPoleDistSqr = Calc2D_DistSqr (-1, 0, fZPoleX, fZPoleY);		// distance from Nyquist
            fDCPoleDistSqr /= Calc2D_DistSqr (-1, 0, fZZeroX, fZZeroY);
         }
         mpBiquad[iPair].fNumerCoeffs [0] = fDCPoleDistSqr;
         mpBiquad[iPair].fNumerCoeffs [1] = -2 * fZZeroX * fDCPoleDistSqr;
         mpBiquad[iPair].fNumerCoeffs [2] = (square(fZZeroX) + square(fZZeroY)) * fDCPoleDistSqr;
         mpBiquad[iPair].fDenomCoeffs [0] = -2 * fZPoleX;
         mpBiquad[iPair].fDenomCoeffs [1] = square(fZPoleX) + square(fZPoleY);
      }
      // Now, if it's odd order, we have one more to do
      if (mOrder & 1)
      {
         int iPair = (mOrder-1)/2; // we'll do it as a biquad, but it's just first-order
         ComplexDiv (fC, 0, -sinh (a) * sin ((2*iPair + 1) * PI / (2 * mOrder)),
            cosh (a) * cos ((2*iPair + 1) * PI / (2 * mOrder)),
            &fSPoleX, &fSPoleY);
         BilinTransform (fSPoleX, fSPoleY, &fZPoleX, &fZPoleY);
         fZZeroX = -1;     // in the s-plane, the zero is at infinity
         fZZeroY = 0;
         if (mFilterSubtype == kLowPass)		// LOWPASS
         {
            fDCPoleDistSqr = sqrt(Calc2D_DistSqr (1, 0, fZPoleX, fZPoleY));
            fDCPoleDistSqr /= 2;
         }
         else
         {
            // Highpass - do the digital LP->HP transform on the poles and zeroes
            ComplexDiv (beta - fZPoleX, -fZPoleY, 1 - beta * fZPoleX, -fZPoleY, &fZPoleX, &fZPoleY);
            fZZeroX = 1;
            fDCPoleDistSqr = sqrt(Calc2D_DistSqr (-1, 0, fZPoleX, fZPoleY));		// distance from Nyquist
            fDCPoleDistSqr /= 2;
         }
         mpBiquad[iPair].fNumerCoeffs [0] = fDCPoleDistSqr;
         mpBiquad[iPair].fNumerCoeffs [1] = -fZZeroX * fDCPoleDistSqr;
         mpBiquad[iPair].fNumerCoeffs [2] = 0;
         mpBiquad[iPair].fDenomCoeffs [0] = -fZPoleX;
         mpBiquad[iPair].fDenomCoeffs [1] = 0;
      }
      break;
   }
   return true;
}