Les sons

Il faut commencer par indiquer au compilateur deux nouvelle bibliothèques (voir tuto 1) : winmm.lib dsound.lib

La fonction de l'API Win32 pour lire les son est PlaySound qui prend en paramètre le nom du clip audio, le handle de l'instance de module où se trouve la ressource audio et un drapeau définissant la manière dont le son est exécuté.

Parmi ces drapeaux on a :

SND_FILENAME : spécifie que le premier paramètre est un nom de fichier wave
SND_RESOURCE : spécifie que le premier paramètre est l'identificateur d'une ressource audio
SND_MEMORY : spécifie que le premier paramètre pointe vers une ressource wave chargée en mémoire
SND_ASYNC : exécution asynchrone, la fonction revient dès le début de la lecture du son
SND_SYNC : exécution ynchrone, la fonction revient à la fin de la lecture du son
SND_LOOP : exécution en loupe (il faut que ce soit aussi asynchrone)
SND_NOSTOP : le son l'est pas exécuté si un autre son est en cours de lecture
SND_NODEFAULT : spécifie que le son système par défaut n'est pas exécuté s'il n'est pas possible de localiser le son spécifié.

Dans la fonction init_ds, on commence par créer l'interface DirectSound, puis on définit le niveau coopératif. Il existe quatre niveaux de priorité :

NORMAL, PRIORITAIRE, EXCLUSIF, ECRITURE TAMPON PRIMAIRE

on a donc, dans init_ds.cpp

#include "init_DS.h"

HRESULT init_DS(HWND hWnd, LPDIRECTSOUND *objDirectSound) {

// Création de DirectSound
if(DirectSoundCreate(NULL, objDirectSound, NULL) != DS_OK)
return E_FAIL;

//Définit le niveau coopératif
if((*objDirectSound)->SetCooperativeLevel(hWnd, DSSCL_NORMAL) != DS_OK)
return E_FAIL;

return DS_OK;
}

Ensuite on crée une fonction pour charger les sons. Elle est un peu compliquée puisqu'il est nécessaire d'extraire les données sonores et les paramètres du fichier wave. On se sert pour cela de la bibliothèque winmm.lib. Dans sons.cpp on aura

#include"init_DS.h"

HRESULT LoadDirectSound(LPDIRECTSOUND *ds, LPDIRECTSOUNDBUFFER *buffer, char* filename)
{

HMMIO mmioWave;
if((mmioWave = mmioOpen(filename, 0, MMIO_READWRITE)) == NULL)
return E_FAIL;

MMCKINFO mmckinfoParent;
//descend jusqu au bloc WAVE
mmckinfoParent.fccType = mmioFOURCC('W', 'A', 'V', 'E'); 
if(mmioDescend(mmioWave, &mmckinfoParent, NULL, MMIO_FINDRIFF))
{ mmioClose(mmioWave, 0);
return E_FAIL;
}

MMCKINFO mmckinfoSubchunk;
//descend jusqu au bloque fmt
mmckinfoSubchunk.ckid = mmioFOURCC('f', 'm', 't', ' ');
if(mmioDescend(mmioWave, &mmckinfoSubchunk, &mmckinfoParent, MMIO_FINDCHUNK))
{ mmioClose(mmioWave, 0);
return E_FAIL;
}

//lecture des donnees du fmt
WAVEFORMATEX wfPCM;
if(mmioRead(mmioWave, (HPSTR)&wfPCM, mmckinfoSubchunk.cksize) == -1)
{ mmioClose(mmioWave, 0);
return E_FAIL;
}

mmioAscend(mmioWave, &mmckinfoSubchunk, 0);

mmckinfoSubchunk.ckid = mmioFOURCC('d', 'a', 't', 'a');
if(mmioDescend(mmioWave, &mmckinfoSubchunk, &mmckinfoParent, MMIO_FINDCHUNK))
{ mmioClose(mmioWave, 0);
return E_FAIL;
}

//creation du directsound buffer
DSBUFFERDESC bufdesc;
ZeroMemory(&bufdesc, sizeof(bufdesc));
bufdesc.dwSize = sizeof(DSBUFFERDESC);
bufdesc.dwFlags = NULL;
bufdesc.dwBufferBytes = mmckinfoSubchunk.cksize;
bufdesc.lpwfxFormat = &wfPCM;

LPDIRECTSOUNDBUFFER lpdsBuffer;

HRESULT rval = (*ds)->CreateSoundBuffer(&bufdesc,&lpdsBuffer,NULL);
if(rval != S_OK)
exit(0);

LPBYTE lpvAudio1, lpvAudio2;
DWORD dwWriteBytes1, dwWriteBytes2;

//verrouille le tampon DirectSound
HRESULT hr = lpdsBuffer->Lock(0, 0, (LPVOID*)&lpvAudio1, &dwWriteBytes1, (LPVOID*)&lpvAudio2, &dwWriteBytes2, DSBLOCK_ENTIREBUFFER);
if(hr == DSERR_BUFFERLOST)
{ lpdsBuffer->Restore();
hr = lpdsBuffer->Lock(0, 0, (LPVOID*)&lpvAudio1, &dwWriteBytes1, (LPVOID*)&lpvAudio2, &dwWriteBytes2, DSBLOCK_ENTIREBUFFER);
}

if(FAILED(hr))

if(lpdsBuffer != NULL) {lpdsBuffer->Release(); lpdsBuffer = NULL;}

mmioClose(mmioWave, 0);
return E_FAIL;
}

