예제 #1
0
        /// <summary>
        /// 排他モード用。ビットデプスとチャンネル数を変更する。
        /// </summary>
        private byte[] PcmDepthChannelConvert(byte[] from, int fromOffs, int fromBytes,
                                              DeviceFormat fromFormat, DeviceFormat toFormat)
        {
            System.Diagnostics.Debug.Assert(fromFormat.SampleRate == toFormat.SampleRate);

            int numFrames = fromBytes / (fromFormat.NumChannels * WasapiCS.SampleFormatTypeToUseBitsPerSample(fromFormat.SampleFormat) / 8);

            var pcmFrom = new PcmDataLib.PcmData();

            pcmFrom.SetFormat(fromFormat.NumChannels, WasapiCS.SampleFormatTypeToUseBitsPerSample(fromFormat.SampleFormat),
                              WasapiCS.SampleFormatTypeToValidBitsPerSample(fromFormat.SampleFormat),
                              fromFormat.SampleRate, PcmDataLib.PcmData.ValueRepresentationType.SInt, numFrames);
            pcmFrom.SetSampleLargeArray(new WWUtil.LargeArray <byte>(from, fromOffs, fromBytes));

            // ビットデプスを変更する。
            var conv  = new WasapiPcmUtil.PcmFormatConverter(fromFormat.NumChannels);
            var pcmTo = conv.Convert(pcmFrom, toFormat.SampleFormat,
                                     new WasapiPcmUtil.PcmFormatConverter.BitsPerSampleConvArgs(WasapiPcmUtil.NoiseShapingType.None));

            // チャンネル数を変更する。
            var toBytes = WasapiPcmUtil.PcmFormatConverter.ChangeChannelCount(
                fromFormat.SampleFormat, WasapiCS.StreamType.PCM,
                fromFormat.NumChannels, pcmTo.GetSampleLargeArray().ToArray(),
                toFormat.NumChannels);

            return(toBytes);
        }
예제 #2
0
        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);
        }
예제 #3
0
        private void buttonInspectDevice_Click(object sender, RoutedEventArgs e)
        {
            bool bRv;

            {   // read num of channels
                int numOfChannels;
                bRv = Int32.TryParse(textBoxNumOfChannels.Text, out numOfChannels);
                if (!bRv || numOfChannels <= 1)
                {
                    string s = Properties.Resources.ErrorNumChannels;
                    MessageBox.Show(s);
                    AddLog(s);
                    AddLog("\r\n");
                    return;
                }
                mPref.NumOfChannels = numOfChannels;
            }

            int dwChannelMask = 0;

            if (checkBoxSetDwChannelMask.IsChecked == true)
            {
                dwChannelMask = WasapiCS.GetTypicalChannelMask(mPref.NumOfChannels);
            }

            {
                string s = mWasapiCtrl.InspectDevice(listBoxDevices.SelectedIndex, dwChannelMask);
                AddLog(s);
            }
        }
        /// <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);
        }
예제 #5
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;
            }
        }
예제 #6
0
 public void Term()
 {
     mWasapi.Stop();
     mWasapi.Unsetup();
     mWasapi.Term();
     ReleaseCaptureMemory();
     mWasapi      = null;
     mDeviceInUse = false;
 }
예제 #7
0
        private long TotalFrames()
        {
            if (mPref.RecordingBufferSizeMB < 0)
            {
                return(0);
            }

            return((long)mPref.RecordingBufferSizeMB * 1024 * 1024 / WasapiCS.SampleFormatTypeToUseBitsPerSample(mPref.SampleFormat) / mPref.NumOfChannels * 8);
        }
예제 #8
0
        void MainWindow_Closed(object sender, EventArgs e)
        {
            wasapi.Stop();
            wasapi.Unsetup();
            wasapi.Term();
            wasapi = null;

            Application.Current.Shutdown(0);
        }
        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);
        }
