//////////////////////////////////////////////////////////////////// // US AQ共用ワーカースレッド private int CpuUpsample(USWorkerArgs args, PcmData pcmDataIn, PcmData pcmDataOut) { int hr = 0; int sampleTotalTo = (int)pcmDataOut.NumFrames; float[] sampleData = new float[pcmDataIn.NumFrames]; for (int ch = 0; ch < pcmDataIn.NumChannels; ++ch) { for (int i = 0; i < pcmDataIn.NumFrames; ++i) { sampleData[i] = pcmDataIn.GetSampleValueInFloat(ch, i); } WWUpsampleCpu us = new WWUpsampleCpu(); if (args.addJitter) { hr = us.Setup(args.convolutionN, sampleData, sampleData.Length, pcmDataIn.SampleRate, pcmDataOut.SampleRate, sampleTotalTo, args.resamplePosArray, args.fractionArray); } else { hr = us.Setup(args.convolutionN, sampleData, sampleData.Length, pcmDataIn.SampleRate, pcmDataOut.SampleRate, sampleTotalTo); } if (hr < 0) { break; } for (int offs = 0; offs < sampleTotalTo; offs += args.sampleSlice) { int sample1 = args.sampleSlice; if (sampleTotalTo - offs < sample1) { sample1 = sampleTotalTo - offs; } if (sample1 < 1) { break; } float[] outFragment = new float[sample1]; hr = us.Do(offs, sample1, outFragment); if (hr < 0) { // ここからbreakしても外のfor文までしか行かない us.Unsetup(); sampleData = null; break; } if (m_USAQworker.CancellationPending) { // ここからbreakしても外のfor文までしか行かない us.Unsetup(); sampleData = null; hr = -1; break; } if (0 <= hr) { // 成功。出てきたデータをpcmDataOutに詰める。 for (int j = 0; j < sample1; ++j) { pcmDataOut.SetSampleValueInFloat(ch, offs + j, outFragment[j]); } } outFragment = null; // 10%~99% m_USAQworker.ReportProgress( 10 + (int)(89L * offs / sampleTotalTo + 89L * ch) / pcmDataIn.NumChannels); } if (m_USAQworker.CancellationPending) { break; } if (hr < 0) { break; } us.Unsetup(); } sampleData = null; return(hr); }
private int GpuUpsample(USWorkerArgs args, PcmData pcmDataIn, PcmData pcmDataOut) { int hr = 0; int sampleTotalTo = (int)pcmDataOut.NumFrames; float[] sampleData = new float[pcmDataIn.NumFrames]; for (int ch = 0; ch < pcmDataIn.NumChannels; ++ch) { for (int i = 0; i < pcmDataIn.NumFrames; ++i) { sampleData[i] = pcmDataIn.GetSampleValueInFloat(ch, i); } WWUpsampleGpu us = new WWUpsampleGpu(); if (args.addJitter) { hr = us.Init(args.convolutionN, sampleData, (int)pcmDataIn.NumFrames, pcmDataIn.SampleRate, args.resampleFrequency, sampleTotalTo, args.resamplePosArray, args.fractionArray); } else { hr = us.Init(args.convolutionN, sampleData, (int)pcmDataIn.NumFrames, pcmDataIn.SampleRate, args.resampleFrequency, sampleTotalTo); } if (hr < 0) { us.Term(); return(hr); } int sampleRemain = sampleTotalTo; int offs = 0; while (0 < sampleRemain) { int sample1 = args.sampleSlice; if (sampleRemain < sample1) { sample1 = sampleRemain; } hr = us.ProcessPortion(offs, sample1); if (hr < 0) { break; } if (m_USAQworker.CancellationPending) { us.Term(); return(-1); } sampleRemain -= sample1; offs += sample1; // 10%~99% m_USAQworker.ReportProgress( 10 + (int)(89L * offs / sampleTotalTo + 89L * ch) / pcmDataIn.NumChannels); } if (0 <= hr) { float[] output = new float[sampleTotalTo]; hr = us.GetResultFromGpuMemory(ref output, sampleTotalTo); if (0 <= hr) { // すべて成功。 for (int i = 0; i < pcmDataOut.NumFrames; ++i) { pcmDataOut.SetSampleValueInFloat(ch, i, output[i]); } } output = null; } us.Term(); if (hr < 0) { break; } } sampleData = null; return(hr); }
private int Convert1(ConvertArgs ca) { int hr = 0; CallEvent(EventCallbackTypes.Started, PROGRESS_STARTED, hr); hr = mResampleGpu.ChooseAdapter(ca.mGpuId); if (hr < 0) { CallEvent(EventCallbackTypes.InitGpuAdapterFailed, 0, hr); return(hr); } var flacR = new FlacRW(); hr = flacR.DecodeAll(ca.mInPath); if (hr < 0) { CallEvent(EventCallbackTypes.ReadFailed, 0, hr); return(hr); } else { CallEvent(EventCallbackTypes.ReadCompleted, PROGRESS_READ_END, hr); } Metadata metaR; flacR.GetDecodedMetadata(out metaR); var inPcmOfCh = new List <float[]>(); for (int ch = 0; ch < metaR.channels; ++ch) { var pcm = new LargeArray <byte>(metaR.BytesPerSample * metaR.totalSamples); int fragmentSamples = 1024 * 1024; for (long posSamples = 0; posSamples < metaR.totalSamples; posSamples += fragmentSamples) { int copySamples = fragmentSamples; if ((metaR.totalSamples - posSamples) < copySamples) { copySamples = (int)(metaR.totalSamples - posSamples); } var b = new byte[metaR.BytesPerSample * copySamples]; flacR.GetPcmOfChannel(ch, posSamples, ref b, copySamples); pcm.CopyFrom(b, 0, metaR.BytesPerSample * posSamples, metaR.BytesPerSample * copySamples); } var pcmData = new PcmData(); pcmData.SetFormat(1, metaR.bitsPerSample, metaR.bitsPerSample, metaR.sampleRate, PcmData.ValueRepresentationType.SInt, metaR.totalSamples); pcmData.SetSampleLargeArray(pcm); var fb = new float[metaR.totalSamples]; for (long i = 0; i < metaR.totalSamples; ++i) { fb[i] = pcmData.GetSampleValueInFloat(0, i); } pcmData = null; pcm = null; inPcmOfCh.Add(fb); } { CallEvent(EventCallbackTypes.PrepareDataCompleted, PROGRESS_PREPARE_END, hr); } System.Diagnostics.Debug.Assert(0.5 <= ca.mSampleRateScale & ca.mSampleRateScale <= 2.0); int sampleRateTo = (int)(ca.mSampleRateScale * metaR.sampleRate); int sampleTotalTo = (int)(ca.mSampleRateScale * metaR.totalSamples); // metaW: 出力フォーマット。 var metaW = new Metadata(metaR); if (ca.mSampleRateScale < 1.0) { // 曲の長さを縮めると、エイリアシング雑音が出るのでローパスフィルターが必要になる。 // 出力サンプルレートを倍にしてローパスフィルターを省略。 sampleRateTo = (int)(2.0 * ca.mSampleRateScale * metaR.sampleRate); sampleTotalTo = (int)(2.0 * ca.mSampleRateScale * metaR.totalSamples); metaW.sampleRate *= 2; } metaW.bitsPerSample = 24; metaW.totalSamples = sampleTotalTo; // ローパスフィルターが不要になる条件。 System.Diagnostics.Debug.Assert(metaR.sampleRate <= metaW.sampleRate); var outPcmOfCh = new List <float[]>(); for (int ch = 0; ch < metaR.channels; ++ch) { var inPcm = inPcmOfCh[ch]; mResampleGpu.Setup(SINC_CONVOLUTION_N, inPcm, (int)metaR.totalSamples, metaR.sampleRate, sampleRateTo, sampleTotalTo); for (int i = 0; i < sampleTotalTo; i += GPU_WORK_COUNT) { // 出力サンプル数countの調整。 int count = GPU_WORK_COUNT; if (sampleTotalTo < i + count) { count = sampleTotalTo - i; } hr = mResampleGpu.Dispatch(i, count); if (hr < 0) { CallEvent(EventCallbackTypes.ConvertFailed, 0, hr); return(hr); } else { float progress0to1 = ((float)ch / metaR.channels) + (1.0f / metaR.channels) * ((float)i / sampleTotalTo); int percent = (int)(PROGRESS_CONV_START + progress0to1 * (PROGRESS_CONV_END - PROGRESS_CONV_START)); CallEvent(EventCallbackTypes.ConvProgress, percent, hr); } } var outPcm = new float[sampleTotalTo]; mResampleGpu.ResultGetFromGpuMemory(outPcm); outPcmOfCh.Add(outPcm); mResampleGpu.Unsetup(); } CallEvent(EventCallbackTypes.WriteStarted, PROGRESS_CONV_END, hr); var flacW = new FlacRW(); hr = flacW.EncodeInit(metaW); if (hr < 0) { CallEvent(EventCallbackTypes.WriteFailed, 0, hr); return(hr); } if (0 < metaR.pictureBytes) { // 画像。 byte[] metaPicture = null; flacR.GetDecodedPicture(out metaPicture, metaR.pictureBytes); hr = flacW.EncodeSetPicture(metaPicture); if (hr < 0) { CallEvent(EventCallbackTypes.WriteFailed, 0, hr); return(hr); } } for (int ch = 0; ch < metaW.channels; ++ch) { // 24bitのbyteAry作成。 var floatAry = outPcmOfCh[ch]; var byteAry = new LargeArray <byte>(3 * metaW.totalSamples); //< 24bitなので1サンプルあたり3バイト。 for (long i = 0; i < metaW.totalSamples; ++i) { var b = PcmDataUtil.ConvertTo24bitLE(floatAry[i]); byteAry.CopyFrom(b, 0, i * 3, 3); } flacW.EncodeAddPcm(ch, byteAry); } hr = flacW.EncodeRun(ca.mOutPath); if (hr < 0) { CallEvent(EventCallbackTypes.WriteFailed, 0, hr); return(hr); } flacW.EncodeEnd(); flacR.DecodeEnd(); return(hr); }