WaveOutWrite: Unterschied zwischen den Versionen
K |
(Beispielcode überarbeitet: Kommentar in der Callback und Loop bis Buffer fertig gespielt wurden ergänzt.) |
||
Zeile 43: | Zeile 43: | ||
Private Declare Function waveOutClose Lib "winmm.dll" (ByVal hWaveOut As Long) As Long | Private Declare Function waveOutClose Lib "winmm.dll" (ByVal hWaveOut As Long) As Long | ||
− | + | ||
Private Declare Function waveOutWrite Lib "winmm.dll" (ByVal hWaveOut As Long, _ | Private Declare Function waveOutWrite Lib "winmm.dll" (ByVal hWaveOut As Long, _ | ||
ByRef lpWaveOutHdr As WAVEHDR, ByVal uSize As Long) As Long | ByRef lpWaveOutHdr As WAVEHDR, ByVal uSize As Long) As Long | ||
− | + | ||
Private Type WAVEFORMATEX | Private Type WAVEFORMATEX | ||
wFormatTag As Integer | wFormatTag As Integer | ||
Zeile 82: | Zeile 82: | ||
Private lBufferFinished As Long | Private lBufferFinished As Long | ||
− | + | ||
Public Sub TestAudioOutput() | Public Sub TestAudioOutput() | ||
If OpenOutputDevice(0) Then | If OpenOutputDevice(0) Then | ||
Zeile 92: | Zeile 92: | ||
End If | End If | ||
+ | Do While lBufferFinished <> 0 | ||
+ | 'warten bis beide Buffer abgespielt wurden | ||
+ | Loop | ||
CloseOutputDevice | CloseOutputDevice | ||
Else | Else | ||
Zeile 97: | Zeile 100: | ||
End If | End If | ||
End Sub | End Sub | ||
− | + | ||
Private Sub CreateTestData() | Private Sub CreateTestData() | ||
'Diese Funktion erstellt zwei verschiedene Wellenformen in den beiden Buffern | 'Diese Funktion erstellt zwei verschiedene Wellenformen in den beiden Buffern | ||
Zeile 103: | Zeile 106: | ||
Dim x As Long | Dim x As Long | ||
Dim lSample As Long | Dim lSample As Long | ||
− | + | ||
'Sägezahn Schwingung in Buffer 1: | 'Sägezahn Schwingung in Buffer 1: | ||
lSample = 0 | lSample = 0 | ||
Zeile 125: | Zeile 128: | ||
Next | Next | ||
End Sub | End Sub | ||
− | + | ||
− | + | ||
Public Function OpenOutputDevice(DevID As Long) As Boolean | Public Function OpenOutputDevice(DevID As Long) As Boolean | ||
Dim udtWaveFormat As WAVEFORMATEX | Dim udtWaveFormat As WAVEFORMATEX | ||
Zeile 163: | Zeile 166: | ||
CloseOutputDevice | CloseOutputDevice | ||
Else | Else | ||
+ | lBufferFinished = 3 | ||
OpenOutputDevice = True | OpenOutputDevice = True | ||
End If | End If | ||
End If | End If | ||
End Function | End Function | ||
− | + | ||
Public Function CloseOutputDevice() | Public Function CloseOutputDevice() | ||
If hDevice <> INVALID_HANDLE_VALUE Then | If hDevice <> INVALID_HANDLE_VALUE Then | ||
Zeile 176: | Zeile 180: | ||
End If | End If | ||
End Function | End Function | ||
− | + | ||
Private Sub CallBack(ByVal hDev As Long, ByVal uMsg As Long, dwInstance As Long, _ | Private Sub CallBack(ByVal hDev As Long, ByVal uMsg As Long, dwInstance As Long, _ | ||
dwParam1 As WAVEHDR, dwParam2 As Long) | dwParam1 As WAVEHDR, dwParam2 As Long) | ||
+ | 'Achtung: innerhalb der Callback Funktion dürfen nur wenige Funktionen und API Calls erfolgen! | ||
+ | 'MSDN: | ||
+ | 'Applications should not call any system-defined functions from inside a callback function, | ||
+ | 'except for EnterCriticalSection, LeaveCriticalSection, midiOutLongMsg, midiOutShortMsg, | ||
+ | 'OutputDebugString, PostMessage, PostThreadMessage, SetEvent, timeGetSystemTime, timeGetTime, | ||
+ | 'timeKillEvent, and timeSetEvent. Calling other wave functions will cause deadlock. | ||
+ | ' | ||
+ | 'Zu bedenken ist auch, dass viele VB Funktionen ihrerseits im Hintergrund APIs aufrufen und dies | ||
+ | 'die Limitierungen verletzen könnte. Ein Zuwiederhandeln zeigt sich meist erst in der kompilierten | ||
+ | 'EXE (Absturz) wohingegen der Code in der IDE fehlerfrei läuft! | ||
+ | |||
If uMsg = WOM_DONE Then | If uMsg = WOM_DONE Then | ||
lBufferFinished = lBufferFinished And (Not dwParam1.dwUser) | lBufferFinished = lBufferFinished And (Not dwParam1.dwUser) | ||
Zeile 184: | Zeile 199: | ||
End Sub | End Sub | ||
</code> | </code> | ||
− | |||
==Quelle(n)== | ==Quelle(n)== |
Version vom 12. Januar 2011, 18:07 Uhr
Die API-Funktion waveOutWrite weißt das Ausgabegerät an, den übergebenen Audiobuffer abzuspielen.
Declare Function waveOutWrite lib "winmm.dll" _
Alias "waveOutWrite" ( _ ByVal hWaveOut As Long, _ ByRef lpWaveOutHdr As WAVEHDR, _ ByVal uSize As Long) As Long
Parameter
hWaveOut
- Handle des Devices zu dem der Buffer hinzugefügt werden soll. Siehe waveOutOpen.
lpWaveOutHdr
- Zeiger auf die WAVEHDR Struktur des Buffers. Die Struktur muss mittels waveOutPrepareHeader vorbereitet worden sein.
uSize
- Grösse der übergebenen WAVEHDR Struktur.
Rückgabe(n)
0 bei Erfolg, ansonsten Fehlercode.
Beispiel
In diesem Beispiel wird ein Gerät zur Ausgabe von 16 Bit 44.1kHz Mono Audiodaten geöffnet, zwei Buffer werden reserviert und in diesen werden Testdaten generiert. Schlussendlich werden die beiden Buffer ausgegeben und das Device wieder geschlossen.
'Module1
Option Explicit
Private Declare Function waveOutOpen Lib "winmm.dll" (hWaveOut As Long, _
ByVal uDeviceID As Long, Format As Any, ByVal dwCallback As Long, _ ByVal dwInstance As Long, ByVal dwFlags As Long) As Long
Private Declare Function waveOutPrepareHeader Lib "winmm.dll" ( _
ByVal hWaveOut As Long, lpWaveInHdr As Any, ByVal uSize As Long) As Long
Private Declare Function waveOutUnprepareHeader Lib "winmm.dll" ( _
ByVal hWaveOut As Long, lpWaveInHdr As Any, ByVal uSize As Long) As Long
Private Declare Function waveOutClose Lib "winmm.dll" (ByVal hWaveOut As Long) As Long
Private Declare Function waveOutWrite Lib "winmm.dll" (ByVal hWaveOut As Long, _
ByRef lpWaveOutHdr As WAVEHDR, ByVal uSize As Long) As Long
Private Type WAVEFORMATEX
wFormatTag As Integer nChannels As Integer nSamplesPerSec As Long nAvgBytesPerSec As Long nBlockAlign As Integer wBitsPerSample As Integer cbSize As Integer
End Type
Private Type WAVEHDR
lpData As Long dwBufferLength As Long dwBytesRecorded As Long dwUser As Long dwFlags As Long dwLoops As Long lpNext As Long Reserved As Long
End Type
Private Const WAVE_FORMAT_PCM As Long = 1 Private Const CALLBACK_FUNCTION As Long = &H30000 Private Const INVALID_HANDLE_VALUE As Long = -1 Private Const WOM_DONE As Long = &H3BD
Private hDevice As Long
Private udtBuffer1Hdr As WAVEHDR Private btWaveOutBuffer1() As Byte
Private udtBuffer2Hdr As WAVEHDR Private btWaveOutBuffer2() As Byte
Private lBufferFinished As Long
Public Sub TestAudioOutput()
If OpenOutputDevice(0) Then CreateTestData If Not waveOutWrite(hDevice, udtBuffer1Hdr, LenB(udtBuffer1Hdr)) = 0 Then 'error ElseIf Not waveOutWrite(hDevice, udtBuffer2Hdr, LenB(udtBuffer2Hdr)) = 0 Then 'error End If Do While lBufferFinished <> 0 'warten bis beide Buffer abgespielt wurden Loop CloseOutputDevice Else Debug.Print "Kann Gerät 0 nicht öffnen!" End If
End Sub
Private Sub CreateTestData()
'Diese Funktion erstellt zwei verschiedene Wellenformen in den beiden Buffern 'damit ein Unterschied hörbar ist. Dim x As Long Dim lSample As Long 'Sägezahn Schwingung in Buffer 1: lSample = 0 For x = 0 To UBound(btWaveOutBuffer1) Step 2 lSample = lSample + 5 If lSample > 32767 Then lSample = 0 End If btWaveOutBuffer1(x) = (lSample And &HFF00&) \ &H100 btWaveOutBuffer1(x + 1) = lSample And &HFF& Next 'Sägezahn Schwingung in Buffer 2: lSample = 0 For x = 0 To UBound(btWaveOutBuffer2) Step 2 lSample = lSample + 8 If lSample > 32767 Then lSample = 0 End If btWaveOutBuffer2(x) = (lSample And &HFF00&) \ &H100 btWaveOutBuffer2(x + 1) = lSample And &HFF& Next
End Sub
Public Function OpenOutputDevice(DevID As Long) As Boolean
Dim udtWaveFormat As WAVEFORMATEX 'Definition des abzuspielenden Formats: With udtWaveFormat .cbSize = 0 .wFormatTag = WAVE_FORMAT_PCM 'wave format .nChannels = 1 'mono .nSamplesPerSec = 44100 '44.1 kHz .wBitsPerSample = 16 '16 Bits pro Sample .nBlockAlign = .nChannels * .wBitsPerSample / 8 .nAvgBytesPerSec = .nSamplesPerSec * .nBlockAlign End With If waveOutOpen(hDevice, DevID, udtWaveFormat, AddressOf CallBack, 0, CALLBACK_FUNCTION) <> 0 Then 'Failed hDevice = INVALID_HANDLE_VALUE Else 'Device erfolgreich geöffnet, jetzt zwei buffer, jeweils 1/4 sekunde '16 bit audio reservieren: ReDim btWaveOutBuffer1(udtWaveFormat.nSamplesPerSec * udtWaveFormat.nBlockAlign * 0.25 - 1) ReDim btWaveOutBuffer2(udtWaveFormat.nSamplesPerSec * udtWaveFormat.nBlockAlign * 0.25 - 1) With udtBuffer1Hdr .lpData = VarPtr(btWaveOutBuffer1(0)) .dwBufferLength = UBound(btWaveOutBuffer1) + 1 .dwUser = 1 End With With udtBuffer2Hdr .lpData = VarPtr(btWaveOutBuffer2(0)) .dwBufferLength = UBound(btWaveOutBuffer2) + 1 .dwUser = 2 End With If waveOutPrepareHeader(hDevice, udtBuffer1Hdr, LenB(udtBuffer1Hdr)) Or _ waveOutPrepareHeader(hDevice, udtBuffer2Hdr, LenB(udtBuffer2Hdr)) <> 0 Then CloseOutputDevice Else lBufferFinished = 3 OpenOutputDevice = True End If End If
End Function
Public Function CloseOutputDevice()
If hDevice <> INVALID_HANDLE_VALUE Then waveOutUnprepareHeader hDevice, udtBuffer1Hdr, LenB(udtBuffer1Hdr) waveOutUnprepareHeader hDevice, udtBuffer2Hdr, LenB(udtBuffer2Hdr) waveOutClose hDevice hDevice = INVALID_HANDLE_VALUE End If
End Function
Private Sub CallBack(ByVal hDev As Long, ByVal uMsg As Long, dwInstance As Long, _
dwParam1 As WAVEHDR, dwParam2 As Long) 'Achtung: innerhalb der Callback Funktion dürfen nur wenige Funktionen und API Calls erfolgen! 'MSDN: 'Applications should not call any system-defined functions from inside a callback function, 'except for EnterCriticalSection, LeaveCriticalSection, midiOutLongMsg, midiOutShortMsg, 'OutputDebugString, PostMessage, PostThreadMessage, SetEvent, timeGetSystemTime, timeGetTime, 'timeKillEvent, and timeSetEvent. Calling other wave functions will cause deadlock. ' 'Zu bedenken ist auch, dass viele VB Funktionen ihrerseits im Hintergrund APIs aufrufen und dies 'die Limitierungen verletzen könnte. Ein Zuwiederhandeln zeigt sich meist erst in der kompilierten 'EXE (Absturz) wohingegen der Code in der IDE fehlerfrei läuft!
If uMsg = WOM_DONE Then lBufferFinished = lBufferFinished And (Not dwParam1.dwUser) End If
End Sub
Quelle(n)
- MSDN US-Libary