示例#1
0
        /// <summary>
        /// 指定チャンネルのPCMデータを取得。
        /// </summary>
        /// <param name="ch">チャンネル番号 0から始まる。</param>
        /// <param name="posSamples">取得開始サンプル番号。</param>
        /// <param name="copySamples">取得するサンプル数。</param>
        /// <returns>float型のPCMデータ。-1 ≦ v < +1</returns>
        public LargeArray <float> GetFloatPcmOfChannel(int ch, long posSamples, long copySamples)
        {
            System.Diagnostics.Debug.Assert(mDecodedMetadata != null);
            System.Diagnostics.Debug.Assert(mPcmAllBuffer != null);
            System.Diagnostics.Debug.Assert(0 <= ch && ch < mDecodedMetadata.channels);

            int bpf = mDecodedMetadata.BytesPerFrame;
            int bps = mDecodedMetadata.BytesPerSample;

            // copySamplesを決定します。
            long totalSamples = mPcmAllBuffer.LongLength / bpf;

            if (totalSamples < posSamples + copySamples)
            {
                copySamples = (int)(totalSamples - posSamples);
            }
            if (copySamples < 0)
            {
                copySamples = 0;
            }

            var  samples = new LargeArray <float>(copySamples);
            long toIdx   = 0;

            switch (bps)
            {
            case 2:
                for (long pos = posSamples; pos < posSamples + copySamples; ++pos)
                {
                    long  idx = bpf * pos + ch * bps;
                    short vS  = (short)(mPcmAllBuffer.At(idx) + (mPcmAllBuffer.At(idx + 1) << 8));
                    float vF  = vS / 32768.0f;
                    samples.Set(toIdx++, vF);
                    //Console.WriteLine("{0:+00000;-00000}", vS);
                }
                break;

            case 3:
                for (long pos = posSamples; pos < posSamples + copySamples; ++pos)
                {
                    long idx = bpf * pos + ch * bps;
                    int  vI  = (int)((mPcmAllBuffer.At(idx + 0) << 8)
                                     + (mPcmAllBuffer.At(idx + 1) << 16)
                                     + (mPcmAllBuffer.At(idx + 2) << 24));

                    //Console.WriteLine("{0:+00000000;-00000000}", vI);

                    float vF = vI / 2147483648.0f;
                    samples.Set(toIdx++, vF);
                }
                break;

            default:
                throw new ArgumentException(string.Format("Unexpected BytesPerSample {0}", bps));
            }

            return(samples);
        }
        public LargeArray <WWComplex> ForwardFft(LargeArray <WWComplex> aFrom)
        {
            if (aFrom == null || aFrom.LongLength != mNumPoints)
            {
                throw new ArgumentOutOfRangeException("aFrom");
            }
            var aTo = new LargeArray <WWComplex>(aFrom.LongLength);

            var aTmp0 = new LargeArray <WWComplex>(mNumPoints);

            for (int i = 0; i < aTmp0.LongLength; ++i)
            {
                aTmp0.Set(i, aFrom.At((long)mBitReversalTable.At(i)));
            }
            var aTmp1 = new LargeArray <WWComplex>(mNumPoints);

            for (int i = 0; i < aTmp1.LongLength; ++i)
            {
                aTmp1.Set(i, WWComplex.Zero());
            }

            var aTmps = new LargeArray <WWComplex> [2];

            aTmps[0] = aTmp0;
            aTmps[1] = aTmp1;

            for (int i = 0; i < mNumStage - 1; ++i)
            {
                FftStageN(i, aTmps[((i & 1) == 1) ? 1 : 0], aTmps[((i & 1) == 0) ? 1 : 0]);
            }
            FftStageN(mNumStage - 1, aTmps[(((mNumStage - 1) & 1) == 1) ? 1 : 0], aTo);

            return(aTo);
        }
        public LargeArray <WWComplex> InverseFft(LargeArray <WWComplex> aFrom,
                                                 double?compensation = null)
        {
            for (int i = 0; i < aFrom.LongLength; ++i)
            {
                var t = new WWComplex(aFrom.At(i).real, -aFrom.At(i).imaginary);
                aFrom.Set(i, t);
            }

            var aTo = ForwardFft(aFrom);

            double c = 1.0 / mNumPoints;

            if (compensation != null)
            {
                c = (double)compensation;
            }

            for (int i = 0; i < aTo.LongLength; ++i)
            {
                var t = new WWComplex(aTo.At(i).real *c, -aTo.At(i).imaginary *c);
                aTo.Set(i, t);
            }

            return(aTo);
        }
        public WWRadix2FftLargeArray(long numPoints)
        {
            if (!Functions.IsPowerOfTwo(numPoints) || numPoints < 2)
            {
                throw new ArgumentException("numPoints must be power of two integer and larger than 2");
            }
            mNumPoints = numPoints;

            mWn = new LargeArray <WWComplex>(mNumPoints);
            for (long i = 0; i < mNumPoints; ++i)
            {
                double angle = -2.0 * Math.PI * i / mNumPoints;
                mWn.Set(i, new WWComplex(Math.Cos(angle), Math.Sin(angle)));
            }

            // mNumStage == log_2(mNumPoints)
            long t = mNumPoints;

            for (int i = 0; 0 < t; ++i)
            {
                t       >>= 1;
                mNumStage = i;
            }

            mBitReversalTable = new LargeArray <ulong>(mNumPoints);
            for (long i = 0; i < mNumPoints; ++i)
            {
                mBitReversalTable.Set(i, BitReversal(mNumStage, (ulong)i));
            }
        }
