示例#1
0
        private void CaptureRunning(byte[] data)
        {
            // 届いたPCMデータをmCapturedPcmDataにAppendし、
            // mCapturedBytesを更新する。
            if (mCapturedBytes + data.Length <= mCapturedPcmData.LongLength)
            {
                mCapturedPcmData.CopyFrom(data, 0, mCapturedBytes, data.Length);
                mCapturedBytes += data.Length;

                long capturedFrames = mCapturedBytes
                                      / mStartTestingArgs.numChannels
                                      / (WasapiCS.SampleFormatTypeToUseBitsPerSample(mPref.RecSampleFormat) / 8);

                //Console.WriteLine("Captured {0} frames", capturedFrames);
            }
            else
            {
                int copyBytes = (int)(mCapturedPcmData.LongLength - mCapturedBytes);

                mCapturedPcmData.CopyFrom(data, 0, mCapturedBytes, copyBytes);
                mCapturedBytes += copyBytes;

                // キャプチャー終了. データの整合性チェックはRecRunWorkerCompletedで行う。
                mState = State.RecCompleted;
            }
        }
示例#2
0
        /// <summary>
        /// ヘッダと全PCMデータを抽出する。
        /// この関数呼び出し後
        /// ・GetDecodedMetadata()でメタデータを取り出す。
        /// ・GetDecodedCuesheet()でキューシートを取り出す。
        /// ・GetDecodedPicture()でアルバムカバー画像を取り出す。
        /// ・GetDecodedPcmBytes()でPCMデータを取り出す。
        /// ・DecodeEnd()で後片付けする。
        ///
        /// DecodeAll()が中で呼んでいる関数を個別に呼び出しても良い。
        /// </summary>
        /// <param name="path">FLACのファイル名</param>
        /// <returns>0以上のとき成功。負のときFlacErrorCode</returns>
        public int DecodeAll(string path)
        {
            int rv = 0;

            rv = DecodeStreamStart(path);
            if (rv < 0)
            {
                return(rv);
            }

            rv = GetDecodedMetadata(out mDecodedMetadata);
            if (rv < 0)
            {
                return(rv);
            }

            mPcmAllBuffer = new LargeArray <byte>(mDecodedMetadata.PcmBytes);
            long pos = 0;

            while (pos < mDecodedMetadata.PcmBytes)
            {
                byte[] fragment;
                rv = DecodeStreamOne(out fragment);
                if (rv < 0)
                {
                    return(rv);
                }
                mPcmAllBuffer.CopyFrom(fragment, 0, pos, fragment.Length);
                pos += fragment.Length;
            }

            // mPcmAllBufferから取り出す。

            return(0);
        }
示例#3
0
        private long FlacWriteConvertTo24bitPcm(double [] y, WWFlacRWCS.Metadata metaW, LargeArray <byte> pcmW, long posY)
        {
            var yPcm = ConvertToIntegerPcm(y, metaW.BytesPerSample);

            pcmW.CopyFrom(yPcm, 0, posY, yPcm.Length);
            posY += yPcm.Length;
            return(posY);
        }
