示例#1
0
        private void buttonItUpsampleStart_Click(object sender, RoutedEventArgs e)
        {
            var args = new FirWorkerArgs();

            args.inputPath  = textBoxItUpsampleInputPath.Text;
            args.outputPath = textBoxItUpsampleOutputPath.Text;

            if (true == radioButtonItUpsampleSint16.IsChecked)
            {
                args.outputBitsPerSample     = 16;
                args.valueRepresentationType = PcmData.ValueRepresentationType.SInt;
            }
            if (true == radioButtonItUpsampleSint24.IsChecked)
            {
                args.outputBitsPerSample     = 24;
                args.valueRepresentationType = PcmData.ValueRepresentationType.SInt;
            }
            if (true == radioButtonItUpsampleSfloat32.IsChecked)
            {
                args.outputBitsPerSample     = 32;
                args.valueRepresentationType = PcmData.ValueRepresentationType.SFloat;
            }

            mFreqMagnitude = 0;
            if (!Int32.TryParse(textBoxItUpsampleFreqMagnitude.Text, out mFreqMagnitude) ||
                mFreqMagnitude <= 1)
            {
                MessageBox.Show("アップサンプル倍率は2以上の整数を入力して下さい");
                return;
            }

            mItUpsampleType = ItUpsampleType.Unknown;
            if (true == radioButtonItUpsampleImpulse.IsChecked)
            {
                mItUpsampleType = ItUpsampleType.ImpulseTrain;
            }
            if (true == radioButtonItUpsampleSampleHold.IsChecked)
            {
                mItUpsampleType = ItUpsampleType.SampleHold;
            }
            if (true == radioButtonItUpsampleLinear.IsChecked)
            {
                mItUpsampleType = ItUpsampleType.Linear;
            }
            if (true == radioButtonItUpsampleCubic.IsChecked)
            {
                mItUpsampleType = ItUpsampleType.Cubic;
            }
            System.Diagnostics.Debug.Assert(mItUpsampleType != ItUpsampleType.Unknown);

            textBoxItUpsampleLog.Text += string.Format("開始。{0} ==> {1} {2}x\r\n",
                                                       args.inputPath, args.outputPath, mFreqMagnitude);
            textBoxItUpsampleLog.ScrollToEnd();

            buttonItUpsampleDo.IsEnabled = false;
            mItUpsampleWorker.RunWorkerAsync(args);
        }
示例#2
0
        /// <summary>
        /// FIR実行
        /// </summary>
        private void buttonFirDo_Click(object sender, RoutedEventArgs e)
        {
            int filterLength;

            if (!Int32.TryParse(textBoxFirLength.Text, out filterLength) ||
                (filterLength & 1) == 0 || filterLength <= 0)
            {
                MessageBox.Show("FIRフィルタ長は正の奇数の数値を半角数字で入力してください。処理中断。");
                return;
            }
            m_firTapN = filterLength + 1;

            var args = new FirWorkerArgs();

            args.inputPath  = textBoxFirInputPath.Text;
            args.outputPath = textBoxFirOutputPath.Text;
            if (radioButtonFir16bit.IsChecked == true)
            {
                args.outputBitsPerSample     = 16;
                args.valueRepresentationType = PcmData.ValueRepresentationType.SInt;
            }
            if (radioButtonFir24bit.IsChecked == true)
            {
                args.outputBitsPerSample     = 24;
                args.valueRepresentationType = PcmData.ValueRepresentationType.SInt;
            }
            if (radioButtonFir32bitFloat.IsChecked == true)
            {
                args.outputBitsPerSample     = 32;
                args.valueRepresentationType = PcmData.ValueRepresentationType.SFloat;
            }

            if (!Double.TryParse(textBoxKaiserAlpha.Text, out args.kaiserAlpha) ||
                args.kaiserAlpha <= 4.0 || 9.0 <= args.kaiserAlpha)
            {
                MessageBox.Show("カイザー窓α値は4.0<α<9.0の範囲の数値を半角数字で入力してください。処理中断。");
                return;
            }

            if (radioButtonFirBlackman.IsChecked == true)
            {
                args.windowFunc = WindowFuncType.Blackman;
            }
            else
            {
                args.windowFunc = WindowFuncType.Kaiser;
            }

            AddFirLog(string.Format("開始。{0} → {1}\r\n", args.inputPath, args.outputPath));
            buttonFirDo.IsEnabled           = false;
            groupBoxFirInputFile.IsEnabled  = false;
            groupBoxFirEq.IsEnabled         = false;
            groupBoxFirOutputFile.IsEnabled = false;
            groupBoxFirWindow.IsEnabled     = false;
            m_FirWorker.RunWorkerAsync(args);
        }
        private void buttonItUpsampleStart_Click(object sender, RoutedEventArgs e)
        {
            var args = new FirWorkerArgs();
            args.inputPath = textBoxItUpsampleInputPath.Text;
            args.outputPath = textBoxItUpsampleOutputPath.Text;

            if (true == radioButtonItUpsampleSint16.IsChecked) {
                args.outputBitsPerSample = 16;
                args.valueRepresentationType = PcmData.ValueRepresentationType.SInt;
            }
            if (true == radioButtonItUpsampleSint24.IsChecked) {
                args.outputBitsPerSample = 24;
                args.valueRepresentationType = PcmData.ValueRepresentationType.SInt;
            }
            if (true == radioButtonItUpsampleSfloat32.IsChecked) {
                args.outputBitsPerSample = 32;
                args.valueRepresentationType = PcmData.ValueRepresentationType.SFloat;
            }

            mFreqMagnitude = 0;
            if (!Int32.TryParse(textBoxItUpsampleFreqMagnitude.Text, out mFreqMagnitude)
                    || mFreqMagnitude <= 1) {
                MessageBox.Show("アップサンプル倍率は2以上の整数を入力して下さい");
                return;
            }

            mItUpsampleType = ItUpsampleType.Unknown;
            if (true == radioButtonItUpsampleImpulse.IsChecked) {
                mItUpsampleType = ItUpsampleType.ImpulseTrain;
            }
            if (true == radioButtonItUpsampleSampleHold.IsChecked) {
                mItUpsampleType = ItUpsampleType.SampleHold;
            }
            if (true == radioButtonItUpsampleLinear.IsChecked) {
                mItUpsampleType = ItUpsampleType.Linear;
            }
            if (true == radioButtonItUpsampleCubic.IsChecked) {
                mItUpsampleType = ItUpsampleType.Cubic;
            }
            System.Diagnostics.Debug.Assert(mItUpsampleType != ItUpsampleType.Unknown);

            textBoxItUpsampleLog.Text += string.Format("開始。{0} ==> {1} {2}x\r\n",
                args.inputPath, args.outputPath, mFreqMagnitude);
            textBoxItUpsampleLog.ScrollToEnd();

            buttonItUpsampleDo.IsEnabled = false;
            mItUpsampleWorker.RunWorkerAsync(args);
        }
