public override WWUtil.LargeArray <double> FilterDo(WWUtil.LargeArray <double> inPcmLA)
        {
            var inPcm = inPcmLA.ToArray();

            double[] outPcm = null;
            if (mProcessed == 0)
            {
                outPcm = new double[inPcm.Length - INSPECT_BITS + 1];
            }
            else
            {
                outPcm = new double[inPcm.Length];
            }

            int writePos = 0;

            for (int readPos = 0; readPos < inPcm.Length; ++readPos)
            {
                double y = 0;
                if (!Process(inPcm[readPos], out y))
                {
                    // まだ出力から値が出てこない。
                }
                else
                {
                    outPcm[writePos++] = y;
                }
            }

            return(new WWUtil.LargeArray <double>(outPcm));
        }
        /*
         * Transfer function H(z):
         *           (r・e^{jθ} - z^{-1})(r・e^{-jθ} - z^{-1})
         *   H(z) = ------------------------------------------------
         *           (1 - r・e^{jθ}・z^{-1})(1 - r・e^{-jθ}・z^{-1})
         *
         *           r^2 - 2r・cos(θ)z^{-1} + z^{-2}
         *        = -------------------------------
         *           1 - 2r・cos(θ)z^{-1} + r^2・z^{-2}
         *
         * Difference equation:
         * Input:  x[n]
         * Output: y[n]
         *
         * y[n] = r^2 * x[n] - 2rcosθ * x[n-1] + x[n-2] + 2rcosθ * y[n-1] - r^2 * y[n-2]
         */
        public override WWUtil.LargeArray <double> FilterDo(WWUtil.LargeArray <double> inPcmLA)
        {
            var inPcm  = inPcmLA.ToArray();
            var outPcm = new double[inPcm.Length];

            double θ = T * Math.PI / 180.0;

            for (int i = 0; i < inPcm.Length; ++i)
            {
                double x = inPcm[i];

                // direct form implementation of the difference equation
                double y = R * R * x - 2 * R * Math.Cos(θ) * mLastX[0] + mLastX[1];
                y += 2 * R * Math.Cos(θ) * mLastY[0] - R * R * mLastY[1];

                outPcm[i] = y;

                mLastX[1] = mLastX[0];
                mLastX[0] = x;
                mLastY[1] = mLastY[0];
                mLastY[0] = y;
            }

            return(new WWUtil.LargeArray <double>(outPcm));
        }
