Leçon 5 : Audio
Présentation
Nous allons d'abord étudier ici Direct Music, qui fait partie du SDK DirectX, et nous allons l'utiliser pour lire des fichiers midi.
Lecture audio avec DirectMusic
Pour utiliser Direct Music, vous devrez d'abord inclure les librairies dxguid.lib et dsound.lib à votre projet. Nous alons maintenant définir les en-têtes et les variables globales :
#include <windows.h> #include <dmusici.h> #define INITGUID HINSTANCE hInstance; HWND hWnd; IDirectMusicLoader8 *DMLoader = NULL; IDirectMusicPerformance8 *DMPerform = NULL; IDirectMusicSegment8 *DMSegment = NULL;
DMLoader servira à charger un fichier .wav dans DMSegment et DMPerform à le lire. Ces déclarations faites, nous allons créer un programme fenêtré en 800x600. Ceci fait, nous pourrons inclure nos fonctions Direct Music :
LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { case WM_DESTROY: PostQuitMessage(0); break; default: break; } return DefWindowProc(hWnd, msg, wParam, lParam); } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { WNDCLASS wc; wc.style = CS_OWNDC; wc.lpfnWndProc = WindowProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); wc.lpszMenuName = NULL; wc.lpszClassName = "DMusic"; RegisterClass(&wc); hWnd = CreateWindow("DMusic", "Programme Direct Music", WS_CAPTION | WS_POPUPWINDOW | WS_VISIBLE,0,0,800,600, NULL,NULL, hInstance, NULL); MSG msg; while (TRUE) { while (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); if (msg.message == WM_QUIT) break; } if (msg.message==WM_QUIT) break; if (GetAsyncKeyState(VK_ESCAPE)) PostQuitMessage(0); } return 0; }
Désormais, nous avons un programme Windows avec une boucle d'écoute des messages. Nous allons désormais voir de début d'une fonction qui initiaisera Direct Music.
void DMInit() { CoInitialize(NULL); // Comme certaines variables sont en fait des objets COM, // il faut initialiser COM, aprés quoi on initialisera le // Loader et le Perform : CoCreateInstance(CLSID_DirectMusicLoader, NULL,CLSCTX_INPROC, IID_IDirectMusicLoader8, (void**)&DMLoader); // Le seul paramètre changeable est &DMLoader, l'adresse du Loader, // le reste sera utilisé tel quel. Après le Loader, on initialise Perform : CoCreateInstance(CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC, IID_IDirectMusicPerformance8, (void**)&DMPerform ); // De même que pour le Loader, on ne changera que l'adresse du Performance. // Maintenant, on va finir d'initialiser DMPerform : DMPerform->InitAudio(NULL, NULL, hWnd, DMUS_APATH_DYNAMIC_STEREO, 64, DMUS_AUDIOF_ALL,NULL); }
En gros, on créé les instances du Loader et du Performance. En fin de fonction, on initialise DMPerform avec a fonction InitAudio. Les deux premiers arguments sont nuls. Le troisième contient le handle de la fenêtre, le quatrième le type de lecture du son (3d, mono, stereo) : nous utiliserons ici DMUS_APATH_DYNAMIC_STEREO, un son stéréo classique. Le cinquième paramètre contient le nombre de canaux que l'on utilise pour lire le son et le sixième les possibilité de Perform, dont voici les différentes possibilités :
- DMUS_AUDIOF_3D : utilisation de buffers 3D.
- DMUS_AUDIOF_BUFFERS : permet d'utiliser plusieurs buffers audio
- DMUS_AUDIOF_EAX : permet d'utiliser les effets EAX.
- DMUS_AUDIOF_STREAMING : permet d'utiliser le streaming du son.
- DMUS_AUDIOF_ALL : toutes les possibilités précédentes pourront être utilisées.
Enfin, le dernier paramètre doit rester null. Ceci fait, nous allons donner au Load l'adresse où il ira chercher les fichiers sonnores :
WCHAR SoundFolder[MAX_PATH] = L"Musiques";
On créé un tableau SoundFolder qui contiendra l'adresse du dossier Musiques en partant du dossier de l'exécutable (d'où le L avant la chaîne de caractère). Nous allons maintenant définir ce dossier comme dossier de base où le Loader ira chercher les fichiers sonores :
DMLoader->SetSearchDirectory(GUID_DirectMusicAllTypes, SoundFolder, false);
Le premier argument indique que tous les sons sont utilisables, le second est le dossier et le troisième ne sert, pour l'instant, à rien. Nous allons maintenant charger un son dans le Segment et afficher un message d'erreur en cas de problème.
WCHAR File[MAX_PATH] = L"Fichier Sonore.wav"; if (FAILED(DMLoader->LoadObjectFromFile(CLSID_DirectMusicSegment, IID_IDirectMusicSegment8, File, (LPVOID*) &DMSegment))) MessageBox(hWnd, "Fichier son introvable.", "Leçon 5 : Direct Music", MB_OK);
Voilà, la fonction est terminée. Comme pour le dossier, on créé un tableau de caractères qui contiendra l'adresse du fichier sonore. Ensuite on charge le son dans le Loader via File. Les deux premiers arguments de LoadObjectFromFile() doivent rester ainsi. Le troisième indique l'emplacement du fichier et le dernier l'adresse où sera chargé le fichier (&DMSegment). Voici donc la fonction complète d'initialisation de Direct Music :
void DMInit() { CoInitialize(NULL); // Comme certaines variables sont en fait des objets COM, // il faut initialiser COM, aprés quoi on initialisera le // Loader et le Perform : CoCreateInstance(CLSID_DirectMusicLoader, NULL,CLSCTX_INPROC, IID_IDirectMusicLoader8, (void**)&DMLoader); // Le seul paramètre changeable est &DMLoader, l'adresse du Loader, // le reste sera utilisé tel quel. Après le Loader, on initialise Perform : CoCreateInstance(CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC, IID_IDirectMusicPerformance8, (void**)&DMPerform ); // De même que pour le Loader, on ne changera que l'adresse du Performance. // Maintenant, on va finir d'initialiser DMPerform : DMPerform->InitAudio(NULL, NULL, hWnd, DMUS_APATH_DYNAMIC_STEREO, 64, DMUS_AUDIOF_ALL, NULL); WCHAR SoundFolder[MAX_PATH] = L"Musiques"; DMLoader->SetSearchDirectory( GUID_DirectMusicAllTypes, SoundFolder,false ); WCHAR File[MAX_PATH] = L"Fichier sonore.wav"; if (FAILED(DMLoader->LoadObjectFromFile(CLSID_DirectMusicSegment, IID_IDirectMusicSegment8, File, (LPVOID*) &DMSegment))) MessageBox(hWnd,"Fichier son introvable.", "Leçon 5 : Direct Music", MB_OK); }
Ceci fait, il ne nous reste plus qu'à lire le son : pour ce faire, nous allons créer une fonction Play qui lire simplement un son et prendra en paramètre des pointeurs sur les segments à jouer :
void Play(IDirectMusicSegment8* SegmentToPlay, IDirectMusicPerformance8* Performance) { SegmentToPlay->Download( Performance ); Performance->PlaySegmentEx(SegmentToPlay, NULL, NULL, NULL, 0, NULL, NULL, NULL); }
Tout d'abord, on charge le son dans l'interpréteur, qui le jouera, puis on joue le son avec une fonction qui prend beaucoup d'arguments null, mis à part le Segment à jouer. Comme nous avons une fonction pour lire le son, il nous faut aussi une fonction pour l'arrêter : nous allons créer une fonction Stop qui se chargera de le faire :
void Stop(IDirectMusicSegment8* SegmentToStop, IDirectMusicPerformance8* Performance) { Performance->Stop(SegmentToStop, NULL, 0, 0); }
Cette fonction fait, encore une fois, appel à une fonction déjà définie de l'interpréteur, mais il est plus pratique pour vous d'écrire Stop(Segment, Perform) que Perform->Stop(Segment,NULL,0,0). Enfin, dans notre fonction de sortie, il faudra libérer tous les sons chargés en mémoire avec une fonction DMExit() :
void DMExit() { if (DMPerformance) DMPerformance->CloseDown(); if (DMLoader) DMLoader->Release(); if (DMPerformance) DMPerformance->Release(); if (DMSegment) DMSegment->Release(); CoUninitialize(); }
Cette fonction vérifie si les sons existent et si oui, les libère de la mémoire. Nous avons donc tous les ingrédients nécessaires pour lire des musiques dans nos programmes. Ne pas oublier de lancer DMInit() en début de prog et DMExit() en fin. Vous pouvez lancer les sons comme vous voulez.