FAQ SDL
FAQ SDLConsultez toutes les FAQ
Nombre d'auteurs : 6, nombre de questions : 67, création le 10 mai 2013
Si vous voulez juste jouer quelques fichiers, vous pouvez simplement utiliser les fonctions définies dans SDL_audio.h.
Ce module ne permet par contre que de manipuler le format WAV, ce qui peut être ennuyeux si vous avez un problème d'utilisation disque (voir https://jeux.developpez.com/faq/sdl/?page=audio#AUDIO_formats).
La bibliothèque de base SDL permet de lire facilement les fichiers au format WAV, mais uniquement ceux-ci. Cependant, il faut travailler un peu pour faire jouer plusieurs morceaux en même temps.
Afin d'accéder à d'autres formats et à d'autres fonctionnalités, on peut utiliser les bibliothèques auxiliaires de la SDL. Les deux possibles sont :
- SDL_sound ;
- SDL_mixer.
Les deux permettent de lire la plupart des formats (WAV, MP3, OGG…). Ensuite, l'avantage de SDL_mixer est la possibilité de facilement faire jouer plusieurs sons en même temps (c'est possible avec SDL_sound, mais cela demande un peu plus de boulot).
Lien : Documentation de référence de SDL_mixer
Lien : Documentation de référence de SDL_sound
Lorsque nous utilisons les fonctions de base SDL pour le son, nous devons définir une fonction qui sera appelée pour jouer les sons (ou mixer). Son prototype est le suivant :
void
joue_audio
(
void
*
udata, Uint8 *
stream, int
len);
Le premier argument est utilisé par le programmeur pour donner des informations diverses ou pour donner les différents flux utilisés. Il s'agit généralement d'un pointeur vers une structure/classe globale qui contient tous les flux audio en cours d'utilisation.
Dire à SDL d'appeler cette fonction se fait avec la fonction suivante :
extern
DECLSPEC int
SDLCALL SDL_OpenAudio(SDL_AudioSpec *
desired, SDL_AudioSpec *
obtained);
Le premier argument représente ce que nous voudrions comme flux, on définit généralement ces éléments de la structure SDL_AudioSpec :
/* Définir le format audio*/
flux.freq =
22050
;
flux.format =
AUDIO_S16;
flux.channels =
2
; /* 1 = mono, 2 = stéréo */
flux.samples =
1024
; /* Une bonne valeur pour le temps entre appels */
flux.callback =
joue_audio; /* Mise en place de l'appel vers notre fonction */
flux.userdata =
nosmusique; /* On utilisera un pointeur vers nos musiques */
On commence par définir une structure permettant d'avoir le flux audio, la position courante dans le flux audio ainsi que sa longueur :
struct
sample
{
Uint8 *
data;
Uint32 dpos;
Uint32 dlen;
}
;
Il faut maintenant la remplir. Nous avons besoin pour cela de quatre variables locales :
void
PlaySound
(
const
char
*
fichier, struct
sample *
son)
{
SDL_AudioSpec wav; /* La structure qui contiendra les informations du fichier */
Uint8 *
donnees; /* Le pointeur vers les données audio */
Uint32 dlong; /* La longueur du flux audio */
SDL_AudioCVT cvt; /* La structure de conversion utilisée par SDL */
Ensuite, on charge le fichier audio :
/* Charger le son en utilisant en SDL_LoadWave */
if
(
SDL_LoadWAV
(
fichier, &
wav, &
donnees, &
dlong) ==
NULL
)
{
fprintf
(
stderr, "
Erreur chargeant %s: %s
\n
"
, fichier, SDL_GetError
(
));
return
;
}
Nous avons maintenant un flux wav, mais nous devons le convertir afin que SDL puisse s'en servir. Ceci se fait avec la fonction SDL_BuildAudioCVT. Les trois derniers paramètres doivent être les mêmes que ce qui a été passé à SDL_OpenAudio (voir https://jeux.developpez.com/faq/sdl/?page=audio#AUDIO_ouvrir_flux).
SDL_BuildAudioCVT
(&
cvt, wav.format, wav.channels, wav.freq, AUDIO_S16, 2
, 22050
);
/* Mise en place de la structure cvs */
cvt.buf =
malloc
(
dlong*
cvt.len_mult);
memcpy
(
cvt.buf, donnees, dlong);
cvt.len =
dlong;
/* On convertit */
SDL_ConvertAudio
(&
cvt);
/* On libère la mémoire */
SDL_FreeWAV
(
donnees);
Ensuite on va mettre à jour notre variable qui va contenir le son. Il se peut que ce son soit en cours d'utilisation. Visiblement, le programme veut utiliser cette zone mémoire, donc on arrête le son pour mettre à jour l'information. Ceci est fait en utilisant les fonctions SDL_LockAudio et SDL_UnlockAudio.
/* Pour arrêter le son pendant qu'on change le pointeur son ; cela arrête le callback */
SDL_LockAudio
(
);
son->
donnees =
cvt.buf;
son->
dlong =
cvt.len_cvt;
son->
dpos =
0
;
/* Pour remettre en place le callback */
SDL_UnlockAudio
(
);
}
Cette fonction est appelée lorsque SDL a terminé de jouer le flux audio courant. Il faut donc mettre dans le flux le reste du son à jouer. Nous pouvons aussi mélanger plusieurs flux audio provenant de différentes sources pour jouer plusieurs morceaux en même temps.
Rappelons que cette fonction prend trois arguments. Le premier est un pointeur vers nos flux audio et, peut-être, d'autres informations nécessaires. Nous définissons ce pointeur lors de l'appel à SDL_OpenAudio.
Dans mon exemple, c'est un pointeur vers un tableau de flux (voir https://jeux.developpez.com/faq/sdl/?page=audio#AUDIO_ouvrir_flux pour l'utilisation de SDL_OpenAudio et la définition de la structure).
Le deuxième paramètre est le flux que SDL va jouer à la sortie de cette fonction. Ce flux a une longueur len. Pour chaque morceau que nous voulons jouer, nous regardons combien d'octets il y a encore à jouer et nous comparons cette longueur avec la longueur du flux à jouer. De façon évidente, nous prenons le minimum des deux.
void
fill_audio
(
void
*
udata, Uint8 *
stream, int
len)
{
int
i; Uint32 amount;
struct
sample *
ptr =
udata;
/* On parcourt chaque son, s'il n'y en a pas dans la case, amount sera égale à 0 */
for
(
i=
0
; i<
NUM_SOUNDS; ++
i )
{
/* On regarde ce qui reste à jouer */
amount =
(
ptr[i].dlen-
ptr[i].dpos);
/* On regarde la taille du flux qu'on va à présent jouer */
if
(
amount >
len )
amount =
len;
/* On mixe le son */
SDL_MixAudio
(
stream, &
ptr[i].data[ptr[i].dpos], amount, SDL_MIX_MAXVOLUME);
/* On met à jour la position du flux audio */
ptr[i].dpos +=
amount;
}
}