Example #3
0
        public override WWUtil.LargeArray <double> FilterDo(WWUtil.LargeArray <double> inPcmLA)
        {
            var inPcm = inPcmLA.ToArray();

            var result = new double[inPcm.Length - (mFilterCoeffs.Length - mSampleDelay.Count - 1)];
            int pos    = 0;

            foreach (double v in inPcm)
            {
                mSampleDelay.Enqueue(v);

                if (mFilterCoeffs.Length <= mSampleDelay.Count)
                {
                    double sum  = 0.0;
                    int    offs = 0;
                    foreach (double d in mSampleDelay)
                    {
                        sum += mFilterCoeffs[offs] * d;
                        ++offs;
                    }
                    result[pos] = sum;
                    ++pos;

                    mSampleDelay.Dequeue();
                }
            }

            return(new WWUtil.LargeArray <double>(result));
        }
        public override WWUtil.LargeArray <double> FilterDo(WWUtil.LargeArray <double> inPcmLA)
        {
            var inPcm = inPcmLA.ToArray();

            var outPcm = new double[inPcm.Length];

            for (int i = 0; i < outPcm.Length; ++i)
            {
                double sampleD = inPcm[i];

                int sampleI24;
                if (1.0 <= sampleD)
                {
                    sampleI24 = 8388607;
                }
                else if (sampleD < -1.0)
                {
                    sampleI24 = -8388608;
                }
                else
                {
                    sampleI24 = (int)(8388608 * sampleD);
                }

                sampleI24 = mNoiseShaper.Filter24(sampleI24);

                outPcm[i] = (double)sampleI24 * (1.0 / 8388608);
            }

            return(new WWUtil.LargeArray <double>(outPcm));
        }
        public override WWUtil.LargeArray <double> FilterDo(WWUtil.LargeArray <double> inPcmLA)
        {
            var inPcm = inPcmLA.ToArray();

            double[] outPcm;
            int      i = 0;

            if (mFirst)
            {
                outPcm = new double[(inPcm.Length - 1) * Factor];
                mLastOriginalSampleValue = inPcm[0];
                mFirst = false;
                i      = 1;
            }
            else
            {
                outPcm = new double[inPcm.Length * Factor];
                // i==0
            }

            int pos = 0;

            for (; i < inPcm.Length; ++i)
            {
                for (int r = 0; r < Factor; ++r)
                {
                    double ratio = (r + 1.0) / Factor;
                    outPcm[pos] = inPcm[i] * ratio + mLastOriginalSampleValue * (1.0 - ratio);
                    ++pos;
                }
                mLastOriginalSampleValue = inPcm[i];
            }

            return(new WWUtil.LargeArray <double>(outPcm));
        }
        public override WWUtil.LargeArray <double> FilterDo(WWUtil.LargeArray <double> inPcmLA)
        {
            var inPcm = inPcmLA.ToArray();

            var outPcm = new double[inPcm.Length];

            for (int i = 0; i < outPcm.Length; ++i)
            {
                double sampleD = 0.0;
                for (int order = 0; order < 5; ++order)
                {
                    sampleD += mC[order] * mS[order];
                }

                if (1 == TargetBitsPerSample)
                {
                    if (0.0 <= sampleD)
                    {
                        outPcm[i] = 8388607.0 / 8388608.0;
                    }
                    else
                    {
                        outPcm[i] = -1.0;
                    }
                }
                else
                {
                    int sampleI = 0;
                    if (1.0f <= sampleD)
                    {
                        sampleI = Int32.MaxValue;
                    }
                    else if (sampleD < -1.0f)
                    {
                        sampleI = Int32.MinValue;
                    }
                    else
                    {
                        sampleI = (int)(sampleD * -1.0 * Int32.MinValue);
                    }

                    sampleI = (int)((sampleI) & mMask);

                    outPcm[i] = sampleI * (-1.0 / Int32.MinValue);
                }

                mS[4] += mS[3];
                mS[3] += mS[2] - mF[1] * mS[4];
                mS[2] += mS[1];
                mS[1] += mS[0] - mF[0] * mS[2];
                mS[0] += (inPcm[i] - outPcm[i]);
            }

            return(new WWUtil.LargeArray <double>(outPcm));
        }
