Version 2.0!
Features
Tutorials
Files
Glossary
Projects
Contact
Links
Message Board
Extras
LuckyCam
Old News
Sign Guestbook
View Guestbook
VB Horoscope
VB Photo Album
.
ATTENTION READERS! Lucky's VB Gaming Site is no longer active. For updated game programming information and tutorials, please visit The Game Programming Wiki!

DirectSound

Vaak hebben we het niet door, maar als het er niet zou zijn, dan wordt het gewoon saai.
Inderdaad, ik hebt het over geluid!

Laten we beginnen met de initialisatie stappen:

Dim ds As DirectSound
Dim dx as New DirectX7

Set ds = dx.DirectSoundCreate("")
ds.SetCooperativeLevel Me.hWnd DDSCL_PRIORITY


Wat hier gebeurt, is het aanmaken van een DirectSound instantie via het hoofd-object "dx". In dit geval is "ds" ons DirectSound object en, zoals gewoonlijk, stellen we de cooperative level ervan in. We geven de "SetCooperativeLevel" de "DDSCL_PRIORITY" flag mee, omdat dit ons exclusieve toegang tot het geluids-systeem verleent. Als eerste argument geef je natuurlijk de handle van het venster waarmee je werkt mee, in dit geval is de code in het venster zelf en gebruiken we "Me.hWnd".

Nu we DirectSound hebben opgestart, moeten we een buffer en zijn descriptie opstellen:

Dim DSBuffer As DirectSoundBuffer
Dim DSBufferDescription as DSBUFFERDESC
Dim DSFormat as WAVEFORMATEX


"DSBuffer" zal onze wave data bevatten (het kan andere types data bevatten, maar we laten her hier maar bij) en we zullen de "DSBUFFERDESC" en "WAVEFORMATEX" objecten moeten opstellen om zo correct de buffer te laden met data. Door gebruik te maken van de "DSBUFFERDESC", DSBufferDescription, kunnen we de verschillende opties dat onze buffer moet hebben specifieren. Dit doen we door de eigenschap ".lFlags" in te vullen. Dit zijn de vier (meest voorkomende) waarden:

DSBCAPS_CTRLFREQUENCY - Dit laat ons toe om de buffer's output frequentie te wijzigen
DSBCAPS_CTRLPAN - Dit laat ons toe om de sound panel te modifieren (vb. Uit welke speaker het geluid komt)
DSBCAPS_CTRLVOLUME - Vrij logisch...
DSBCAPS_CTRLPOSITIONNOTIFY - Dit is zéér handig. Het laat ons toe om bepaalde events te onderscheppen op verschillende locaties binnen een geluid's playback.

Het "WAVEFORMATEX" object heeft een aantal items die we moeten assigneren:

nFormatTag - Welke 'data format' (=data formaat) gebruiken we? WAVES! Dus geef de "WAVE_FORMAT_PCM" constante door.
nChannels - Hoeveel channels (=kanalen) willen we gebruiken? 1 = mono, 2 = stereo.
lSamplesPerSec - Hoeveel cycles/seconde - Hertz - willen we? De standaard waarde is 22050.
nBitsPerSample - Welke "bit depth" wil je gebruiken? Standaard wordt hier '16' gebruikt.
nBlockAlign - Laat het gewoon op "nBitsPerSample / 8 * nChannels"...
lAvgBytesPerSec - Stel deze in op "lSamplesPerSec * nBlockAlign".

DSBufferDescription.lFlags = DSBCAPS_CTRLPOSITIONNOTIFY Or DSBCAPS_CTRLFREQUENCY Or DSBCAPS_CTRLPAN Or DSBCAPS_CTRLVOLUME

With DSFormat
        .nFormatTag = WAVE_FORMAT_PCM
        .nChannels = 2
        .lSamplesPerSec = 22050
        .nBitsPerSample = 16
        .nBlockAlign = .nBitsPerSample / 8 * .nChannels
        .lAvgBytesPerSec = .lSamplesPerSec * .nBlockAlign
