/// <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); }
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 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); }
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; } }
public void Term() { mWasapi.Stop(); mWasapi.Unsetup(); mWasapi.Term(); ReleaseCaptureMemory(); mWasapi = null; mDeviceInUse = false; }
private long TotalFrames() { if (mPref.RecordingBufferSizeMB < 0) { return(0); } return((long)mPref.RecordingBufferSizeMB * 1024 * 1024 / WasapiCS.SampleFormatTypeToUseBitsPerSample(mPref.SampleFormat) / mPref.NumOfChannels * 8); }
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); }
/// <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); }
public int WasapiInit() { System.Diagnostics.Debug.Assert(wasapi == null); wasapi = new WasapiCS(); int hr = wasapi.Init(); return(hr); }
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; }
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); }
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; }
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(); }
// 開始ボタンを押すと以下の順に実行される。 // 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); }
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; } }
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; } }
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); }
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); }
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; }
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)); }
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; } }
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); }
public void Term() { Console.WriteLine("D: PlaybackController.Term()"); mWasapi.Term(); mWasapi = null; }
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; } }
private static int GetBytesPerSec(Preference pref) { return(pref.NumOfChannels * pref.SampleRate * WasapiCS.SampleFormatTypeToUseBitsPerSample(pref.SampleFormat) / 8); }
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); }
public WasapiCS.SampleFormatType GetSampleFormatType() { return(WasapiCS.BitAndFormatToSampleFormatType(bitsPerSample, validBitsPerSample, bitFormatType)); }