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; } }
/// <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); }
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); }
/// <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); } }
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; } }
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)); }
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; }
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); }