Exemple #1
0
        bool Run(string inFile, float scale, string firCoeffsFile, string outFile)
        {
            int rv;

            // 係数ファイルを読む。
            var coeffs = ReadCoeffsFile(firCoeffsFile);

            if (coeffs.Length == 0)
            {
                Console.WriteLine("Error: FIR coeffs file read error: {0}", firCoeffsFile);
                return(false);
            }

            Console.WriteLine("  FIR taps = {0}", coeffs.Length);

            // coeffsをスケールする。
            for (int i = 0; i < coeffs.Length; ++i)
            {
                coeffs[i] = coeffs[i] * scale;
            }

            var      writePcmList = new List <LargeArray <byte> >();
            Metadata meta;

            byte[] picture = null;

            {
                var fr = new FlacRW();
                // 入力FLACファイルを読む。
                rv = fr.DecodeAll(inFile);
                if (rv < 0)
                {
                    Console.WriteLine("Error: FLAC read error {0}: {1}", FlacRW.ErrorCodeToStr(rv), inFile);
                    return(false);
                }

                fr.GetDecodedMetadata(out meta);
                if (0 < meta.pictureBytes)
                {
                    picture = new byte[meta.pictureBytes];
                    rv      = fr.GetDecodedPicture(out picture, picture.Length);
                    if (rv < 0)
                    {
                        Console.WriteLine("Error: FLAC get picture error {0}: {1}", FlacRW.ErrorCodeToStr(rv), inFile);
                        return(false);
                    }
                }

                Console.WriteLine("  SampleRate={0}Hz, BitDepth={1}, Channels={2}", meta.sampleRate, meta.bitsPerSample, meta.channels);

                for (int ch = 0; ch < meta.channels; ++ch)
                {
                    writePcmList.Add(null);
                }

                // FIR係数を畳み込む。
                // 申し訳程度の最適化:2チャンネル音声の場合2スレッドで並列動作。
                float maxMagnitude = 0;
                Parallel.For(0, meta.channels, ch => {
                    var inData = fr.GetFloatPcmOfChannel(ch, 0, meta.totalSamples);
#if true
                    var conv = new FIRConvolution();

                    var convoluted = conv.Convolution(inData, coeffs);

                    if (maxMagnitude < conv.MaxMagnitude)
                    {
                        maxMagnitude = conv.MaxMagnitude;
                    }
                    var pcm = FlacRW.ConvertToByteArrayPCM(convoluted, meta.BytesPerSample);
#else
                    // debug: output unchanged input file
                    var pcm = FlacRW.ConvertToByteArrayPCM(inData, meta.BytesPerSample);
#endif
                    writePcmList[ch] = pcm;
                });

                if (8388607.0f / 8388608.0f < maxMagnitude)
                {
                    Console.WriteLine("Error: convolution result PCM value overflow. Please reduce input PCM gain further by {0:0.00} dB",
                                      20.0 * Math.Log10(maxMagnitude));
                    return(false);
                }
                else
                {
                    Console.WriteLine("  Max PCM magnitude = {0}", maxMagnitude);
                }

                fr.DecodeEnd();
            }

            {
                // FLACファイルを書き込む。
                var fw = new FlacRW();
                fw.EncodeInit(meta);
                for (int ch = 0; ch < meta.channels; ++ch)
                {
                    fw.EncodeAddPcm(ch, writePcmList[ch]);
                }
                if (picture != null)
                {
                    fw.EncodeSetPicture(picture);
                }

                rv = fw.EncodeRun(outFile);
                if (rv < 0)
                {
                    Console.WriteLine("Error: FLAC write error {0}: {1}", FlacRW.ErrorCodeToStr(rv), outFile);
                    return(false);
                }

                fw.EncodeEnd();
            }

            return(true);
        }
Exemple #2
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);
        }