Example #7
0
        public override WWUtil.LargeArray <double> FilterDo(WWUtil.LargeArray <double> inPcmLA)
        {
            var inPcm = inPcmLA.ToArray();

            var outPcm = new double[inPcm.Length];

            for (int i = 0; i < outPcm.Length; ++i)
            {
                outPcm[i] = inPcm[i] * Amplitude;
            }
            return(new WWUtil.LargeArray <double>(outPcm));
        }
        public override WWUtil.LargeArray <double> FilterDo(WWUtil.LargeArray <double> inPcmLA)
        {
            var inPcm = inPcmLA.ToArray();

            var outPcm = new double[inPcm.Length];

            for (int i = 0; i < outPcm.Length; ++i)
            {
                outPcm[i] = inPcm[i] + mGNG.NextFloat() * NoiseLevelScale();
            }
            return(new WWUtil.LargeArray <double>(outPcm));
        }
        public override WWUtil.LargeArray <double> FilterDo(WWUtil.LargeArray <double> inPcmLA)
        {
            if (inPcmLA.LongLength == 0)
            {
                return(new WWUtil.LargeArray <double>(0));
            }

            var inPcm = inPcmLA.ToArray();
            var pcmF  = mFFT.ForwardFft(inPcm);

            double scaleLsb     = Math.Pow(10, LsbScalingDb / 20.0);
            double maxMagnitude = FFT_LENGTH / 2;

            for (int i = 0; i < pcmF.Length; ++i)
            {
                /*   -144 dBより小さい: そのまま
                 *   -144 dB: scaleLsb倍
                 *   -72 dB: scaleLsb/2倍
                 *    0 dB: 1倍
                 * になるようなスケーリングをする。
                 * 出力データは音量が増えるので、後段にノーマライズ処理を追加すると良い。
                 */

                // magnitudeは0.0~1.0の範囲の値。
                double magnitude = pcmF[i].Magnitude() / maxMagnitude;

                double db = float.MinValue;
                if (float.Epsilon < magnitude)
                {
                    db = 20.0 * Math.Log10(magnitude);
                }

                double scale = 1.0;
                if (db < LSB_DECIBEL)
                {
                    scale = 1.0;
                }
                else if (0 <= db)
                {
                    scale = 1.0;
                }
                else
                {
                    scale = 1.0 + db * (scaleLsb - 1) / LSB_DECIBEL;
                }

                pcmF[i] = WWComplex.Mul(pcmF[i], scale);
            }

            return(new WWUtil.LargeArray <double>(mFFT.InverseFft(pcmF)));
        }
        public override WWUtil.LargeArray <double> FilterDo(WWUtil.LargeArray <double> inPcmLA)
        {
            System.Diagnostics.Debug.Assert(inPcmLA.LongLength == NumOfSamplesNeeded());

            var inPcm = inPcmLA.ToArray();

            var outPcm = new double[inPcm.Length * Factor];

            for (int i = 0; i < inPcm.Length; ++i)
            {
                outPcm[i * Factor] = inPcm[i];
            }

            return(new WWUtil.LargeArray <double>(outPcm));
        }
Example #11
0
        public override WWUtil.LargeArray <double> FilterDo(WWUtil.LargeArray <double> inPcmLA)
        {
            var inPcm = inPcmLA.ToArray();

            var outPcm = new double[inPcm.Length];

            var dict = new Dictionary <int, int>();

            for (int i = 0; i < outPcm.Length; ++i)
            {
                double sampleD = inPcm[i];

                int sampleI24;
                if (1.0 <= sampleD)
                {
                    sampleI24 = 8388607;
                }
                else if (sampleD < -1.0)
                {
                    sampleI24 = -8388608;
                }
                else
                {
                    sampleI24 = (int)(8388608 * sampleD);
                }

                sampleI24 = mNoiseShaper1bit.Filter24(sampleI24);


                if (dict.ContainsKey(sampleI24))
                {
                    ++dict[sampleI24];
                }
                else
                {
                    dict.Add(sampleI24, 1);
                }

                outPcm[i] = (double)sampleI24 * (1.0 / 8388608);
            }

            foreach (var n in dict)
            {
                Console.WriteLine("{0} {1}", n.Key, n.Value);
            }

            return(new WWUtil.LargeArray <double>(outPcm));
        }
        public override WWUtil.LargeArray <double> FilterDo(WWUtil.LargeArray <double> inPcmLA)
        {
            var inPcm = inPcmLA.ToArray();

            var outPcm = new double[inPcm.Length];

            // 32bit integerにサンプル値を左寄せで詰める。
            // maskで下位ビットを0にすることで量子化ビット数を減らす。

            uint mask = 0xffffff00U << (24 - TargetBitsPerSample);

            for (long i = 0; i < outPcm.Length; ++i)
            {
                double sampleD = inPcm[i];

                int sampleI24;
                if (1.0 <= sampleD)
                {
                    sampleI24 = 8388607;
                }
                else if (sampleD < -1.0)
                {
                    sampleI24 = -8388608;
                }
                else
                {
                    sampleI24 = (int)(8388608 * sampleD);
                }

                int sampleI32 = sampleI24 << 8;

                if (TargetBitsPerSample == 1)
                {
                    sampleI32 = (0 <= sampleI32) ? Int32.MaxValue : Int32.MinValue;
                }
                else
                {
                    sampleI32 = (int)(((int)sampleI32) & mask);
                }

                sampleI24 = sampleI32 >> 8;

                outPcm[i] = (double)sampleI24 * (1.0 / 8388608);
            }

            return(new WWUtil.LargeArray <double>(outPcm));
        }
        public override WWUtil.LargeArray <double> FilterDo(WWUtil.LargeArray <double> inPcmLA)
        {
            var inPcm = inPcmLA.ToArray();

            int i = 0;

            double[] outPcm;
            if (mDelay.Count == 0)
            {
                outPcm = new double[(inPcm.Length - 3) * Factor];
                mDelay.Add(0);
                for (i = 0; i < 3; ++i)
                {
                    mDelay.Add(inPcm[i]);
                }
                // i==3
            }
            else
            {
                outPcm = new double[inPcm.Length * Factor];
                // i==0
            }

            int pos = 0;

            for (; i < inPcm.Length; ++i)
            {
                // p0 and p1: 2つの隣接する入力サンプル値
                // m0 and m1: p0地点、p1地点の傾き
                double p0 = mDelay[1];
                double p1 = mDelay[2];
                double m0 = mDelay[2] - mDelay[0];
                double m1 = mDelay[3] - mDelay[1];

                for (int r = 0; r < Factor; ++r)
                {
                    // tは補間時刻。0 < t ≦ 1まで変化する
                    double t = (r + 1.0) / Factor;
                    outPcm[pos] = H00(t) * p0 + H10(t) * m0 + H01(t) * p1 + H11(t) * m1;
                    ++pos;
                }

                mDelay.RemoveAt(0);
                mDelay.Add(inPcm[i]);
            }
            return(new WWUtil.LargeArray <double>(outPcm));
        }
