public WWFilterCpp CreateIIRFilterCpp(int osr, int decimation) { var fg = mIIRFilterDesign.CreateIIRFilterGraph(); var fgSerial = fg as IIRFilterSerial; var fgParallel = fg as IIRFilterParallel; var r = new WWFilterCpp(); if (fgSerial != null) { r.BuildIIRSerial(fg.BlockCount()); } else { r.BuildIIRParallel(fg.BlockCount()); } for (int i = 0; i < fg.BlockCount(); ++i) { var block = fg.GetNthBlock(i); var a = block.A(); var b = block.B(); r.AddIIRBlock(a.Length, a, b.Length, b); } r.SetParam(osr, decimation); return(r); }
/// <summary> /// mLoopFiltersを設計する。 /// </summary> /// <param name="order">フィルターの次数(3,5,7)。</param> /// <param name="numChannels">音声のチャンネル数。</param> public void Design(int order, int numChannels) { mCh = numChannels; var ntfHz = new NTFHzcoeffs(order); // フィードバック係数g。Hzの分子の零(単位円上)のz=1からの角度 ω → g = 2 - 2cos(ω) var g = new double[order / 2]; for (int i = 0; i < g.Length; ++i) { // Hzの分子の零の位置r。 var r = ntfHz.ZeroNth(i); var cosω = r.real; g[i] = 2.0 - 2.0 * cosω; } var d = new double[order + 1]; for (int i = 0; i < d.Length; ++i) { d[i] = ntfHz.D(i); } // CRFB構造のノイズシェイピングフィルターの係数a[]。 // R. Schreier and G. Temes, ΔΣ型アナログ/デジタル変換器入門,丸善,2007, pp.95,96 var a = new double[order]; switch (order) { case 2: a[0] = d[0] + d[1] - g[0] + 1; a[1] = 1 - d[0]; break; case 3: a[0] = 1 + d[0] + d[1] + d[2]; a[1] = 2 - d[0] + d[2] - g[0]; a[2] = 1 + d[0]; break; case 4: a[0] = 1 + d[0] + d[1] + d[2] + d[3] - 3 * g[0] - d[0] * g[0] - d[3] * g[0] + g[0] * g[0]; a[1] = 2 - 2 * d[0] - d[1] + d[3] - g[0] + d[0] * g[0]; a[2] = 3 + d[0] + d[3] - g[0] - g[1]; a[3] = 1 - d[0]; break; case 5: a[0] = 1 + d[0] + d[1] + d[2] + d[3] + d[4]; a[1] = 3 - 2 * d[0] - d[1] + d[3] + 2 * d[4] - 4 * g[0] + d[0] * g[0] - d[4] * g[0] + g[0] * g[0]; a[2] = 3 + 3 * d[0] + d[1] + d[4] - g[0] - d[0] * g[0]; a[3] = 4 - d[0] + d[4] - g[0] - g[1]; a[4] = 1 + d[0]; break; case 6: a[0] = 1 + d[0] + d[1] + d[2] + d[3] + d[4] + d[5] - 6 * g[0] - 3 * d[0] * g[0] - d[1] * g[0] - d[4] * g[0] - 3 * d[5] * g[0] + 5 * g[0] * g[0] + d[0] * g[0] * g[0] + d[5] * g[0] * g[0] - g[0] * g[0] * g[0]; a[1] = 3 - 3 * d[0] - 2 * d[1] - d[2] + d[4] + 2 * d[5] - 4 * g[0] + 4 * d[0] * g[0] + d[1] * g[0] - d[5] * g[0] + g[0] * g[0] - d[0] * g[0] * g[0]; a[2] = 6 + 3 * d[0] + d[1] + d[4] + 3 * d[5] - 5 * g[0] - d[0] * g[0] - d[5] * g[0] + g[0] * g[0] - 5 * g[1] - d[0] * g[1] - d[5] * g[1] + g[0] * g[1] + g[1] * g[1]; a[3] = 4 - 4 * d[0] - d[1] + d[5] - g[0] + d[0] * g[0] - g[1] + d[0] * g[1]; a[4] = 5 + d[0] + d[5] - g[0] - g[1] - g[2]; a[5] = 1 - d[0]; break; case 7: a[0] = 1 + d[0] + d[1] + d[2] + d[3] + d[4] + d[5] + d[6]; a[1] = 4 - 3 * d[0] - 2 * d[1] - d[2] + d[4] + 2 * d[5] + 3 * d[6] - 10 * g[0] + 4 * d[0] * g[0] + d[1] * g[0] - d[5] * g[0] - 4 * d[6] * g[0] + 6 * g[0] * g[0] - d[0] * g[0] * g[0] + d[6] * g[0] * g[0] - g[0] * g[0] * g[0]; a[2] = 6 + 6 * d[0] + 3 * d[1] + d[2] + d[5] + 3 * d[6] - 5 * g[0] - 5 * d[0] * g[0] - d[1] * g[0] - d[6] * g[0] + g[0] * g[0] + d[0] * g[0] * g[0]; a[3] = 10 - 4 * d[0] - d[1] + d[5] + 4 * d[6] - 6 * g[0] + d[0] * g[0] - d[6] * g[0] + g[0] * g[0] - 6 * g[1] + d[0] * g[1] - d[6] * g[1] + g[0] * g[1] + g[1] * g[1]; a[4] = 5 + 5 * d[0] + d[1] + d[6] - g[0] - d[0] * g[0] - g[1] - d[0] * g[1]; a[5] = 6 - d[0] + d[6] - g[0] - g[1] - g[2]; a[6] = 1 + d[0]; break; default: throw new NotImplementedException(); } // CRFBでSTF==1になるようなb[]の係数。 var b = new double[order + 1]; for (int i = 0; i < order; ++i) { b[i] = a[i]; } b[order] = 1.0; /* * Console.Write("double [] g = {"); * for (int i = 0; i < g.Length; ++i) { * Console.Write("{0:R}, ", g[i]); * } * Console.WriteLine("};"); * * Console.Write("double [] a = {"); * for (int i = 0; i < a.Length; ++i) { * Console.Write("{0:R}, ", a[i]); * } * Console.WriteLine("};"); * * Console.Write("double [] b = {"); * for (int i = 0; i < b.Length; ++i) { * Console.Write("{0:R}, ", b[i]); * } * Console.WriteLine("};"); * * Console.Write("double [] n = {"); * for (int i = 0; i < order+1; ++i) { * Console.Write("{0:R}, ", ntfHz.N(i)); * } * Console.WriteLine("};"); * * Console.Write("double [] d = {"); * for (int i = 0; i < d.Length; ++i) { * Console.Write("{0:R}, ", d[i]); * } * Console.WriteLine("};"); */ #if USE_CPP mLoopFiltersCpp = new WWFilterCpp[numChannels]; for (int ch = 0; ch < numChannels; ++ch) { var p = new WWFilterCpp(); p.BuildCrfb(order, a, b, g, 0.5); mLoopFiltersCpp[ch] = p; } #else mLoopFilters = new LoopFilterCRFB[numChannels]; for (int ch = 0; ch < numChannels; ++ch) { mLoopFilters[ch] = new LoopFilterCRFB(a, b, g); } #endif }
public BWCompletedParam DoWork(BWStartParams param, ProgressReportDelegate ReportProgress) { int rv = 0; var flacR = new WWFlacRWCS.FlacRW(); do { // FLACファイルからメタデータ、画像、音声を取り出す。 WWFlacRWCS.Metadata metaR; rv = flacR.DecodeAll(param.inputFile); if (rv < 0) { // do-whileを抜けたところでflacR.DecodeEndする。 break; } flacR.GetDecodedMetadata(out metaR); byte[] picture = null; if (0 < metaR.pictureBytes) { rv = flacR.GetDecodedPicture(out picture, metaR.pictureBytes); if (rv < 0) { // do-whileを抜けたところでflacR.DecodeEndする。 break; } } // flacRはまだ使用するのでここではDecodeEndしない。 long lcm = WWMath.Functions.LCM(metaR.sampleRate, param.targetSampleRate); int upsampleScale = (int)(lcm / metaR.sampleRate); int downsampleScale = (int)(lcm / param.targetSampleRate); // IIRフィルターを設計。 // ストップバンド最小周波数fs。 double fs = metaR.sampleRate / 2 * STOPBAND_FREQ_RATIO; if (param.targetSampleRate / 2 * STOPBAND_FREQ_RATIO < fs) { fs = param.targetSampleRate / 2 * STOPBAND_FREQ_RATIO; } // カットオフ周波数fc。 double fc = CUTOFF_STOPBAND_RATIO * fs; mIIRFilterDesign = new IIRFilterDesign(); mIIRFilterDesign.Design(fc, fs, lcm, param.method); ReportProgress(CONVERT_START_PERCENT, new BWProgressParam(State.FilterDesigned, string.Format("Read FLAC completed.\nSource sample rate = {0}kHz.\nTarget sample rate = {1}kHz. ratio={2}/{3}\n", metaR.sampleRate / 1000.0, param.targetSampleRate / 1000.0, lcm / metaR.sampleRate, lcm / param.targetSampleRate))); double RESAMPLE_RATIO = param.targetSampleRate / metaR.sampleRate; mSw.Restart(); // 書き込み準備。 WWFlacRWCS.Metadata metaW = new WWFlacRWCS.Metadata(metaR); metaW.sampleRate = param.targetSampleRate; metaW.pictureBytes = metaR.pictureBytes; metaW.bitsPerSample = 24; metaW.totalSamples = metaR.totalSamples * upsampleScale / downsampleScale; if (param.isTargetPcm) { mFlacWrite = new FlacWrite(); mFlacWrite.Setup(metaW, picture); } else { mDsfWrite = new DsfWrite(); mDsfWrite.Setup(metaW, picture); } var stat = new SampleValueStatistics(); long totalSamplesOfAllChannels = metaR.totalSamples * metaR.channels; long processedSamples = 0; // Mathematica用の設定。 WWComplex.imaginaryUnit = "I"; // 変換する for (int ch = 0; ch < metaR.channels; ++ch) { //Parallel.For(0, metaR.channels, (int ch) => { var pcmW = new WWUtil.LargeArray <byte>(metaW.totalSamples * metaW.BytesPerSample); #if USE_ZOH_UPSAMPLE // 零次ホールドのハイ落ち補償フィルター。 # if USE_CPP var zohCompensation = new WWFilterCpp(); zohCompensation.BuildZohCompensation(); # else var zohCompensation = new WWIIRFilterDesign.ZohNosdacCompensation(33); # endif