示例#5
0
        /// <summary>
        /// dataにcoeffsを畳み込む。
        /// </summary>
        public LargeArray <float> Convolution(LargeArray <float> data, float[] coeffs)
        {
            mMaxMagnitude = 0;

            var r = new LargeArray <float>(data.LongLength);

            // rIdx: 出力サンプル列rの書き込みidx。1づつ増える。
            for (long rIdx = 0; rIdx < data.LongLength; ++rIdx)
            {
                // v: 畳み込み結果。
                float v = 0;

                // dIdx: dataの読み出し要素番号。
                long dIdx = rIdx - coeffs.Length / 2;

                // cIdx: coeffsの読み出し要素番号。1づつ減る。
                for (int cIdx = coeffs.Length - 1; 0 <= cIdx; --cIdx)
                {
                    // dataの範囲外を読まないようにする。
                    if (0 <= dIdx && dIdx < data.LongLength)
                    {
                        v += data.At(dIdx++) * coeffs[cIdx];
                    }
                }

                if (mMaxMagnitude < Math.Abs(v))
                {
                    mMaxMagnitude = v;
                }

                r.Set(rIdx, v);
            }

            return(r);
        }
示例#6
0
        private LargeArray <byte> CreatePcmSamples(double[] mls, WasapiCS.SampleFormatType sft, int numCh, int playCh)
        {
            int  sampleBytes = (WasapiCS.SampleFormatTypeToUseBitsPerSample(sft) / 8);
            int  frameBytes  = sampleBytes * numCh;
            long bytes       = (long)mls.Length * frameBytes;
            var  r           = new LargeArray <byte>(bytes);

            long writePos = 0;

            for (long i = 0; i < mls.Length; ++i)
            {
                for (int ch = 0; ch < numCh; ++ch)
                {
                    if (ch != playCh)
                    {
                        for (int c = 0; c < sampleBytes; ++c)
                        {
                            r.Set(writePos++, 0);
                        }
                    }
                    else
                    {
                        int v = 0x7fffffff;

                        // -6dBする。
                        v /= 2;

                        if (mls[i] < 0)
                        {
                            v = -v;
                        }

                        uint uV = (uint)v;

                        for (int c = 0; c < sampleBytes; ++c)
                        {
                            byte b = (byte)(uV >> (8 * (4 - sampleBytes + c)));
                            r.Set(writePos++, b);
                        }
                    }
                }
            }
            return(r);
        }
