private void m_USAQworker_DoWork(object sender, DoWorkEventArgs e) { // System.Threading.Thread.CurrentThread.Priority = System.Threading.ThreadPriority.Lowest; USWorkerArgs args = (USWorkerArgs)e.Argument; PcmData pcmDataIn = ReadWavFile(args.inputPath); if (null == pcmDataIn) { e.Result = string.Format("WAVファイル 読み込み失敗: {0}", args.inputPath); return; } // ファイル読み込み完了。 if (args.addJitter) { // ジッター負荷の場合、サンプリング周波数は変更しない。 args.resampleFrequency = pcmDataIn.SampleRate; } if (args.resampleFrequency < pcmDataIn.SampleRate) { e.Result = string.Format("エラー: ダウンサンプルは対応していません {0} from={1} to={2}", args.inputPath, pcmDataIn.SampleRate, args.resampleFrequency); return; } if (0x7fff0000L < pcmDataIn.NumFrames * 4 * pcmDataIn.NumChannels * args.resampleFrequency / pcmDataIn.SampleRate) { e.Result = string.Format("エラー: リサンプル後のファイルサイズが2GBを超えそうなので中断しました {0}", args.inputPath); return; } m_USAQworker.ReportProgress(1); var conv = new WasapiPcmUtil.PcmFormatConverter(pcmDataIn.NumChannels); pcmDataIn = conv.Convert(pcmDataIn, WasapiCS.BitAndFormatToSampleFormatType(32, 32, WasapiCS.BitFormatType.SFloat), null); PcmData pcmDataOut = new PcmData(); pcmDataOut.CopyFrom(pcmDataIn); int sampleTotalTo = (int)(args.resampleFrequency * pcmDataIn.NumFrames / pcmDataIn.SampleRate); { // PcmDataOutのサンプルレートとサンプル数を更新する。 byte[] outSampleArray = new byte[(long)sampleTotalTo * pcmDataOut.NumChannels * 4]; pcmDataOut.SetSampleArray(sampleTotalTo, outSampleArray); pcmDataOut.SampleRate = args.resampleFrequency; outSampleArray = null; } // 再サンプルテーブル作成 args.resamplePosArray = null; args.fractionArray = null; if (args.addJitter) { // ジッター付加の場合、サンプルレートは変更しない。 args.resamplePosArray = new int[pcmDataIn.NumFrames]; args.fractionArray = new double[pcmDataIn.NumFrames]; /* sampleRate == 96000 Hz jitterFrequency == 50 Hz jitterPicoseconds == 1 ps の場合 サンプル位置posのθ= 2 * PI * pos * 50 / 96000 (ラジアン) サンプル間隔= 1/96000秒 = 10.4 μs 1ms = 10^-3秒 1μs= 10^-6秒 1ns = 10^-9秒 1ps = 10^-12秒 1psのずれ x サンプルのずれ ───────────── = ───────── 10.4 μs(1/96000)sのずれ 1 サンプルのずれ 1psのサンプルずれA = 10^-12 ÷ (1/96000) (サンプルのずれ) サンプルを採取する位置= pos + Asin(θ) */ args.thetaCoefficientSeqJitter = 2.0 * Math.PI * args.sequentialJitterFrequency / pcmDataIn.SampleRate; args.ampSeqJitter = 1.0e-12 * pcmDataIn.SampleRate * args.sequentialJitterPicoseconds; args.ampTpdfJitter = 1.0e-12 * pcmDataIn.SampleRate * args.tpdfJitterPicoseconds; args.ampRpdfJitter = 1.0e-12 * pcmDataIn.SampleRate * args.rpdfJitterPicoseconds; PrepareResamplePosArray( args, pcmDataIn.SampleRate, pcmDataOut.SampleRate, (int)pcmDataIn.NumFrames, sampleTotalTo, args.resamplePosArray, args.fractionArray); } System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch(); sw.Start(); int hr = 0; if (args.device == ProcessDevice.Gpu) { hr = GpuUpsample(args, pcmDataIn, pcmDataOut); } else { hr = CpuUpsample(args, pcmDataIn, pcmDataOut); } // args.resamplePosArrayは中でコピーされるのでここで不要になる。 args.resamplePosArray = null; args.fractionArray = null; if (m_USAQworker.CancellationPending) { e.Result = string.Format("キャンセル完了。"); e.Cancel = true; return; } if (hr < 0) { e.Result = string.Format("Upsample エラー 0x{0:X8}", hr); return; } sw.Stop(); // 成功した。レベル制限する。 float scale = pcmDataOut.LimitLevelOnFloatRange(); if (args.outputVRT != PcmData.ValueRepresentationType.SFloat) { // ビットフォーマット変更。 var formatConv = new WasapiPcmUtil.PcmFormatConverter(pcmDataOut.NumChannels); pcmDataOut = formatConv.Convert(pcmDataOut, WasapiCS.BitAndFormatToSampleFormatType(args.outputBitsPerSample, args.outputBitsPerSample, (WasapiCS.BitFormatType)args.outputVRT), null); } try { WriteWavFile(pcmDataOut, args.outputPath); } catch (IOException ex) { // 書き込みエラー。 e.Result = ex.ToString(); return; } e.Result = string.Format("書き込み成功。処理時間 {0}秒\r\n", sw.ElapsedMilliseconds * 0.001); if (scale < 1.0f) { e.Result = string.Format("書き込み成功。処理時間 {0}秒。" + "レベルオーバーのため音量調整{1}dB({2}倍)しました。\r\n", sw.ElapsedMilliseconds * 0.001, 20.0 * Math.Log10(scale), scale); } m_USAQworker.ReportProgress(100); }