Example #14
0
        public override WWUtil.LargeArray <double> FilterDo(WWUtil.LargeArray <double> inPcmLA)
        {
            var inPcm = inPcmLA.ToArray();

            System.Diagnostics.Debug.Assert(inPcm.Length == mResamplePosArray.Length);
            System.Diagnostics.Debug.Assert(inPcm.Length == mFractionArray.Length);

            double [] outPcm = new double[inPcm.Length];

            long processed = 0;

            Parallel.For(0, inPcm.Length, toPos => {
                int fromPos        = mResamplePosArray[toPos];
                double fraction    = mFractionArray[toPos];
                double sinFraction = Math.Sin(-Math.PI * mFractionArray[toPos]);
                double v           = 0.0;

                for (int convOffs = -ConvolutionLengthMinus1 / 2; convOffs <= ConvolutionLengthMinus1 / 2; ++convOffs)
                {
                    long pos = convOffs + fromPos;
                    if (0 <= pos && pos < inPcm.LongLength)
                    {
                        double x = Math.PI * (convOffs - fraction);

                        double sinX = sinFraction;
                        if (0 != (convOffs & 1))
                        {
                            sinX *= -1.0;
                        }

                        double sinc = SincD(sinX, x);

                        v += inPcm[pos] * sinc;
                    }
                }
                outPcm[toPos] = v;

                // report progress.
                Interlocked.Increment(ref processed);
                if (0xffff == (processed & 0xffff))
                {
                    ProgressReport((double)processed / inPcm.Length);
                }
            });

            return(new WWUtil.LargeArray <double>(outPcm));
        }
Example #15
0
        public override WWUtil.LargeArray<double> FilterDo(WWUtil.LargeArray<double> inPcmLA) {
            System.Diagnostics.Debug.Assert(inPcmLA.LongLength == NumOfSamplesNeeded());
            var inPcm = inPcmLA.ToArray();

            int inputSamples = (int)((UpsampledWindowLen + 1) / Factor + PROCESS_SLICE);

            if (mFirst) {
                var silence = new double[(UpsampledWindowLen + 1) / Factor / 2];
                mInputDelay.AddRange(silence);
            }

            mInputDelay.AddRange(inPcm);
            if (inputSamples < mInputDelay.Count) {
                int count = mInputDelay.Count - inputSamples;
                mInputDelay.RemoveRange(0, count);
            }

            var fromPcm = mInputDelay.ToArray();
            var toPcm = new double[PROCESS_SLICE * Factor];

#if false
            for (int i=0; i<PROCESS_SLICE; ++i) {
#else
            Parallel.For(0, PROCESS_SLICE, i => {
#endif
                for (int f = 0; f < Factor; ++f) {
                    double sampleValue = 0;
                    for (long offs = 0; offs + Factor - f < mCoeffs.LongLength; offs += Factor) {
                        double input = mInputDelay[(int)(offs / Factor + i)];
                        if (input != 0.0) {
                            sampleValue += mCoeffs.At(offs + Factor - f) * input;
                        }
                    }
                    toPcm[i * Factor + f] = sampleValue;
                } 
#if false
            }
#else
            });
#endif

            mFirst = false;
            return new WWUtil.LargeArray<double>(toPcm);
        }
    }