예제 #10
0
        /// <returns>WASAPIエラーコード。</returns>
        private int Setup(int deviceId, PcmDataLib.PcmData format)
        {
            int ercd = 0;

            var mixFormat = mWasapi.GetMixFormat(deviceId);

            if (WasapiCS.ShareMode.Shared == mShareMode)
            {
                // 共有モード。
                ercd = mWasapi.Setup(deviceId, WasapiCS.DeviceType.Play, WasapiCS.StreamType.PCM,
                                     mixFormat.sampleRate, WasapiCS.SampleFormatType.Sfloat, mixFormat.numChannels,
                                     mixFormat.dwChannelMask, WasapiCS.MMCSSCallType.Enable,
                                     WasapiCS.MMThreadPriorityType.High, WasapiCS.SchedulerTaskType.ProAudio,
                                     mShareMode, mDataFeedMode, mBufferSizeMillisec, mZeroFlushMillisec, 10000, true);
                if (ercd < 0)
                {
                    Console.WriteLine("Wasapi.Setup({0} {1}) failed", mixFormat.sampleRate, WasapiCS.SampleFormatType.Sfloat);
                    mWasapi.Unsetup();
                }
                else
                {
                    Console.WriteLine("Wasapi.Setup({0} {1}) success", mixFormat.sampleRate, WasapiCS.SampleFormatType.Sfloat);
                    mDeviceFormat.Set(mixFormat.numChannels, mixFormat.sampleRate,
                                      WasapiCS.SampleFormatType.Sfloat, mixFormat.dwChannelMask);
                }
            }
            else
            {
                // 排他モード。

                // ビットデプスの候補をすべて試す。
                var sampleFormatCandidates = SampleFormatCandidates(format.ValidBitsPerSample);
                for (int i = 0; i < sampleFormatCandidates.Length; ++i)
                {
                    ercd = mWasapi.Setup(deviceId, WasapiCS.DeviceType.Play, WasapiCS.StreamType.PCM,
                                         format.SampleRate, sampleFormatCandidates[i], mixFormat.numChannels,
                                         mixFormat.dwChannelMask, WasapiCS.MMCSSCallType.Enable,
                                         WasapiCS.MMThreadPriorityType.High, WasapiCS.SchedulerTaskType.ProAudio,
                                         mShareMode, mDataFeedMode, mBufferSizeMillisec, mZeroFlushMillisec, 10000, true);
                    if (ercd < 0)
                    {
                        Console.WriteLine("Wasapi.Setup({0} {1}) failed", format.SampleRate, sampleFormatCandidates[i]);
                        mWasapi.Unsetup();
                    }
                    else
                    {
                        Console.WriteLine("Wasapi.Setup({0} {1}) success", format.SampleRate, sampleFormatCandidates[i]);
                        mDeviceFormat.Set(mixFormat.numChannels, format.SampleRate,
                                          sampleFormatCandidates[i],
                                          WasapiCS.GetTypicalChannelMask(format.NumChannels));
                        break;
                    }
                }
            }

            return(ercd);
        }
예제 #11
0
        public int WasapiInit()
        {
            System.Diagnostics.Debug.Assert(wasapi == null);

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

            return(hr);
        }
예제 #12
0
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            mPref = PreferenceStore.Load();
            LocalizeUI();

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

            mWasapiRec = new WasapiCS();
            mWasapiRec.Init();
            mCaptureDataArrivedDelegate = new Wasapi.WasapiCS.CaptureCallback(CaptureDataArrived);
            mWasapiRec.RegisterCaptureCallback(mCaptureDataArrivedDelegate);

            mBwStartTesting                     = new BackgroundWorker();
            mBwStartTesting.DoWork             += new DoWorkEventHandler(BwStartTesting_DoWork);
            mBwStartTesting.RunWorkerCompleted += new RunWorkerCompletedEventHandler(BwStartTesting_RunWorkerCompleted);

            mPlayWorker                            = new BackgroundWorker();
            mPlayWorker.DoWork                    += new DoWorkEventHandler(PlayDoWork);
            mPlayWorker.RunWorkerCompleted        += new RunWorkerCompletedEventHandler(PlayRunWorkerCompleted);
            mPlayWorker.WorkerSupportsCancellation = true;

            mRecWorker                            = new BackgroundWorker();
            mRecWorker.DoWork                    += new DoWorkEventHandler(RecDoWork);
            mRecWorker.RunWorkerCompleted        += new RunWorkerCompletedEventHandler(RecRunWorkerCompleted);
            mRecWorker.WorkerSupportsCancellation = true;
            mRecWorker.WorkerReportsProgress      = true;
            mRecWorker.ProgressChanged           += new ProgressChangedEventHandler(RecWorkerProgressChanged);

            UpdateDeviceList();

            textBoxLog.Text = string.Format("WWImpulseResponse version {0}\r\n", AssemblyVersion);

            mStateChanged = new Wasapi.WasapiCS.StateChangedCallback(StateChangedCallback);
            mWasapiPlay.RegisterStateChangedCallback(mStateChanged);

            mTimeDomainPlot.SetFunctionType(WWUserControls.TimeDomainPlot.FunctionType.DiscreteTimeSequence);
            mTimeDomainPlot.SetDiscreteTimeSequence(new double[1], 44100);

            mFreqResponse.Mode = WWUserControls.FrequencyResponse.ModeType.ZPlane;
            mFreqResponse.SamplingFrequency = 48000;
            mFreqResponse.PhaseUnwarp       = true;
            //mFreqResponse.ShowPhase = false;
            mFreqResponse.ShowGroupDelay = false;
            mFreqResponse.UpdateMagnitudeRange(WWUserControls.FrequencyResponse.MagnitudeRangeType.M48dB);
            mFreqResponse.Update();

            mLevelMeterUC.PreferenceToUI(1, -6, -100);
            mLevelMeterUC.YellowLevelChangeEnable(false);
            mLevelMeterUC.SetParamChangedCallback(LevelMeterUCParamChanged);

            PreferenceToUI();

            mInitialized = true;
        }