示例#4
0
            /// <summary>
            /// PCMデータを無加工で読み出す。
            /// </summary>
            /// <param name="startFrame">0を指定すると最初から。</param>
            /// <param name="endFrame">負の値を指定するとファイルの最後まで。</param>
            /// <returns>false: ファイルの読み込みエラーなど</returns>
            public bool ReadDataChunkData(BinaryReader br, int numChannels, int bitsPerSample,
                                          long startFrame, long endFrame)
            {
                br.BaseStream.Seek(Offset, SeekOrigin.Begin);

                // endBytesがファイルの終わり指定(負の値)の場合の具体的位置を設定する。
                // startBytesとendBytesがファイルの終わり以降を指していたら修正する。
                // ・endBytesがファイルの終わり以降…ファイルの終わりを指す。
                // ・startBytesがファイルの終わり以降…サイズ0バイトのWAVファイルにする。

                int  frameBytes = bitsPerSample / 8 * numChannels;
                long startBytes = startFrame * frameBytes;
                long endBytes   = endFrame * frameBytes;

                System.Diagnostics.Debug.Assert(0 <= startBytes);

                if (endBytes < 0 ||
                    (NumFrames * frameBytes) < endBytes)
                {
                    // 終了位置はファイルの終わり。
                    endBytes = NumFrames * frameBytes;
                }

                long newNumFrames = (endBytes - startBytes) / frameBytes;

                if (newNumFrames <= 0 ||
                    NumFrames * frameBytes <= startBytes ||
                    endBytes <= startBytes)
                {
                    // サイズが0バイトのWAV。
                    mRawData  = null;
                    NumFrames = 0;
                    return(true);
                }

                if (0 < startBytes)
                {
                    PcmDataLib.PcmDataUtil.BinaryReaderSkip(br, startBytes);
                }

                mRawData = new LargeArray <byte>(newNumFrames * frameBytes);
                int fragmentBytes = 1048576;

                for (long pos = 0; pos < mRawData.LongLength; pos += fragmentBytes)
                {
                    int bytes = fragmentBytes;
                    if (mRawData.LongLength - pos < bytes)
                    {
                        bytes = (int)(mRawData.LongLength - pos);
                    }
                    var buff = br.ReadBytes(bytes);
                    mRawData.CopyFrom(buff, 0, pos, bytes);
                }
                NumFrames = newNumFrames;
                return(true);
            }
        private void CsCaptureCallback(byte[] pcmData)
        {
            if (pcmData == null || pcmData.Length == 0)
            {
                return;
            }

            if (mRecord)
            {
                if (mCapturedPcmData.LongLength <= mNextWritePos + pcmData.Length)
                {
                    return;
                }

                mCapturedPcmData.CopyFrom(pcmData, 0, mNextWritePos, pcmData.Length);
                mNextWritePos += pcmData.Length;
            }

            if (mControlCaptureCallback != null)
            {
                mControlCaptureCallback(pcmData);
            }
        }
示例#6
0
        private void CaptureSync(byte[] data)
        {
            // 届いたPCMデータ dataの中の値を調べて、SYNCの値(4)が現れる位置を調べ
            // mRecSyncPosInBytesにセットし、SYNCが正常に取得できていたら
            // 届いたPCMデータをSYNCで頭出ししてmCapturedPcmDataに保存する。
            // mCapturedPcmDataに入ったPCMデータのバイト数をmCapturedBytesに保存する。
            // 再生リストをSYNC再生後にREADYを再生するよう変更する。
            int useBitsPerSample  = WasapiCS.SampleFormatTypeToUseBitsPerSample(mRecSampleFormat) / 8;
            int nFrames           = (int)(data.Length / useBitsPerSample / NUM_CHANNELS);
            int recSyncPosInBytes = -1;
            int zeroSamples       = 0;
            int syncSamples       = 0;

            for (int pos = 0; pos < data.Length; pos += useBitsPerSample)
            {
                switch (mRecSampleFormat)
                {
                case WasapiCS.SampleFormatType.Sint16:
                    if (data[pos] == 0 && data[pos + 1] == 0)
                    {
                        ++zeroSamples;
                    }
                    if (data[pos] == 4 && data[pos + 1] == 0)
                    {
                        ++syncSamples;
                        recSyncPosInBytes = pos;
                    }
                    break;

                case WasapiCS.SampleFormatType.Sint24:
                    if (data[pos] == 0 && data[pos + 1] == 0 && data[pos + 2] == 0)
                    {
                        ++zeroSamples;
                    }
                    if (data[pos] == 4 && data[pos + 1] == 0 && data[pos + 2] == 0)
                    {
                        ++syncSamples;
                        recSyncPosInBytes = pos;
                    }
                    break;

                case WasapiCS.SampleFormatType.Sint32V24:
                    if (data[pos + 1] == 0 && data[pos + 2] == 0 && data[pos + 3] == 0)
                    {
                        ++zeroSamples;
                    }
                    if (data[pos + 1] == 4 && data[pos + 2] == 0 && data[pos + 3] == 0)
                    {
                        ++syncSamples;
                        recSyncPosInBytes = pos;
                    }
                    break;

                default:
                    System.Diagnostics.Debug.Assert(false);
                    break;
                }
            }

            /*
             * Console.WriteLine("recSyncPosInBytes={0} zeroSamples={1} syncSamples={2} nSamples={3}",
             *  recSyncPosInBytes, zeroSamples, syncSamples, nFrames * NUM_CHANNELS);
             */

            if (0 <= recSyncPosInBytes && zeroSamples + syncSamples == nFrames * NUM_CHANNELS)
            {
                // SYNC frame arrived
                mSyncTimeout.Stop();

                //Console.WriteLine("Sync Frame arrived. offset={0}", recSyncPosInBytes);

                mCapturedPcmData.CopyFrom(data, recSyncPosInBytes, 0, data.Length - recSyncPosInBytes);
                mCapturedBytes = data.Length - recSyncPosInBytes;

                // SYNCの次に再生する曲をREADYに変更。
                mWasapiPlay.ConnectPcmDataNext((int)AudioContentType.SYNC, (int)AudioContentType.READY);
                mState = State.Running;
            }
        }