if(dwWriteBytes1 != mmckinfoSubchunk.cksize)
{ if(lpdsBuffer != NULL) {lpdsBuffer->Release(); lpdsBuffer = NULL;}
mmioClose(mmioWave, 0);
return E_FAIL;
}

if(mmioRead(mmioWave, (HPSTR)lpvAudio1, mmckinfoSubchunk.cksize) == -1)
{ if(lpdsBuffer != NULL) {lpdsBuffer->Release(); lpdsBuffer = NULL;}
mmioClose(mmioWave, 0);
return E_FAIL;
}

//déverrouille le tampon DirectSound
if(FAILED(lpdsBuffer->Unlock((LPVOID)lpvAudio1, dwWriteBytes1, (LPVOID)lpvAudio2, dwWriteBytes2)))
{ if(lpdsBuffer != NULL) {lpdsBuffer->Release(); lpdsBuffer = NULL;}
mmioClose(mmioWave, 0);
return E_FAIL;
}

//fermture
mmioClose(mmioWave, 0);

*buffer = lpdsBuffer;

return S_OK;
}

On a trois nouveaux fichiers entête, NBR_SNDS correspond au nombre de waves à charger, ici il y en a 5 : son du missile, accélération, décélération, musique d'ambiance et impact. Les données sonnores sont donc transférées dans 5 buffers sons différents.

init_DS.h

#include <Dsound.h>

#define NBR_SNDS 5

// pointeurs sur directsound et directsoundbuffer
static LPDIRECTSOUND obj_DirectSound;
static LPDIRECTSOUNDBUFFER DSbuffer[NBR_SNDS];

decl_init_DS.h

HRESULT init_DS(HWND hWnd, LPDIRECTSOUND *obj_DirectSound);

decl_sons.h

HRESULT LoadDirectSound(LPDIRECTSOUND*, LPDIRECTSOUNDBUFFER*, char*);

Dans la fonction Cleaup on libère la mémoire commencant par les buffers puis par le pointeur obj_DirectSound.

if( obj_Direct3D2 != NULL)
obj_Direct3D2->Release();

unsigned int i;

for (i = 0; i<NBR_SNDS; i++) 
if( DSbuffer[i] != NULL)
DSbuffer[i]->Release();

if( obj_DirectSound != NULL)
obj_DirectSound->Release();