예제 #13
0
        public bool Init()
        {
            mWasapi = new WasapiCS();
            int ercd = mWasapi.Init();

            if (ercd < 0)
            {
                Console.WriteLine("PlaybackController::Init() Wasapi.Init() failed {0}", ercd);
                return(false);
            }
            return(true);
        }
예제 #14
0
        private void SaveRecordedData()
        {
            var bytes   = wasapi.GetCapturedData(mCapturedPcmData);
            var nFrames = bytes / WasapiCS.SampleFormatTypeToUseBytesPerSample(mSampleFormat) / mNumChannels;

            if (nFrames == 0)
            {
                return;
            }

            textBoxLog.Text += string.Format("captured frames={0} ({1:F1} seconds) glichCount={2}\r\n",
                                             nFrames, (double)nFrames / mSamplingFrequency, wasapi.GetCaptureGlitchCount());

            Microsoft.Win32.SaveFileDialog dlg = new Microsoft.Win32.SaveFileDialog();
            dlg.DefaultExt = ".wav";
            dlg.Filter     = "WAVEファイル|*.wav";

            Nullable <bool> result = dlg.ShowDialog();

            if (result != true)
            {
                return;
            }

            // あとで本のサイズに戻す。
            var originalSize = mCapturedPcmData.Length;

            Array.Resize(ref mCapturedPcmData, (int)bytes);

            mWavData = new WavData();
            mWavData.Set(mNumChannels, WasapiCS.SampleFormatTypeToUseBytesPerSample(mSampleFormat) * 8, WasapiCS.SampleFormatTypeToValidBitsPerSample(mSampleFormat),
                         mSamplingFrequency, SampleFormatToVRT(mSampleFormat), nFrames, mCapturedPcmData);

            try {
                using (BinaryWriter w = new BinaryWriter(File.Open(dlg.FileName, FileMode.Create))) {
                    mWavData.Write(w);

                    textBoxLog.Text += string.Format("ファイル保存成功: {0}\r\n", dlg.FileName);
                }
            } catch (Exception ex) {
                string s = string.Format("E: ファイル保存失敗: {0}\r\n{1}\r\n", dlg.FileName, ex);
                textBoxLog.Text += s;
                MessageBox.Show(s);
            }

            slider1.Value  = 0;
            label1.Content = "0/0";
            Array.Resize(ref mCapturedPcmData, originalSize);
        }
        private void SetSampleDataToWasapiStart(int idx, WWFlacRWCS.FlacRW flac)
        {
            WWFlacRWCS.Metadata meta;
            flac.GetDecodedMetadata(out meta);

            mFromFormat = new DeviceFormat();
            mFromFormat.Set(meta.channels, meta.sampleRate,
                            WasapiCS.BitAndFormatToSampleFormatType(meta.bitsPerSample, meta.bitsPerSample, WasapiCS.BitFormatType.SInt));

            long totalBytes = meta.totalSamples * mDeviceFormat.BytesPerFrame();

            mWasapi.AddPlayPcmDataAllocateMemory(idx, totalBytes);

            mDecodedPcmOffs = 0;
        }
예제 #16
0
        public MainWindow()
        {
            InitializeComponent();

            int hr = 0;

            wasapi               = new WasapiCS();
            hr                   = wasapi.Init();
            textBoxLog.Text     += string.Format("wasapi.Init() {0:X8}\r\n", hr);
            textBoxLatency.Text  = string.Format("{0}", DEFAULT_OUTPUT_LATENCY_MS);
            textBoxRecMaxMB.Text = string.Format("{0}", DEFAULT_BUFFER_SIZE_MB);

            Closed += new EventHandler(MainWindow_Closed);

            CreateDeviceList();
        }
