private void buttonASCreate_Click(object sender, RoutedEventArgs e)
        {
            var args = new AnalyticSignalWorkerArgs();

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

            args.inputPath = textBoxASInputPath.Text;

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

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

            args.hilbertFilterType = WWHilbert.HilbertFilterType.HighPass;
            if (radioButtonASBandlimited.IsChecked == true)
            {
                args.hilbertFilterType = WWHilbert.HilbertFilterType.Bandlimited;
            }

            m_analyticSignalList.Clear();
            ASViewUpdate();

            buttonASCreate.IsEnabled = false;
            m_ASWorker.RunWorkerAsync(args);
        }
        private void buttonASCreate_Click(object sender, RoutedEventArgs e)
        {
            var args = new AnalyticSignalWorkerArgs();
            if (!Int32.TryParse(textBoxASFilterLength.Text, out args.firLength) ||
                (args.firLength & 1) == 0 || args.firLength <= 0) {
                MessageBox.Show("FIRフィルタ長は正の奇数の数値を半角数字で入力してください。処理中断。");
                return;
            }

            args.inputPath = textBoxASInputPath.Text;

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

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

            args.hilbertFilterType = WWHilbert.HilbertFilterType.HighPass;
            if (radioButtonASBandlimited.IsChecked == true) {
                args.hilbertFilterType = WWHilbert.HilbertFilterType.Bandlimited;
            }

            m_analyticSignalList.Clear();
            ASViewUpdate();

            buttonASCreate.IsEnabled = false;
            m_ASWorker.RunWorkerAsync(args);
        }
        private void m_AnalyticSignalWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            AnalyticSignalWorkerArgs args = e.Argument as AnalyticSignalWorkerArgs;

            Stopwatch sw = new Stopwatch();

            sw.Start();

            // pcmファイルを読み込んでサンプル配列pcm1chを作成。
            PcmData pcmDataIn = null;

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

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

            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));
                    m_ASWorker.ReportProgress(percentage);
                }
                fir.Unsetup();
            }

            // 解析信号を出力。
            m_analyticSignalList.Clear();
            for (int ch = 0; ch < pcmDataReal.NumChannels; ++ch)
            {
                double [] signal = new double[pcmDataImaginary.NumFrames * 2];
                for (long pos = 0; pos < pcmDataReal.NumFrames; ++pos)
                {
                    signal[pos * 2 + 0] = pcmDataReal.GetSampleValueInDouble(ch, pos);
                    signal[pos * 2 + 1] = pcmDataImaginary.GetSampleValueInDouble(ch, pos);
                }
                m_analyticSignalList.Add(signal);
            }

            sw.Stop();
            e.Result = "";
        }