Example #16
0
        public override WWUtil.LargeArray <double> FilterDo(WWUtil.LargeArray <double> inPcmLA)
        {
            var inPcm  = inPcmLA.ToArray();
            var outPcm = new double[inPcm.LongLength * Factor];

            long pos = 0;

            for (long i = 0; i < inPcm.LongLength; ++i)
            {
                for (int r = 0; r < Factor; ++r)
                {
                    outPcm[pos] = inPcm[i];
                    ++pos;
                }
            }

            return(new WWUtil.LargeArray <double>(outPcm));
        }
Example #17
0
        public override WWUtil.LargeArray <double> FilterDo(WWUtil.LargeArray <double> inPcmLA)
        {
            var inPcm = inPcmLA.ToArray();

            System.Diagnostics.Debug.Assert(inPcm.Length == NumOfSamplesNeeded());

            var outPcm = new double[inPcm.Length / Factor];

            long writePos = 0;

            for (long i = PickSampleIndex; i < inPcm.Length; i += Factor)
            {
                outPcm[writePos] = inPcm[i];
                ++writePos;
            }

            return(new WWUtil.LargeArray <double>(outPcm));
        }
        public override WWUtil.LargeArray <double> FilterDo(WWUtil.LargeArray <double> inPcmLA)
        {
            var inPcm = inPcmLA.ToArray();

            var pcmF = mFFTfwd.Process(inPcm);

            if (pcmF.Length == 0)
            {
                return(new WWUtil.LargeArray <double>(0));
            }

            int idx20Hz = (int)(20.0 * mFftLength / mPcmFormat.SampleRate);
            int idx40Hz = (int)(40.0 * mFftLength / mPcmFormat.SampleRate);

            for (int i = 0; i < idx40Hz - idx20Hz; ++i)
            {
                // 正の周波数
                {
                    var v = pcmF[i + idx40Hz];
                    v = WWComplex.Mul(v, Gain);
                    pcmF[i + idx20Hz] = WWComplex.Add(pcmF[i + idx20Hz], v);
                }

                // 負の周波数
                {
                    var v = pcmF[mFftLength - (i + idx40Hz)];
                    v = WWComplex.Mul(v, Gain);
                    pcmF[mFftLength - (i + idx20Hz)] = WWComplex.Add(pcmF[mFftLength - (i + idx20Hz)], v);
                }
            }

            var r = new WWUtil.LargeArray <double>(mFFTinv.Process(pcmF));

            // 進捗表示。
            mProcessedSamples += inPcm.Length;
            ProgressReport((double)mProcessedSamples / mTotalSamples);

            return(r);
        }
        public override WWUtil.LargeArray <double> FilterDo(WWUtil.LargeArray <double> inPcmLA)
        {
            System.Diagnostics.Debug.Assert(inPcmLA.LongLength == NumOfSamplesNeeded());
            var inPcm = inPcmLA.ToArray();

            int inputSamples = (WindowLength + 1) + PROCESS_SLICE * Factor;

            if (mFirst)
            {
                var silence = new double[(WindowLength + 1) / 2];
                mInputDelay.AddRange(silence);
            }

            mInputDelay.AddRange(inPcm);
            if (inputSamples < mInputDelay.Count)
            {
                int count = mInputDelay.Count - inputSamples;
                mInputDelay.RemoveRange(0, count);
            }

            var fromPcm = mInputDelay.ToArray();
            var toPcm   = new double[PROCESS_SLICE];

            Parallel.For(0, PROCESS_SLICE, i => {
                double sampleValue = 0;
                for (int offs = 0; offs < mCoeffs.Length; ++offs)
                {
                    double input = mInputDelay[offs + i * Factor];
                    if (input != 0.0)
                    {
                        sampleValue += mCoeffs[offs] * input;
                    }
                }
                toPcm[i] = sampleValue;
            });

            mFirst = false;
            return(new WWUtil.LargeArray <double>(toPcm));
        }
        /*
         * Transfer function H(z):
         *            -a + z^{-1}
         *   H(z) = ------------------
         *            1 - a * z^{-1}
         *
         *       for a : real value
         *
         * Difference equation:
         * Input:  x[n]
         * Output: y[n]
         *
         * y[n] = -a * x[n] + x[n-1] + a * y[n-1]
         */
        public override WWUtil.LargeArray <double> FilterDo(WWUtil.LargeArray <double> inPcmLA)
        {
            var inPcm  = inPcmLA.ToArray();
            var outPcm = new double[inPcm.Length];

            for (int i = 0; i < inPcm.Length; ++i)
            {
                double x = inPcm[i];

                // direct form implementation of the difference equation
                double y = -A * x + mLastX;
                y += A * mLastY;

                outPcm[i] = y;

                mLastX = x;
                mLastY = y;

                //Console.WriteLine("A={0:g} n={1:g} y={2:g}", A, i, y);
            }

            return(new WWUtil.LargeArray <double>(outPcm));
        }