for (i = 0; i<10; i++) {
if (mtm[i]->Materiaux)
delete[] mtm[i]->Materiaux;

Dans la fonction rendu, lors du traitement de l'impact entre missile et module on a :

while(cell0) {

int lib = 0;

if(rp2->rayon*rp2->rayon>(rp2->coord_0.z-cell0->coord.z)*(rp2->coord_0.z-cell0->coord.z) + (rp2->coord_0.x-cell0->coord.x)*(rp2->coord_0.x-cell0->coord.x)) {

if(DSbuffer[2] && et_module.haut!=1) {
DSbuffer[2]->SetCurrentPosition(0); // Met le fichier wav au début
DSbuffer[2]->Play(0,0,0); // Joue le son
}

rp2->tcr = .2f;
rp2->vies-=.10f;

Dans la fonction MsgProc, c'est lors de l'interception des touches clavier que l'on va traiter le son

case WM_KEYDOWN :

switch(wParam) {

case 'M':
if(DSbuffer[0] && et_module.feu!=1) {
DSbuffer[0]->SetCurrentPosition(0); // Met le fichier wav au début
DSbuffer[0]->Play(0,0,0); // Joue le son
}

et_module.feu=1;


break;

case 'F':
if(DSbuffer[0] && et_module2.feu!=1) {
DSbuffer[0]->SetCurrentPosition(0); // Met le fichier wav au début
DSbuffer[0]->Play(0,0,0); // Joue le son
}

et_module2.feu=1;
break;

case VK_UP:
if(DSbuffer[3]&& et_module.haut!=1) {
DSbuffer[3]->SetCurrentPosition(0); // Met le fichier wav au début
DSbuffer[3]->Play(0,0,0); // Joue le son
}
if(DSbuffer[4]&& et_module.haut!=1) 
DSbuffer[4]->Stop();

et_module.haut=1;et_module.bas=0;


break;

case 'Z':
if(DSbuffer[3]&& et_module2.haut!=1) {
DSbuffer[3]->SetCurrentPosition(0); // Met le fichier wav au début
DSbuffer[3]->Play(0,0,0); // Joue le son
}
if(DSbuffer[4]&& et_module2.haut!=1)
DSbuffer[4]->Stop();

et_module2.haut=1;et_module2.bas=0;
break;

case VK_RIGHT:
et_module.droite=1;et_module.gauche=0;
break;

case 'D':
et_module2.droite=1;et_module2.gauche=0;
break;

case VK_LEFT:
et_module.gauche=1;et_module.droite=0;
break;

case 'Q':
et_module2.gauche=1;et_module2.droite=0;
break;

}

break;

case WM_KEYUP :

switch(wParam) {

case VK_UP:
if(DSbuffer[4]&& et_module.haut!=2) {
DSbuffer[4]->SetCurrentPosition(0); // Met le fichier wav au début
DSbuffer[4]->Play(0,0,0); // Joue le son
}
if(DSbuffer[3]&& et_module.haut!=2)
DSbuffer[3]->Stop();

et_module.haut=2;et_module.bas=0;
break;

case 'Z':
if(DSbuffer[4]&& et_module2.haut!=2) {
DSbuffer[4]->SetCurrentPosition(0); // Met le fichier wav au début
DSbuffer[4]->Play(0,0,0); // Joue le son
}
if(DSbuffer[3]&& et_module2.haut!=2)
DSbuffer[3]->Stop();

et_module2.haut=2;et_module2.bas=0;
break;

Dans la fonction main principale on initialise Directound et on charge en mémoire les buffers

// Initialise Direct3D

if(( SUCCEEDED( InitD3D(hCtrl_1, LONG_FENETRE, LARG_FENETRE, &obj_Direct3D, &obj_Direct3DDevice))
&&
SUCCEEDED( InitD3D(hCtrl_2, LONG_FENETRE, LARG_FENETRE, &obj_Direct3D2, &obj_Direct3DDevice2))
) == E_FAIL)
return -1;


unsigned int i, k = 0;

if(init_DS(hWnd, &obj_DirectSound) != DS_OK)
return -1;

for(i = 0; i < NBR_SNDS; i++)
if(LoadDirectSound(&obj_DirectSound, &(DSbuffer[i]), "sound.wav") != S_OK)
return -1;

Enfin toujours dans la fonction main principale on lance la musique de fond avec un LOOP :

ShowWindow(hWnd, SW_SHOWDEFAULT);
UpdateWindow(hWnd);

if(DSbuffer[1]) {
DSbuffer[1]->SetCurrentPosition(0); // Met le fichier wav au début
DSbuffer[1]->Play(0,0,DSBPLAY_LOOPING); // Joue le son
}

MSG msg;
ZeroMemory( &msg, sizeof(msg) );

Téléchargez la source, cliquez ci-dessous :