End With


Nu hebben we al onze "DSBUFFERDESC" en "WAVEFORMATEX" objecten en kunnen we doorgaan met het laden van de sound buffer (=geluidsbuffer), DSBuffer, met data:

Set DSBuffer = ds.CreateSoundBufferFromFile(App.Path & "\WaveFile.WAV", DSBufferDescription, DSFormat)

Voor diegenen die een bestand willen laden van een resource:

Set DSBuffer = ds.CreateSoundBufferFromResource("", "WaveFile", DSBufferDescription, DSFormat)

Omdat we onze buffer hebben gemaakt door gebruik te maken van de "DSBCAPS_CTRLPOSITIONNOTIFY" flag MOETEN we een notificatie positie opstellen in het bestand zelf.
Als je toepassing niet gewaarschuwd moet worden wanneer een geluid beeindigd is of wanneer het een bepaalde locatie heeft berijkt, verwijder dan gewoon de "DSBCAPS_CTRLPOSITIONNOTIFY" flag en negeer de volgende code:

Dim DSPosition(0) As DSBPOSITIONNOTIFY
Dim DSNotification as Long

DSNotification = dx.CreateEvent(FormObject)
DSPosition(0).hEventNotify = DSNotification
DSPosition(0).lOffset = DSBPN_OFFSETSTOP
DSBuffer.SetNotificationPositions 1, DSPosition()


Hier hebben we twee nieuwe variabelen. "DSPosition(0)" zal onze "DSBPOSITIONNOTIFY" array worden waarmee we de locaties - binnenin de wave data - kunnen bepalen waar we events willen onderscheppen. "DSNotification" zal de event handle, teruggegeven van de "CreateEvent" methode, bewaren.

Door gebruikt te maken van de "dx.CreateEvent" methode, maken we een event en bewaren we zijn handle in "DSNotification". We moeten ook een 'Form' object doorgeven. De Form die we doorgeven zal het venster zijn waarin de event gemaakt wordt. Nu bewaren we de event handle in "DSPosition(0).hEventNotify" en kennen we "DSPosition(0).lOffset" een "position offset" toe. In de voorbeeldcode wordt er "DSBPN_OFFSETSTOP" gebruikt. Dit betekent dat de event gegenereerd zal worden wanneer het wave bestand het einde berijkt.
Eens het "DSPosition" object 'ingevuld' is, kunnen we een oproep doen aan de "DSBuffer.SetNotificationsPosition" methode. Het eerste argument dat we doorgeven is gewoonweg het aantal posities die we een event toekennen (in dit geval 1, namelijk het einde van het bestand). Het tweede argument verijst een "DSBPOSITIONNOTIFY" array, dus geven we het "DSPosition()" object door.

Noot: Je MOET een ARRAY aanmaken voor de "DSBPOSITIONNOTIFY" variabele, aangezien de "SetNotificationsPositions" methode alleen arrays aanvaardt. In bovenstaand voorbeeld, bevat onze array slechts 1 positie descriptie. Je zou er eventueel meerdere kunnen toekennen door gebruik te maken van een grotere array.

Het Form object dat we doorgaven aan de "CreateEvent" methode, zal een paar wijzigingen moeten ondergaan:

Implements DirectXEvent

Private Sub DirectXEvent_DXCallback(ByVal eventid As Long)

End Sub


Je moet de "Implements DirectXEvent" toevoegen aan de header (=hoofding) van de Form code. Dit zal je toelaten om een niew event in de form te plaatsen, DirectXEvent_DXCallback. Deze event zal ge-triggered (trigger betekent eigenlijk, het opstarten van een mechanisme door een oorzaak) worden wanneer een wave bestand een offset waarde (met een event toegekend) bereikt. Als "DirectXEvent_DXCallback" ge-triggered wordt, zal de aangemaakte variabele "eventid" de event handle bevatten die gebruikt werd toen de event aangemaakt werd. Gebruikt dit om te bepalen WELKE wave file deze event triggerde, en zo de nodige acties te ondergaan.

