private static void AssembleSample(List <WWUtil.LargeArray <double> > dataList, long count,
                                           out WWUtil.LargeArray <double> gathered, out WWUtil.LargeArray <double> remainings)
        {
            gathered = new WWUtil.LargeArray <double>(count);

            // この関数が呼び出されるときにはdataListにはcountバイト丁度か、
            // countバイトよりも少し多いバイト数を含んでいて配列の個数は丁度必要な数入っている。
            // もしも余剰バイトがあるときはそれは最後の配列に含まれる。

            long offs         = 0;
            long remainLength = 0;

            foreach (var d in dataList)
            {
                long length = d.LongLength;
                remainLength = 0;
                if (count < offs + length)
                {
                    length       = count - offs;
                    remainLength = d.LongLength - length;
                }

                gathered.CopyFrom(d, 0, offs, length);
                offs += length;
            }

            remainings = new WWUtil.LargeArray <double>(remainLength);
            if (0 < remainLength)
            {
                long lastDataLength = dataList[dataList.Count - 1].LongLength;
                remainings.CopyFrom(dataList[dataList.Count - 1], lastDataLength - remainLength, 0, remainLength);
            }
        }
        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));
        }
Exemple #3
0
        /// <summary>
        /// PCMデータの形式を設定する。
        /// </summary>
        public void SetFormat(
            int numChannels,
            int bitsPerSample,
            int validBitsPerSample,
            int sampleRate,
            ValueRepresentationType sampleValueRepresentation,
            long numFrames)
        {
            NumChannels                   = numChannels;
            BitsPerSample                 = bitsPerSample;
            ValidBitsPerSample            = validBitsPerSample;
            SampleRate                    = sampleRate;
            SampleValueRepresentationType = sampleValueRepresentation;
            mNumFrames                    = numFrames;

            if (SampleDataType == PcmDataLib.PcmData.DataType.DoP)
            {
                BitRate = SampleRate * numChannels * 16;
            }
            else
            {
                BitRate = SampleRate * numChannels * validBitsPerSample;
            }

            mSampleLargeArray = null;
            IsLossyCompressed = false;
        }
        /// <summary>
        /// double型のLargeArrayを入力するバージョン。
        /// </summary>
        public void SetPcmInDouble(WWUtil.LargeArray <double> pcm, long toPos)
        {
            long fromPos = 0;

            long copyCount = pcm.LongLength;

            if (mTotalSamples < toPos + pcm.LongLength)
            {
                copyCount = mTotalSamples - toPos;
            }

            for (long remain = copyCount; 0 < remain;)
            {
                int fragmentCount = WWUtil.LargeArray <byte> .ARRAY_FRAGMENT_LENGTH_NUM;
                if (remain < fragmentCount)
                {
                    fragmentCount = (int)(remain);
                }

                var fragment = new double[fragmentCount];
                pcm.CopyTo(fromPos, ref fragment, 0, fragmentCount);
                SetPcmInDouble(fragment, toPos);
                fragment = null;

                fromPos += fragmentCount;
                toPos   += fragmentCount;
                remain  -= fragmentCount;
            }
        }
Exemple #5
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));
        }