예제 #17
0
        // 開始ボタンを押すと以下の順に実行される。
        //                BwStartTesting_DoWork()
        //                └PreparePcmData()
        //                BwStartTesting_RunWorkerCompleted()
        //                     ↓                       ↓
        // mPlayWorker.RunWorkerAsync()         mRecWorker.RunWorkerAsync()
        // PlayDoWork()                         RecDoWork() → CaptureDataArrived()
        //   (リピート再生)                        │           ├CaptureSync()
        //                                        │           └CaptureRunning()
        //                                        └ProcessCapturedData() → RecWorkerProgressChanged()
        //
        //                                      ユーザーがStopボタン押下
        //                                             ↓
        // PlayRunWorkerCompleted()   ←──────────── mWasapiPlay.Stop()
        //                                          mWasapiRec.Stop()
        //                                      RecRunWorkerCompleted()
        private void buttonStart_Click(object sender, RoutedEventArgs e)
        {
            if (!UpdateTestParamsFromUI())
            {
                return;
            }

            //Console.WriteLine("buttonStart_Click()");

            groupBoxPcmDataSettings.IsEnabled = false;
            groupBoxPlayback.IsEnabled        = false;
            groupBoxRecording.IsEnabled       = false;

            UpdateButtonStartStop(ButtonStartStopState.Disable);

            textBoxLog.Text += "Preparing data.\n";
            textBoxLog.ScrollToEnd();

            int numCh        = mPref.NumOfChannels;
            int playDwChMask = WasapiCS.GetTypicalChannelMask(numCh);

            int recDwChMask = 0;

            if (mPref.SetDwChannelMask)
            {
                recDwChMask = WasapiCS.GetTypicalChannelMask(numCh);
            }

            mLevelMeterUC.UpdateNumOfChannels(mPref.NumOfChannels);

            mTimeDomainPlot.Clear();

            mFreqResponse.SamplingFrequency = mPref.SampleRate;
            mFreqResponse.TransferFunction  = (WWComplex z) => { return(new WWComplex(1, 0)); };
            mFreqResponse.Update();

            Directory.CreateDirectory(textboxOutputFolder.Text);

            int numSamples = 1 << mPref.MLSOrder;

            mFFT = new WWRadix2Fft(numSamples);

            mStartTestingArgs = new StartTestingArgs(mPref.MLSOrder,
                                                     numCh, mPref.TestChannel, playDwChMask, recDwChMask, textboxOutputFolder.Text);
            mBwStartTesting.RunWorkerAsync(mStartTestingArgs);
        }
예제 #18
0
        private void CaptureRunning(byte[] data)
        {
            if (mCapturedBytes + data.Length <= mCapturedPcmData.Length)
            {
                Array.Copy(data, 0, mCapturedPcmData, mCapturedBytes, data.Length);
                mCapturedBytes += data.Length;

                int capturedFrames = mCapturedBytes / NUM_CHANNELS / (WasapiCS.SampleFormatTypeToUseBitsPerSample(mRecSampleFormat) / 8);

                //Console.WriteLine("Captured {0} frames", capturedFrames);
            }
            else
            {
                // キャプチャー終了. データの整合性チェックはRecRunWorkerCompletedで行う。
                mState = State.RecCompleted;
            }
        }
예제 #19
0
        private void PreparePcmData()
        {
            mPcmSync  = new PcmDataLib.PcmData();
            mPcmReady = new PcmDataLib.PcmData();
            mPcmTest  = new PcmDataLib.PcmData();

            mPcmSync.SetFormat(NUM_CHANNELS,
                               WasapiCS.SampleFormatTypeToUseBitsPerSample(mPlaySampleFormat),
                               WasapiCS.SampleFormatTypeToValidBitsPerSample(mPlaySampleFormat),
                               mSampleRate,
                               PcmDataLib.PcmData.ValueRepresentationType.SInt, mSampleRate);
            var data = new byte[(WasapiCS.SampleFormatTypeToUseBitsPerSample(mPlaySampleFormat) / 8) * NUM_CHANNELS * mPcmSync.NumFrames];

            mPcmSync.SetSampleArray(data);

            mPcmReady.CopyFrom(mPcmSync);
            data = new byte[(WasapiCS.SampleFormatTypeToUseBitsPerSample(mPlaySampleFormat) / 8) * NUM_CHANNELS * mPcmSync.NumFrames];
            mPcmReady.SetSampleArray(data);

            mPcmTest.CopyFrom(mPcmSync);
            data = new byte[(WasapiCS.SampleFormatTypeToUseBitsPerSample(mPlaySampleFormat) / 8) * NUM_CHANNELS * mNumTestFrames];
            mRand.NextBytes(data);
            mPcmTest.SetSampleArray(mNumTestFrames, data);

            mCapturedPcmData = new byte[(WasapiCS.SampleFormatTypeToUseBitsPerSample(mRecSampleFormat) / 8) * NUM_CHANNELS * (mNumTestFrames + NUM_PROLOGUE_FRAMES)];
            Array.Clear(mCapturedPcmData, 0, mCapturedPcmData.Length);

            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;
            }
        }