示例#4
0
        void m_HilbWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            FirWorkerArgs args = (FirWorkerArgs)e.Argument;

            Stopwatch sw = new Stopwatch();

            sw.Start();

            string result;

            if (!FirDoLoadConvertSave(args, HilbertDo, out result))
            {
                e.Result = result;
                return;
            }

            sw.Stop();
            e.Result = string.Format("{0}\r\n所要時間 {1}秒",
                                     result, sw.ElapsedMilliseconds / 1000);
        }
示例#5
0
        // この関数は音量制限を行わない。呼び出し側で必要に応じて音量を制限する。
        private bool PhaseRotationDo(FirWorkerArgs argsFWA, PcmData pcmDataIn, out PcmData pcmDataOutput)
        {
            PhaseRotationWorkerArgs args = argsFWA as PhaseRotationWorkerArgs;

            var     conv        = new WasapiPcmUtil.PcmFormatConverter(pcmDataIn.NumChannels);
            PcmData pcmDataReal = conv.Convert(pcmDataIn, Wasapi.WasapiCS.SampleFormatType.Sdouble, null);

            pcmDataOutput = new PcmData();
            pcmDataOutput.CopyFrom(pcmDataIn);

            PcmData pcmDataImaginary = new PcmData();

            pcmDataImaginary.CopyFrom(pcmDataReal);

            var dft = new WWDirectComputeCS.WWDftCpu();

            var hilb = WWHilbert.HilbertFirCoeff(args.hilbertFilterType, args.firLength);

            System.Diagnostics.Debug.Assert(hilb.Length == args.firLength);

            // 窓関数
            double [] window;
            if (args.windowFunc == WindowFuncType.Blackman)
            {
                WWWindowFunc.BlackmanWindow(args.firLength, out window);
            }
            else
            {
                WWWindowFunc.KaiserWindow(args.firLength, args.kaiserAlpha, out window);
            }

            // FIR coeffの個数は、window.Length個。
            // ヒルベルト変換パラメータは未来から過去の方向に並んでいるので左右をひっくり返す。
            double [] coeff = new double[args.firLength];
            for (int i = 0; i < coeff.Length; ++i)
            {
                int pos = coeff.Length - i - 1;
                coeff[i] = hilb[pos] * window[i];
            }

            for (int ch = 0; ch < pcmDataImaginary.NumChannels; ++ch)
            {
                var pcm1ch = new double[pcmDataImaginary.NumFrames];
                for (long i = 0; i < pcm1ch.Length; ++i)
                {
                    pcm1ch[i] = pcmDataImaginary.GetSampleValueInDouble(ch, i);
                }

                // 少しずつFIRする。
                var fir = new WWFirCpu();
                fir.Setup(coeff, pcm1ch);

                const int FIR_SAMPLE = 65536;
                for (int offs = 0; offs < pcm1ch.Length; offs += FIR_SAMPLE)
                {
                    int nSample = FIR_SAMPLE;
                    if (pcm1ch.Length < offs + nSample)
                    {
                        nSample = pcm1ch.Length - offs;
                    }

                    var pcmFir = new double[nSample];
                    fir.Do(offs - window.Length / 2, nSample, pcmFir);

                    // 結果を出力に書き込む。
                    for (long i = 0; i < pcmFir.Length; ++i)
                    {
                        var re = pcmFir[i];
                        pcmDataImaginary.SetSampleValueInDouble(ch, i + offs,
                                                                (float)(re));
                    }

                    // 進捗Update。
                    int percentage = (int)(
                        (100L * ch / pcmDataImaginary.NumChannels) +
                        (100L * (offs + 1) / pcm1ch.Length / pcmDataImaginary.NumChannels));
                    mPRWorker.ReportProgress(percentage);
                }
                fir.Unsetup();
            }

            // 音の位相を回転。
            for (int ch = 0; ch < pcmDataReal.NumChannels; ++ch)
            {
                for (long pos = 0; pos < pcmDataReal.NumFrames; ++pos)
                {
                    // 解析信号の各サンプル値を極座標表現に変換。オリジナルの長さと位相を得る。
                    // 長さをそのままに位相を回転し、回転後の実数成分を出力する。

                    double x = pcmDataReal.GetSampleValueInDouble(ch, pos);
                    double y = pcmDataImaginary.GetSampleValueInDouble(ch, pos);

                    double norm  = Math.Sqrt(x * x + y * y);
                    double theta = Math.Atan2(y, x);

                    double re = norm * Math.Cos(theta + args.phaseRadian);
                    pcmDataOutput.SetSampleValueInDouble(ch, pos, re);
                }
            }
            return(true);
        }
        // この関数は音量制限を行わない。呼び出し側で必要に応じて音量を制限する。
        private bool PhaseRotationDo(FirWorkerArgs argsFWA, PcmData pcmDataIn, out PcmData pcmDataOutput)
        {
            PhaseRotationWorkerArgs args = argsFWA as PhaseRotationWorkerArgs;

            var conv = new WasapiPcmUtil.PcmFormatConverter(pcmDataIn.NumChannels);
            PcmData pcmDataReal = conv.Convert(pcmDataIn, Wasapi.WasapiCS.SampleFormatType.Sdouble, null);

            pcmDataOutput = new PcmData();
            pcmDataOutput.CopyFrom(pcmDataIn);

            PcmData pcmDataImaginary = new PcmData();
            pcmDataImaginary.CopyFrom(pcmDataReal);

            var dft = new WWDirectComputeCS.WWDftCpu();

            var hilb = WWHilbert.HilbertFirCoeff(args.hilbertFilterType, args.firLength);
            System.Diagnostics.Debug.Assert(hilb.Length == args.firLength);

            // 窓関数
            double [] window;
            if (args.windowFunc == WindowFuncType.Blackman) {
                WWWindowFunc.BlackmanWindow(args.firLength, out window);
            } else {
                WWWindowFunc.KaiserWindow(args.firLength, args.kaiserAlpha, out window);
            }

            // FIR coeffの個数は、window.Length個。
            // ヒルベルト変換パラメータは未来から過去の方向に並んでいるので左右をひっくり返す。
            double [] coeff = new double[args.firLength];
            for (int i=0; i < coeff.Length; ++i) {
                int pos = coeff.Length - i - 1;
                coeff[i] = hilb[pos] * window[i];
            }

            for (int ch=0; ch < pcmDataImaginary.NumChannels; ++ch) {
                var pcm1ch = new double[pcmDataImaginary.NumFrames];
                for (long i=0; i < pcm1ch.Length; ++i) {
                    pcm1ch[i] = pcmDataImaginary.GetSampleValueInDouble(ch, i);
                }

                // 少しずつFIRする。
                var fir = new WWFirCpu();
                fir.Setup(coeff, pcm1ch);

                const int FIR_SAMPLE = 65536;
                for (int offs=0; offs < pcm1ch.Length; offs += FIR_SAMPLE) {
                    int nSample = FIR_SAMPLE;
                    if (pcm1ch.Length < offs + nSample) {
                        nSample = pcm1ch.Length - offs;
                    }

                    var pcmFir = new double[nSample];
                    fir.Do(offs - window.Length / 2, nSample, pcmFir);

                    // 結果を出力に書き込む。
                    for (long i=0; i < pcmFir.Length; ++i) {
                        var re = pcmFir[i];
                        pcmDataImaginary.SetSampleValueInDouble(ch, i + offs,
                            (float)(re));
                    }

                    // 進捗Update。
                    int percentage = (int)(
                        (100L * ch / pcmDataImaginary.NumChannels) +
                        (100L * (offs + 1) / pcm1ch.Length / pcmDataImaginary.NumChannels));
                    mPRWorker.ReportProgress(percentage);
                }
                fir.Unsetup();

            }

            // 音の位相を回転。
            for (int ch=0; ch < pcmDataReal.NumChannels; ++ch) {
                for (long pos=0; pos < pcmDataReal.NumFrames; ++pos) {

                    // 解析信号の各サンプル値を極座標表現に変換。オリジナルの長さと位相を得る。
                    // 長さをそのままに位相を回転し、回転後の実数成分を出力する。

                    double x = pcmDataReal.GetSampleValueInDouble(ch, pos);
                    double y = pcmDataImaginary.GetSampleValueInDouble(ch, pos);

                    double norm = Math.Sqrt(x * x + y * y);
                    double theta = Math.Atan2(y, x);

                    double re = norm * Math.Cos(theta + args.phaseRadian);
                    pcmDataOutput.SetSampleValueInDouble(ch, pos, re);
                }
            }
            return true;
        }
        private bool HilbertDo(FirWorkerArgs argsFir, PcmData pcmDataIn, out PcmData pcmDataOutput)
        {
            HilbertWorkerArgs args = argsFir as HilbertWorkerArgs;

            var dft = new WWDirectComputeCS.WWDftCpu();

            var hilb = WWHilbert.HilbertFirCoeff(args.hilbertFilterType, args.firLength);
            System.Diagnostics.Debug.Assert(hilb.Length == args.firLength);

            // 窓関数
            double [] window;
            if (args.windowFunc == WindowFuncType.Blackman) {
                WWWindowFunc.BlackmanWindow(args.firLength, out window);
            } else {
                WWWindowFunc.KaiserWindow(args.firLength, args.kaiserAlpha, out window);
            }

            // FIR coeffの個数は、window.Length個。
            // ヒルベルト変換パラメータは未来から過去の方向に並んでいるので左右をひっくり返す。
            double [] coeff = new double[args.firLength];
            for (int i=0; i<coeff.Length; ++i) {
                int pos = coeff.Length - i - 1;
                coeff[i] = hilb[pos] * window[i];
            }

            /*
            for (int i=0; i < coeff.Length; ++i) {
                System.Console.WriteLine("coeff {0:D2} {1}", i, coeff[i]);
            }
            System.Console.WriteLine("");
            */

            pcmDataOutput = new PcmData();
            pcmDataOutput.CopyFrom(pcmDataIn);

            for (int ch=0; ch < pcmDataOutput.NumChannels; ++ch) {
                // 全てのチャンネルでループ。

                var pcm1ch = new double[pcmDataOutput.NumFrames];
                for (long i=0; i < pcm1ch.Length; ++i) {
                    pcm1ch[i] = pcmDataOutput.GetSampleValueInDouble(ch, i);
                }

                // 少しずつFIRする。
                var fir = new WWFirCpu();
                fir.Setup(coeff, pcm1ch);

                const int FIR_SAMPLE = 65536;
                for (int offs=0; offs < pcm1ch.Length; offs += FIR_SAMPLE) {
                    int nSample = FIR_SAMPLE;
                    if (pcm1ch.Length < offs + nSample) {
                        nSample = pcm1ch.Length - offs;
                    }

                    var pcmFir = new double[nSample];
                    fir.Do(offs - window.Length / 2, nSample, pcmFir);

                    // 結果を出力に書き込む。
                    for (long i=0; i < pcmFir.Length; ++i) {
                        var re = pcmFir[i];
                        pcmDataOutput.SetSampleValueInDouble(ch, i + offs, re);
                    }

                    // 進捗Update。
                    int percentage = (int)(
                        ( 100L * ch / pcmDataOutput.NumChannels ) +
                        ( 100L * ( offs + 1 ) / pcm1ch.Length / pcmDataOutput.NumChannels ) );
                    m_HilbWorker.ReportProgress(percentage);
                }
                fir.Unsetup();
            }

            return true;
        }
        private bool ItUpsampleDo(FirWorkerArgs args, PcmData pcmDataIn, out PcmData pcmDataOut)
        {
            pcmDataOut = new PcmData();
            pcmDataOut.SetFormat(pcmDataIn.NumChannels, 64, 64,
                pcmDataIn.SampleRate * mFreqMagnitude,
                PcmData.ValueRepresentationType.SFloat, pcmDataIn.NumFrames * mFreqMagnitude);
            pcmDataOut.SetSampleArray(new byte[pcmDataOut.NumFrames * pcmDataOut.BitsPerFrame / 8]);

            var pcm = pcmDataOut;

            switch (mItUpsampleType) {
            case ItUpsampleType.ImpulseTrain:
                Parallel.For(0, pcmDataIn.NumFrames, (pos) => {
                    for (int ch=0; ch < pcmDataIn.NumChannels; ++ch) {
                        var v = pcmDataIn.GetSampleValueInDouble(ch, pos);
                        pcm.SetSampleValueInDouble(ch, pos * mFreqMagnitude, v);
                    }
                });
                break;

            case ItUpsampleType.SampleHold:
                Parallel.For(0, pcmDataIn.NumFrames, (pos) => {
                    for (int ch=0; ch < pcmDataIn.NumChannels; ++ch) {
                        var v = pcmDataIn.GetSampleValueInDouble(ch, pos);
                        for (int i=0; i < mFreqMagnitude; ++i) {
                            pcm.SetSampleValueInDouble(ch, pos * mFreqMagnitude+i, v);
                        }
                    }
                });
                break;

            case ItUpsampleType.Linear:
                Parallel.For(0, pcmDataIn.NumFrames - 1, (pos) => {
                    // 0 <= pos <= NumFrames-2まで実行する
                    for (int ch=0; ch < pcmDataIn.NumChannels; ++ch) {
                        var v0 = pcmDataIn.GetSampleValueInDouble(ch, pos);
                        var v1 = pcmDataIn.GetSampleValueInDouble(ch, pos + 1);
                        for (int i=0; i < mFreqMagnitude; ++i) {
                            var ratio = (double)i / mFreqMagnitude;
                            var v = v0 * (1 - ratio) + v1 * ratio;
                            pcm.SetSampleValueInDouble(ch, pos * mFreqMagnitude + i, v);
                        }
                    }
                });

                // 最後の1区間は0に向かう
                for (int ch=0; ch < pcmDataIn.NumChannels; ++ch) {
                    var pos = pcmDataIn.NumFrames-1;
                    var v = pcmDataIn.GetSampleValueInDouble(ch, pos);
                    for (int i=0; i < mFreqMagnitude; ++i) {
                        pcm.SetSampleValueInDouble(ch, pos * mFreqMagnitude + i, v * (mFreqMagnitude - i-1) / mFreqMagnitude);
                    }
                }
                break;

            case ItUpsampleType.Cubic: {
                    var h = new double[4 * mFreqMagnitude];
                    double a = -0.5;
                    for (int i=0; i < mFreqMagnitude; ++i) {
                        double t = (double)i/mFreqMagnitude;
                        h[mFreqMagnitude * 2 + i] = (a + 2) * t * t * t - (a + 3) * t * t + 1;
                        h[mFreqMagnitude * 2 - i] = h[mFreqMagnitude * 2 +i];
                    }
                    for (int i=mFreqMagnitude; i < mFreqMagnitude * 2; ++i) {
                        double t = (double)i / mFreqMagnitude;
                        h[mFreqMagnitude * 2 + i] = a * t * t * t - 5 * a * t * t + 8 * a * t - 4 * a;
                        h[mFreqMagnitude * 2 - i] = h[mFreqMagnitude * 2 + i];
                    }
                    Parallel.For(0, pcmDataOut.NumFrames, (pos) => {
                        for (int ch=0; ch < pcmDataIn.NumChannels; ++ch) {
                            var x = new double[4 * mFreqMagnitude];
                            for (int i=0; i < 4 * mFreqMagnitude; ++i) {
                                if (0 == (pos + i) % mFreqMagnitude) {
                                    x[i] = pcmDataIn.GetSampleValueInDouble(ch, (pos+i)/mFreqMagnitude);
                                }
                            }
                            double v = 0;
                            for (int i=0; i < 4* mFreqMagnitude; ++i) {
                                v += h[i] * x[i];
                            }
                            pcm.SetSampleValueInDouble(ch, pos, v);
                        }
                    });
                }
                break;
            default:
                System.Diagnostics.Debug.Assert(false);
                break;
            }

            return true;
        }