示例#7
0
            public SampleData1ch(long size)
            {
                sdmData = new LargeArray <byte>(size);
                pos     = 0;

                // 念のため無音をセットする。
                for (long i = 0; i < size; ++i)
                {
                    sdmData.Set(i, 0x69);
                }
            }
示例#8
0
        private LargeArray <float> StereoToMono(LargeArray <byte> v)
        {
            var m = new LargeArray <float>(v.LongLength / 4);

            for (long i = 0; i < v.LongLength / 4; ++i)
            {
                short l = (short)((int)v.At(i * 4 + 0) + 256 * v.At(i * 4 + 1));
                short r = (short)((int)v.At(i * 4 + 2) + 256 * v.At(i * 4 + 3));

                short mix = (short)((l + r) / 2);
                m.Set(i, mix / 32768.0f);
            }

            return(m);
        }
示例#9
0
        public static LargeArray <double> BlackmanWindow(long length)
        {
            // nは奇数
            System.Diagnostics.Debug.Assert((length & 1) == 1);

            var window = new LargeArray <double>(length);

            // 教科書通りに計算すると両端の値が0.0になって
            // せっかくのデータが0にされて勿体無いので両端(pos==0とpos==length-1)の値はカットし、両端を1ずつ広げる
            long m = length + 1;

            for (long i = 0; i < length; ++i)
            {
                long   pos = i + 1;
                double v   = 0.42 - 0.5 * Math.Cos(2.0 * Math.PI * pos / m) + 0.08 * Math.Cos(4.0 * Math.PI * pos / m);
                window.Set(i, v);
            }

            return(window);
        }
        private void FftStageN(int stageNr, LargeArray <WWComplex> x, LargeArray <WWComplex> y)
        {
            /*
             * stage0: 2つの入力データにバタフライ演算 (length=8の時) 4回 (nRepeat=4, nSubRepeat=2)
             * y[0] = x[0] + w_n^(0*4) * x[1]
             * y[1] = x[0] + w_n^(1*4) * x[1]
             *
             * y[2] = x[2] + w_n^(0*4) * x[3]
             * y[3] = x[2] + w_n^(1*4) * x[3]
             *
             * y[4] = x[4] + w_n^(0*4) * x[5]
             * y[5] = x[4] + w_n^(1*4) * x[5]
             *
             * y[6] = x[6] + w_n^(0*4) * x[7]
             * y[7] = x[6] + w_n^(1*4) * x[7]
             */

            /*
             * stage1: 4つの入力データにバタフライ演算 (length=8の時) 2回 (nRepeat=2, nSubRepeat=4)
             * y[0] = x[0] + w_n^(0*2) * x[2]
             * y[1] = x[1] + w_n^(1*2) * x[3]
             * y[2] = x[0] + w_n^(2*2) * x[2]
             * y[3] = x[1] + w_n^(3*2) * x[3]
             *
             * y[4] = x[4] + w_n^(0*2) * x[6]
             * y[5] = x[5] + w_n^(1*2) * x[7]
             * y[6] = x[4] + w_n^(2*2) * x[6]
             * y[7] = x[5] + w_n^(3*2) * x[7]
             */

            /*
             * stage2: 8つの入力データにバタフライ演算 (length=8の時) 1回 (nRepeat=1, nSubRepeat=8)
             * y[0] = x[0] + w_n^(0*1) * x[4]
             * y[1] = x[1] + w_n^(1*1) * x[5]
             * y[2] = x[2] + w_n^(2*1) * x[6]
             * y[3] = x[3] + w_n^(3*1) * x[7]
             * y[4] = x[0] + w_n^(4*1) * x[4]
             * y[5] = x[1] + w_n^(5*1) * x[5]
             * y[6] = x[2] + w_n^(6*1) * x[6]
             * y[7] = x[3] + w_n^(7*1) * x[7]
             */

            /*
             * stageN:
             */

            long nRepeat    = Pow2(mNumStage - stageNr - 1);
            long nSubRepeat = mNumPoints / nRepeat;

            for (long i = 0; i < nRepeat; ++i)
            {
                long offsBase = i * nSubRepeat;

                bool allZero = true;
                for (long j = 0; j < nSubRepeat / 2; ++j)
                {
                    long offs = offsBase + (j % (nSubRepeat / 2));
                    if (Double.Epsilon < x.At(offs).Magnitude())
                    {
                        allZero = false;
                        break;
                    }
                    if (Double.Epsilon < x.At(offs + nSubRepeat / 2).Magnitude())
                    {
                        allZero = false;
                        break;
                    }
                }

                if (allZero)
                {
                    for (long j = 0; j < nSubRepeat; ++j)
                    {
                        y.Set(j + offsBase, WWComplex.Zero());
                    }
                }
                else
                {
                    for (long j = 0; j < nSubRepeat; ++j)
                    {
                        long offs = offsBase + (j % (nSubRepeat / 2));
                        var  t    = x.At(offs);

                        var t2 = WWComplex.Mul(mWn.At(j * nRepeat), x.At(offs + nSubRepeat / 2));
                        var t3 = WWComplex.Add(t, t2);

                        y.Set(j + offsBase, t3);
                    }
                }
            }
        }
