public MainWindow()
        {
            InitializeComponent();

            wasapi = new WasapiCS();
            wasapi.Init();

            Prepare();
        }
Пример #2
0
        public MainWindow()
        {
            InitializeComponent();

            wasapi = new WasapiCS();
            wasapi.Init();

            Prepare();
        }
Пример #3
0
        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();
        }
Пример #4
0
        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;
                }
            });
        }
        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;
            }
        }
 public static PcmData.ValueRepresentationType BftToVrt(WasapiCS.BitFormatType bft)
 {
     return (PcmData.ValueRepresentationType)bft;
 }
Пример #14
0
 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;
 }
Пример #30
0
 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;
                }
            });
        }
Пример #32
0
 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;
 }