示例#9
0
        private bool HilbertDo(FirWorkerArgs argsFir, PcmData pcmDataIn, out PcmData pcmDataOutput)
        {
            HilbertWorkerArgs args = argsFir as HilbertWorkerArgs;

            var dft = new WWDirectComputeCS.WWDftCpu();

            var hilb = WWHilbert.HilbertFirCoeff(args.hilbertFilterType, args.firLength);

            System.Diagnostics.Debug.Assert(hilb.Length == args.firLength);

            // 窓関数
            double [] window;
            if (args.windowFunc == WindowFuncType.Blackman)
            {
                WWWindowFunc.BlackmanWindow(args.firLength, out window);
            }
            else
            {
                WWWindowFunc.KaiserWindow(args.firLength, args.kaiserAlpha, out window);
            }

            // FIR coeffの個数は、window.Length個。
            // ヒルベルト変換パラメータは未来から過去の方向に並んでいるので左右をひっくり返す。
            double [] coeff = new double[args.firLength];
            for (int i = 0; i < coeff.Length; ++i)
            {
                int pos = coeff.Length - i - 1;
                coeff[i] = hilb[pos] * window[i];
            }

            /*
             * for (int i=0; i < coeff.Length; ++i) {
             *  System.Console.WriteLine("coeff {0:D2} {1}", i, coeff[i]);
             * }
             * System.Console.WriteLine("");
             */

            pcmDataOutput = new PcmData();
            pcmDataOutput.CopyFrom(pcmDataIn);

            for (int ch = 0; ch < pcmDataOutput.NumChannels; ++ch)
            {
                // 全てのチャンネルでループ。

                var pcm1ch = new double[pcmDataOutput.NumFrames];
                for (long i = 0; i < pcm1ch.Length; ++i)
                {
                    pcm1ch[i] = pcmDataOutput.GetSampleValueInDouble(ch, i);
                }

                // 少しずつFIRする。
                var fir = new WWFirCpu();
                fir.Setup(coeff, pcm1ch);

                const int FIR_SAMPLE = 65536;
                for (int offs = 0; offs < pcm1ch.Length; offs += FIR_SAMPLE)
                {
                    int nSample = FIR_SAMPLE;
                    if (pcm1ch.Length < offs + nSample)
                    {
                        nSample = pcm1ch.Length - offs;
                    }

                    var pcmFir = new double[nSample];
                    fir.Do(offs - window.Length / 2, nSample, pcmFir);

                    // 結果を出力に書き込む。
                    for (long i = 0; i < pcmFir.Length; ++i)
                    {
                        var re = pcmFir[i];
                        pcmDataOutput.SetSampleValueInDouble(ch, i + offs, re);
                    }

                    // 進捗Update。
                    int percentage = (int)(
                        (100L * ch / pcmDataOutput.NumChannels) +
                        (100L * (offs + 1) / pcm1ch.Length / pcmDataOutput.NumChannels));
                    m_HilbWorker.ReportProgress(percentage);
                }
                fir.Unsetup();
            }

            return(true);
        }