示例#7
0
        private void PreparePcmData()
        {
            // mPcmSync : 長さ2秒、同期をするために頭に1回小さいクリック音を入れる。これを連続再生する。
            // mPcmReady : 長さ2秒、頭に小さいクリック音がある。このPCMの直後にテストデータを再生する。

            const int SYNC_PCM_SECONDS = 1;

            {
                mPcmSync = new PcmDataLib.PcmData();
                mPcmSync.SetFormat(NUM_CHANNELS,
                                   WasapiCS.SampleFormatTypeToUseBitsPerSample(mPlaySampleFormat),
                                   WasapiCS.SampleFormatTypeToValidBitsPerSample(mPlaySampleFormat),
                                   mSampleRate,
                                   PcmDataLib.PcmData.ValueRepresentationType.SInt, SYNC_PCM_SECONDS * mSampleRate);
                var syncData = new LargeArray <byte>((WasapiCS.SampleFormatTypeToUseBitsPerSample(mPlaySampleFormat) / 8) * NUM_CHANNELS * mPcmSync.NumFrames);
                mPcmSync.SetSampleLargeArray(syncData);
            }

            {
                mPcmReady = new PcmDataLib.PcmData();
                mPcmReady.CopyFrom(mPcmSync);
                var readyData = new LargeArray <byte>((WasapiCS.SampleFormatTypeToUseBitsPerSample(mPlaySampleFormat) / 8) * NUM_CHANNELS * mPcmSync.NumFrames);
                mPcmReady.SetSampleLargeArray(readyData);
            }

            switch (mPlaySampleFormat)
            {
            case WasapiCS.SampleFormatType.Sint16:
                mPcmSync.SetSampleValueInInt32(0, 0, 0x00040000);
                mPcmReady.SetSampleValueInInt32(0, 0, 0x00030000);
                break;

            case WasapiCS.SampleFormatType.Sint24:
            case WasapiCS.SampleFormatType.Sint32V24:
                mPcmSync.SetSampleValueInInt32(0, 0, 0x00000400);
                mPcmReady.SetSampleValueInInt32(0, 0, 0x00000300);
                break;

            default:
                System.Diagnostics.Debug.Assert(false);
                break;
            }

            // mPcmTest : テストデータ。このPCMデータを再生し、再生データと録音データが一致するかどうかを調べる。
            if (mUseFile)
            {
                var conv = new WasapiPcmUtil.PcmFormatConverter(NUM_CHANNELS);
                mPcmTest = conv.Convert(mPlayPcmData, mPlaySampleFormat,
                                        new WasapiPcmUtil.PcmFormatConverter.BitsPerSampleConvArgs(WasapiPcmUtil.NoiseShapingType.None));
                mNumTestFrames = mPcmTest.NumFrames;
            }
            else
            {
                mPcmTest = new PcmDataLib.PcmData();
                mPcmTest.CopyHeaderInfoFrom(mPcmSync);
                var randData = new LargeArray <byte>((long)(WasapiCS.SampleFormatTypeToUseBitsPerSample(mPlaySampleFormat) / 8) * NUM_CHANNELS * mNumTestFrames);
                var fragment = new byte[4096];

                for (long i = 0; i < randData.LongLength; i += fragment.Length)
                {
                    long count = fragment.Length;
                    if (randData.LongLength < i + count)
                    {
                        count = randData.LongLength - i;
                    }

                    mRand.NextBytes(fragment);
                    randData.CopyFrom(fragment, 0, i, (int)count);
                }
                mPcmTest.SetSampleLargeArray(mNumTestFrames, randData);
            }

            // 録音データ置き場。
            mCapturedPcmData = new LargeArray <byte>((long)(WasapiCS.SampleFormatTypeToUseBitsPerSample(mRecSampleFormat) / 8)
                                                     * NUM_CHANNELS * (mNumTestFrames + (4 * SYNC_PCM_SECONDS) * mSampleRate));
        }