예제 #20
0
        private LargeArray <byte> CreatePcmSamples(double[] mls, WasapiCS.SampleFormatType sft, int numCh, int playCh)
        {
            int  sampleBytes = (WasapiCS.SampleFormatTypeToUseBitsPerSample(sft) / 8);
            int  frameBytes  = sampleBytes * numCh;
            long bytes       = (long)mls.Length * frameBytes;
            var  r           = new LargeArray <byte>(bytes);

            long writePos = 0;

            for (long i = 0; i < mls.Length; ++i)
            {
                for (int ch = 0; ch < numCh; ++ch)
                {
                    if (ch != playCh)
                    {
                        for (int c = 0; c < sampleBytes; ++c)
                        {
                            r.Set(writePos++, 0);
                        }
                    }
                    else
                    {
                        int v = 0x7fffffff;

                        // -6dBする。
                        v /= 2;

                        if (mls[i] < 0)
                        {
                            v = -v;
                        }

                        uint uV = (uint)v;

                        for (int c = 0; c < sampleBytes; ++c)
                        {
                            byte b = (byte)(uV >> (8 * (4 - sampleBytes + c)));
                            r.Set(writePos++, b);
                        }
                    }
                }
            }
            return(r);
        }
예제 #21
0
        private int SetSampleDataToWasapiStart(int idx, WWFlacRWCS.FlacRW flac)
        {
            int hr = 0;

            mDecodedPcmOffs = 0;

            WWFlacRWCS.Metadata meta;
            flac.GetDecodedMetadata(out meta);

            mFromFormat = new DeviceFormat();
            mFromFormat.Set(meta.channels, meta.sampleRate,
                            WasapiCS.BitAndFormatToSampleFormatType(
                                meta.bitsPerSample, meta.bitsPerSample, WasapiCS.BitFormatType.SInt),
                            WasapiCS.GetTypicalChannelMask(meta.channels));

            if (WasapiCS.ShareMode.Exclusive == mShareMode)
            {
                // 排他モードの時。サンプルレート変換しないので
                // サンプル数がFromと同じ。
                long totalBytes = meta.totalSamples * mDeviceFormat.BytesPerFrame();
                mWasapi.AddPlayPcmDataAllocateMemory(idx, totalBytes);
            }
            else
            {
                // 共有モードの時。サンプルレート変換する。
                long totalBytes = (meta.totalSamples * mDeviceFormat.SampleRate / mFromFormat.SampleRate) * mDeviceFormat.BytesPerFrame();
                mWasapi.AddPlayPcmDataAllocateMemory(idx, totalBytes);

                var resampleFrom = new WWMFResamplerCs.WWPcmFormat(WWMFResamplerCs.WWPcmFormat.SampleFormat.SF_Int,
                                                                   mFromFormat.NumChannels, mFromFormat.UseBitsPerSample(), mFromFormat.SampleRate,
                                                                   WasapiCS.GetTypicalChannelMask(mFromFormat.NumChannels), mFromFormat.ValidBitsPerSample());
                var resampleTo = new WWMFResamplerCs.WWPcmFormat(WWMFResamplerCs.WWPcmFormat.SampleFormat.SF_Float,
                                                                 mDeviceFormat.NumChannels, mDeviceFormat.UseBitsPerSample(), mDeviceFormat.SampleRate,
                                                                 mDeviceFormat.DwChannelMask, mDeviceFormat.ValidBitsPerSample());
                hr = mMfResampler.Init(resampleFrom, resampleTo, 60);
                if (hr < 0)
                {
                    Console.WriteLine("mMfResampler.Init() failed {0:X8}", hr);
                }
            }

            return(hr);
        }