示例#11
0
        public static LargeArray <byte> ConvertTo32bitInt(
            int bitsPerSample, long numSamples,
            PcmData.ValueRepresentationType valueType, LargeArray <byte> data)
        {
            if (bitsPerSample == 32 && valueType == PcmData.ValueRepresentationType.SInt)
            {
                // すでに所望の形式。
                return(data);
            }

            var data32 = new LargeArray <byte>(numSamples * 4);

            switch (valueType)
            {
            case PcmData.ValueRepresentationType.SInt:
                switch (bitsPerSample)
                {
                case 16:
                    for (long i = 0; i < numSamples; ++i)
                    {
                        short v16 = (short)(
                            (uint)data.At(i * 2)
                            + ((uint)data.At(i * 2 + 1) << 8));
                        int v32 = v16;
                        v32 *= 65536;
                        data32.Set(i * 4 + 0, 0);
                        data32.Set(i * 4 + 1, 0);
                        data32.Set(i * 4 + 2, (byte)((v32 & 0x00ff0000) >> 16));
                        data32.Set(i * 4 + 3, (byte)((v32 & 0xff000000) >> 24));
                    }
                    return(data32);

                case 24:
                    for (long i = 0; i < numSamples; ++i)
                    {
                        int v32 = (int)(
                            ((uint)data.At(i * 3 + 0) << 8)
                            + ((uint)data.At(i * 3 + 1) << 16)
                            + ((uint)data.At(i * 3 + 2) << 24));
                        data32.Set(i * 4 + 0, 0);
                        data32.Set(i * 4 + 1, (byte)((v32 & 0x0000ff00) >> 8));
                        data32.Set(i * 4 + 2, (byte)((v32 & 0x00ff0000) >> 16));
                        data32.Set(i * 4 + 3, (byte)((v32 & 0xff000000) >> 24));
                    }
                    return(data32);

                case 32:
                    // 所望の形式。
                    System.Diagnostics.Debug.Assert(false);
                    return(null);

                case 64:
                    for (long i = 0; i < numSamples; ++i)
                    {
                        // 16.48 fixed point
                        int v32 = (int)(
                            ((uint)data.At(i * 8 + 2) << 0)
                            + ((uint)data.At(i * 8 + 3) << 8)
                            + ((uint)data.At(i * 8 + 4) << 16)
                            + ((uint)data.At(i * 8 + 5) << 24));
                        data32.Set(i * 4 + 0, (byte)((v32 & 0x000000ff) >> 0));
                        data32.Set(i * 4 + 1, (byte)((v32 & 0x0000ff00) >> 8));
                        data32.Set(i * 4 + 2, (byte)((v32 & 0x00ff0000) >> 16));
                        data32.Set(i * 4 + 3, (byte)((v32 & 0xff000000) >> 24));
                    }
                    return(data32);

                default:
                    System.Diagnostics.Debug.Assert(false);
                    return(null);
                }

            case PcmData.ValueRepresentationType.SFloat:
                for (long i = 0; i < numSamples; ++i)
                {
                    double v;
                    switch (bitsPerSample)
                    {
                    case 32: {
                        var b4 = new byte[4];
                        data.CopyTo(i * 4, ref b4, 0, 4);
                        v = BitConverter.ToSingle(b4, 0);
                    }
                    break;

                    case 64: {
                        var b8 = new byte[8];
                        data.CopyTo(i * 8, ref b8, 0, 8);
                        v = BitConverter.ToDouble(b8, 0);
                    }
                    break;

                    default:
                        System.Diagnostics.Debug.Assert(false);
                        return(null);
                    }

                    int v32 = 0;
                    if (1.0f <= v)
                    {
                        v32 = Int32.MaxValue;
                    }
                    else if (v < -1.0f)
                    {
                        v32 = Int32.MinValue;
                    }
                    else
                    {
                        long vMax = -((long)Int32.MinValue);

                        long v64 = (long)(v * vMax);
                        if (Int32.MaxValue < v64)
                        {
                            v64 = Int32.MaxValue;
                        }
                        v32 = (int)v64;
                    }

                    data32.Set(i * 4 + 0, (byte)((v32 & 0x000000ff) >> 0));
                    data32.Set(i * 4 + 1, (byte)((v32 & 0x0000ff00) >> 8));
                    data32.Set(i * 4 + 2, (byte)((v32 & 0x00ff0000) >> 16));
                    data32.Set(i * 4 + 3, (byte)((v32 & 0xff000000) >> 24));
                }
                return(data32);

            default:
                System.Diagnostics.Debug.Assert(false);
                return(null);
            }
        }
