public MainWindow() { InitializeComponent(); wasapi = new WasapiCS(); wasapi.Init(); Prepare(); }
public void Update(byte [] pcm) { for (int ch = 0; ch < mCh; ++ch) { mPeakCalcArray[ch].UpdateBegin(); } int sampleBytes = WasapiCS.SampleFormatTypeToUseBitsPerSample(mSampleFormat) / 8; int nFrames = pcm.Length / (mCh * sampleBytes); int pos = 0; for (int n = 0; n < nFrames; ++n) { for (int ch = 0; ch < mCh; ++ch) { double v = GetSampleValue(pcm, pos); mPeakCalcArray[ch].NextSample(v); pos += sampleBytes; } } for (int ch = 0; ch < mCh; ++ch) { mPeakCalcArray[ch].UpdateEnd(); if (0 < mPeakHoldSec) { // 最後のピーク値 x 時間減衰。 double lastPeakDb = mLastPeakLevelDb[ch] - ReleaseTimeDbPerSec * mSw.ElapsedMilliseconds / 1000.0; if (mPeakCalcArray[ch].PeakDb < lastPeakDb) { mPeakCalcArray[ch].UpdatePeakDbTo(lastPeakDb); } mLastPeakLevelDb[ch] = mPeakCalcArray[ch].PeakDb; } } mSw.Restart(); }
private void Window_Closed(object sender, EventArgs e) { if (wasapi != null) { Stop(); // バックグラウンドスレッドにjoinして、完全に止まるまで待ち合わせする。 // そうしないと、バックグラウンドスレッドによって使用中のオブジェクトが // この後のTermの呼出によって開放されてしまい問題が起きる。 while (m_playWorker.IsBusy) { System.Windows.Threading.Dispatcher.CurrentDispatcher.Invoke( System.Windows.Threading.DispatcherPriority.Background, new System.Threading.ThreadStart(delegate { })); System.Threading.Thread.Sleep(100); } wasapi.Term(); wasapi = null; } }
private byte[] ConvI32V24toI24(PcmData pcmFrom, WasapiCS.SampleFormatType toFormat, BitsPerSampleConvArgs args) { return ConvCommon(pcmFrom, toFormat, args, (from, to, nSample, noiseShaping) => { int fromPos = 0; int toPos = 0; for (int i = 0; i < nSample; ++i) { // truncate lower 8-bit of 32-bit PCM to create 24-bit PCM to[toPos++] = from[fromPos + 1]; to[toPos++] = from[fromPos + 2]; to[toPos++] = from[fromPos + 3]; fromPos += 4; } }); }
private byte[] ConvI32toF64(PcmData pcmFrom, WasapiCS.SampleFormatType toFormat, BitsPerSampleConvArgs args) { return ConvCommon(pcmFrom, toFormat, args, (from, to, nSample, noiseShaping) => { int fromPos = 0; int toPos = 0; for (int i = 0; i < nSample; ++i) { int iv = ((int)from[fromPos + 1] << 8) + ((int)from[fromPos + 2] << 16) + ((int)from[fromPos + 3] << 24); double dv = ((double)iv) * (1.0 / 2147483648.0); byte [] b = System.BitConverter.GetBytes(dv); for (int j=0; j < 8; ++j) { to[toPos++] = b[j]; } fromPos += 4; } }); }
private byte[] ConvI24toI32(PcmData pcmFrom, WasapiCS.SampleFormatType toFormat, BitsPerSampleConvArgs args) { return ConvCommon(pcmFrom, toFormat, args, (from, to, nSample, noiseShaping) => { int fromPos = 0; int toPos = 0; for (int i = 0; i < nSample; ++i) { // Lower 8-bit: fill 0s to[toPos++] = 0; // Higher 24-bit: copy PCM to[toPos++] = from[fromPos++]; to[toPos++] = from[fromPos++]; to[toPos++] = from[fromPos++]; } }); }
private byte[] ConvI16toF64(PcmData pcmFrom, WasapiCS.SampleFormatType toFormat, BitsPerSampleConvArgs args) { return ConvCommon(pcmFrom, toFormat, args, (from, to, nSample, noiseShaping) => { int fromPos = 0; int toPos = 0; for (int i = 0; i < nSample; ++i) { short iv = (short)(from[fromPos] + (from[fromPos + 1] << 8)); double dv = ((double)iv) * (1.0 / 32768.0); byte [] b = System.BitConverter.GetBytes(dv); for (int j=0; j < 8; ++j) { to[toPos++] = b[j]; } fromPos += 2; } }); }
private byte[] ConvF64toI32(PcmData pcmFrom, WasapiCS.SampleFormatType toFormat, BitsPerSampleConvArgs args) { return ConvCommon(pcmFrom, toFormat, args, (from, to, nSample, noiseShaping) => { int fromPos = 0; int toPos = 0; for (int i = 0; i < nSample; ++i) { double dv = System.BitConverter.ToDouble(from, fromPos); int iv = 0; if ((long)Int32.MaxValue < (long)(dv * Int32.MaxValue)) { iv = Int32.MaxValue; IncrementClippedCounter(); } else if ((long)(-dv * Int32.MinValue) < (long)Int32.MinValue) { iv = Int32.MinValue; IncrementClippedCounter(); } else { iv = (int)(-dv * Int32.MinValue); } to[toPos++] = (byte)((iv >> 0) & 0xff); to[toPos++] = (byte)((iv >> 8) & 0xff); to[toPos++] = (byte)((iv >> 16) & 0xff); to[toPos++] = (byte)((iv >> 24) & 0xff); fromPos += 8; } }); }
private byte[] ConvF64toF32(PcmData pcmFrom, WasapiCS.SampleFormatType toFormat, BitsPerSampleConvArgs args) { return ConvCommon(pcmFrom, toFormat, args, (from, to, nSample, noiseShaping) => { int fromPos = 0; int toPos = 0; for (int i = 0; i < nSample; ++i) { double dv = System.BitConverter.ToDouble(from, fromPos); float fv = (float)dv; if (SAMPLE_VALUE_MAX_FLOAT <= fv) { fv = SAMPLE_VALUE_MAX_FLOAT_TO_I24; IncrementClippedCounter(); } if (fv < SAMPLE_VALUE_MIN_FLOAT) { fv = SAMPLE_VALUE_MIN_FLOAT; IncrementClippedCounter(); } byte [] b = System.BitConverter.GetBytes(fv); to[toPos++] = b[0]; to[toPos++] = b[1]; to[toPos++] = b[2]; to[toPos++] = b[3]; fromPos += 8; } }); }
private byte[] ConvF32toI16(PcmData pcmFrom, WasapiCS.SampleFormatType toFormat, BitsPerSampleConvArgs args) { return ConvCommon(pcmFrom, toFormat, args, (from, to, nSample, noiseShaping) => { int fromPos = 0; int toPos = 0; switch (noiseShaping) { case NoiseShapingType.None: for (int i = 0; i < nSample; ++i) { float fv = System.BitConverter.ToSingle(from, fromPos); if (SAMPLE_VALUE_MAX_FLOAT <= fv) { fv = SAMPLE_VALUE_MAX_FLOAT_TO_I16; IncrementClippedCounter(); } if (fv < SAMPLE_VALUE_MIN_FLOAT) { fv = SAMPLE_VALUE_MIN_FLOAT; IncrementClippedCounter(); } int iv = (int)(fv * 32768.0f); to[toPos++] = (byte)(iv & 0xff); to[toPos++] = (byte)((iv >> 8) & 0xff); fromPos += 4; } break; case NoiseShapingType.AddDither: { for (int i = 0; i < nSample; ++i) { float fv = System.BitConverter.ToSingle(from, fromPos); if (SAMPLE_VALUE_MAX_FLOAT <= fv) { fv = SAMPLE_VALUE_MAX_FLOAT_TO_I16; IncrementClippedCounter(); } if (fv < SAMPLE_VALUE_MIN_FLOAT) { fv = SAMPLE_VALUE_MIN_FLOAT; IncrementClippedCounter(); } long iv = (long)(fv * Int32.MaxValue); // TPDF int dither = (int)((mRand.NextDouble() + mRand.NextDouble() - 0.5) * 65536); iv += dither; int vOut; if (Int32.MaxValue < iv) { vOut = Int32.MaxValue; } else if (iv < Int32.MinValue) { vOut = Int32.MinValue; } else { vOut = (int)iv; } to[toPos++] = (byte)((vOut >> 16) & 0xff); to[toPos++] = (byte)((vOut >> 24) & 0xff); fromPos += 4; } args.noiseShapingOrDitherPerformed = true; } break; case NoiseShapingType.NoiseShaping1stOrder: { long nFrame = nSample / pcmFrom.NumChannels; System.Diagnostics.Debug.Assert(mErr != null && mErr.Length == pcmFrom.NumChannels); for (int i = 0; i < nFrame; ++i) { for (int ch=0; ch < pcmFrom.NumChannels; ++ch) { float fv = System.BitConverter.ToSingle(from, fromPos); if (SAMPLE_VALUE_MAX_FLOAT <= fv) { fv = SAMPLE_VALUE_MAX_FLOAT_TO_I16; IncrementClippedCounter(); } if (fv < SAMPLE_VALUE_MIN_FLOAT) { fv = SAMPLE_VALUE_MIN_FLOAT; IncrementClippedCounter(); } long lv = (long)((double)fv * ((long)Int32.MaxValue + 1L) + mErr[ch]); int iv; if (Int32.MaxValue < lv) { iv = Int32.MaxValue; } else if (lv < Int32.MinValue) { iv = Int32.MinValue; } else { iv = (int)lv; } iv = (int)(iv & 0xffff0000); mErr[ch] = (int)(lv - iv); to[toPos++] = (byte)((iv >> 16) & 0xff); to[toPos++] = (byte)((iv >> 24) & 0xff); fromPos += 4; } } args.noiseShapingOrDitherPerformed = true; } break; case NoiseShapingType.DitheredNoiseShaping1stOrder: { long nFrame = nSample / pcmFrom.NumChannels; System.Diagnostics.Debug.Assert(mErr != null && mErr.Length == pcmFrom.NumChannels); for (int i = 0; i < nFrame; ++i) { for (int ch=0; ch < pcmFrom.NumChannels; ++ch) { float fv = System.BitConverter.ToSingle(from, fromPos); if (SAMPLE_VALUE_MAX_FLOAT <= fv) { fv = SAMPLE_VALUE_MAX_FLOAT_TO_I16; IncrementClippedCounter(); } if (fv < SAMPLE_VALUE_MIN_FLOAT) { fv = SAMPLE_VALUE_MIN_FLOAT; IncrementClippedCounter(); } // RPDF double dither = (mRand.NextDouble() - 0.5) * 65536 / 4; long lv = (long)((double)fv * ((long)Int32.MaxValue + 1L) + mErr[ch] + dither); int iv; if (Int32.MaxValue < lv) { iv = Int32.MaxValue; } else if (lv < Int32.MinValue) { iv = Int32.MinValue; } else { iv = (int)lv; } iv = (int)(iv & 0xffff0000); mErr[ch] = (int)(lv - iv); to[toPos++] = (byte)((iv >> 16) & 0xff); to[toPos++] = (byte)((iv >> 24) & 0xff); fromPos += 4; } } args.noiseShapingOrDitherPerformed = true; } break; } }); }
public static PcmData.ValueRepresentationType BftToVrt(WasapiCS.BitFormatType bft) { return (PcmData.ValueRepresentationType)bft; }
public void Set(int samplingRate, WasapiCS.SampleFormatType fmt, int numChannels, int latencyMillisec, int zeroFlushMillisec, WasapiDataFeedModeType dfm, WasapiSharedOrExclusiveType shareMode, RenderThreadTaskType threadTaskType, int resamplerConversionQuality, WasapiCS.StreamType streamType, WasapiCS.MMThreadPriorityType threadPriority) { this.setuped = true; this.samplingRate = samplingRate; this.sampleFormat = fmt; this.NumChannels = numChannels; this.latencyMillisec = latencyMillisec; this.zeroFlushMillisec = zeroFlushMillisec; this.dfm = dfm; this.shareMode = shareMode; this.threadTaskType = threadTaskType; this.ResamplerConversionQuality = resamplerConversionQuality; this.StreamType = streamType; this.ThreadPriority = threadPriority; }
private void Term() { // バックグラウンドスレッドにjoinして、完全に止まるまで待ち合わせするブロッキング版のStopを呼ぶ。 // そうしないと、バックグラウンドスレッドによって使用中のオブジェクトが // この後のUnsetupの呼出によって開放されてしまい問題が起きる。 StopBlocking(); if (mWasapiRec != null) { mWasapiRec.Unsetup(); mWasapiRec.Term(); mWasapiRec = null; } if (mWasapiPlay != null) { mWasapiPlay.Unsetup(); mWasapiPlay.Term(); mWasapiPlay = null; } }
public bool IsNoiseShapingOrDitherCapable(PcmData pdFrom, WasapiCS.SampleFormatType toFormat) { return mConv.IsConversionNoiseshapingOrDitherCapable( WasapiCS.BitAndFormatToSampleFormatType(pdFrom.BitsPerSample, pdFrom.ValidBitsPerSample, SampleFormatInfo.VrtToBft(pdFrom.SampleValueRepresentationType)), toFormat); }
private void Window_Loaded(object sender, RoutedEventArgs e) { LocalizeUI(); mWasapiPlay = new WasapiCS(); mWasapiPlay.Init(); mWasapiRec = new WasapiCS(); mWasapiRec.Init(); mCaptureDataArrivedDelegate = new Wasapi.WasapiCS.CaptureCallback(CaptureDataArrived); mWasapiRec.RegisterCaptureCallback(mCaptureDataArrivedDelegate); mPlayWorker = new BackgroundWorker(); mPlayWorker.DoWork += new DoWorkEventHandler(PlayDoWork); mPlayWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(PlayRunWorkerCompleted); mPlayWorker.WorkerSupportsCancellation = true; mPlayWorker.WorkerReportsProgress = true; mPlayWorker.ProgressChanged += new ProgressChangedEventHandler(PlayWorkerProgressChanged); mRecWorker = new BackgroundWorker(); mRecWorker.DoWork += new DoWorkEventHandler(RecDoWork); mRecWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(RecRunWorkerCompleted); mRecWorker.WorkerSupportsCancellation = true; UpdateDeviceList(); mSyncTimeout = new DispatcherTimer(); mSyncTimeout.Tick += new EventHandler(SyncTimeoutTickCallback); mSyncTimeout.Interval = new TimeSpan(0, 0, 5); textBoxLog.Text = string.Format("WasapiBitmatchChecker version {0}\r\n", AssemblyVersion); mStateChanged = new Wasapi.WasapiCS.StateChangedCallback(StateChangedCallback); mWasapiPlay.RegisterStateChangedCallback(mStateChanged); }
private byte[] ConvF32toI32(PcmData pcmFrom, WasapiCS.SampleFormatType toFormat, BitsPerSampleConvArgs args) { return ConvCommon(pcmFrom, toFormat, args, (from, to, nSample, noiseShaping) => { int fromPos = 0; int toPos = 0; for (int i = 0; i < nSample; ++i) { float fv = System.BitConverter.ToSingle(from, fromPos); if (SAMPLE_VALUE_MAX_FLOAT <= fv) { fv = SAMPLE_VALUE_MAX_FLOAT_TO_I24; IncrementClippedCounter(); } if (fv < SAMPLE_VALUE_MIN_FLOAT) { fv = SAMPLE_VALUE_MIN_FLOAT; IncrementClippedCounter(); } int iv = (int)(fv * 8388608.0f); to[toPos++] = 0; to[toPos++] = (byte)(iv & 0xff); to[toPos++] = (byte)((iv >> 8) & 0xff); to[toPos++] = (byte)((iv >> 16) & 0xff); fromPos += 4; } }); }
private byte[] ConvI32V24toI32(PcmData pcmFrom, WasapiCS.SampleFormatType toFormat, BitsPerSampleConvArgs args) { return ConvCommon(pcmFrom, toFormat, args, (from, to, nSample, noiseShaping) => { int fromPos = 0; int toPos = 0; for (int i = 0; i < nSample; ++i) { // discard lower 8-bit because it is garbage to[toPos++] = 0; to[toPos++] = from[fromPos + 1]; to[toPos++] = from[fromPos + 2]; to[toPos++] = from[fromPos + 3]; fromPos += 4; } }); }
private byte[] ConvF64toI24orI32V24(PcmData pcmFrom, WasapiCS.SampleFormatType toFormat, BitsPerSampleConvArgs args) { return ConvCommon(pcmFrom, toFormat, args, (from, to, nSample, noiseShaping) => { int fromPos = 0; int toPos = 0; bool writePad = toFormat == WasapiCS.SampleFormatType.Sint32V24; for (int i = 0; i < nSample; ++i) { double dv = System.BitConverter.ToDouble(from, fromPos); if (SAMPLE_VALUE_MAX_DOUBLE <= dv) { dv = SAMPLE_VALUE_MAX_DOUBLE_TO_I24; IncrementClippedCounter(); } if (dv < SAMPLE_VALUE_MIN_DOUBLE) { dv = SAMPLE_VALUE_MIN_DOUBLE; IncrementClippedCounter(); } int iv = (int)(dv * 8388608.0); if (writePad) { to[toPos++] = 0; } to[toPos++] = (byte)(iv & 0xff); to[toPos++] = (byte)((iv >> 8) & 0xff); to[toPos++] = (byte)((iv >> 16) & 0xff); fromPos += 8; } }); }
/// <summary> /// Converts sample format to toFormat and returns new instance of PcmData. /// pcmFrom is not changed. /// </summary> /// <param name="toFormat">sample format to convert</param> /// <returns>Newly instanciated PcmData</returns> public PcmData Convert(PcmData pcmFrom, WasapiCS.SampleFormatType toFormat, BitsPerSampleConvArgs args) { if (args == null) { args = new BitsPerSampleConvArgs(NoiseShapingType.None); } var fromFormat = WasapiCS.BitAndFormatToSampleFormatType(pcmFrom.BitsPerSample, pcmFrom.ValidBitsPerSample, SampleFormatInfo.VrtToBft(pcmFrom.SampleValueRepresentationType)); if (fromFormat == WasapiCS.SampleFormatType.Unknown || toFormat == WasapiCS.SampleFormatType.Unknown) { return null; } var newSampleArray = mConvert[(int)fromFormat][(int)toFormat](pcmFrom, toFormat, args); PcmData newPcmData = new PcmData(); newPcmData.CopyHeaderInfoFrom(pcmFrom); newPcmData.SetFormat(pcmFrom.NumChannels, WasapiCS.SampleFormatTypeToUseBitsPerSample(toFormat), WasapiCS.SampleFormatTypeToValidBitsPerSample(toFormat), pcmFrom.SampleRate, SampleFormatInfo.BftToVrt(WasapiCS.SampleFormatTypeToBitFormatType(toFormat)), pcmFrom.NumFrames); newPcmData.SetSampleArray(newSampleArray); return newPcmData; }
private byte[] ConvI16toF32(PcmData pcmFrom, WasapiCS.SampleFormatType toFormat, BitsPerSampleConvArgs args) { return ConvCommon(pcmFrom, toFormat, args, (from, to, nSample, noiseShaping) => { int fromPos = 0; int toPos = 0; for (int i = 0; i < nSample; ++i) { short iv = (short)(from[fromPos] + (from[fromPos + 1] << 8)); float fv = ((float)iv) * (1.0f / 32768.0f); byte [] b = System.BitConverter.GetBytes(fv); to[toPos++] = b[0]; to[toPos++] = b[1]; to[toPos++] = b[2]; to[toPos++] = b[3]; fromPos += 2; } }); }
public bool IsConversionNoiseshapingOrDitherCapable(WasapiCS.SampleFormatType fromFormat, WasapiCS.SampleFormatType toFormat) { System.Diagnostics.Debug.Assert(0 <= (int)fromFormat && (int)fromFormat <= (int)WasapiCS.SampleFormatType.Sdouble); System.Diagnostics.Debug.Assert(0 <= (int)toFormat && (int)toFormat <= (int)WasapiCS.SampleFormatType.Sdouble); if (fromFormat == WasapiCS.SampleFormatType.Unknown || toFormat == WasapiCS.SampleFormatType.Unknown) { return false; } return mNoiseShapingOrDitherCapabilityTable[(int)fromFormat][(int)toFormat]; }
private byte[] ConvI24or32toI16(PcmData pcmFrom, WasapiCS.SampleFormatType toFormat, BitsPerSampleConvArgs args) { return ConvCommon(pcmFrom, toFormat, args, (from, to, nSample, noiseShaping) => { int fromPos = 0; int toPos = 0; int fromBytesPerSample = pcmFrom.BitsPerSample / 8; switch (noiseShaping) { case NoiseShapingType.None: { int fromSkipCount = 1; if (pcmFrom.BitsPerSample == 32) { fromSkipCount = 2; } for (int i = 0; i < nSample; ++i) { // discard lower bits fromPos += fromSkipCount; to[toPos++] = from[fromPos++]; to[toPos++] = from[fromPos++]; } } break; case NoiseShapingType.AddDither: { if (pcmFrom.BitsPerSample == 32) { // discard lower 8-bit ++fromPos; } for (int i = 0; i < nSample; ++i) { long v = (int)((from[fromPos] << 8) + (from[fromPos + 1] << 16) + (from[fromPos + 2] << 24)); // TPDF dither (width 131072, center 32768, left edge -32768, right edge 98304) int dither = (int)((mRand.NextDouble() + mRand.NextDouble() - 0.5) * 65536); v += dither; int vOut; if (Int32.MaxValue < v) { vOut = Int32.MaxValue; } else if (v < Int32.MinValue) { vOut = Int32.MinValue; } else { vOut = (int)v; } to[toPos++] = (byte)((vOut >> 16) & 0xff); to[toPos++] = (byte)((vOut >> 24) & 0xff); fromPos += fromBytesPerSample; } args.noiseShapingOrDitherPerformed = true; } break; case NoiseShapingType.NoiseShaping1stOrder: { long nFrame = nSample / pcmFrom.NumChannels; System.Diagnostics.Debug.Assert(mErr != null && mErr.Length == pcmFrom.NumChannels); if (pcmFrom.BitsPerSample == 32) { // discard lower 8-bit ++fromPos; } for (int i = 0; i < nFrame; ++i) { for (int ch=0; ch < pcmFrom.NumChannels; ++ch) { int v = (short)(from[fromPos + 1] + (from[fromPos + 2] << 8)); v += mErr[ch] >> 8; if (32767 < v) { v = 32767; } mErr[ch] -= ((mErr[ch]) >> 8) << 8; mErr[ch] += from[fromPos]; to[toPos++] = (byte)(v & 0xff); to[toPos++] = (byte)((v >> 8) & 0xff); fromPos += fromBytesPerSample; } } args.noiseShapingOrDitherPerformed = true; } break; case NoiseShapingType.DitheredNoiseShaping1stOrder: { long nFrame = nSample / pcmFrom.NumChannels; System.Diagnostics.Debug.Assert(mErr != null && mErr.Length == pcmFrom.NumChannels); if (pcmFrom.BitsPerSample == 32) { // discard lower 8-bit ++fromPos; } for (int i = 0; i < nFrame; ++i) { for (int ch=0; ch < pcmFrom.NumChannels; ++ch) { long v = (int)((from[fromPos] << 8) + (from[fromPos + 1] << 16) + (from[fromPos + 2] << 24)); // RPDF int dither = (int)((mRand.NextDouble() - 0.5) * 65536 / 4); v += mErr[ch] + dither; int vOut; if (Int32.MaxValue < v) { vOut = Int32.MaxValue; } else if (v < Int32.MinValue) { vOut = Int32.MinValue; } else { vOut = (int)v; } vOut = (int)(vOut & 0xffff0000); mErr[ch] = (int)(v - vOut); to[toPos++] = (byte)((vOut >> 16) & 0xff); to[toPos++] = (byte)((vOut >> 24) & 0xff); fromPos += fromBytesPerSample; } } args.noiseShapingOrDitherPerformed = true; } break; } }); }
private byte[] ConvClone(PcmData from, WasapiCS.SampleFormatType toFormat, BitsPerSampleConvArgs args) { return (byte[])from.GetSampleArray().Clone(); }
private byte[] ConvI32toF32(PcmData pcmFrom, WasapiCS.SampleFormatType toFormat, BitsPerSampleConvArgs args) { return ConvCommon(pcmFrom, toFormat, args, (from, to, nSample, noiseShaping) => { int fromPos = 0; int toPos = 0; for (int i = 0; i < nSample; ++i) { int iv = ((int)from[fromPos + 1] << 8) + ((int)from[fromPos + 2] << 16) + ((int)from[fromPos + 3] << 24); float fv = ((float)iv) * (1.0f / 2147483648.0f); byte [] b = System.BitConverter.GetBytes(fv); to[toPos++] = b[0]; to[toPos++] = b[1]; to[toPos++] = b[2]; to[toPos++] = b[3]; fromPos += 4; } }); }
private byte[] ConvCommon(PcmData pcmFrom, WasapiCS.SampleFormatType toFormat, BitsPerSampleConvArgs args, ConversionLoop convLoop) { var from = pcmFrom.GetSampleArray(); long nSample = from.LongLength * 8 / pcmFrom.BitsPerSample; var to = new byte[nSample * WasapiCS.SampleFormatTypeToUseBitsPerSample(toFormat) / 8]; convLoop(from, to, nSample, args.noiseShaping); return to; }
private byte[] ConvI32toI24orI32V24(PcmData pcmFrom, WasapiCS.SampleFormatType toFormat, BitsPerSampleConvArgs args) { return ConvCommon(pcmFrom, toFormat, args, (from, to, nSample, noiseShaping) => { int fromPos = 0; int toPos = 0; bool writePad = toFormat == WasapiCS.SampleFormatType.Sint32V24; switch (noiseShaping) { case NoiseShapingType.None: { for (int i = 0; i < nSample; ++i) { // discard lower 8-bit if (writePad) { to[toPos++] = 0; } to[toPos++] = from[fromPos + 1]; to[toPos++] = from[fromPos + 2]; to[toPos++] = from[fromPos + 3]; fromPos += 4; } } break; case NoiseShapingType.AddDither: { for (int i = 0; i < nSample; ++i) { long v = (int)((from[fromPos + 0] << 0) + (from[fromPos + 1] << 8) + (from[fromPos + 2] << 16) + (from[fromPos + 3] << 24)); // TPDF dither (width 512, center 128, left edge -128, right edge 384) int dither = (int)((mRand.NextDouble() + mRand.NextDouble() - 0.5) * 256); v += dither; int vOut; if (Int32.MaxValue < v) { vOut = Int32.MaxValue; } else if (v < Int32.MinValue) { vOut = Int32.MinValue; } else { vOut = (int)v; } if (writePad) { to[toPos++] = 0; } to[toPos++] = (byte)((vOut >> 8) & 0xff); to[toPos++] = (byte)((vOut >> 16) & 0xff); to[toPos++] = (byte)((vOut >> 24) & 0xff); fromPos += 4; } args.noiseShapingOrDitherPerformed = true; } break; case NoiseShapingType.NoiseShaping1stOrder: { long nFrame = nSample / pcmFrom.NumChannels; System.Diagnostics.Debug.Assert(mErr != null && mErr.Length == pcmFrom.NumChannels); for (int i = 0; i < nFrame; ++i) { for (int ch=0; ch < pcmFrom.NumChannels; ++ch) { int v = (short)(from[fromPos + 1] + (from[fromPos + 2] << 8) + (from[fromPos + 3] << 16)); v += mErr[ch] >> 8; if (8388607 < v) { v = 8388607; } mErr[ch] -= ((mErr[ch]) >> 8) << 8; mErr[ch] += from[fromPos]; if (writePad) { to[toPos++] = 0; } to[toPos++] = (byte)(v & 0xff); to[toPos++] = (byte)((v >> 8) & 0xff); to[toPos++] = (byte)((v >> 16) & 0xff); fromPos += 4; } } args.noiseShapingOrDitherPerformed = true; } break; case NoiseShapingType.DitheredNoiseShaping1stOrder: { long nFrame = nSample / pcmFrom.NumChannels; System.Diagnostics.Debug.Assert(mErr != null && mErr.Length == pcmFrom.NumChannels); for (int i = 0; i < nFrame; ++i) { for (int ch=0; ch < pcmFrom.NumChannels; ++ch) { long v = (int)((from[fromPos + 0] << 0) + (from[fromPos + 1] << 8) + (from[fromPos + 2] << 16) + (from[fromPos + 3] << 24)); // RPDF int dither = (int)((mRand.NextDouble() - 0.5) * 256 / 4); v += mErr[ch] + dither; int vOut; if (Int32.MaxValue < v) { vOut = Int32.MaxValue; } else if (v < Int32.MinValue) { vOut = Int32.MinValue; } else { vOut = (int)v; } vOut = (int)(vOut & 0xffffff00); mErr[ch] = (int)(v - vOut); if (writePad) { to[toPos++] = 0; } to[toPos++] = (byte)((vOut >> 8) & 0xff); to[toPos++] = (byte)((vOut >> 16) & 0xff); to[toPos++] = (byte)((vOut >> 24) & 0xff); fromPos += 4; } } args.noiseShapingOrDitherPerformed = true; } break; } }); }
private byte[] ConvError(PcmData from, WasapiCS.SampleFormatType toFormat, BitsPerSampleConvArgs args) { System.Diagnostics.Debug.Assert(false); return null; }
public bool Is( int samplingRate, WasapiCS.SampleFormatType fmt, int numChannels, int latencyMillisec, int zeroFlushMillisec, WasapiDataFeedModeType dfm, WasapiSharedOrExclusiveType shareMode, RenderThreadTaskType threadTaskType, int resamplerConversionQuality, WasapiCS.StreamType streamType, WasapiCS.MMThreadPriorityType threadPriority) { return (this.setuped && this.samplingRate == samplingRate && this.sampleFormat == fmt && this.NumChannels == numChannels && this.latencyMillisec == latencyMillisec && this.zeroFlushMillisec == zeroFlushMillisec && this.dfm == dfm && this.shareMode == shareMode && this.threadTaskType == threadTaskType && this.ResamplerConversionQuality == resamplerConversionQuality && this.StreamType == streamType && this.ThreadPriority == threadPriority); }
private byte[] ConvF32toF64(PcmData pcmFrom, WasapiCS.SampleFormatType toFormat, BitsPerSampleConvArgs args) { return ConvCommon(pcmFrom, toFormat, args, (from, to, nSample, noiseShaping) => { int fromPos = 0; int toPos = 0; for (int i = 0; i < nSample; ++i) { float fv = System.BitConverter.ToSingle(from, fromPos); double dv = (double)fv; byte [] b = System.BitConverter.GetBytes(dv); for (int j=0; j < 8; ++j) { to[toPos++] = b[j]; } fromPos += 4; } }); }
private static bool SampleFormatIsCompatible( WasapiCS.SampleFormatType lhs, WasapiCS.SampleFormatType rhs) { switch (lhs) { case WasapiCS.SampleFormatType.Sint24: case WasapiCS.SampleFormatType.Sint32V24: return rhs == WasapiCS.SampleFormatType.Sint24 || rhs == WasapiCS.SampleFormatType.Sint32V24; default: return lhs == rhs; } }
/// <summary> /// 量子化ビット数を、もし必要なら変更する。 /// </summary> /// <param name="pd">入力PcmData</param> /// <returns>変更後PcmData</returns> public PcmData BitsPerSampleConvAsNeeded(PcmData pd, WasapiCS.SampleFormatType fmt, WasapiPcmUtil.PcmFormatConverter.BitsPerSampleConvArgs args) { switch (fmt) { case WasapiCS.SampleFormatType.Sfloat: // System.Console.WriteLine("Converting to Sfloat32bit..."); pd = mConv.Convert(pd, WasapiCS.SampleFormatType.Sfloat, args); break; case WasapiCS.SampleFormatType.Sint16: // System.Console.WriteLine("Converting to SInt16bit..."); pd = mConv.Convert(pd, WasapiCS.SampleFormatType.Sint16, args); break; case WasapiCS.SampleFormatType.Sint24: // System.Console.WriteLine("Converting to SInt24..."); pd = mConv.Convert(pd, WasapiCS.SampleFormatType.Sint24, args); break; case WasapiCS.SampleFormatType.Sint32V24: // System.Console.WriteLine("Converting to SInt32V24..."); pd = mConv.Convert(pd, WasapiCS.SampleFormatType.Sint32V24, args); break; case WasapiCS.SampleFormatType.Sint32: // System.Console.WriteLine("Converting to SInt32bit..."); pd = mConv.Convert(pd, WasapiCS.SampleFormatType.Sint32, args); break; default: System.Diagnostics.Debug.Assert(false); break; } return pd; }