Example #1
0
        public TrackGain(int sampleRate)
        {
            if (!ReplayGain.IsSupportedFormat(sampleRate))
            {
                throw new NotSupportedException("Unsupported sampling rate");
            }

            this.freqIndex = ReplayGain.FreqInfos.IndexOf(i => i.SampleRate == sampleRate);

            this.gainData = new GainData();

            this.lInPreBuf = new double[ReplayGain.MAX_ORDER * 2];
            this.lStepBuf  = new double[ReplayGain.MAX_SAMPLES_PER_WINDOW + ReplayGain.MAX_ORDER];
            this.lOutBuf   = new double[ReplayGain.MAX_SAMPLES_PER_WINDOW + ReplayGain.MAX_ORDER];
            this.rInPreBuf = new double[ReplayGain.MAX_ORDER * 2];
            this.rStepBuf  = new double[ReplayGain.MAX_SAMPLES_PER_WINDOW + ReplayGain.MAX_ORDER];
            this.rOutBuf   = new double[ReplayGain.MAX_SAMPLES_PER_WINDOW + ReplayGain.MAX_ORDER];

            this.sampleWindow = (int)Math.Ceiling(sampleRate * ReplayGain.RMS_WINDOW_TIME);

            this.lInPre = new CPtr <double>(lInPreBuf, ReplayGain.MAX_ORDER);
            this.lStep  = new CPtr <double>(lStepBuf, ReplayGain.MAX_ORDER);
            this.lOut   = new CPtr <double>(lOutBuf, ReplayGain.MAX_ORDER);
            this.rInPre = new CPtr <double>(rInPreBuf, ReplayGain.MAX_ORDER);
            this.rStep  = new CPtr <double>(rStepBuf, ReplayGain.MAX_ORDER);
            this.rOut   = new CPtr <double>(rOutBuf, ReplayGain.MAX_ORDER);
        }
Example #2
0
 private void FilterButter(CPtr <double> input, CPtr <double> output, long nSamples, double[] aKernel, double[] bKernel)
 {
     while (nSamples-- != 0)
     {
         output[0] =
             input[0] * bKernel[0]
             - output[-1] * aKernel[1]
             + input[-1] * bKernel[1]
             - output[-2] * aKernel[2]
             + input[-2] * bKernel[2];
         ++output;
         ++input;
     }
 }
Example #3
0
        /// <summary>
        /// Disposes the resources used to calculate ReplayGain, but doesn't clear the result of the analysis.
        /// </summary>
        public void Dispose()
        {
            this.lInPreBuf = null;
            this.lStepBuf  = null;
            this.lOutBuf   = null;
            this.rInPreBuf = null;
            this.rStepBuf  = null;
            this.rOutBuf   = null;

            this.lInPre = new CPtr <double>();
            this.lStep  = new CPtr <double>();
            this.lOut   = new CPtr <double>();
            this.rInPre = new CPtr <double>();
            this.rStep  = new CPtr <double>();
            this.rOut   = new CPtr <double>();
        }
