public override void BufferData(int index, AudioChunk chunk) { if (chunk.Length > dataSizes[index]) { IntPtr ptr = dataHandles[index]; if (ptr != IntPtr.Zero) { Marshal.FreeHGlobal(ptr); } dataHandles[index] = Marshal.AllocHGlobal(chunk.Length); } IntPtr handle = dataHandles[index]; fixed(byte *data = chunk.Data) { MemUtils.memcpy((IntPtr)data, handle, chunk.Length); ApplyVolume(handle, chunk); } WaveHeader header = default(WaveHeader); header.DataBuffer = handle; header.BufferLength = chunk.Length; header.Loops = 1; WaveHeader *hdr = (WaveHeader *)headers + index; *hdr = header; uint result = WinMM.waveOutPrepareHeader(devHandle, (IntPtr)hdr, waveHeaderSize); CheckError(result, "PrepareHeader"); result = WinMM.waveOutWrite(devHandle, (IntPtr)hdr, waveHeaderSize); CheckError(result, "Write"); }
void SendNextBuffer( AudioChunk chunk ) { Console.WriteLine( "send buffer " + buffersIndex ); WaveHeader header = new WaveHeader(); byte[] data = chunk.Data; GCHandle bufferHandle = GCHandle.Alloc( data, GCHandleType.Pinned ); header.DataBuffer = bufferHandle.AddrOfPinnedObject(); header.BufferLength = data.Length; header.Loops = 1; UserData userData = new UserData(); userData.BufferHandle = bufferHandle; userData.Index = buffersIndex; GCHandle userDataHandle = GCHandle.Alloc( userData, GCHandleType.Pinned ); header.UserData = GCHandle.ToIntPtr( userDataHandle ); buffers[buffersIndex] = header; uint result = PrepareHeader( handle, ref buffers[buffersIndex], (uint)waveHeaderSize ); CheckError( result ); result = Write( handle, ref buffers[buffersIndex], (uint)waveHeaderSize ); CheckError( result ); }
void ProcessWaveOutCallback( IntPtr handle, WaveOutMessage message, UIntPtr user, ref WaveHeader header, UIntPtr reserved ) { Console.WriteLine( "callback:" + message + "," + buffersIndex ); if( message == WaveOutMessage.Done ) { Free( ref header ); // TODO: This probably needs to be rewritten. // Due to the asynchronous nature of WinMm, this function can be invoked on the thread that plays the music (I think?) // It would be much better regardless of this was invoked on the thread that called the player to begin with. if( chunks.MoveNext() ) { SendNextBuffer( chunks.Current ); buffersIndex++; } else { if( buffersIndex <= 0 ) { reachedEnd = true; } } } }
void Free( ref WaveHeader header ) { uint result = UnprepareHeader( handle, ref header, (uint)waveHeaderSize ); CheckError( result ); GCHandle userDataHandle = GCHandle.FromIntPtr( header.UserData ); UserData userData = (UserData)userDataHandle.Target; GCHandle bufferHandle = userData.BufferHandle; bufferHandle.Free(); buffersIndex = userData.Index; }
static extern uint Write( IntPtr handle, ref WaveHeader header, uint headerByteSize );
static extern uint UnprepareHeader( IntPtr handle, ref WaveHeader header, uint headerByteSize );