Manipulation des CD Audio avec SDL
Un article de Games Creators Network.
Au dela de son rôle de librairie graphique, la SDL possède aussi d'autres fonctionnalités utiles : gestion du joystick, des threads... ce tutorial vous montrera comment manipuler (lecture, prise d'informations…) les CD audio avec la SDL. Cela peut par exemple être utilisé dans un jeu : si l'utilisateur le souhaite, il a la possibilité d'insérer un CD audio dans son ordinateur pour qu'il soit joué durant le jeu. Pour peu que vous ayez quelques bases avec la SDL, ce tutorial ne devrait vous poser aucun problème. La gestion des CD audio se fait de façon trés simple avec cette librairie.
Même si ce tutoriel a été écrit en s'appuyant sur la version 1.2.5 de la librairie, il devrait normalement être valide pour les versions de la SDL à partir de la 1.1.4 (en dessous, on note quelques différences pour la manipulation des CD audio mais rien de fondamental).
Sommaire |
[modifier] Initialisation de la SDL
Pour pouvoir gérer les CD audio, il ne faut surtout pas oublier d'initialiser la librairie avec SDL_INIT_CDROM, de cette manière :
if(SDL_Init(SDL_INIT_CDROM)<0) exit (1);
On suppose ici que seule la partie CD-ROM de la SDL sera nécessaire pour votre programme - la partie graphique de la SDL ne sera pas accessible, à moins bien sûr d'initialiser avec SDL_INIT_VIDEO également.
[modifier] Détection du nombre de lecteurs CD et sélection d'un lecteur
Entrons maintenant dans le vif du sujet. Tout d'abord, la détection du nombre de lecteurs de CD-ROM présents sur la machine de l'utilisateur. Il faut pour cela utiliser la fonction SDL_CDNumDrives, dont voici le prototype : int SDL_CDNumDrives(void). Pensez à vérifier que l'utilisateur possède au moins un lecteur CD.
Une fois qu'on a le nombre de lecteurs CD, il faut en ouvrir un (on ne parle pas ici d'ouvrir le cadie du lecteur mais bel et bien d'ouvrir un accés au lecteur et au CD qu'il contient ;-). Pour cela, il suffit d'utiliser SDL_CD *SDL_CDOpen(int drive). Cette fonction prend en paramètre le numéro du lecteur à ouvrir, en sachant que 0 est le numéro du lecteur par défaut du système. Elle renvoie un pointeur vers une structure SDL_CD qui contient des informations sur le CD présent dans le lecteur, ou bien NULL si le lecteur est non-valide ou a un quelconque problème. Voila la définition de la structure SDL_CD :
typedef struct{ int id; CDstatus status; int numtracks; int cur_track; int cur_frame; SDL_CDtrack track[SDL_MAX_TRACKS+1]; } SDL_CD;
id contient un ID privé d'identification du lecteur et numtracks contient le nombre de pistes présentes sur le CD. Nous aborderons les autres champs de cette structure de données un peu plus loin. Si numtracks=0, c'est certainement qu'il n'y a aucun CD dans le lecteur (ou que le CD est vierge), nous verrons plus loin qu'en examinant le statut du lecteur on peut déterminer si un CD est présent ou non.
[modifier] Informations sur les pistes
Pour collecter des informations sur les pistes, il vous suffit d'utiliser la structure SDL_CD renvoyée par SDL_CDOpen. Vous pouvez déjà connaitre (comme dit plus haut) le nombre de pistes audio du CD à l'aide du champ numtracks de la structure en question. Si vous souhaitez obtenir plus d'informations sur les pistes (comme la taille de chaque piste, etc...), vous devrez regarder dans le tableau SDL_CDtrack track[SDL_MAX_TRACKS+1] de la structure SDL_CD. C'est un tableau de structures de données SDL_CDtrack, qui permet le stockage des propriétés d'une piste.Voici la définition de cette structure :
typedef struct{ Uint8 id; Uint8 type; Uint32 length; Uint32 offset; } SDL_CDtrack;
Le champ id contient le numéro de la piste (valeur pouvant varier de 0, la 1ere piste, à 99). Le champ type est utile : s'il est égal à la constante SDL_AUDIO_TRACK, alors la piste est une piste audio mais si ce champ est égal à SDL_DATA_TRACK, alors c'est une piste de données. length contient la taille (la longueur) de la piste. Cette longueur n'est pas indiquée en secondes, mais en frames. En effet, il faut savoir qu'un CD-ROM est organisé en plusieurs (ou une) piste(s), chacune consistant en un certain nombre de frames. Une frame a une taille d'environ 2 ko. A une vitesse normale de lecture, un CD audio est lu à 75 frames par secondes. Quoiqu'il en soit, si vous souhaitez obtenir une unité de longueur de piste plus pratique à manipuler, sachez que la SDL définit la constante CD_FPS qui contient le nombre de frames par secondes (à priori 75), il vous suffit donc de faire SDL_CDtrack.length/CD_FPS pour obtenir une taille de piste en secondes. Vous pouvez aussi utiliser une macro trés pratique : FRAMES_TO_MSF(f, M,S,F), où f est le nombre de frames à convertir, M, S et F des pointeurs respectivement vers des variables de stockage des minutes, des secondes et des frames (des frames restantes aprés la division en secondes, donc des frames qui restent mais pas suffisament pour former une seconde en longueur) correspondantes. Il existe aussi l'inverse de cette macro : MSF_TO_FRAMES(min, sec, frame), qui renvoie le nombre de frames correspondantes aux données temporelles passées comme paramètres.
Enfin, offset est le numero de la frame (depuis le début du CD audio) où est positionné le début de la piste.
[modifier] Lecture audio
Avant de pouvoir lire une ou des pistes audio, il faut vous renseigner concernant le statut du lecteur CD (aucun CD dans le lecteur, CD en cours de lecture…), utilisez CDstatus SDL_CDStatus(SDL_CD *cdrom) pour ce faire. Cette fonction peut renvoyer différents statuts :
- CD_TRAYEMPTY : le lecteur CD est vide
- CD_STOPPED : aucune lecture du CD en cours (mais un CD est présent)
- CD_PLAYING : le CD est en cours de lecture
- CD_PAUSED : la lecture du CD est actuellement mise en pause
- CD_ERROR : une erreur est survenue durant la prise du statut
Ainsi, vous pourrez vérifier que le lecteur contient bien un CD et que celui-ci n'est pas déjà en train d'être lu. Si vous souhaitez connaitre la piste en cours de lecture, vous devez examiner le champ cur_track de la structure SDL_CD qui vous l'indiquera. Par ailleurs, le champ cur_frame de cette même structure vous indiquera la frame actuellement en cours de lecture (du point de vue du CD, et non du point de vue de la piste en cours de lecture), ainsi vous pouvez trés précisément déterminer la position actuelle de lecture sur le CD.
Remarque : la macro CD_INDRIVE, qui prend en paramètre le statut du lecteur CD (renvoyé comme nous l'avons dit par SDL_CDStatus), renvoie 0 si il n'y a aucun CD dans le lecteur, une autre valeur sinon. Cette macro permet d'alléger la lecture du code.
Pour (enfin) lire le CD audio, on dispose de deux fonctions. La première est int SDL_CDPlay(SDL_CD *cdrom, int start, int length). Cette fonction prend en paramètre tout d'abord le descripteur de CD qui a été renvoyé par SDL_CDOpen, puis la frame de début de lecture, enfin la longueur de musique à lire (toujours en frames). Cela peut permettre de faire par exemple un mode intro où on joue uniquement les 10 premières secondes de chaque musique. La fonction renvoie aussi une valeur : 0 si la lecture se déroule avec succés, -1 sinon (en cas d'erreur). La seconde fonction permettant de lire les CD audio est int SDL_CDPlayTracks(SDL_CD *cdrom, int start_track, int start_frame, int ntracks, int nframes)), qui permet de lire plusieurs pistes/morceaux de pistes. Voici la liste de ses arguments avec une petite explication :
- SDL_CD *cdrom : C'est bien sûr le descripteur de CD renvoyé auparavant par SDL_CDOpen.
- int start_track : La piste de début de lecture.
- int start_frame : La frame, à partir du début de la piste de début de lecture, à partir de laquelle commencer la lecture audio (donc 0 si vous voulez commencer depuis le tout début de la piste).
- int ntracks : Le nombres de pistes à lire (à partir de la piste de début - start_track).
- int nframes : La frame, à partir du début de la dernière piste lue (cette dernière piste étant égale à start_track + ntracks), où arréter la lecture audio.
Le renvoi de la fonction SDL_CDPlayTracks suit les même règle que SDL_CDPlay.
Remarque : ces deux fonctions de lecture jouent la musique en arrière plan du programme.
Voici un exemple de code commandant la lecture de la deuxième piste dans son intégralité :
/* Pour stocker plus tard le descripteur de CD */ SDL_CD* mon_cd; /* Initialisation de la partie CD-ROM de la SDL */ if(SDL_Init(SDL_INIT_CDROM)<0) /* En cas d'échec on sort */ exit (1); /* ... ouverture avec SDL_CDopen ... */ /* Lecture de la seconde piste */ if(SDL_CDPlay(mon_cd, mon_cd->track[1].offset, mon_cd->track[1].length)!=0) /* En cas d'échec on sort */ exit (2);
A noter qu'il manque ici la vérification de la présence d'un CD, de l'existence d'une seconde piste, etc. par ailleurs, si on avait voulu lire par exemple la piste 2, suivie de 15 secondes de la 3eme piste, on aurait pu remplacer l'appel à SDL_CDPlay par :
/* Lecture de la seconde piste puis de 15 secondes de la 3eme */ if(SDL_CDPlayTracks(mon_cd, 2, 0, 2, CD_FPS*15)!=0) /* En cas d'échec on sort */ exit (2);
Comme vous l'aurez remarqué, on a indiqué "1" comme piste de début. C'est parce que le numéro de piste spécifié à la fonction SDL_CDPlayTracks est régit par les mêmes règles que les indices de tableaux : ils commencent à 0.
Pour stopper, mettre en pause et reprendre la lecture du CD, il vous faut utiliser respectivement les fonctions int SDL_CDStop(SDL_CD *cdrom), int SDL_CDPause(SDL_CD *cdrom) et int SDL_CDResume(SDL_CD *cdrom). Elles fonctionnent toutes de la même manière, en prenant en paramètre le descripteur de CD sur lequel il faut agir, et en renvoyant 0 si l'opération est un succés, -1 en cas d'erreur.
Enfin, aprés avoir effectué toutes les opérations de lecture désirées, il convient de fermer l'accés au CD à l'aide de la fonction void SDL_CDClose(SDL_CD *cdrom) (qui, bien entendu, prend en paramètre le descripteur du CD à fermer).
[modifier] Fonctions diverses
Il reste encore deux petites fonctions assez utiles concernant les CD audio. La première permet d'ouvrir le cadie du lecteur (où, pour les lecteur dénués de cadies, de simplement éjecter le CD du lecteur). La fonction en question est int SDL_CDEject(SDL_CD *cdrom), elle renvoie -1 en cas d'erreur, 0 sinon. La seconde fonction que nous n'avons pas abordé est const char *SDL_CDName(int drive), qui renvoie un nom humainement lisible du lecteur spécifié en paramètre (le paramètre est en fait le numéro du lecteur - rappel : 0 est le lecteur par défaut du système). Le "nom" renvoyé est trés dépendant du système, ainsi sous windows il pourrait par exemple être "D:\", tandis que sous linux cela pourrait être "/dev/cdrom".
Remarque : Pour toutes les fonctions prenant en paramètre un descripteur CD, en spécifiant NULL c'est le descripteur du dernier CD ouvert qui sera utilisé. Cela peut vous être utile, surtout si vous n'utilisez qu'un seul descripteur de CD durant tout le programme.
[modifier] Pour finir
Vous devriez maintenant être capable de manier la lecture de CD audio en C/C++ avec la SDL ;-). Par ailleurs, ce tutoriel est livré avec un code source d'exemple rédigé en langage C++, qui est en fait un cours programme chargé de jouer les 7 premières secondes de chaque piste d'un CD audio. Ce code source devrait vous aider si un point ne vous parait pas clair ci-dessus ^_^.
Ce document a été publié sur la version 3 du G.C.N. par Solozerk.
- Auteur Original : Solozerk
- Date de publication : 10 mai 2003