예제 #22
0
        private void SaveRecordedData()
        {
            var  pcm     = mWasapiCtrl.GetCapturedData();
            long nFrames = pcm.LongLength / WasapiCS.SampleFormatTypeToUseBitsPerSample(mPref.SampleFormat) / mPref.NumOfChannels * 8;

            if (pcm == null || nFrames == 0)
            {
                return;
            }

            textBoxLog.Text += string.Format("captured frames={0} ({1:F1} {2}) glichCount={3}\r\n",
                                             nFrames, (double)nFrames / mPref.SampleRate,
                                             Properties.Resources.Seconds, mWasapiCtrl.GetCaptureGlitchCount());

            Microsoft.Win32.SaveFileDialog dlg = new Microsoft.Win32.SaveFileDialog();
            dlg.DefaultExt = ".wav";
            dlg.Filter     = "WAVE files|*.wav";

            Nullable <bool> result = dlg.ShowDialog();

            if (result != true)
            {
                return;
            }

            try {
                using (BinaryWriter bw = new BinaryWriter(File.Open(dlg.FileName, FileMode.Create, FileAccess.Write, FileShare.Write))) {
                    WavRWLib2.WavWriter.Write(bw, mPref.NumOfChannels,
                                              WasapiCS.SampleFormatTypeToUseBitsPerSample(mPref.SampleFormat),
                                              WavRWLib2.WavWriterLowLevel.WAVE_FORMAT_PCM,
                                              mPref.SampleRate, nFrames, pcm);
                    textBoxLog.Text += string.Format("{0} : {1}\r\n", Properties.Resources.SaveFileSucceeded, dlg.FileName);
                }
            } catch (Exception ex) {
                string s = string.Format("{0} : {1}\r\n{2}\r\n", Properties.Resources.SaveFileFailed, dlg.FileName, ex);
                MessageBox.Show(s);
                AddLog(s);
            }

            slider1.Value = 0;
        }
예제 #23
0
        private void PreparePcmData(StartTestingArgs args)
        {
            mMLSDecon = new MLSDeconvolution(args.order);
            var seq = mMLSDecon.MLSSequence();

            var sampleData = CreatePcmSamples(seq, mPref.PlaySampleFormat, args.numChannels, args.testChannel);

            // mPcmPlay : テストデータ。このPCMデータを再生し、インパルス応答特性を調べる。
            mPcmPlay = new PcmDataLib.PcmData();
            mPcmPlay.SetFormat(args.numChannels,
                               WasapiCS.SampleFormatTypeToUseBitsPerSample(mPref.PlaySampleFormat),
                               WasapiCS.SampleFormatTypeToValidBitsPerSample(mPref.PlaySampleFormat),
                               mPref.SampleRate,
                               PcmDataLib.PcmData.ValueRepresentationType.SInt, seq.Length);
            mPcmPlay.SetSampleLargeArray(sampleData);

            // 録音データ置き場。Maximum Length Seqneuceのサイズよりも1サンプル多くしておく。
            int recBytesPerSample = WasapiCS.SampleFormatTypeToUseBitsPerSample(mPref.RecSampleFormat) / 8;

            mCapturedPcmData = new LargeArray <byte>((long)recBytesPerSample * args.numChannels * (seq.Length + 1));
        }
예제 #24
0
        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;
            }
        }
예제 #25
0
        private int DeviceSetup()
        {
            int  hr;
            bool bRv;

            {   // read num of channels
                int numOfChannels;
                bRv = Int32.TryParse(textBoxNumOfChannels.Text, out numOfChannels);
                if (!bRv || numOfChannels <= 1)
                {
                    string s = Properties.Resources.ErrorNumChannels;
                    MessageBox.Show(s);
                    AddLog(s);
                    AddLog("\r\n");
                    return(-1);
                }
                mPref.NumOfChannels = numOfChannels;
            }

            {   // read WASAPI buffer millisec from the textbox
                int wasapiBufferSizeMS = -1;
                bRv = Int32.TryParse(textBoxWasapiBufferSizeMS.Text, out wasapiBufferSizeMS);
                if (!bRv || wasapiBufferSizeMS <= 0)
                {
                    string s = Properties.Resources.ErrorWasapiBufferSize;
                    MessageBox.Show(s);
                    AddLog(s);
                    AddLog("\r\n");
                    return(-1);
                }
                mPref.WasapiBufferSizeMS = wasapiBufferSizeMS;
            }

            {   // read recording buffer size
                int megaBytes = 0;
                bRv = Int32.TryParse(textBoxRecordingBufferSizeMB.Text, out megaBytes);
                if (megaBytes <= 0 || 2097151 < megaBytes)
                {
                    string s = Properties.Resources.ErrorRecordingBufferSize;
                    MessageBox.Show(s);
                    AddLog(s);
                    AddLog("\r\n");
                    return(-1);
                }
                mPref.RecordingBufferSizeMB = megaBytes;
            }

            int dwChannelMask = 0;

            if (mPref.SetDwChannelMask)
            {
                dwChannelMask = WasapiCS.GetTypicalChannelMask(mPref.NumOfChannels);
            }

            if (!mWasapiCtrl.AllocateCaptureMemory(
                    1024L * 1024 * mPref.RecordingBufferSizeMB))
            {
                string s = Properties.Resources.ErrorCouldNotAllocateMemory;
                MessageBox.Show(s);
                AddLog(s);
                AddLog("\r\n");
                return(-1);
            }

            hr = mWasapiCtrl.Setup(listBoxDevices.SelectedIndex,
                                   mPref.WasapiDataFeedMode, mPref.WasapiBufferSizeMS,
                                   mPref.SampleRate, mPref.SampleFormat, mPref.NumOfChannels, dwChannelMask);
            {
                if (hr < 0)
                {
                    string s = string.Format("Error: wasapi.Setup({0}Hz, {1}, {2}ms, {3}, {4}ch, dwChannelMask={5})\r\nError code = {6:X8} {7}\r\n",
                                             mPref.SampleRate, mPref.SampleFormat,
                                             mPref.WasapiBufferSizeMS, mPref.WasapiDataFeedMode,
                                             mPref.NumOfChannels, dwChannelMask, hr, mWasapiCtrl.ErrorCodeToStr(hr));
                    MessageBox.Show(s);
                    AddLog(s);

                    AddLog("wasapi.Unsetup()\r\n");
                    mWasapiCtrl.Unsetup();
                    mWasapiCtrl.ReleaseCaptureMemory();
                    return(hr);
                }
                else
                {
                    string s = string.Format("wasapi.Setup({0}Hz, {1}, {2}ms, {3}, {4}ch) Succeeded {5:X8}\r\n",
                                             mPref.SampleRate, mPref.SampleFormat,
                                             mPref.WasapiBufferSizeMS, mPref.WasapiDataFeedMode,
                                             mPref.NumOfChannels, hr);
                    AddLog(s);
                }
            }

            mPref.PreferredDeviceIdString = mDeviceList[listBoxDevices.SelectedIndex].DeviceIdString;

            return(0);
        }
