Jump to content
Tuts 4 You

VB .NET Low Level winmm Audio playback


Recommended Posts

Hello guys,


I tried to work the low level winmm.dll functionality out in VB .NET, but encountered several problems. My goal is to play a wave file from stream using WaveOutOpen, WaveOutPrepareHeader und WaveOutWrite, using it only once to play the whole file:

Imports System.GlobalizationImports System.Runtime.InteropServicesImports System.TextImports System.IOImports System.ThreadingPublic Class Form1    <StructLayout(LayoutKind.Sequential)> _    Private Structure WAVEHDR        Public lpData As Integer        Public dwBufferLength As Integer        Public dwBytesRecorded As Integer        Public dwUser As Integer        Public dwFlags As Integer        Public dwLoops As Integer        Public lpNext As Integer        Public Reserved As Integer    End Structure    <StructLayout(LayoutKind.Sequential)> _    Private Structure WAVEFORMATEX        Public wFormatTag As Int16        Public nChannels As Int16        Public nSamplesPerSec As Int32        Public nAvgBytesPerSec As Int32        Public nBlockAlign As Int16        Public wBitsPerSample As Int16        Public cbSize As Int16    End Structure    Public Const CALLBACK_WINDOW As UInteger = &H10000    Private Declare Function waveOutGetNumDevs Lib "winmm.dll" () As UInteger    Private Declare Function waveOutOpen Lib "winmm.dll" (ByRef lphWaveOut As Int32, ByVal uDeviceID As Int32, ByRef lpFormat As WAVEFORMATEX, ByVal dwCallback As waveOutProc, ByVal dwInstance As Int32, ByVal dwFlags As Int32) As Int32    Private Declare Function waveOutClose Lib "winmm.dll" (ByVal hWaveOut As Int32) As Int32    Private Declare Function waveOutPrepareHeader Lib "winmm.dll" (ByVal hWaveOut As Int32, ByRef lpWaveOutHdr As IntPtr, ByVal uSize As Int32) As Int32    Private Declare Function waveOutUnprepareHeader Lib "winmm.dll" (ByVal hWaveOut As Int32, ByRef lpWaveOutHdr As IntPtr, ByVal uSize As Int32) As Int32    Private Declare Function waveOutWrite Lib "winmm.dll" (ByVal hWaveOut As Int32, ByRef lpWaveOutHdr As IntPtr, ByVal uSize As Int32) As Int32    Private Delegate Sub waveOutProc(ByVal hwo As IntPtr, ByVal uMsg As Integer, ByVal dwInstance As IntPtr, ByVal dwParam1 As IntPtr, ByVal dwParam2 As IntPtr)    Dim hWaveOut As IntPtr = 0    Private callback As waveOutProc    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load        Dim Song As Stream = My.Resources.AiR___Waves_Complete_VST_RTAS_TDM_7_1_1_6_installer        'FormatDataLength lesen.        Song.Seek(16, SeekOrigin.Begin)        Dim FormatDataLength As Integer = Song.ReadByte '16 or 17 or 18 Bytes Sized FormatDataBlock. => Benötigt für Bytes Luft.        FormatDataLength += Song.ReadByte * 256        FormatDataLength += Song.ReadByte * 256 * 256        FormatDataLength += Song.ReadByte * 256 * 256 * 256        'FormatType lesen.        Song.Seek(20, SeekOrigin.Begin)        Dim FormatType As Short = Song.ReadByte '1 = PCM.        FormatType += Song.ReadByte * 256        'Channels lesen.        Song.Seek(22, SeekOrigin.Begin)        Dim Channels As Short = Song.ReadByte '2 Channels.        Channels += Song.ReadByte * 256        'SampleRate lesen.        Song.Seek(24, SeekOrigin.Begin)        Dim SampleRate As Integer = Song.ReadByte '44100 Hz.        SampleRate += Song.ReadByte * 256        SampleRate += Song.ReadByte * 256 * 256        SampleRate += Song.ReadByte * 256 * 256 * 256        'Bytes / Second lesen.        Song.Seek(28, SeekOrigin.Begin)        Dim BytesPerSecond As Integer = Song.ReadByte '176400 Bytes/s.        BytesPerSecond += Song.ReadByte * 256        BytesPerSecond += Song.ReadByte * 256 * 256        BytesPerSecond += Song.ReadByte * 256 * 256 * 256        'Bytes / Sample lesen.        Song.Seek(32, SeekOrigin.Begin)        Dim BytesPerSample As Short = Song.ReadByte '4 Bytes/Sample.        BytesPerSample += Song.ReadByte * 256        'Bits / Sample lesen.        Song.Seek(34, SeekOrigin.Begin)        Dim BitsPerSample As Short = Song.ReadByte '16 Bits/Sample.        BitsPerSample += Song.ReadByte * 256        'DataSize und DataBeginOffset lesen.        Dim DataSize As Integer = 0        Dim DataOffset As Byte = 0        If 18 - FormatDataLength = 2 Then '0 Bytes Luft.            'DataSize auslesen.            Song.Seek(40, SeekOrigin.Begin)            'Ab Offset 44 ist alles Data innerhalb der Datasize.            DataOffset = 44        ElseIf 18 - FormatDataLength = 1 Then '1 Byte Luft.            'DataSize auslesen.            Song.Seek(41, SeekOrigin.Begin)            'Ab Offset 45 ist alles Data innerhalb der Datasize.            DataOffset = 45        ElseIf 18 - FormatDataLength = 0 Then '2 Byte Luft.            'DataSize auslesen.            Song.Seek(42, SeekOrigin.Begin)            'Ab Offset 46 ist alles Data innerhalb der Datasize.            DataOffset = 46        End If        DataSize += Song.ReadByte        DataSize += Song.ReadByte * 256        DataSize += Song.ReadByte * 256 * 256        DataSize += Song.ReadByte * 256 * 256 * 256        Dim wfx As New WAVEFORMATEX        With wfx            .wFormatTag = FormatType            .nChannels = Channels            .nSamplesPerSec = SampleRate            .nAvgBytesPerSec = BytesPerSecond            .nBlockAlign = BytesPerSample            .wBitsPerSample = BitsPerSample            .cbSize = 0        End With        waveOutOpen(hWaveOut, -1, wfx, callback, CType(0, IntPtr), 196608 Or 8)        Dim bufferData(DataSize - 1) As Byte        For i = 0 To DataSize - 1            bufferData(i) = Song.ReadByte        Next        Dim dataHandle As GCHandle = GCHandle.Alloc(bufferData, GCHandleType.Pinned)        Dim wavHeader As New WAVEHDR        With wavHeader            .dwBufferLength = 44100 * Channels * ((BitsPerSample + 7) / 8)            .dwFlags = 0            .lpData = dataHandle.AddrOfPinnedObject            .dwBytesRecorded = 0            .dwUser = IntPtr.Zero            .dwLoops = 0            .lpNext = IntPtr.Zero            .Reserved = 0        End With        Dim headerHandle As GCHandle = GCHandle.Alloc(wavHeader, GCHandleType.Pinned)        MsgBox(waveOutPrepareHeader(hWaveOut, headerHandle.AddrOfPinnedObject(), bufferData.Length))        MsgBox(waveOutWrite(hWaveOut, headerHandle.AddrOfPinnedObject, bufferData.Length))   End SubEnd Class

Unfortunately, the last messagebox (WaveOutWrite) returns the code "UNPREPARED = 34". I don´t understand this, I´ve prepared the header before... Can you help me to fix this?


Best regards

VB .NET Wave Player.rar

Link to comment

Thanks Kao this sounds interesting.


I could need a full source to understand the bridges between these snippets... And I ask myself, why this

MsgBox(waveOutPrepareHeader(hWaveOut, headerHandle.AddrOfPinnedObject(), bufferData.Length))

is valid and returns no error, even with a incorrect size?!

Link to comment

Thanks, but I am not that familiar with C++  and it´s hard to understand for me :(


It would be easier if anybody could tell me what in my source is wrong and how it should be done at this point...

Link to comment

So... because it's hard for you to understand other people's code, someone else has to go to greath lengths understanding your VB code and finding your mistake in it? Sorry, nope.

Link to comment

I only want to find my mistake, I don´t want to blow the full thing up...

Ofc you are free to help or not xD Somebody who has experience with the waveout api

can just download the attachment and open in visual studio and tell me what´s wrong. That should not be too much work I think.


I don´t need somebody who googles for me, I can do that myself. I need somebody who is willing to explain me the waveout thing in .NET to get my project working.

Edited by Freefall63
Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Create New...