示例#10
0
        private bool FirDoLoadConvertSave(FirWorkerArgs args, FirDelegate Do, out string result)
        {
            // pcmファイルを読み込んでサンプル配列pcm1chを作成。
            PcmData pcmDataIn = null;

            try {
                pcmDataIn = ReadWavFile(args.inputPath);
            } catch (IOException ex) {
                result = string.Format("WAVファイル {0} 読み込み失敗\r\n{1}", args.inputPath, ex);
                return(false);
            }
            if (null == pcmDataIn)
            {
                result = string.Format("WAVファイル {0} 読み込み失敗", args.inputPath);
                return(false);
            }

            var formatConv = new WasapiPcmUtil.PcmFormatConverter(pcmDataIn.NumChannels);

            pcmDataIn = formatConv.Convert(pcmDataIn, Wasapi.WasapiCS.SampleFormatType.Sdouble, null);

            PcmData pcmDataOutput;

            if (!Do(args, pcmDataIn, out pcmDataOutput))
            {
                result = "FIR処理失敗";
                return(false);
            }

            // サンプルフォーマットが整数型の時だけ音量制限処理する。
            double scale    = 1.0;
            double maxLevel = 0.0f;

            if (args.valueRepresentationType == PcmData.ValueRepresentationType.SInt)
            {
                scale = pcmDataOutput.LimitLevelOnDoubleRange();
            }
            else
            {
                double maxV, minV;
                pcmDataOutput.FindMaxMinValueOnDoubleBuffer(out maxV, out minV);
                maxLevel = Math.Max(Math.Abs(maxV), Math.Abs(minV));
            }

            PcmData pcmDataWrite = formatConv.Convert(pcmDataOutput,
                                                      Wasapi.WasapiCS.BitAndFormatToSampleFormatType(args.outputBitsPerSample, args.outputBitsPerSample, (Wasapi.WasapiCS.BitFormatType)args.valueRepresentationType), null);

            bool writeResult = false;

            try {
                writeResult = WriteWavFile(pcmDataWrite, args.outputPath);
            } catch (IOException ex) {
                result = string.Format("WAVファイル書き込み失敗: {0}\r\n{1}", args.outputPath, ex);
                return(false);
            }
            if (!writeResult)
            {
                result = string.Format("WAVファイル書き込み失敗: {0}", args.outputPath);
                return(false);
            }

            if (args.valueRepresentationType == PcmData.ValueRepresentationType.SInt)
            {
                if (scale == 1.0)
                {
                    result = string.Format("WAVファイル書き込み成功: {0}", args.outputPath);
                }
                else
                {
                    result = string.Format("WAVファイル書き込み成功: {0}\r\nレベルオーバーのため音量を{1:0.######}倍しました({2:0.######}dB)",
                                           args.outputPath, scale, 20.0 * Math.Log10(scale));
                }
            }
            else
            {
                result = string.Format("WAVファイル書き込み成功: {0}\r\nサンプル値の絶対値の最大値 {1:0.######}",
                                       args.outputPath, maxLevel);
            }
            return(true);
        }