예제 #26
0
 public void Term()
 {
     Console.WriteLine("D: PlaybackController.Term()");
     mWasapi.Term();
     mWasapi = null;
 }
예제 #27
0
        private void BwStartTesting_DoWork(object sender, DoWorkEventArgs e)
        {
            //Console.WriteLine("BwStartTesting_DoWork()");
            var args = e.Argument as StartTestingArgs;
            var r    = new StartTestingResult();

            r.result = false;
            r.text   = "StartTesting failed!\n";
            e.Result = r;

            PreparePcmData(args);

            System.GC.Collect();

            lock (mLock) {
                int hr = 0;

                // 録音
                mCapturedBytes = 0;
                mReceivedBytes = 0;

                mLevelMeter = new LevelMeter(mPref.RecSampleFormat, args.numChannels, mPref.PeakHoldSeconds,
                                             mPref.RecWasapiBufferSizeMS * 0.001, mPref.ReleaseTimeDbPerSec);

                hr = mWasapiRec.Setup(mRecDeviceIdx,
                                      WasapiCS.DeviceType.Rec, WasapiCS.StreamType.PCM,
                                      mPref.SampleRate, mPref.RecSampleFormat, args.numChannels, args.recDwChannelMask,
                                      WasapiCS.MMCSSCallType.Enable, WasapiCS.MMThreadPriorityType.None,
                                      WasapiCS.SchedulerTaskType.ProAudio, WasapiCS.ShareMode.Exclusive,
                                      mPref.RecDataFeedMode, mPref.RecWasapiBufferSizeMS, ZERO_FLUSH_MILLISEC, TIME_PERIOD, true);
                if (hr < 0)
                {
                    r.result = false;
                    r.text   = string.Format(Properties.Resources.msgRecSetupError,
                                             mPref.SampleRate, mPref.RecSampleFormat, args.numChannels, mPref.RecDataFeedMode,
                                             mPref.RecWasapiBufferSizeMS, WasapiCS.GetErrorMessage(hr)) + "\n";
                    e.Result = r;
                    StopUnsetup();
                    return;
                }

                // 再生

                hr = mWasapiPlay.Setup(mPlayDeviceIdx,
                                       WasapiCS.DeviceType.Play, WasapiCS.StreamType.PCM,
                                       mPref.SampleRate, mPref.PlaySampleFormat, args.numChannels, args.playDwChannelMask,
                                       WasapiCS.MMCSSCallType.Enable, WasapiCS.MMThreadPriorityType.None,
                                       WasapiCS.SchedulerTaskType.ProAudio, WasapiCS.ShareMode.Exclusive,
                                       mPref.PlayDataFeedMode, mPref.PlayWasapiBufferSizeMS, ZERO_FLUSH_MILLISEC, TIME_PERIOD, true);
                if (hr < 0)
                {
                    mWasapiPlay.Unsetup();
                    r.result = false;
                    r.text   = string.Format(Properties.Resources.msgPlaySetupError,
                                             mPref.SampleRate, mPref.PlaySampleFormat, args.numChannels,
                                             mPref.PlayDataFeedMode, mPref.PlayWasapiBufferSizeMS) + "\n";
                    e.Result = r;
                    return;
                }

                var ss = mWasapiPlay.GetSessionStatus();

                mWasapiPlay.ClearPlayList();
                mWasapiPlay.AddPlayPcmDataStart();
                mWasapiPlay.AddPlayPcmData(0, mPcmPlay.GetSampleLargeArray());
                mWasapiPlay.AddPlayPcmDataEnd();

                mWasapiPlay.SetPlayRepeat(true);

                var playAttr = mWasapiPlay.GetDeviceAttributes(mPlayDeviceIdx);
                var recAttr  = mWasapiRec.GetDeviceAttributes(mRecDeviceIdx);

                r.result = true;
                r.text   = string.Format(Properties.Resources.msgTestStarted, mPref.SampleRate,
                                         mPcmPlay.NumFrames / mPref.SampleRate, mPcmPlay.NumFrames * 0.001 * 0.001);
                r.text += string.Format(Properties.Resources.msgPlaySettings,
                                        mPref.PlaySampleFormat, mPref.PlayWasapiBufferSizeMS,
                                        mPref.PlayDataFeedMode, playAttr.Name);
                r.text += string.Format(Properties.Resources.msgRecSettings,
                                        mPref.RecSampleFormat, mPref.RecWasapiBufferSizeMS,
                                        mPref.RecDataFeedMode, recAttr.Name);
                e.Result = r;
            }
        }