Een voorbeeld zal helpen dit wat duidelijker maken: in bovenstaande code hebben we een event aangemaakt voor het "DSBuffer" object en het was een event handle toegekend, dat opgeslagen was in "DSNotification". Als we onze "DSBuffer" spelen en het einde van het wave-bestand bereikt is, zal de "DirectXEvent_DXCallback" subroutine ge-triggered worden binnenin de Form. De "eventid" gegenereerd door "DirectXEvent_DXCallback" zal identiek zijn aan de event handle dat we opgeslagen hebben in "DSNotification".

Nu denk je waarschijnlijk dat het simpeler is om de Visual Basic Multimedia OCX te gebruiken, of de API.
Fout... Vanaf nu zal het wat makkelijker worden en komt de flexibiliteit van DirectSound te boven.

Om je bestand af te spelen gebruik je:

DSBuffer.Play DSBPLAY_DEFAULT

Als je het wil laten spelen in een loop:

DSBuffer.Play DSBPLAY_LOOPING

Simpel, hé? Om het geluid te stoppen tijdens het spelen:

DSBuffer.Stop

Dit is eigenlijk meer PAUZEREN. Want het geluid is gestopt, maar de positie van het bestand is niet gewijzigd.
Om dit terug op 0 te zetten gebruik je gewoon:

DSBuffer.SetCurrentPosition 0

Nu weet je hoe je een buffer moet laden, afspelen, pauzeren en stoppen. Maar het leukste is nog niet aan bod gekomen. Herinner je dat we in het begin bij het "DSBUFFERDESC" object speciale instellingen hebben gegeven waardoor we de frequentie, het volume, de panels... konden wijzigen?
Die moeten we nog kunnen gebruiken. Dit zou je eventueel kunnen doen:

Const LeftPan = -10000
Const RightPan = 10000
Const CenterPan = 0
Const MaxVolume = 0
Const MinVolume = -10000
Const MaxFrequency = 100000
Const MinFrequency = 100

Dim Freq as Long
Dim Pan as Long
Dim Vol as Long

Freq = DSBuffer.GetFrequency()
DSBuffer.SetFrequency Freq - 1
Pan = DSBuffer.GetPan()
DSBuffer.SetPan Pan - 1

Vol = DSBuffer.GetVolume()
DSBuffer.SetVolume = Vol - 1


De "GetFrequenty" methode geeft de frequentie terug, in Hertz, van de wave in de buffer. Door gebruik te maken van de "SetFrequency" methode, kunnen we de frequency wijzigen binnen de grenzen, bepaald door "MaxFrequency" en "MinFrequency". De "GetPan" methode geeft de huidige "Pan" waarde terug van de buffer. Het midden (M.a.w. Het geluid is gelijk verdeeld, zowel links, als rechts) is op '0', volledig links is '-10000' en volledig rechts is '10000'. Met "SetPan" kunnen we de "pan" van de buffer wijzigen. "GetVolume" geeft de huidige volume status weer van de buffer. De maximale volume waarde is '0', de minimale is '-10000'. Wees voorzichtig: volume wordt gemeten in decibels, dat gebruikt maakt van een logaritmische schaalwaarde. Het lichtjes verminderen van de volume met de "SetVolume" methode zal scherp gedefinieerde effecten hebben op de output van het wave-bestand.

Dit was eigenlijk de basis van DirectSound. Vergeet natuurlijk niet, uit goede gewoonte, je rommel pop te ruimen :^)

Set DSBuffer = Nothing

Hier zijn enkele voorbeelden:
1. Een voorbeeld project
2. Een spelletje dat dit illustreert

Translated by Djamel Grine