Exemple #6
0
 public PcmData()
 {
     NumChannels                   = 0;
     SampleRate                    = 0;
     BitsPerSample                 = 0;
     ValidBitsPerSample            = 0;
     SampleValueRepresentationType = ValueRepresentationType.SInt;
     mNumFrames                    = 0;
     mSampleLargeArray             = null;
     Id             = -1;
     Ordinal        = -1;
     GroupId        = -1;
     FileName       = null;
     FullPath       = null;
     DisplayName    = null;
     StartTick      = 0;
     EndTick        = -1;
     AlbumTitle     = "";
     ArtistName     = "";
     ComposerName   = "";
     CueSheetIndex  = 1;
     PictureBytes   = 0;
     PictureData    = null;
     SampleDataType = DataType.PCM;
     LastWriteTime  = -1;
     TrackId        = 0;
 }
        /*
         * 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));
        }
        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));
        }
        /// <summary>
        /// double型のLargeArrayを戻すバージョン。
        /// </summary>
        /// <param name="longCount">取得する要素数。範囲外の領域は0が入る。</param>
        /// <returns></returns>
        public WWUtil.LargeArray <double> GetPcmInDoublePcm(long longCount)
        {
            // 確保するサイズはlongCount個。
            var result = new WWUtil.LargeArray <double>(longCount);

            long fromPos = mOffsBytes / (mBitsPerSample / 8);
            long toPos   = 0;

            // コピーするデータの個数はcount個よりも少ないことがある。
            long copyCount = result.LongLength;

            if (mTotalSamples < fromPos + copyCount)
            {
                copyCount = (int)(mTotalSamples - fromPos);
            }

            for (long remain = copyCount; 0 < remain;)
            {
                int fragmentCount = WWUtil.LargeArray <byte> .ARRAY_FRAGMENT_LENGTH_NUM;
                if (remain < fragmentCount)
                {
                    fragmentCount = (int)remain;
                }

                var fragment = GetPcmInDoublePcm(fragmentCount);
                result.CopyFrom(fragment, 0, toPos, fragmentCount);
                fragment = null;

                toPos  += fragmentCount;
                remain -= fragmentCount;
            }

            return(result);
        }
        private bool SetupTimingErrorFile()
        {
            if (TimingErrorFile == null || TimingErrorFile.Length == 0)
            {
                TimingErrorFileNanosec = 0.0;
                return(true);
            }

            AudioData ad;
            int       rv = AudioDataIO.Read(TimingErrorFile, out ad);

            if (rv < 0)
            {
                return(false);
            }

            if (ad.meta.totalSamples < mTotalSamples)
            {
                MessageBox.Show(Properties.Resources.ErrorTimingErrorFile);
                return(false);
            }

            // Uses Left channel of Timing Error audio file.
            // sample value range is -1.0 ≦ v < +1.0
            mTimingErrorFromAudioFile = ad.pcm[0].GetPcmInDouble(mTotalSamples);

            return(true);
        }
Exemple #11
0
        /// <param name="audioFormat">WavWriterLowLevel.WAVE_FORMAT_PCM or WavWriterLowLevel.WAVE_FORMAT_IEEE_FLOAT</param>
        public static bool Write(BinaryWriter bw,
                                 int numChannels,
                                 int bitsPerSample,
                                 int audioFormat,
                                 int sampleRate,
                                 long numFrames,
                                 WWUtil.LargeArray <byte> sampleArray)
        {
            if (IsRf64Size(sampleArray.LongLength))
            {
                WriteRF64Header(bw, numChannels, bitsPerSample, audioFormat, sampleRate, numFrames);
            }
            else
            {
                WriteRiffHeader(bw, numChannels, bitsPerSample, audioFormat, sampleRate, sampleArray.LongLength);
            }

            for (int i = 0; i < sampleArray.ArrayNum(); ++i)
            {
                var pcmFragment = sampleArray.ArrayNth(i);
                bw.Write(pcmFragment);
            }

            if ((sampleArray.LongLength & 1) == 1)
            {
                byte pad = 0;
                bw.Write(pad);
            }
            return(true);
        }
Exemple #12
0
        public PcmData MonoToStereo()
        {
            System.Diagnostics.Debug.Assert(NumChannels == 1);

            // サンプルあたりビット数が8の倍数でないとこのアルゴリズムは使えない
            System.Diagnostics.Debug.Assert((BitsPerSample & 7) == 0);

            var newSampleArray = new WWUtil.LargeArray <byte>(mSampleLargeArray.LongLength * 2);

            {
                int bytesPerSample = BitsPerSample / 8;

                // sampleArrayのフレーム数はこれよりも少ないことがある。
                // 実際に存在するサンプル数sampleFramesだけ処理する。
                long sampleFrames = mSampleLargeArray.LongLength / bytesPerSample; // NumChannels==1なので。
                long fromPosBytes = 0;
                for (long frame = 0; frame < sampleFrames; ++frame)
                {
                    for (int offs = 0; offs < bytesPerSample; ++offs)
                    {
                        byte b = mSampleLargeArray.At(fromPosBytes + offs);
                        newSampleArray.Set(fromPosBytes * 2 + offs, b);
                        newSampleArray.Set(fromPosBytes * 2 + bytesPerSample + offs, b);
                    }
                    fromPosBytes += bytesPerSample;
                }
            }
            PcmData newPcmData = new PcmData();

            newPcmData.CopyHeaderInfoFrom(this);
            newPcmData.SetFormat(2, BitsPerSample, ValidBitsPerSample, SampleRate, SampleValueRepresentationType, NumFrames);
            newPcmData.SetSampleLargeArray(newSampleArray);

            return(newPcmData);
        }
Exemple #13
0
 /// <summary>
 /// rhsの内容をコピーする。PCMデータ配列だけはコピーしない。(nullをセットする)
 /// PCMデータ配列は、SetSampleArrayで別途設定する。
 /// </summary>
 /// <param name="rhs">コピー元</param>
 public void CopyHeaderInfoFrom(PcmData rhs)
 {
     NumChannels                   = rhs.NumChannels;
     SampleRate                    = rhs.SampleRate;
     BitsPerSample                 = rhs.BitsPerSample;
     ValidBitsPerSample            = rhs.ValidBitsPerSample;
     SampleValueRepresentationType = rhs.SampleValueRepresentationType;
     mNumFrames                    = rhs.mNumFrames;
     mSampleLargeArray             = null;
     Id             = rhs.Id;
     Ordinal        = rhs.Ordinal;
     GroupId        = rhs.GroupId;
     FileName       = rhs.FileName;
     FullPath       = rhs.FullPath;
     DisplayName    = rhs.DisplayName;
     StartTick      = rhs.StartTick;
     EndTick        = rhs.EndTick;
     AlbumTitle     = rhs.AlbumTitle;
     ArtistName     = rhs.ArtistName;
     ComposerName   = rhs.ComposerName;
     CueSheetIndex  = rhs.CueSheetIndex;
     PictureBytes   = rhs.PictureBytes;
     PictureData    = rhs.PictureData;
     SampleDataType = rhs.SampleDataType;
     LastWriteTime  = rhs.LastWriteTime;
     TrackId        = rhs.TrackId;
 }
        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));
        }
Exemple #15
0
 public override WWUtil.LargeArray <double> FilterDo(WWUtil.LargeArray <double> inPcm)
 {
     WWUtil.LargeArray <double> outPcm = new WWUtil.LargeArray <double>(inPcm.LongLength);
     for (long i = 0; i < outPcm.LongLength; ++i)
     {
         outPcm.Set(i, inPcm.At(inPcm.LongLength - i - 1));
     }
     return(outPcm);
 }
Exemple #16
0
        /// <summary>
        /// ヘッダー情報、サンプルデータ領域をクローンする。
        /// </summary>
        public void CopyFrom(PcmData rhs)
        {
            CopyHeaderInfoFrom(rhs);

            mSampleLargeArray = null;
            if (rhs.mSampleLargeArray != null)
            {
                mSampleLargeArray = rhs.mSampleLargeArray.Clone();
            }
        }
        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));
        }
        public WWUtil.LargeArray <double> GetPcmInDoubleSdm1bit(long longCount)
        {
            // サンプル数 / 8 == バイト数。
            var result = new WWUtil.LargeArray <double>(longCount);

            if (mTotalSamples / 8 <= mOffsBytes || longCount == 0)
            {
                // 完全に範囲外の時。
                int writePos = 0;
                for (long i = 0; i < (longCount + 7) / 8; ++i)
                {
                    byte b = 0x69; // DSD silence

                    // 1バイト内のビットの並びはMSBから古い順にデータが詰まっている。
                    for (int bit = 7; 0 <= bit; --bit)
                    {
                        if (longCount <= writePos)
                        {
                            break;
                        }
                        result.Set(writePos++, ((b >> bit) & 1) == 1 ? 1.0 : -1.0);
                    }
                }

                return(result);
            }
            else
            {
                long copySamples = longCount;
                if (mTotalSamples < mOffsBytes * 8 + copySamples)
                {
                    copySamples = mTotalSamples - mOffsBytes * 8;
                }

                long toPos = 0;
                for (long remain = copySamples; 0 < remain;)
                {
                    int fragmentCount = WWUtil.LargeArray <byte> .ARRAY_FRAGMENT_LENGTH_NUM;
                    if (remain < fragmentCount)
                    {
                        fragmentCount = (int)remain;
                    }

                    var fragment = GetPcmInDoubleSdm1bit(fragmentCount);
                    result.CopyFrom(fragment, 0, toPos, fragmentCount);
                    fragment = null;

                    toPos  += fragmentCount;
                    remain -= fragmentCount;
                }

                return(result);
            }
        }
Exemple #19
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 virtual WWUtil.LargeArray <double> FilterDo(WWUtil.LargeArray <double> inPcm)
        {
            long num = NumOfSamplesNeeded();

            if (inPcm.LongLength != num)
            {
                throw new ArgumentOutOfRangeException("inPcm");
            }

            WWUtil.LargeArray <double> outPcm = new WWUtil.LargeArray <double>(num);
            outPcm.CopyFrom(inPcm, 0, 0, num);
            return(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));
        }
Exemple #24
0
        private void TrimInternal(long startFrame, long endFrame)
        {
            if (startFrame == 0 && endFrame < 0)
            {
                // データTrimの必要はない。
                return;
            }

            if (endFrame < 0 ||
                NumFrames < endFrame)
            {
                // 終了位置はファイルの終わり。
                endFrame = NumFrames;
            }

            if (endFrame < startFrame)
            {
                // 1サンプルもない。
                startFrame = endFrame;
            }

            long startBytes = startFrame * BitsPerFrame / 8;
            long endBytes   = endFrame * BitsPerFrame / 8;

            Debug.Assert(0 <= startBytes);
            Debug.Assert(0 <= endBytes);
            Debug.Assert(startBytes <= endBytes);
            Debug.Assert(null != mSampleLargeArray);
            Debug.Assert(startBytes <= mSampleLargeArray.LongLength);
            Debug.Assert(endBytes <= mSampleLargeArray.LongLength);

            long newNumSamples = endFrame - startFrame;

            mNumFrames = newNumSamples;
            if (newNumSamples == 0 ||
                mSampleLargeArray.LongLength <= startBytes)
            {
                mSampleLargeArray = null;
                mNumFrames        = 0;
            }
            else
            {
                var newArray = new WWUtil.LargeArray <byte>(endBytes - startBytes);
                newArray.CopyFrom(mSampleLargeArray, startBytes, 0, endBytes - startBytes);
                mSampleLargeArray = null;
                mSampleLargeArray = newArray;
            }
        }
        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));
        }
        Add(WWUtil.LargeArray <double> a, WWUtil.LargeArray <double> b)
        {
            if (a.LongLength != b.LongLength)
            {
                return(null);
            }

            var result = new WWUtil.LargeArray <double>(a.LongLength);

            for (long i = 0; i < a.LongLength; ++i)
            {
                result.Set(i, a.At(i) + b.At(i));
            }

            return(result);
        }
        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();

            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));
        }
        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));
        }
        Mul(WWUtil.LargeArray <WWComplex> a, WWUtil.LargeArray <WWComplex> b)
        {
            if (a.LongLength != b.LongLength)
            {
                return(null);
            }

            var result = new WWUtil.LargeArray <WWComplex>(a.LongLength);

            for (long i = 0; i < a.LongLength; ++i)
            {
                var t = a.At(i);
                result.Set(i, WWComplex.Mul(t, b.At(i)));
            }

            return(result);
        }