Example #4
0
        private void AnalyzeSamples(CPtr <double> leftSamples, CPtr <double> rightSamples)
        {
            int numSamples = leftSamples.Length;

            CPtr <double> curLeft;
            CPtr <double> curRight;
            long          batchSamples = numSamples;
            long          curSamples;
            long          curSamplePos = 0;

            if (numSamples < ReplayGain.MAX_ORDER)
            {
                Array.Copy(leftSamples.Array, 0, this.lInPreBuf, ReplayGain.MAX_ORDER, numSamples);
                Array.Copy(rightSamples.Array, 0, this.rInPreBuf, ReplayGain.MAX_ORDER, numSamples);
            }
            else
            {
                Array.Copy(leftSamples.Array, 0, this.lInPreBuf, ReplayGain.MAX_ORDER, ReplayGain.MAX_ORDER);
                Array.Copy(rightSamples.Array, 0, this.rInPreBuf, ReplayGain.MAX_ORDER, ReplayGain.MAX_ORDER);
            }

            while (batchSamples > 0)
            {
                curSamples = batchSamples > this.sampleWindow - this.totSamp ? this.sampleWindow - this.totSamp : batchSamples;
                if (curSamplePos < ReplayGain.MAX_ORDER)
                {
                    curLeft  = this.lInPre + curSamplePos;
                    curRight = this.rInPre + curSamplePos;
                    if (curSamples > ReplayGain.MAX_ORDER - curSamplePos)
                    {
                        curSamples = ReplayGain.MAX_ORDER - curSamplePos;
                    }
                }
                else
                {
                    curLeft  = leftSamples + curSamplePos;
                    curRight = rightSamples + curSamplePos;
                }

                FilterYule(curLeft, this.lStep + this.totSamp, curSamples, ReplayGain.FreqInfos[this.freqIndex].AYule, ReplayGain.FreqInfos[this.freqIndex].BYule);
                FilterYule(curRight, this.rStep + this.totSamp, curSamples, ReplayGain.FreqInfos[this.freqIndex].AYule, ReplayGain.FreqInfos[this.freqIndex].BYule);

                FilterButter(this.lStep + this.totSamp, this.lOut + this.totSamp, curSamples, ReplayGain.FreqInfos[this.freqIndex].AButter, ReplayGain.FreqInfos[this.freqIndex].BButter);
                FilterButter(this.rStep + this.totSamp, this.rOut + this.totSamp, curSamples, ReplayGain.FreqInfos[this.freqIndex].AButter, ReplayGain.FreqInfos[this.freqIndex].BButter);

                curLeft  = this.lOut + this.totSamp;                  // Get the squared values
                curRight = this.rOut + this.totSamp;

                for (long i = curSamples % 16; i-- != 0;)
                {
                    this.lSum += Sqr(curLeft[0]);
                    ++curLeft;
                    this.rSum += Sqr(curRight[0]);
                    ++curRight;
                }

                for (long i = curSamples / 16; i-- != 0;)
                {
                    this.lSum += Sqr(curLeft[0])
                                 + Sqr(curLeft[1])
                                 + Sqr(curLeft[2])
                                 + Sqr(curLeft[3])
                                 + Sqr(curLeft[4])
                                 + Sqr(curLeft[5])
                                 + Sqr(curLeft[6])
                                 + Sqr(curLeft[7])
                                 + Sqr(curLeft[8])
                                 + Sqr(curLeft[9])
                                 + Sqr(curLeft[10])
                                 + Sqr(curLeft[11])
                                 + Sqr(curLeft[12])
                                 + Sqr(curLeft[13])
                                 + Sqr(curLeft[14])
                                 + Sqr(curLeft[15]);
                    curLeft   += 16;
                    this.rSum += Sqr(curRight[0])
                                 + Sqr(curRight[1])
                                 + Sqr(curRight[2])
                                 + Sqr(curRight[3])
                                 + Sqr(curRight[4])
                                 + Sqr(curRight[5])
                                 + Sqr(curRight[6])
                                 + Sqr(curRight[7])
                                 + Sqr(curRight[8])
                                 + Sqr(curRight[9])
                                 + Sqr(curRight[10])
                                 + Sqr(curRight[11])
                                 + Sqr(curRight[12])
                                 + Sqr(curRight[13])
                                 + Sqr(curRight[14])
                                 + Sqr(curRight[15]);
                    curRight += 16;
                }

                batchSamples -= curSamples;
                curSamplePos += curSamples;
                this.totSamp += curSamples;
                if (this.totSamp == this.sampleWindow)
                {
                    // Get the Root Mean Square (RMS) for this set of samples
                    double val  = ReplayGain.STEPS_PER_DB * 10.0 * Math.Log10((this.lSum + this.rSum) / this.totSamp * 0.5 + 1.0e-37);
                    int    ival = (int)val;
                    if (ival < 0)
                    {
                        ival = 0;
                    }
                    if (ival >= this.gainData.Accum.Length)
                    {
                        ival = this.gainData.Accum.Length - 1;
                    }
                    this.gainData.Accum[ival]++;
                    this.lSum = this.rSum = 0.0;

                    if (this.totSamp > int.MaxValue)
                    {
                        throw new OverflowException("Too many samples! Change to long and recompile!");
                    }

                    Array.Copy(this.lOutBuf, (int)this.totSamp, this.lOutBuf, 0, ReplayGain.MAX_ORDER);
                    Array.Copy(this.rOutBuf, (int)this.totSamp, this.rOutBuf, 0, ReplayGain.MAX_ORDER);
                    Array.Copy(this.lStepBuf, (int)this.totSamp, this.lStepBuf, 0, ReplayGain.MAX_ORDER);
                    Array.Copy(this.rStepBuf, (int)this.totSamp, this.rStepBuf, 0, ReplayGain.MAX_ORDER);

                    this.totSamp = 0;
                }
                if (this.totSamp > this.sampleWindow)
                {
                    // somehow I really screwed up: Error in programming! Contact author about totsamp > sampleWindow
                    throw new Exception("Gain analysis error!");
                }
            }

            if (numSamples < ReplayGain.MAX_ORDER)
            {
                Array.Copy(this.lInPreBuf, numSamples, this.lInPreBuf, 0, ReplayGain.MAX_ORDER - numSamples);
                Array.Copy(this.rInPreBuf, numSamples, this.rInPreBuf, 0, ReplayGain.MAX_ORDER - numSamples);
                Array.Copy(leftSamples.Array, leftSamples.Index, this.lInPreBuf, ReplayGain.MAX_ORDER - numSamples, numSamples);
                Array.Copy(rightSamples.Array, rightSamples.Index, this.rInPreBuf, ReplayGain.MAX_ORDER - numSamples, numSamples);
            }
            else
            {
                Array.Copy(leftSamples.Array, leftSamples.Index + numSamples - ReplayGain.MAX_ORDER, this.lInPreBuf, 0, ReplayGain.MAX_ORDER);
                Array.Copy(rightSamples.Array, rightSamples.Index + numSamples - ReplayGain.MAX_ORDER, this.rInPreBuf, 0, ReplayGain.MAX_ORDER);
            }
        }