示例#8
0
        private void LoadPcm_DoWork(object sender, DoWorkEventArgs e)
        {
            string path = (string)e.Argument;
            var    r    = new LoadPcmResult();

            r.path    = path;
            r.result  = false;
            r.pcmData = null;

            mPlayPcmData = null;
            try {
                using (var br = new BinaryReader(File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read))) {
                    var reader = new WavRWLib2.WavReader();
                    if (reader.ReadHeaderAndSamples(br, 0, -1) &&
                        reader.NumChannels == NUM_CHANNELS)
                    {
                        var b = reader.GetSampleLargeArray();
                        r.pcmData = new PcmDataLib.PcmData();
                        r.pcmData.SetFormat(NUM_CHANNELS, reader.BitsPerSample, reader.ValidBitsPerSample,
                                            reader.SampleRate, reader.SampleValueRepresentationType, reader.NumFrames);
                        r.pcmData.SetSampleLargeArray(b);
                    }
                }
            } catch (Exception ex) {
                Console.WriteLine(ex);
                r.pcmData = null;
            }

            if (r.pcmData == null)
            {
                try {
                    var flacRW = new WWFlacRWCS.FlacRW();
                    int rv     = flacRW.DecodeAll(r.path);
                    if (0 <= rv)
                    {
                        WWFlacRWCS.Metadata metaData;
                        flacRW.GetDecodedMetadata(out metaData);
                        if (metaData.channels == NUM_CHANNELS)
                        {
                            var pcmBytes = new LargeArray <byte>(metaData.PcmBytes);

                            int bytesPerSample = metaData.bitsPerSample / 8;
                            var fragment       = new byte[bytesPerSample];
                            for (long pos = 0; pos < metaData.totalSamples; ++pos)
                            {
                                for (int ch = 0; ch < NUM_CHANNELS; ++ch)
                                {
                                    flacRW.GetDecodedPcmBytes(ch, pos * bytesPerSample, out fragment, bytesPerSample);
                                    pcmBytes.CopyFrom(fragment, 0, (long)bytesPerSample * (NUM_CHANNELS * pos + ch), bytesPerSample);
                                }
                            }

                            r.pcmData = new PcmDataLib.PcmData();
                            r.pcmData.SetFormat(NUM_CHANNELS, metaData.bitsPerSample, metaData.bitsPerSample,
                                                metaData.sampleRate, PcmDataLib.PcmData.ValueRepresentationType.SInt, metaData.totalSamples);
                            r.pcmData.SetSampleLargeArray(pcmBytes);
                        }
                    }
                    flacRW.DecodeEnd();
                } catch (Exception ex) {
                    Console.WriteLine(ex);
                    r.pcmData = null;
                }
            }

            if (r.pcmData != null)
            {
                r.result = true;
            }
            else
            {
                r.result = false;
            }

            e.Result = r;
        }
示例#9
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);
        }