示例#11
0
        private bool FirDo(FirWorkerArgs args, PcmData pcmDataIn, out PcmData pcmDataOut)
        {
            var dft = new WWDirectComputeCS.WWDftCpu();

            var from = FreqGraphToIdftInput(pcmDataIn.SampleRate);

            double [] idftResult;
            dft.Idft1d(from, out idftResult);

            // 窓関数の要素数は、IDFT結果の複素数の個数 -1個。
            double [] window;

            if (args.windowFunc == WindowFuncType.Blackman)
            {
                WWWindowFunc.BlackmanWindow((idftResult.Length / 2) - 1, out window);
            }
            else
            {
                WWWindowFunc.KaiserWindow((idftResult.Length / 2) - 1, args.kaiserAlpha, out window);
            }

            // FIR coeffの個数は、window.Length個。
            double [] coeff;
            dft.IdftComplexToFirCoeff1d(idftResult, window, out coeff);

            /*
             * for (int i=0; i < coeff.Length; ++i) {
             *  System.Console.WriteLine("coeff {0:D2} {1}", i, coeff[i]);
             * }
             * System.Console.WriteLine("");
             */

            pcmDataOut = new PcmData();
            pcmDataOut.CopyFrom(pcmDataIn);

            for (int ch = 0; ch < pcmDataOut.NumChannels; ++ch)
            {
                // 全てのチャンネルでループ。

                var pcm1ch = new double[pcmDataOut.NumFrames];
                for (long i = 0; i < pcm1ch.Length; ++i)
                {
                    pcm1ch[i] = pcmDataOut.GetSampleValueInDouble(ch, i);
                }

                // 少しずつFIRする。
                var fir = new WWFirCpu();
                fir.Setup(coeff, pcm1ch);

                const int FIR_SAMPLE = 65536;
                for (int offs = 0; offs < pcm1ch.Length; offs += FIR_SAMPLE)
                {
                    int nSample = FIR_SAMPLE;
                    if (pcm1ch.Length < offs + nSample)
                    {
                        nSample = pcm1ch.Length - offs;
                    }

                    var pcmFir = new double[nSample];
                    fir.Do(offs - window.Length / 2, nSample, pcmFir);

                    // 結果を出力に書き込む。
                    for (long i = 0; i < pcmFir.Length; ++i)
                    {
                        var re = pcmFir[i];
                        pcmDataOut.SetSampleValueInDouble(ch, i + offs, re);
                    }

                    // 進捗Update。
                    int percentage = (int)(
                        (100L * ch / pcmDataOut.NumChannels) +
                        (100L * (offs + 1) / pcm1ch.Length / pcmDataOut.NumChannels));
                    m_FirWorker.ReportProgress(percentage);
                }
                fir.Unsetup();
            }
            return(true);
        }
