////////////////////////////////////////////////////////////////////
        // 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);
        }
Beispiel #3
0
        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);
        }