示例#12
0
        /// <summary>
        /// float配列のPCMデータを指定ビットデプスのbyte配列PCMデータにする。
        /// </summary>
        public static LargeArray <byte> ConvertToByteArrayPCM(LargeArray <float> from, int bytesPerSample)
        {
            var  w    = new LargeArray <byte>(from.LongLength * bytesPerSample);
            long wIdx = 0;

            switch (bytesPerSample)
            {
            case 2:
                for (long pos = 0; pos < from.LongLength; ++pos)
                {
                    // 値vを取得。
                    float vF = from.At(pos);
                    if (vF < -1.0f)
                    {
                        vF = -1.0f;
                    }
                    if (32767.0f / 32768.0f < vF)
                    {
                        vF = 32767.0f / 32768.0f;
                    }

                    // 型変換。
                    short vS = (short)(vF * 32768.0f);

                    //Console.WriteLine("{0:+00000;-00000}", vS);

                    // 書き込み。
                    w.Set(wIdx++, (byte)(vS & 0xff));
                    w.Set(wIdx++, (byte)((vS >> 8) & 0xff));
                }
                break;

            case 3:
                for (long pos = 0; pos < from.LongLength; ++pos)
                {
                    // 値vを取得。
                    float vF = from.At(pos);
                    if (vF < -1.0f)
                    {
                        vF = -1.0f;
                    }
                    if (8388607.0f / 8388608.0f < vF)
                    {
                        vF = 8388607.0f / 8388608.0f;
                    }

                    // 型変換。
                    int vI = (int)(vF * 2147483648.0f);

                    // 書き込み。
                    w.Set(wIdx++, (byte)((vI >> 8) & 0xff));
                    w.Set(wIdx++, (byte)((vI >> 16) & 0xff));
                    w.Set(wIdx++, (byte)((vI >> 24) & 0xff));
                }
                break;

            default:
                throw new ArgumentException(string.Format("Unexpected BytesPerSample {0}", bytesPerSample));
            }

            return(w);
        }