예제 #28
0
 private static int GetBytesPerSec(Preference pref)
 {
     return(pref.NumOfChannels * pref.SampleRate *
            WasapiCS.SampleFormatTypeToUseBitsPerSample(pref.SampleFormat) / 8);
 }
예제 #29
0
        private void ProcessCapturedData(BackgroundWorker bw, string folder)
        {
            // 録音したデータをrecPcmDataに入れる。
            var recPcmData = new PcmDataLib.PcmData();

            recPcmData.SetFormat(mStartTestingArgs.numChannels,
                                 WasapiCS.SampleFormatTypeToUseBitsPerSample(mPref.RecSampleFormat),
                                 WasapiCS.SampleFormatTypeToValidBitsPerSample(mPref.RecSampleFormat),
                                 mPref.SampleRate,
                                 PcmDataLib.PcmData.ValueRepresentationType.SInt,
                                 mPcmPlay.NumFrames + 1); //< 再生したMaximum Length Sequenceのサイズよりも1サンプル多い。
            recPcmData.SetSampleLargeArray(mCapturedPcmData);

            // インパルス応答impulse[]を得る。
            var recorded = recPcmData.GetDoubleArray(mStartTestingArgs.testChannel);
            var decon    = mMLSDecon.Deconvolution(recorded.ToArray());
            var impulse  = new double[decon.Length];

            for (int i = 0; i < decon.Length; ++i)
            {
                impulse[i] = 2.0 * decon[decon.Length - 1 - i];
            }

            {
                // ファイルに保存。
                string path = string.Format("{0}/ImpulseResponse{1}_{2}.csv", folder, DateTime.Now.ToString("yyyyMMddHHmmss"), mCaptureCounter);
                OutputImpulseToCsvFile(impulse, mPref.SampleRate, path);
            }

            ++mCaptureCounter;

            lock (mLock) {
                mTimeDomainPlot.SetDiscreteTimeSequence(impulse, mPref.SampleRate);
            }

            // 周波数特性を計算する。
            var fr = CalcFrequencyResponse(impulse);

            {
                // ファイルに保存。
                string path = string.Format("{0}/FrequencyResponse{1}_{2}.csv", folder, DateTime.Now.ToString("yyyyMMddHHmmss"), mCaptureCounter);
                OutputFrequencyResponseToCsvFile(fr, mPref.SampleRate, path);
            }

            lock (mLock) {
                mFreqResponse.TransferFunction = (WWComplex z) => {
                    double θ      = Math.Atan2(z.imaginary, z.real);
                    double freq01 = θ / Math.PI;

                    int pos = (int)(freq01 * fr.Length / 2);
                    if (pos < 0)
                    {
                        return(WWComplex.Zero());
                    }

                    return(fr[pos]);
                };
            }

            // この後描画ができるタイミング(RecWorkerProgressChanged())でmTimeDomainPlot.Update()を呼ぶ。
            bw.ReportProgress(10);
        }
예제 #30
0
 public WasapiCS.SampleFormatType GetSampleFormatType()
 {
     return(WasapiCS.BitAndFormatToSampleFormatType(bitsPerSample, validBitsPerSample, bitFormatType));
 }