Example #21
0
        /// <summary>
        /// Understanding digital signal processing 3rd ed. pp.558 - 562
        /// int型のデータをQ次、ディレイDのCICで処理するとき、
        /// 中間データは32(intのビット数) + Q * log_2(D)ビットのデータ型である必要がある。
        /// </summary>
        public override WWUtil.LargeArray <double> FilterDo(WWUtil.LargeArray <double> inPcmLA)
        {
            System.Diagnostics.Debug.Assert(inPcmLA.LongLength == NumOfSamplesNeeded());
            var inPcm = inPcmLA.ToArray();

            int gain = (int)Math.Pow(Delay, Order);

            var result = new double[inPcm.Length];

            for (int i = 0; i < inPcm.Length; ++i)
            {
                double vD = inPcm[i];

                long v = PCMDoubleToInt(vD);

                for (int j = 0; j < Order; ++j)
                {
                    v += mIntegratorZ[j];
                    mIntegratorZ[j] = v;
                }

                for (int j = 0; j < Order; ++j)
                {
                    mCombQueue[j].Enqueue(v);
                    if (Delay < mCombQueue[j].Count)
                    {
                        v -= mCombQueue[j].Dequeue();
                    }
                }

                v /= gain;

                result[i] = PCMIntToDouble((int)v);
            }

            return(new WWUtil.LargeArray <double>(result));
        }
Example #22
0
        public override WWUtil.LargeArray <double> FilterDo(WWUtil.LargeArray <double> inPcmLA)
        {
            System.Diagnostics.Debug.Assert(inPcmLA.LongLength == NumOfSamplesNeeded());
            var inPcm = inPcmLA.ToArray();

            // inPcmTをFFTしてinPcmFを得る。
            // inPcmFを0で水増ししたデータoutPcmFを作って逆FFTしoutPcmを得る。

            var inPcmF = mFFT.ForwardFft(inPcm);

            var outPcmF = new WWComplex[UpsampleFftLength];

            for (int i = 0; i < outPcmF.Length; ++i)
            {
                if (i <= FftLength / 2)
                {
                    outPcmF[i] = inPcmF[i];
                }
                else if (UpsampleFftLength - FftLength / 2 <= i)
                {
                    int pos = i + FftLength - UpsampleFftLength;
                    outPcmF[i] = inPcmF[pos];
                }
                else
                {
                    outPcmF[i] = WWComplex.Zero();
                }
            }
            inPcmF = null;

            var outPcm = mFFT.InverseFft(outPcmF);

            outPcmF = null;

            return(new WWUtil.LargeArray <double>(outPcm));
        }