示例#12
0
        private bool ItUpsampleDo(FirWorkerArgs args, PcmData pcmDataIn, out PcmData pcmDataOut)
        {
            pcmDataOut = new PcmData();
            pcmDataOut.SetFormat(pcmDataIn.NumChannels, 64, 64,
                                 pcmDataIn.SampleRate * mFreqMagnitude,
                                 PcmData.ValueRepresentationType.SFloat, pcmDataIn.NumFrames * mFreqMagnitude);
            pcmDataOut.SetSampleArray(new byte[pcmDataOut.NumFrames * pcmDataOut.BitsPerFrame / 8]);

            var pcm = pcmDataOut;

            switch (mItUpsampleType)
            {
            case ItUpsampleType.ImpulseTrain:
                Parallel.For(0, pcmDataIn.NumFrames, (pos) => {
                    for (int ch = 0; ch < pcmDataIn.NumChannels; ++ch)
                    {
                        var v = pcmDataIn.GetSampleValueInDouble(ch, pos);
                        pcm.SetSampleValueInDouble(ch, pos * mFreqMagnitude, v);
                    }
                });
                break;

            case ItUpsampleType.SampleHold:
                Parallel.For(0, pcmDataIn.NumFrames, (pos) => {
                    for (int ch = 0; ch < pcmDataIn.NumChannels; ++ch)
                    {
                        var v = pcmDataIn.GetSampleValueInDouble(ch, pos);
                        for (int i = 0; i < mFreqMagnitude; ++i)
                        {
                            pcm.SetSampleValueInDouble(ch, pos * mFreqMagnitude + i, v);
                        }
                    }
                });
                break;

            case ItUpsampleType.Linear:
                Parallel.For(0, pcmDataIn.NumFrames - 1, (pos) => {
                    // 0 <= pos <= NumFrames-2まで実行する
                    for (int ch = 0; ch < pcmDataIn.NumChannels; ++ch)
                    {
                        var v0 = pcmDataIn.GetSampleValueInDouble(ch, pos);
                        var v1 = pcmDataIn.GetSampleValueInDouble(ch, pos + 1);
                        for (int i = 0; i < mFreqMagnitude; ++i)
                        {
                            var ratio = (double)i / mFreqMagnitude;
                            var v     = v0 * (1 - ratio) + v1 * ratio;
                            pcm.SetSampleValueInDouble(ch, pos * mFreqMagnitude + i, v);
                        }
                    }
                });

                // 最後の1区間は0に向かう
                for (int ch = 0; ch < pcmDataIn.NumChannels; ++ch)
                {
                    var pos = pcmDataIn.NumFrames - 1;
                    var v   = pcmDataIn.GetSampleValueInDouble(ch, pos);
                    for (int i = 0; i < mFreqMagnitude; ++i)
                    {
                        pcm.SetSampleValueInDouble(ch, pos * mFreqMagnitude + i, v * (mFreqMagnitude - i - 1) / mFreqMagnitude);
                    }
                }
                break;

            case ItUpsampleType.Cubic: {
                var    h = new double[4 * mFreqMagnitude];
                double a = -0.5;
                for (int i = 0; i < mFreqMagnitude; ++i)
                {
                    double t = (double)i / mFreqMagnitude;
                    h[mFreqMagnitude * 2 + i] = (a + 2) * t * t * t - (a + 3) * t * t + 1;
                    h[mFreqMagnitude * 2 - i] = h[mFreqMagnitude * 2 + i];
                }
                for (int i = mFreqMagnitude; i < mFreqMagnitude * 2; ++i)
                {
                    double t = (double)i / mFreqMagnitude;
                    h[mFreqMagnitude * 2 + i] = a * t * t * t - 5 * a * t * t + 8 * a * t - 4 * a;
                    h[mFreqMagnitude * 2 - i] = h[mFreqMagnitude * 2 + i];
                }
                Parallel.For(0, pcmDataOut.NumFrames, (pos) => {
                        for (int ch = 0; ch < pcmDataIn.NumChannels; ++ch)
                        {
                            var x = new double[4 * mFreqMagnitude];
                            for (int i = 0; i < 4 * mFreqMagnitude; ++i)
                            {
                                if (0 == (pos + i) % mFreqMagnitude)
                                {
                                    x[i] = pcmDataIn.GetSampleValueInDouble(ch, (pos + i) / mFreqMagnitude);
                                }
                            }
                            double v = 0;
                            for (int i = 0; i < 4 * mFreqMagnitude; ++i)
                            {
                                v += h[i] * x[i];
                            }
                            pcm.SetSampleValueInDouble(ch, pos, v);
                        }
                    });
            }
            break;

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

            return(true);
        }
示例#13
0
        private bool FirDoLoadConvertSave(FirWorkerArgs args, FirDelegate Do, out string result)
        {
            // pcmファイルを読み込んでサンプル配列pcm1chを作成。
            PcmData pcmDataIn = null;
            try {
                pcmDataIn = ReadWavFile(args.inputPath);
            } catch (IOException ex) {
                result = string.Format("WAVファイル {0} 読み込み失敗\r\n{1}", args.inputPath, ex);
                return false;
            }
            if (null == pcmDataIn) {
                result = string.Format("WAVファイル {0} 読み込み失敗", args.inputPath);
                return false;
            }

            var formatConv = new WasapiPcmUtil.PcmFormatConverter(pcmDataIn.NumChannels);
            pcmDataIn = formatConv.Convert(pcmDataIn, Wasapi.WasapiCS.SampleFormatType.Sdouble, null);

            PcmData pcmDataOutput;

            if (!Do(args, pcmDataIn, out pcmDataOutput)) {
                result = "FIR処理失敗";
                return false;
            }

            // サンプルフォーマットが整数型の時だけ音量制限処理する。
            double scale = 1.0;
            double maxLevel = 0.0f;
            if (args.valueRepresentationType == PcmData.ValueRepresentationType.SInt) {
                scale = pcmDataOutput.LimitLevelOnDoubleRange();
            } else {
                double maxV, minV;
                pcmDataOutput.FindMaxMinValueOnDoubleBuffer(out maxV, out minV);
                maxLevel = Math.Max(Math.Abs(maxV), Math.Abs(minV));
            }

            PcmData pcmDataWrite = formatConv.Convert(pcmDataOutput,
                    Wasapi.WasapiCS.BitAndFormatToSampleFormatType(args.outputBitsPerSample, args.outputBitsPerSample, (Wasapi.WasapiCS.BitFormatType)args.valueRepresentationType), null);

            bool writeResult = false;
            try {
                writeResult = WriteWavFile(pcmDataWrite, args.outputPath);
            } catch (IOException ex) {
                result = string.Format("WAVファイル書き込み失敗: {0}\r\n{1}", args.outputPath, ex);
                return false;
            }
            if (!writeResult) {
                result = string.Format("WAVファイル書き込み失敗: {0}", args.outputPath);
                return false;
            }

            if (args.valueRepresentationType == PcmData.ValueRepresentationType.SInt) {
                if (scale == 1.0) {
                    result = string.Format("WAVファイル書き込み成功: {0}", args.outputPath);
                } else {
                    result = string.Format("WAVファイル書き込み成功: {0}\r\nレベルオーバーのため音量を{1:0.######}倍しました({2:0.######}dB)",
                            args.outputPath, scale, 20.0 * Math.Log10(scale));
                }
            } else {
                result = string.Format("WAVファイル書き込み成功: {0}\r\nサンプル値の絶対値の最大値 {1:0.######}",
                        args.outputPath, maxLevel);
            }
            return true;
        }
示例#14
0
        private bool FirDo(FirWorkerArgs args, PcmData pcmDataIn, out PcmData pcmDataOut)
        {
            var dft = new WWDirectComputeCS.WWDftCpu();

            var from = FreqGraphToIdftInput(pcmDataIn.SampleRate);

            double [] idftResult;
            dft.Idft1d(from, out idftResult);

            // 窓関数の要素数は、IDFT結果の複素数の個数 -1個。
            double [] window;

            if (args.windowFunc == WindowFuncType.Blackman) {
                WWWindowFunc.BlackmanWindow((idftResult.Length / 2) - 1, out window);
            } else {
                WWWindowFunc.KaiserWindow((idftResult.Length / 2) - 1, args.kaiserAlpha, out window);
            }

            // FIR coeffの個数は、window.Length個。
            double [] coeff;
            dft.IdftComplexToFirCoeff1d(idftResult, window, out coeff);

            /*
            for (int i=0; i < coeff.Length; ++i) {
                System.Console.WriteLine("coeff {0:D2} {1}", i, coeff[i]);
            }
            System.Console.WriteLine("");
            */

            pcmDataOut = new PcmData();
            pcmDataOut.CopyFrom(pcmDataIn);

            for (int ch=0; ch < pcmDataOut.NumChannels; ++ch) {
                // 全てのチャンネルでループ。

                var pcm1ch = new double[pcmDataOut.NumFrames];
                for (long i=0; i < pcm1ch.Length; ++i) {
                    pcm1ch[i] = pcmDataOut.GetSampleValueInDouble(ch, i);
                }

                // 少しずつFIRする。
                var fir = new WWFirCpu();
                fir.Setup(coeff, pcm1ch);

                const int FIR_SAMPLE = 65536;
                for (int offs=0; offs < pcm1ch.Length; offs += FIR_SAMPLE) {
                    int nSample = FIR_SAMPLE;
                    if (pcm1ch.Length < offs + nSample) {
                        nSample = pcm1ch.Length - offs;
                    }

                    var pcmFir = new double[nSample];
                    fir.Do(offs - window.Length / 2, nSample, pcmFir);

                    // 結果を出力に書き込む。
                    for (long i=0; i < pcmFir.Length; ++i) {
                        var re = pcmFir[i];
                        pcmDataOut.SetSampleValueInDouble(ch, i + offs, re);
                    }

                    // 進捗Update。
                    int percentage = (int)(
                        ( 100L * ch / pcmDataOut.NumChannels ) +
                        ( 100L * ( offs + 1 ) / pcm1ch.Length / pcmDataOut.NumChannels ) );
                    m_FirWorker.ReportProgress(percentage);
                }
                fir.Unsetup();
            }
            return true;
        }
示例#15
0
        /// <summary>
        /// FIR実行
        /// </summary>
        private void buttonFirDo_Click(object sender, RoutedEventArgs e)
        {
            int filterLength;
            if (!Int32.TryParse(textBoxFirLength.Text, out filterLength) ||
                (filterLength & 1) == 0 || filterLength <= 0) {
                MessageBox.Show("FIRフィルタ長は正の奇数の数値を半角数字で入力してください。処理中断。");
                return;
            }
            m_firTapN = filterLength + 1;

            var args = new FirWorkerArgs();
            args.inputPath = textBoxFirInputPath.Text;
            args.outputPath = textBoxFirOutputPath.Text;
            if (radioButtonFir16bit.IsChecked == true) {
                args.outputBitsPerSample = 16;
                args.valueRepresentationType = PcmData.ValueRepresentationType.SInt;
            }
            if (radioButtonFir24bit.IsChecked == true) {
                args.outputBitsPerSample = 24;
                args.valueRepresentationType = PcmData.ValueRepresentationType.SInt;
            }
            if (radioButtonFir32bitFloat.IsChecked == true) {
                args.outputBitsPerSample = 32;
                args.valueRepresentationType = PcmData.ValueRepresentationType.SFloat;
            }

            if (!Double.TryParse(textBoxKaiserAlpha.Text, out args.kaiserAlpha) ||
                args.kaiserAlpha <= 4.0 || 9.0 <= args.kaiserAlpha) {
                MessageBox.Show("カイザー窓α値は4.0<α<9.0の範囲の数値を半角数字で入力してください。処理中断。");
                return;
            }

            if (radioButtonFirBlackman.IsChecked == true) {
                args.windowFunc = WindowFuncType.Blackman;
            } else {
                args.windowFunc = WindowFuncType.Kaiser;
            }

            AddFirLog(string.Format("開始。{0} → {1}\r\n", args.inputPath, args.outputPath));
            buttonFirDo.IsEnabled = false;
            groupBoxFirInputFile.IsEnabled = false;
            groupBoxFirEq.IsEnabled = false;
            groupBoxFirOutputFile.IsEnabled = false;
            groupBoxFirWindow.IsEnabled = false;
            m_FirWorker.RunWorkerAsync(args);
        }