/// <summary> /// Fills recording buffers. /// </summary> private void EnsureBuffers() { // We keep 3 x buffer. lock (m_pBuffers){ while (m_pBuffers.Count < 3) { byte[] data = new byte[m_BufferSize]; GCHandle dataHandle = GCHandle.Alloc(data, GCHandleType.Pinned); WAVEHDR wavHeader = new WAVEHDR(); wavHeader.lpData = dataHandle.AddrOfPinnedObject(); wavHeader.dwBufferLength = (uint)data.Length; wavHeader.dwBytesRecorded = 0; wavHeader.dwUser = IntPtr.Zero; wavHeader.dwFlags = 0; wavHeader.dwLoops = 0; wavHeader.lpNext = IntPtr.Zero; wavHeader.reserved = 0; GCHandle headerHandle = GCHandle.Alloc(wavHeader, GCHandleType.Pinned); int result = 0; result = WavMethods.waveInPrepareHeader(m_pWavDevHandle, headerHandle.AddrOfPinnedObject(), Marshal.SizeOf(wavHeader)); if (result == MMSYSERR.NOERROR) { m_pBuffers.Add(new BufferItem(ref headerHandle, ref dataHandle, m_BufferSize)); result = WavMethods.waveInAddBuffer(m_pWavDevHandle, headerHandle.AddrOfPinnedObject(), Marshal.SizeOf(wavHeader)); if (result != MMSYSERR.NOERROR) { throw new Exception("Error adding wave in buffer, error: " + result + "."); } } } } }
// Initialize a new WAVEHDR with an allocated memory buffer private void InitBuffer(ref WAVEHDR buffer, uint frames) { /* * Audio buffers must remain in place within memory while playing, * which occurs between WaveOut API calls. In order to prevent the * garbage collector from relocating things, memory is allocated to * the process heap. * * lpData is a pointer to the sample data to be played as output, * and is allocated on the heap. * * dwUser is available for application use. In this situation, a * WAVEHDR-sized buffer is allocated on the heap, which is used to * store a copy of the struct when used in API calls. * * dwLoops is intended for repeating the buffer multiple times * before finishing, but is being used in this class to indicate * that the buffer was the last one in the audio stream. The * looping feature is disabled and unused because the * WHDR_BEGINLOOP and WHDR_ENDLOOP flags are never set in dwFlags. */ buffer.lpData = Marshal.AllocHGlobal((int)frames * 4); buffer.dwBufferLength = frames * 4; buffer.dwBytesRecorded = 0; buffer.dwUser = Marshal.AllocHGlobal((int)WAVEHDR_SIZE); buffer.dwFlags = 0; buffer.dwLoops = 0; buffer.lpNext = IntPtr.Zero; buffer.reserved = IntPtr.Zero; }
/// <summary> /// Processes data and frees buffers that have been used by the application. /// </summary> private void ProcessDone() { IntPtr header; // Pull the header data back out of unmanaged memory lock (this.bufferingLock) { header = this.bufferReleaseQueue.Dequeue(); Monitor.Pulse(this.bufferingLock); } WAVEHDR pwh = (WAVEHDR)Marshal.PtrToStructure(header, typeof(WAVEHDR)); // Find and copy the buffer data IntPtr data = pwh.lpData; // Copy the data and fire the DataReady event if necessary if (pwh.dwBytesRecorded > 0 && this.DataReady != null) { byte[] newData = new byte[pwh.dwBytesRecorded]; Marshal.Copy(data, newData, 0, (int)pwh.dwBytesRecorded); this.DataReady(this, new DataReadyEventArgs(newData)); } // Unprepare the header NativeMethods.Throw( NativeMethods.waveInUnprepareHeader(this.handle, header, Marshal.SizeOf(typeof(WAVEHDR))), NativeMethods.ErrorSource.WaveIn); // Free the unmanaged memory Marshal.FreeHGlobal(data); Marshal.FreeHGlobal(header); }
/// <summary> /// Adds a buffer to the queue. /// </summary> private void AddBuffer() { // Allocate unmanaged memory for the buffer int bufferLength = this.bufferSize * this.recordingFormat.BlockAlign; IntPtr mem = Marshal.AllocHGlobal(bufferLength); // Initialize the buffer header, including a reference to the buffer memory WAVEHDR pwh = new WAVEHDR(); pwh.dwBufferLength = bufferLength; pwh.dwFlags = 0; pwh.lpData = mem; pwh.dwUser = new IntPtr(12345); // Copy the header into unmanaged memory IntPtr header = Marshal.AllocHGlobal(Marshal.SizeOf(pwh)); Marshal.StructureToPtr(pwh, header, false); // Prepare the header NativeMethods.Throw( NativeMethods.waveInPrepareHeader(this.handle, header, Marshal.SizeOf(typeof(WAVEHDR))), NativeMethods.ErrorSource.WaveOut); // Add the buffer to the device NativeMethods.Throw( NativeMethods.waveInAddBuffer(this.handle, header, Marshal.SizeOf(typeof(WAVEHDR))), NativeMethods.ErrorSource.WaveOut); lock (this.bufferingLock) { this.bufferQueueCount++; Monitor.Pulse(this.bufferingLock); } }
private void Prepare() { System.Diagnostics.Debug.Write("call waveOutPrepareHeader"); Thread.Sleep(100); // これがないとなぜか落ちる for (int i = 0; i < WAVEHDR_NUM_; ++i) { wave_hdr_list_[i] = new WAVEHDR(); wave_hdr_list_[i].lpData = Marshal.AllocHGlobal(buffer_length_); wave_hdr_list_[i].dwBufferLength = (uint)buffer_length_; wave_hdr_list_[i].dwBytesRecorded = 0; wave_hdr_list_[i].dwUser = (uint)i; wave_hdr_list_[i].dwFlags = 0; wave_hdr_list_[i].dwLoops = 1; wave_hdr_list_[i].lpNext = (IntPtr)0; wave_hdr_list_[i].reserved = 0; // アンマネージドオブジェクト(WAVEHDR)を確保 p_wave_hdr_list_[i] = Marshal.AllocHGlobal(WAVEHDR_STRUCT_SIZE_); Marshal.StructureToPtr(wave_hdr_list_[i], p_wave_hdr_list_[i], false); uint error_code = waveOutPrepareHeader(h_wave_out_, p_wave_hdr_list_[i], WAVEHDR_STRUCT_SIZE_); if (error_code != 0) { throw new WaveOutApiException("waveOutPrepareHeader " + h_wave_out_.ToInt32().ToString(), error_code); } } state_ = StateKind.Prepared; }
private void WaveCallbackProc(IntPtr h_wave_out, uint message, uint instance, uint param1, uint param2) { System.Diagnostics.Debug.Write("called WaveCallbackProc : " + message + ", " + param1 + ", " + param2); switch (message) { case MM_WOM_OPEN: // waveOutPrepareHeader をこのスレッドで呼んではいけないので、 // 別スレッドを作って呼び出す。 Thread t = new Thread(new ThreadStart(Prepare)); t.IsBackground = true; t.Start(); break; case MM_WOM_CLOSE: for (int i = 0; i < WAVEHDR_NUM_; ++i) { waveOutUnprepareHeader(h_wave_out_, p_wave_hdr_list_[i], WAVEHDR_STRUCT_SIZE_); Marshal.FreeHGlobal(p_wave_hdr_list_[i]); } close_event_.Set(); // 後処理完了を通知 break; case MM_WOM_DONE: IntPtr ptr = new IntPtr(param1); WAVEHDR wave_hdr = (WAVEHDR)Marshal.PtrToStructure(ptr, typeof(WAVEHDR)); int index = (int)wave_hdr.dwUser; // 何番目の WAVEHDR 構造体かを取得 waiting_manager_.Set(index); // 再生完了のシグナル break; } }
/// コールバック関数 void wave_callback(IntPtr hwo, uint uMsg, uint dwInstance, uint dwParam1, uint dwParam2) { #if DEBUG Console.WriteLine("WavePlay.wave_callback; uMsg=" + uMsg); #endif if (uMsg == win32.MM_WOM_DONE) { int index_done = 0; WAVEHDR whdr = (WAVEHDR)Marshal.PtrToStructure(new IntPtr(dwParam1), typeof(WAVEHDR)); int dwuser = whdr.dwUser.ToInt32(); if (dwuser >= _NUM_BUF) { index_done = dwuser - _NUM_BUF; } else { index_done = dwuser; } if (0 <= index_done && index_done < _NUM_BUF) { s_done[index_done] = true; if (s_last_buffer == index_done) { s_playing = false; } if (dwuser >= _NUM_BUF) { s_wave_header[index_done].dwUser = new IntPtr(index_done); } } } }
/// <summary> /// Writes a block of data (in the current forma, set during Open) to the device. /// </summary> /// <param name="bufferData">The data to send to the device.</param> public void Write(byte[] bufferData) { lock (this.startStopLock) { IntPtr mem = Marshal.AllocHGlobal(bufferData.Length); Marshal.Copy(bufferData, 0, mem, bufferData.Length); WAVEHDR pwh = new WAVEHDR(); pwh.dwBufferLength = bufferData.Length; pwh.dwFlags = 0; pwh.lpData = mem; pwh.dwUser = new IntPtr(12345); IntPtr header = Marshal.AllocHGlobal(Marshal.SizeOf(pwh)); Marshal.StructureToPtr(pwh, header, false); NativeMethods.Throw( NativeMethods.waveOutPrepareHeader(this.handle, header, Marshal.SizeOf(typeof(WAVEHDR))), NativeMethods.ErrorSource.WaveOut); NativeMethods.Throw( NativeMethods.waveOutWrite(this.handle, header, Marshal.SizeOf(typeof(WAVEHDR))), NativeMethods.ErrorSource.WaveOut); lock (this.bufferingLock) { this.bufferQueueCount++; Monitor.Pulse(this.bufferingLock); } } }
/* SetupBuffer * * Setups header and buffer used for recording * * Return void */ private void setupBuffer() { pWaveHdr1 = new WAVEHDR(); pWaveHdr1.lpData = bufferPin.AddrOfPinnedObject(); pWaveHdr1.dwBufferLength = INP_BUFFER_SIZE; pWaveHdr1.dwBytesRecorded = 0; pWaveHdr1.dwUser = IntPtr.Zero; pWaveHdr1.dwFlags = 0; pWaveHdr1.dwLoops = 1; pWaveHdr1.lpNext = IntPtr.Zero; pWaveHdr1.reserved = (System.IntPtr)null; int i = waveInPrepareHeader(handle, ref pWaveHdr1, Convert.ToUInt32(Marshal.SizeOf(pWaveHdr1))); if (i != 0) { this.Text = "Error: waveInPrepare " + i.ToString(); return; } i = waveInAddBuffer(handle, ref pWaveHdr1, Convert.ToUInt32(Marshal.SizeOf(pWaveHdr1))); if (i != 0) { this.Text = "Error: waveInAddrBuffer"; return; } }
public MediaSample(int bufferSize) { // Create the header fHeader = new WAVEHDR(bufferSize); // Get a pinned handle on the header fHeaderHandle = GCHandle.Alloc(fHeader, GCHandleType.Pinned); }
public RecordingBuffer(int iSize, IntPtr ipHandle) { m_Head = new WAVEHDR(iSize); m_Handle = GCHandle.Alloc(m_Head, GCHandleType.Pinned); int mmr = waveIn.PrepareHeader(ipHandle, m_Head, Marshal.SizeOf(m_Head)); waveIn.ThrowExceptionForError(mmr); }
private static void PrepareHeader(IntPtr waveOutHandle, ref WAVEHDR waveOutHeader, uint size) { uint err = waveOutPrepareHeader(waveOutHandle, ref waveOutHeader, size); if (err != 0) { throw new Exception("Error preparing header: " + GetErrorText(err) + "."); } }
/// <summary> /// Write a sample to the file /// </summary> /// <param name="wh"></param> private void WriteSample(WAVEHDR wh) { int iBytes = MMIO.Write(m_OutputFile, wh.lpData, wh.dwBytesRecorded); if (iBytes < 0) { throw new Exception("Write Failed"); } m_AudioLength += iBytes; }
/// /// Opens the audio system, enqueues buffers, and otherwise /// gets us ready to play. /// public void Open() { lock (_mainLock) { if (_isOpen) throw new ApplicationExcption( "Open while already open" ); WAVEFORMATEX wfx = new WAVEFORMATEX(); wfx.wFormatTag = WAVE_FORMAT_PCM; wfx.nChannels = 2; // stereo wfx.nSamplesPerSec = 44100; wfx.nBlockAlign = 4; // four bytes per frame, see? wfx.wBitsPerSample = 16; wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec; wfx.cbSize = 0; // no extra info int status = waveOutOpen( out _waveOutHandle, WAVE_MAPPER, wfx, _playEvent.SafeWaitHandle, CALLBACK_EVENT, 0 ); if (status != MMSYSERR_NOERROR) { throw new ApplicationException( "unable to open the default WAVE device" ); } _isOpen = true; // Create audio buffers, including unmanaged data buffers for (int i = 0; i < N_WAVE_HEADERS; i++) { WAVEHDR header = new WAVEHDR(); IntPtr data = Marshal.AllocHGlobal( size ); header.lpData = data; // pointer to the data buffer header.dwBufferLength = 0; // set on each call header.dwBytesRecorded = 0; header.dwUser = size; // hide the real buffer size here header.dwFlags = WHDR_DONE; // so it'll get enqueued header.dwLoops = 0; header.lpNext = 0; // we don't mess with this pointer header.reserved; // or this int // Yeah, this sucker's gonna be pinned for the duration. // This is probably bad. It is better if we unpin it on // each buffer switch? Probably not. _waveHdr[i] = GCHandle.Alloc( header, GCHandldType.Pinned ); } } }
private void Timer_Elapsed(object sender, ElapsedEventArgs e) { if ((data.Flags & WaveHdrFlags.WHDR_DONE) == 0) // still running { // updated managed data data = (WAVEHDR)Marshal.PtrToStructure(dataPointer, typeof(WAVEHDR)); } else // finished { Close(); } }
internal static void WaveOutProc(IntPtr hdrvr, int uMsg, int dwUser, ref WAVEHDR wavhdr, int dwParam2) { if (uMsg == WaveNative.MM_WOM_DONE) { try { GCHandle h = (GCHandle)wavhdr.dwUser; WaveOutBuffer buf = (WaveOutBuffer)h.Target; buf.OnCompleted(); } catch { } } }
// System-invoked callback for audio output events private void waveOutProc(IntPtr hwo, uint uMsg, IntPtr dwInstance, ref WAVEHDR buffer, IntPtr dwParam2) { /* * Inform the main thread that the buffer has finished. The reason * this is done with a concurrent collection is because system * function calls are not permitted by the thread that calls * waveOutProc(). This mechanism essentially transfers control of * the event handler to the thread created in Play(). */ if (uMsg == MM_WOM_DONE) { BuffersDone.Add(buffer); } }
public async Task PlayWave(RiffCodec riff) { uint WAVE_MAPPER = uint.MaxValue; int CALLBACK_NULL = 0; IntPtr handle = IntPtr.Zero; var header = riff.FormatHeader as WaveFormatHeader; int duration = Convert.ToInt32(header.AvgBytesPerSec / header.SampleRate); var waveFormat = new WAVEFORMAT { wFormatTag = header.FormatTag, nChannels = header.ChannelsCount, nSamplesPerSec = header.SampleRate, nAvgBytesPerSec = header.AvgBytesPerSec, nBlockAlign = header.BlockAlign, wBitsPerSample = header.BitsPerSample, cbSize = header.ExtraInfoSize }; var waveHdr = new WAVEHDR { dwBufferLength = riff.DataSize, dwBytesRecorded = riff.DataSize, dwUser = 0, dwFlags = 0, dwLoops = 0 }; using var buffer = new UnamanagedMemory((int)riff.DataSize); Marshal.Copy(riff.Data, 0, buffer.Pointer, riff.Data.Length); waveHdr.lpData = buffer.Pointer; uint res = uint.MaxValue; res = WindowsMultimedia.waveOutOpen(ref handle, WAVE_MAPPER, ref waveFormat, 0, 0, CALLBACK_NULL); CheckMethodResult(nameof(WindowsMultimedia.waveOutOpen), res); res = WindowsMultimedia.waveOutPrepareHeader(handle, ref waveHdr, Marshal.SizeOf(waveHdr)); CheckMethodResult(nameof(WindowsMultimedia.waveOutPrepareHeader), res); res = WindowsMultimedia.waveOutWrite(handle, ref waveHdr, Marshal.SizeOf(waveHdr)); CheckMethodResult(nameof(WindowsMultimedia.waveOutWrite), res); await Task.Delay(duration * 1000); res = WindowsMultimedia.waveOutClose(handle); CheckMethodResult(nameof(WindowsMultimedia.waveOutClose), res); }
public INSBuf(IntPtr waveHandle, int iMaxBuf) { m_MaxLen = iMaxBuf; m_Head = new WAVEHDR(iMaxBuf); m_Head.dwBytesRecorded = 0; // Since waveOutWrite will continue to the buffer after the call // returns, the buffer must be fixed in place. m_Handle = GCHandle.Alloc(m_Head, GCHandleType.Pinned); int mmr = waveOut.PrepareHeader(waveHandle, m_Head, Marshal.SizeOf(typeof(WAVEHDR))); waveOut.ThrowExceptionForError(mmr); // Make it easier for IsBufferFree() to determine when buffers are free m_Head.dwFlags |= WAVEHDR.WHDR.Done; }
/// <summary> /// wavInヘッダをひとつ準備します。 /// 使用前にWAVEHDR構造体のlpData,dwBufferLength,dwFlagsを初期化してください。 /// dwFlags = 0にしてください。 /// </summary> public void WaveInPrepareHeader(ref WAVEHDR whdr) { //初期化 whdr.dwBytesRecorded = 0; whdr.dwFlags = 0; //ヘッダの中身をポインタに写す。写す前にアンマネージ領域 Marshal.StructureToPtr(whdr, this.WaveHeaderPtr, true); //エラーが発生したら例外を投げる MMRESULT result = waveInPrepareHeader(this.WaveInHandle, this.WaveHeaderPtr, (uint)Marshal.SizeOf(whdr)); if (result != MMRESULT.MMSYSERR_NOERROR) { Exception e = new Exception("WaveInPrepareHeader:" + result + "\r\nエラーが発生しました。"); } }
private static void WaveFeed(IntPtr handle, uint message, uint user, ref WAVEHDR header, uint param2) { switch (message) { case MM_WOM_OPEN: Console.WriteLine("!!! OPEN !!!"); break; case MM_WOM_CLOSE: Console.WriteLine("!!! CLOSE !!!"); break; case MM_WOM_DONE: Console.WriteLine("!!! DONE !!!"); break; default: Console.WriteLine("??? {0}", message); break; } }
/// <summary> /// Frees buffers that have been used by the application. /// </summary> private void ProcessDone() { IntPtr header; // Pull the header data back out of unmanaged memory lock (this.bufferingLock) { header = this.bufferReleaseQueue.Dequeue(); Monitor.Pulse(this.bufferingLock); } WAVEHDR pwh = (WAVEHDR)Marshal.PtrToStructure(header, typeof(WAVEHDR)); IntPtr data = pwh.lpData; NativeMethods.Throw( NativeMethods.waveOutUnprepareHeader(this.handle, header, Marshal.SizeOf(typeof(WAVEHDR))), NativeMethods.ErrorSource.WaveOut); Marshal.FreeHGlobal(data); Marshal.FreeHGlobal(header); }
public void QueueDataBlock(Stream stream) { // Reset the stream position and keep track of the previous position. // The former position tells how much data we need to copy. stream.Flush(); int l = (int)stream.Position; // Allocate unmanaged memory to store samples from stream var ptrData = Marshal.AllocHGlobal(l); // Populate a WAVEHDR with samples WAVEHDR hdr; using (var ums = new UnmanagedMemoryStream((byte*)ptrData.ToPointer(), l, l, FileAccess.ReadWrite)) { stream.SetLength(l); stream.Position = 0; stream.CopyTo(ums, l); stream.Position = 0; ums.Position = 0; hdr = new WAVEHDR { BufferLength = (uint)l, Data = new IntPtr(ums.PositionPointer) }; } // Copy WAVEHDR instance to unmanaged space var ptrHdr = Marshal.AllocHGlobal(sizeof(WAVEHDR)); Marshal.StructureToPtr(hdr, ptrHdr, false); // Prepare the header and queue it MMRESULT result; if ((result = waveOutPrepareHeader(_ptrOutputDevice, ptrHdr, sizeof(WAVEHDR))) != MMRESULT.MMSYSERR_NOERROR) throw new ExternalException($"Function 'waveOutPrepareHeader' returned error code {result}"); if ((result = waveOutWrite(_ptrOutputDevice, ptrHdr, sizeof(WAVEHDR))) != MMRESULT.MMSYSERR_NOERROR) throw new ExternalException($"Function 'waveOutWrite' returned error code {result}"); // Increment queue size _queueSize++; }
// Fill and play the next audio buffer // Returns true if the buffer was skipped private bool FillAndPlay(ref WAVEHDR buffer) { // Error checking if (Finished) { return(true); } // Request samples from the application uint frames = OnNext(SamplesF, 0, (uint)SamplesF.Length / 2); // If zero samples were given, assume end of stream if (frames == 0) { Finish(); return(true); } // Process samples into output format for (uint x = 0; x < frames * 2; x++) { float sample = Math.Min(Math.Max(SamplesF[x], -1.0f), 1.0f); SamplesS[x] = (short)Math.Round(sample * 32767.0f); } // Configure the buffer and make a copy of it in process memory buffer.dwBufferLength = frames * 4; buffer.dwFlags = 0; buffer.dwLoops = (uint)(Finished ? 1 : 0); Marshal.StructureToPtr(buffer, buffer.dwUser, true); // Send the buffer to the audio output stream Marshal.Copy(SamplesS, 0, buffer.lpData, (int)frames * 2); waveOutPrepareHeader(WaveHandle, buffer.dwUser, WAVEHDR_SIZE); waveOutWrite(WaveHandle, buffer.dwUser, WAVEHDR_SIZE); // The buffer was not skipped return(false); }
/// <summary> /// Default constructor. /// </summary> /// <param name="wavDevHandle">Wave in device handle.</param> /// <param name="dataSize">Data buffer size in bytes.</param> public BufferItem(IntPtr wavDevHandle, int dataSize) { m_WavDevHandle = wavDevHandle; m_ThisHandle = GCHandle.Alloc(this); m_pBuffer = new byte[dataSize]; m_DataHandle = GCHandle.Alloc(m_pBuffer, GCHandleType.Pinned); m_Header = new WAVEHDR(); m_Header.lpData = m_DataHandle.AddrOfPinnedObject(); m_Header.dwBufferLength = (uint)dataSize; m_Header.dwBytesRecorded = 0; m_Header.dwUser = (IntPtr)m_ThisHandle; m_Header.dwFlags = 0; m_Header.dwLoops = 0; m_Header.lpNext = IntPtr.Zero; m_Header.reserved = 0; m_HeaderHandle = GCHandle.Alloc(m_Header, GCHandleType.Pinned); m_pEventArgs = new EventArgs <byte[]>(m_pBuffer); }
public Wave(IntPtr handle, short[] data) { timer.Interval = 20; timer.AutoReset = true; timer.Elapsed += Timer_Elapsed; this.handle = handle; dataPointer = Marshal.AllocHGlobal(Marshal.SizeOf(this.data)); this.data.Data = Marshal.AllocHGlobal(data.Length * 2); Marshal.Copy(data, 0, this.data.Data, data.Length); this.data.BufferLength = (uint)data.Length * 2; this.data.Flags = 0; Marshal.StructureToPtr(this.data, dataPointer, true); if (waveOutPrepareHeader(handle, dataPointer, Marshal.SizeOf(this.data)) != 0) { throw new ExceptionAudio("Unable to play wave."); } this.data = (WAVEHDR)Marshal.PtrToStructure(dataPointer, typeof(WAVEHDR)); }
/// <summary> /// Thread to process samples when the recording device is done with them /// </summary> private void ProcSample() { int iCount = 0; int iNextSample = 0; // Notify that thread is started m_ProcReady.Set(); do { // Notify that we are ready to process samples m_ProcReady.Set(); // Wait for the callback to receive a sample m_Sample.WaitOne(); if (!m_Closing) { WAVEHDR wh = m_Buffers[iNextSample].GetHdr(); WriteSample(wh); // Send the buffer back to the recording device for re-use int mmr = waveIn.AddBuffer(m_hDevice, m_Buffers[iNextSample].GetPtr(), Marshal.SizeOf(typeof(WAVEHDR))); waveIn.ThrowExceptionForError(mmr); } else { iCount++; } // Loop around iNextSample = (iNextSample + 1) % RECORDINGBUFFERS; } while (iCount < RECORDINGBUFFERS); Debug.WriteLine("Thread Exiting"); m_ProcReady.Set(); }
public static extern int waveOutPrepareHeader( int hWaveOut, ref WAVEHDR lpWaveOutHdr, int uSize );
public void Write(WAVEHDR pwh) { MmException.Try(winmm.waveOutWrite(DeviceHandle, pwh, (int)Marshal.SizeOf(typeof(WAVEHDR))), "waveOutWrite"); }
//public void AddBuffer(IntPtr pwh) //{ // EnsureOpen(); // PrepareHeader(pwh); // MmException.Try(winmm.waveInAddBuffer(DeviceHandle, pwh, (int)Marshal.SizeOf(typeof(WAVEHDR))), "waveInAddBuffer"); //} //public int AddBuffer(ref WAVEHDR pwh) //{ // int result = AddBuffer(ref pwh, (int)Marshal.SizeOf(typeof(WAVEHDR))); // return result; //} //protected int AddBuffer(ref WAVEHDR pwh, int cbwh) //{ // EnsureOpen(); // PrepareHeader(pwh); // int result = winmm.waveInAddBuffer(DeviceHandle, ref pwh, cbwh); // return result; //} //public void PrepareHeader(IntPtr pwh) //{ // EnsureOpen(); // MmException.Try(winmm.waveInPrepareHeader(DeviceHandle, pwh, (int)Marshal.SizeOf(typeof(WAVEHDR))), "waveInPrepareHeader"); //} //public int PrepareHeader(WAVEHDR pwh) //{ // int result = PrepareHeader(pwh, (int)Marshal.SizeOf(typeof(WAVEHDR))); // return result; //} //protected int PrepareHeader(WAVEHDR pwh, int cbwh) //{ // EnsureOpen(); // int result = winmm.waveInPrepareHeader(DeviceHandle, ref pwh, cbwh); // return result; //} //public void UnprepareHeader(IntPtr pwh) //{ // EnsureOpen(); // MmException.Try(winmm.waveInUnprepareHeader(DeviceHandle, pwh, (int)Marshal.SizeOf(typeof(WAVEHDR))), "waveInUnprepareHeader"); //} public int UnprepareHeader(WAVEHDR pwh) { EnsureOpen(); int result = winmm.waveInUnprepareHeader(DeviceHandle, pwh, (int)Marshal.SizeOf(pwh)); return result; }
public static extern int waveOutWrite( int hWaveOut, ref WAVEHDR lpWaveOutHdr, int uSize );
public void ReturnSample(WAVEHDR aSample) { fAvailableSamples.Enqueue(aSample); }
public static extern int waveInAddBuffer(int hWaveIn, ref WAVEHDR lpWaveInHdr, int uSize);
public static extern int waveInUnprepareHeader(int hWaveIn, ref WAVEHDR lpWaveInHdr, int uSize);
/// <summary> /// Plays specified audio data bytes. If player is currently playing, data will be queued for playing. /// </summary> /// <param name="audioData">Audio data. Data boundary must n * BlockSize.</param> /// <param name="offset">Offset in the buffer.</param> /// <param name="count">Number of bytes to play form the specified offset.</param> /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this method is accessed.</exception> /// <exception cref="ArgumentNullException">Is raised when <b>audioData</b> is null.</exception> /// <exception cref="ArgumentException">Is raised when <b>audioData</b> is with invalid length.</exception> public void Play(byte[] audioData,int offset,int count) { if(m_IsDisposed){ throw new ObjectDisposedException("WaveOut"); } if(audioData == null){ throw new ArgumentNullException("audioData"); } if((count % m_BlockSize) != 0){ throw new ArgumentException("Audio data is not n * BlockSize."); } //--- Queue specified audio block for play. -------------------------------------------------------- byte[] data = new byte[count]; Array.Copy(audioData,offset,data,0,count); GCHandle dataHandle = GCHandle.Alloc(data,GCHandleType.Pinned); WAVEHDR wavHeader = new WAVEHDR(); wavHeader.lpData = dataHandle.AddrOfPinnedObject(); wavHeader.dwBufferLength = (uint)data.Length; wavHeader.dwBytesRecorded = 0; wavHeader.dwUser = IntPtr.Zero; wavHeader.dwFlags = 0; wavHeader.dwLoops = 0; wavHeader.lpNext = IntPtr.Zero; wavHeader.reserved = 0; GCHandle headerHandle = GCHandle.Alloc(wavHeader,GCHandleType.Pinned); int result = 0; result = WavMethods.waveOutPrepareHeader(m_pWavDevHandle,headerHandle.AddrOfPinnedObject(),Marshal.SizeOf(wavHeader)); if(result == MMSYSERR.NOERROR){ PlayItem item = new PlayItem(ref headerHandle,ref dataHandle,data.Length); m_pPlayItems.Add(item); // We ran out of minimum buffer, we must pause playing while min buffer filled. if(m_BytesBuffered < 1000){ if(!m_IsPaused){ WavMethods.waveOutPause(m_pWavDevHandle); m_IsPaused = true; } } // Buffering completed,we may resume playing. else if(m_IsPaused && m_BytesBuffered > m_MinBuffer){ WavMethods.waveOutRestart(m_pWavDevHandle); m_IsPaused = false; } m_BytesBuffered += data.Length; result = WavMethods.waveOutWrite(m_pWavDevHandle,headerHandle.AddrOfPinnedObject(),Marshal.SizeOf(wavHeader)); } else{ dataHandle.Free(); headerHandle.Free(); } //-------------------------------------------------------------------------------------------------- }
static extern uint waveOutUnprepareHeader(IntPtr hwo, WAVEHDR* wh, uint cbwh);
/// <summary> /// Fills recording buffers. /// </summary> private void CreateBuffers() { while(m_pBuffers.Count < 10){ byte[] data = new byte[m_BufferSize]; GCHandle dataHandle = GCHandle.Alloc(data,GCHandleType.Pinned); WAVEHDR wavHeader = new WAVEHDR(); wavHeader.lpData = dataHandle.AddrOfPinnedObject(); wavHeader.dwBufferLength = (uint)data.Length; wavHeader.dwBytesRecorded = 0; wavHeader.dwUser = IntPtr.Zero; wavHeader.dwFlags = 0; wavHeader.dwLoops = 0; wavHeader.lpNext = IntPtr.Zero; wavHeader.reserved = 0; GCHandle headerHandle = GCHandle.Alloc(wavHeader,GCHandleType.Pinned); int result = 0; result = waveInPrepareHeader(m_pWavDevHandle,headerHandle.AddrOfPinnedObject(),Marshal.SizeOf(wavHeader)); if(result != MMSYSERR.NOERROR){ throw new Exception("Error preparing wave in buffer, error: " + result + "."); } else{ m_pBuffers.Add(new BufferItem(ref headerHandle,ref dataHandle,m_BufferSize)); result = waveInAddBuffer(m_pWavDevHandle,headerHandle.AddrOfPinnedObject(),Marshal.SizeOf(wavHeader)); if(result != MMSYSERR.NOERROR){ throw new Exception("Error adding wave in buffer, error: " + result + "."); } } } m_pCurrentBuffer = m_pBuffers[0]; }
public static extern int waveOutPrepareHeader(IntPtr hWaveOut, ref WAVEHDR lpWaveOutHdr, int uSize);
private static extern uint waveOutWrite(IntPtr phwi, ref WAVEHDR pwh, uint cbwh);
private static extern uint waveInAddBuffer(IntPtr phwi, ref WAVEHDR pwh, uint cbwh);
int waveOutWrite( IntPtr waveOutHandle, ref WAVEHDR waveHeader, int size );
public void PrepareHeader(WAVEHDR pwh) { MmException.Try(winmm.waveOutPrepareHeader(DeviceHandle, pwh, (int)Marshal.SizeOf(pwh)), "waveOutPrepareHeader"); }
private static extern uint waveOutUnprepareHeader(IntPtr phwi, ref WAVEHDR pwh, uint cbwh);
static extern uint waveOutWrite(IntPtr hwo, WAVEHDR* wh, uint cbwh);
internal static void DSP_Play(byte[] data) { uint len; int freq; MMSYSERROR res; var dataPointer = 0; DSP_Stop(); dataPointer += Read_LE_UInt16(data.AsSpan(20)); if (data[dataPointer] != 1) { return; } len = (Read_LE_UInt32(data.AsSpan(dataPointer)) >> 8) - 2; if (s_dataLen < len) { Array.Resize(ref s_data, (int)len); //s_data = realloc(s_data, len); s_dataLen = len; } Array.Copy(data, dataPointer + 6, s_data, 0, len); //memcpy(s_data, data + 6, len); freq = 1000000 / (256 - data[dataPointer + 4]); var waveFormat = new WAVEFORMATEX { wFormatTag = (short)WaveFormatTag.Pcm, //WAVE_FORMAT_PCM; nChannels = 1, nSamplesPerSec = freq, nAvgBytesPerSec = freq, nBlockAlign = 1, wBitsPerSample = 8, cbSize = 0 //sizeof(WAVEFORMATEX); }; res = waveOutOpen(ref s_waveOut, WaveOutMapperDeviceId /*WAVE_MAPPER*/, ref waveFormat, DSP_Callback_Del, IntPtr.Zero, WaveOpenFlags.CALLBACK_FUNCTION /*CALLBACK_FUNCTION*/); if (res != MMSYSERROR.MMSYSERR_NOERROR) { Trace.WriteLine($"ERROR: waveOutOpen failed ({res})"); s_waveOut = IntPtr.Zero; return; } s_dataAddr = Marshal.AllocHGlobal(s_data.Length); unsafe { fixed(sbyte *first = s_data) Unsafe.CopyBlock(s_dataAddr.ToPointer(), first, (uint)s_data.Length); } var s_waveHdr = new WAVEHDR { lpData = s_dataAddr, //s_data dwBufferLength = (int)len, dwFlags = 0, dwLoops = 0 }; s_waveHdrAddr = Marshal.AllocHGlobal(Marshal.SizeOf(s_waveHdr)); Marshal.StructureToPtr(s_waveHdr, s_waveHdrAddr, false); res = waveOutPrepareHeader(s_waveOut, s_waveHdrAddr, Marshal.SizeOf(typeof(WAVEHDR))); if (res != MMSYSERROR.MMSYSERR_NOERROR) { Trace.WriteLine($"ERROR: waveOutPrepareHeader failed ({res})"); return; } res = waveOutWrite(s_waveOut, s_waveHdrAddr, Marshal.SizeOf(typeof(WAVEHDR))); if (res != MMSYSERROR.MMSYSERR_NOERROR) { Trace.WriteLine($"ERROR: waveOutWrite failed ({res})"); return; } s_playing = true; }
public void UnprepareHeader(WAVEHDR pwh) { EnsureOpen(); MmException.Try(winmm.waveOutUnprepareHeader(DeviceHandle, pwh, Marshal.SizeOf(pwh)), "waveOutUnprepareHeader"); }
/// <summary> /// Default constructor. /// </summary> /// <param name="wavDevHandle">Wave in device handle.</param> /// <param name="dataSize">Data buffer size in bytes.</param> public BufferItem(IntPtr wavDevHandle,int dataSize) { m_WavDevHandle = wavDevHandle; m_ThisHandle = GCHandle.Alloc(this); m_pBuffer = new byte[dataSize]; m_DataHandle = GCHandle.Alloc(m_pBuffer,GCHandleType.Pinned); m_Header = new WAVEHDR(); m_Header.lpData = m_DataHandle.AddrOfPinnedObject(); m_Header.dwBufferLength = (uint)dataSize; m_Header.dwBytesRecorded = 0; m_Header.dwUser = (IntPtr)m_ThisHandle; m_Header.dwFlags = 0; m_Header.dwLoops = 0; m_Header.lpNext = IntPtr.Zero; m_Header.reserved = 0; m_HeaderHandle = GCHandle.Alloc(m_Header,GCHandleType.Pinned); m_pEventArgs = new EventArgs<byte[]>(m_pBuffer); }
/// /// Returns the next header we should write to, or blocks until /// one is available. The returned header is done and prepared. /// void _GetFreeHeader( out GCHandle nextIntPtr, out WAVEHDR nextAsHeader ) { while (true) { // Clear the wave event before checking "done" to // reduce the race condition between checking and // waiting on the event. (it's manual reset...) _playEvent.Reset(); // Note that the header memory fields will be updated // by the wave engine at the same time. Oooh, scary! // OK, so we're just checking one bit in an int, it's not // really dangerous. nextFree = _waveHdr[_nextFreeHeader]; nextAsHeader = (WAVEHDR)nextFree.Target; nextIntPtr = nextIntPtr.ToIntPtr(); if (nextAsHeader.dwFlags & WHDR_DONE) { if (nextAsHeader.dwFlags & WHDR_PREPARED) { int status = waveOutUnprepareHeader ( _waveOutHandle, nextIntPtr, Marshal.sizeof(typeof(WAVEHDR)) ); if (status != MMSYSERR_NOERROR) { // Ugh? Still playing? But WHDR_DONE is set! throw new ApplicationException( String.Format( "Error '{0}' unpreparing wave header", status ) ); } } // Switch buffers. Whee. _nextFreeHeader = _nextFreeHeader ^ 0x01; return; } // The next buffer is not done. Wait for it to be done. // Note there is a race condition here. :( _playEvent.WaitOne( 500, false ); // Could check here to avoid non-buffer-done type events, // but really it doesn't matter. } }
public static extern int waveOutWrite(IntPtr hWaveOut, ref WAVEHDR lpWaveOutHdr, int uSize);
int waveOutUnprepareHeader( IntPtr waveOutHandle, ref WAVEHDR waveHeader, int size );