Example #23
0
        public override WWUtil.LargeArray <double> FilterDo(WWUtil.LargeArray <double> inPcmLA)
        {
            System.Diagnostics.Debug.Assert(inPcmLA.LongLength <= NumOfSamplesNeeded());
            var inPcm = inPcmLA.ToArray();

            var fft = new WWRadix2Fft(FFT_LEN);

            // Overlap and add continuous FFT

            var inTime = new WWComplex[FFT_LEN];

            for (int i = 0; i < inPcm.Length; ++i)
            {
                inTime[i] = new WWComplex(inPcm[i], 0);
            }

            // FFTでinTimeをinFreqに変換
            var inFreq = fft.ForwardFft(inTime);

            inTime = null;

            // FFT後、フィルターHの周波数ドメインデータを掛ける
            var mulFreq = WWComplex.Mul(inFreq, mFilterFreq);

            inFreq = null;

            // inFreqをIFFTしてoutTimeに変換
            var outTime = fft.InverseFft(mulFreq);

            mulFreq = null;

            double [] outReal;
            if (mFirstFilterDo)
            {
                // 最初のFilterDo()のとき、フィルタの遅延サンプル数だけ先頭サンプルを削除する。
                outReal = new double[NumOfSamplesNeeded() - FILTER_DELAY];
                for (int i = 0; i < outReal.Length; ++i)
                {
                    outReal[i] = outTime[i + FILTER_DELAY].real;
                }
                mFirstFilterDo = false;
            }
            else
            {
                outReal = new double[NumOfSamplesNeeded()];
                for (int i = 0; i < outReal.Length; ++i)
                {
                    outReal[i] = outTime[i].real;
                }
            }

            // 前回のIFFT結果の最後のFILTER_LENGTH-1サンプルを先頭に加算する
            if (null != mIfftAddBuffer)
            {
                for (int i = 0; i < mIfftAddBuffer.Length; ++i)
                {
                    outReal[i] += mIfftAddBuffer[i];
                }
            }

            // 今回のIFFT結果の最後のFILTER_LENGTH-1サンプルをmIfftAddBufferとして保存する
            mIfftAddBuffer = new double[FILTER_LENP1];
            for (int i = 0; i < mIfftAddBuffer.Length; ++i)
            {
                mIfftAddBuffer[i] = outTime[outTime.Length - mIfftAddBuffer.Length + i].real;
            }
            outTime = null;

            return(new WWUtil.LargeArray <double>(outReal));
        }
        public override WWUtil.LargeArray <double> FilterDo(WWUtil.LargeArray <double> inPcmLA)
        {
            var inPcm = inPcmLA.ToArray();

            double scaleLsb = Math.Pow(10, LsbScalingDb / 20.0);

            double maxScaling = 0.0;

            for (int b = 0; b < 15; ++b)
            {
                double scale = 1.0 * b / 14.0 + scaleLsb * (14 - b) / 14.0;
                maxScaling += scale * (1 << b);
            }

            var outPcm = new double[inPcm.Length];

            for (int i = 0; i < outPcm.Length; ++i)
            {
                double d    = inPcm[i] * (Int16.MaxValue + 1);
                bool   plus = true;
                int    v;

                if (Int16.MaxValue < d)
                {
                    v = Int16.MaxValue;
                }
                else if (d < Int16.MinValue + 1)
                {
                    v = Int16.MinValue + 1;
                }
                else
                {
                    v = (int)d;
                }

                if (v < 0)
                {
                    v    = -v;
                    plus = false;
                }

                double result = 0.0;
                for (int b = 0; b < 15; ++b)
                {
                    if ((v & (1 << b)) != 0)
                    {
                        double scale = 1.0 * b / 14.0 + scaleLsb * (14 - b) / 14.0;
                        result += (1 << b) * scale;
                    }
                }

                if (!plus)
                {
                    result = -result;
                }

                result /= maxScaling;

                outPcm[i] = result;
            }

            return(new WWUtil.LargeArray <double>(outPcm));
        }