TP : visualisation spectrale du son - Programmation

Transcription

TP : visualisation spectrale du son - Programmation
TP : visualisation spectrale du son - Programmation - Lecture du tutorie...
http://www.siteduzero.com/tuto-3-10147-1-tp-visualisation-spectrale-d...
TP : visualisation spectrale du son
Bienvenue dans ce TP SDL & FMOD !
Eh oui, nous utiliserons dans ce TP les librairies SDL et FMOD
simultanément pour réaliser notre programme
Qu'on se le dise : nous n'allons pas créer de jeu ici ! Certes, la
SDL est tout particulièrement adaptée aux jeux, mais ça ne
veut pas dire qu'elle est faite uniquement pour ça. Ce
chapitre va vous prouver qu'elle peut servir à autre chose
Auteur : M@teo21
Créé le : 23/07/2006 à 20h06
Modifié le : 26/05/2007 à
19h05
Noter et commenter ce tutorial
Imprimer ce tutorial
Qu'allons-nous faire ici ? Nous allons réaliser une visualisation du spectre sonore en SDL.
Nooooon ne partez pas, vous allez voir ce n'est pas si compliqué que ça, et en plus ça nous fera travailler :
La gestion du temps
La librairie FMOD
La modification d'une surface pixel par pixel (on n'a pas encore découvert ça, mais ce TP sera l'occasion idéale
!)
Voici un aperçu de ce que nous allons réaliser ici :
1 sur 11
23/08/2007 02:12
TP : visualisation spectrale du son - Programmation - Lecture du tutorie...
http://www.siteduzero.com/tuto-3-10147-1-tp-visualisation-spectrale-d...
C'est le genre de visualisation qu'on peut retrouver dans les lecteurs audio comme Winamp, Windows Media Player ou
encore AmaroK.
Et pour ne rien gâcher, ce n'est pas bien difficile à faire. D'ailleurs, contrairement au TP Mario Sokoban, cette fois
c'est vous qui allez travailler. Ca vous fera un très bon exercice
Sommaire du chapitre :
Les consignes
La solution
Idées d'amélioration
Les consignes
Les consignes sont simples. Suivez-les pas à pas dans l'ordre, et vous n'aurez pas d'ennuis
1/ Lire un MP3
Pour commencer, vous devez créer un programme qui lit un fichier MP3. Vous n'avez qu'à reprendre la chanson
"Home" du groupe Hype que nous avons utilisée dans le chapitre sur FMOD pour illustrer le fonctionnement de la
lecture d'une musique. Si vous avez bien suivi ce chapitre, il ne vous faudra pas plus de quelques minutes pour
arriver à le faire
Je vous conseille au passage de placer le MP3 dans le dossier de votre projet.
2/ Activer le module DSP de FMOD
Je vous avais dit dans le chapitre sur FMOD que nous n'avions pas vu toutes les possibilités de cette librairie. Elle
peut lire aussi des CD, effectuer des enregistrements, des modifications sur le son, etc etc...
Nous allons ici nous intéresser à un de ses modules, appelé DSP.
A quoi servent les fonctions du module DSP ?
Eh bien ce sont justement elles qui nous donnent des informations sur le son, afin que nous puissions réaliser notre
visualisation spectrale.
Il va falloir activer ce module.
Pourquoi ce module n'est-il pas activé par défaut ?
En fait, cela demande pas mal de calculs supplémentaires à l'ordinateur. Comme on n'en a pas toujours besoin, le
module DSP est désactivé par défaut. Heureusement, l'activer est très simple :
Code : C
FSOUND_DSP_SetActive(FSOUND_DSP_GetFFTUnit(), 1);
Le premier paramètre doit toujours être le résultat renvoyé par la fonction FSOUND_DSP_GetFFTUnit().
Quant au second paramètre, c'est un booléen :
2 sur 11
23/08/2007 02:12
TP : visualisation spectrale du son - Programmation - Lecture du tutorie...
http://www.siteduzero.com/tuto-3-10147-1-tp-visualisation-spectrale-d...
Si on envoie VRAI (1), le module DSP est activé.
Si on envoie FAUX (0), le module DSP est désactivé.
Par conséquent, si on veut désactiver le module DSP juste avant la fin du programme, il suffit d'écrire :
Code : C
FSOUND_DSP_SetActive(FSOUND_DSP_GetFFTUnit(), 0);
3/ Récupérer les données spectrales du son
Pour comprendre comment la visualisation spectrale fonctionne, il est indispensable que je vous explique un peu
comment ça marche à l'intérieur (rapidement hein, pas dans le détail, sinon ça va se transformer en cours de maths
).
Un son peut être découpé en fréquences. Certaines fréquences sont basses, d'autres moyennes, et d'autres hautes.
Ce que nous allons faire dans notre visualisation, c'est afficher la quantité de chacune de ces fréquences sous formes
de barres. Plus la barre est grande, plus la fréquence est utilisée.
Sur la gauche de la fenêtre, nous faisons donc apparaître les basses fréquences, et sur la droite les hautes
fréquences.
Mais comment récupérer les quantités de chaque fréquence ?
FMOD nous mâche le travail
Maintenant que le module DSP est activé, on peut faire appel à la fonction FSOUND_DSP_GetSpectrum().
Il n'y a aucun paramètre à lui donner. En revanche, elle vous renvoie quelque chose de très intéressant : un pointeur
3 sur 11
23/08/2007 02:12
TP : visualisation spectrale du son - Programmation - Lecture du tutorie...
http://www.siteduzero.com/tuto-3-10147-1-tp-visualisation-spectrale-d...
vers un tableau de 512 float.
Rappel : le type float est un type décimal, au même titre que double. La différence entre les deux
vient du fait que double est plus précis que float, mais dans notre cas le type float est suffisant. C'est
celui utilisé par FMOD ici, donc c'est celui que nous devrons utiliser nous aussi.
Il vous faudra donc déclarer un pointeur vers float. La fonction FSOUND_DSP_GetSpectrum() vous renvoie le pointeur
sur le tableau, donc sur le premier élément.
En clair, on déclare le pointeur :
Code : C
float *spectre = NULL;
Et lorsque la musique est en train d'être jouée et que le module DSP est activé, on peut récupérer l'adresse du
tableau de 512 float que nous a créé FMOD :
Code : C
spectre = FSOUND_DSP_GetSpectrum();
On peut ensuite parcourir ce tableau pour obtenir les valeurs de chacune des fréquences :
Code : C
spectre[0] // Fréquence la plus basse (à gauche)
spectre[1]
spectre[2]
...
spectre[509]
spectre[510]
spectre[511] // Fréquence la plus haute (à droite)
Chaque fréquence est un nombre décimal compris entre 0 (rien) et 1 (maximum). Votre travail va consister à afficher
une barre plus ou moins grande en fonction de la valeur que contient chaque case du tableau.
Par exemple, si la valeur est 0.5, vous devrez tracer une barre dont la hauteur correspondra à la moitié de la
fenêtre.
Si la valeur est 1, elle devra faire toute la hauteur de la fenêtre.
Généralement, les valeurs sont assez faibles (plutôt proches de 0 que de 1). Je recommande de
multiplier par 4 toutes les valeurs pour mieux voir le spectre.
ATTENTION : si vous faites ça, vérifiez que vous ne dépassez pas 1 (arrondissez à 1 s'il le faut). Si vous vous
retrouvez avec des valeurs supérieures à 1, vous risquez d'avoir des problèmes pour tracer les barres
verticales par la suite !
Mais les barres doivent bouger au fur et à mesure du temps non ? Comme le son change tout le temps,
il faut mettre à jour le graphique. Comment faire ?
Bonne question. En effet, le tableau de 512 floats que vous renvoie FMOD change toutes les 25 ms (pour être à jour
par rapport au son actuel). Il va donc falloir dans votre code que vous relisiez le tableau de 512 floats (en refaisant
4 sur 11
23/08/2007 02:12
TP : visualisation spectrale du son - Programmation - Lecture du tutorie...
http://www.siteduzero.com/tuto-3-10147-1-tp-visualisation-spectrale-d...
appel à FSOUND_DSP_GetSpectrum()) toutes les 25 ms, puis que vous mettiez à jour votre graphique en barres.
Relisez le chapitre sur la gestion du temps en SDL pour vous rappeler comment faire
Vous avez le choix entre une solution à base de GetTicks ou à base de callbacks. Faites ce qui vous paraît le plus
facile.
4/ Réaliser le dégradé
Dans un premier temps, vous pouvez réaliser des barres de couleur unie. Vous pourrez donc créer des surfaces. Il
devra y avoir 512 surfaces : une pour chaque barre. Chaque surface fera donc 1 pixel de large et la hauteur des
surfaces variera en fonction de l'intensité de chaque fréquence.
Toutefois, je vous propose ensuite d'effectuer une amélioration : la barre doit fondre vers le rouge lorsque le son
devient de plus en plus intense. En clair, la barre doit être verte en bas et rouge en haut.
Mais... une surface ne peut avoir qu'une seule couleur si on utilise SDL_FillRect(). On ne peut pas
faire de dégradé !
En effet. On pourrait certes créer des surfaces de 1 pixel de large et 1 pixel de haut pour chaque couleur du
dégradé, mais ça ferait vraiment beaucoup de surfaces à gérer et ce ne serait pas très optimisé !
Comment fait-on pour dessiner pixel par pixel ?
Je ne vous l'ai pas appris auparavant car cette technique ne méritait pas un chapitre entier. Vous allez voir en effet
que ce n'est pas bien compliqué.
En fait, la SDL ne propose aucune fonction pour dessiner pixel par pixel . Mais on a le droit de l'écrire nous-même
Pour ce faire, il faut suivre ces étapes méthodiquement dans l'ordre :
1. Faites appel à la fonction SDL_LockSurface pour annoncer à la SDL que vous allez modifier la surface
manuellement. Cela "bloque" la surface pour la SDL et vous êtes le seul à y avoir accès tant que la surface est
bloquée.
Ici, je vous conseille de ne travailler qu'avec une seule surface : l'écran. Si vous voulez dessiner un pixel à un
endroit précis de l'écran, vous devrez donc bloquer la surface ecran :
Code : C
SDL_LockSurface(ecran);
2. Vous pouvez ensuite modifier le contenu de chaque pixel de la surface. Comme la SDL ne propose aucune
fonction pour faire ça, il va falloir l'écrire nous-même dans notre programme.
Cette fonction, je vous la donne. Je la tire de la documentation de la SDL. Elle est un peu compliquée car elle
travaille sur la surface directement et gère toutes les profondeurs de couleurs (bits par pixel) possibles. Pas
besoin de la retenir ou de la comprendre, faites simplement un copier-coller dans votre programme pour
pouvoir l'utiliser :
Code : C
5 sur 11
23/08/2007 02:12
TP : visualisation spectrale du son - Programmation - Lecture du tutorie...
http://www.siteduzero.com/tuto-3-10147-1-tp-visualisation-spectrale-d...
void setPixel(SDL_Surface *surface, int x, int y, Uint32 pixel)
{
int bpp = surface->format->BytesPerPixel;
Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
switch(bpp) {
case 1:
*p = pixel;
break;
case 2:
*(Uint16 *)p = pixel;
break;
case 3:
if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
p[0] = (pixel >> 16) & 0xff;
p[1] = (pixel >> 8) & 0xff;
p[2] = pixel & 0xff;
} else {
p[0] = pixel & 0xff;
p[1] = (pixel >> 8) & 0xff;
p[2] = (pixel >> 16) & 0xff;
}
break;
case 4:
*(Uint32 *)p = pixel;
break;
}
}
Elle est simple à utiliser. Envoyez les paramètres suivants :
Le pointeur vers la surface à modifier (cette surface doit préalablement avoir été bloquée avec
SDL_LockSurface)
La position en abscisse du pixel à modifier dans la surface (x).
La position en ordonnée du pixel à modifier dans la surface (y).
La nouvelle couleur à donner à ce pixel. Cette couleur doit être au format Uint32, vous pouvez donc la
générer à l'aide de la fonction SDL_MapRGB() que vous connaissez bien maintenant
3. Enfin, lorsque vous avez fini de travailler sur la surface, il ne faut pas oublier de la débloquer en appelant
SDL_UnlockSurface.
Code : C
SDL_UnlockSurface(ecran);
Code résumé d'exemple
Si on résume, vous allez voir que c'est tout simple.
Ce code dessine un pixel rouge au milieu de la surface ecran (donc au milieu de la fenêtre).
Code : C
SDL_LockSurface(ecran); /* On bloque la surface */
setPixel(ecran, ecran->w / 2, ecran->h / 2, SDL_MapRGB(ecran->format, 255, 0, 0)); /* On dessine un pixel rouge au
milieu de l'écran */
SDL_UnlockSurface(ecran); /* On débloque la surface*/
Débrouillez-vous avec ça pour réaliser les dégradés du vert au rouge.
Un indice : il faut utiliser des boucles
(quoi vous aviez deviné tout seul ?
)
6 sur 11
23/08/2007 02:12
TP : visualisation spectrale du son - Programmation - Lecture du tutorie...
http://www.siteduzero.com/tuto-3-10147-1-tp-visualisation-spectrale-d...
La solution
Alors, comment vous avez trouvé le sujet ?
Il est pas bien difficile à appréhender, il faut juste faire quelques calculs surtout pour la réalisation du dégradé.
C'est du niveau de tout le monde, il faut juste réfléchir un petit peu.
Certains mettent plus de temps que d'autres pour trouver la solution. Si vous avez du mal, ce n'est pas bien grave. Ce
qui compte c'est de finir par y arriver.
Quel que soit le projet dans lequel vous vous lancez, vous aurez forcément des petits moments où il ne suffit pas de
savoir programmer, il faut aussi être logique et bien réfléchir.
Je vous donne le code complet ci-dessous. Il est suffisamment commenté.
Code : C
7 sur 11
23/08/2007 02:12
TP : visualisation spectrale du son - Programmation - Lecture du tutorie...
http://www.siteduzero.com/tuto-3-10147-1-tp-visualisation-spectrale-d...
#include <stdlib.h>
#include <stdio.h>
#include <SDL/SDL.h>
#include <FMOD/fmod.h>
#define LARGEUR_FENETRE
512 /* DOIT rester à 512 impérativement car il y a 512 barres (correspondant aux
512 floats) */
#define HAUTEUR_FENETRE
400 /* Vous pouvez la faire varier celle-là par contre :o) */
#define RATIO
(HAUTEUR_FENETRE / 255.0)
#define DELAI_RAFRAICHISSEMENT 25 /* Temps en ms entre chaque mise à jour du graphe. 25 ms est la valeur
minimale. */
void setPixel(SDL_Surface *surface, int x, int y, Uint32 pixel);
int main(int argc, char *argv[])
{
SDL_Surface *ecran = NULL, *ligne = NULL;
SDL_Event event;
SDL_Rect position;
int continuer = 1, hauteurBarre = 0, tempsActuel = 0, tempsPrecedent = 0, i = 0, j = 0;
float *spectre = NULL;
/* Initialisation de FMOD
---------------------On charge FMOD, la musique, on active le module DSP et on lance la lecture
de la musique */
FSOUND_Init(44100, 4, 0);
FSOUND_STREAM* musique = FSOUND_Stream_Open("Hype_Home.mp3", 0, 0, 0);
if (musique == NULL)
{
fprintf(stderr, "Impossible d'ouvrir la musique");
exit(EXIT_FAILURE);
}
FSOUND_DSP_SetActive(FSOUND_DSP_GetFFTUnit(), 1);
FSOUND_Stream_Play(FSOUND_FREE, musique);
/* Initialisation de la SDL
-----------------------On charge la SDL, on ouvre la fenêtre et on écrit dans sa barre de titre.
On récupère au passage un pointeur vers la surface ecran, qui sera la seule
surface utilisée dans ce programme */
SDL_Init(SDL_INIT_VIDEO);
ecran = SDL_SetVideoMode(LARGEUR_FENETRE, HAUTEUR_FENETRE, 32, SDL_SWSURFACE |
SDL_DOUBLEBUF);
SDL_WM_SetCaption("Visualisation spectrale du son", NULL);
/* Boucle principale */
while (continuer)
{
SDL_PollEvent(&event); /* On doit utiliser PollEvent car il ne faut pas attendre d'évènement
de l'utilisateur pour mettre à jour la fenêtre*/
switch(event.type)
{
case SDL_QUIT:
continuer = 0;
break;
}
/* On efface l'écran à chaque fois avant de dessiner le graphe (fond noir */
SDL_FillRect(ecran, NULL, SDL_MapRGB(ecran->format, 0, 0, 0));
/* Gestion du temps
----------------On compare le temps actuel par rapport au temps précédent (dernier passage dans la boucle)
Si ça fait moins de 25 ms (DELAI_RAFRAICHISSEMENT), alors on attend le
temps qu'il faut pour qu'au moins 25 ms se soit écoulées. On met ensuite à
jour tempsPrecedent avec le nouveau temps */
8 sur 11
tempsActuel = SDL_GetTicks();
23/08/2007 02:12
TP : visualisation spectrale du son - Programmation - Lecture du tutorie...
http://www.siteduzero.com/tuto-3-10147-1-tp-visualisation-spectrale-d...
Vous devriez obtenir un résultat correspondant à la capture d'écran que je vous avais montrée au début du chapitre :
Bien entendu, il vaut mieux une animation pour voir le résultat. C'est donc ce que je vous propose ci-dessous
Voir l'animation "Visualisation spectrale du son" (4,3 Mo)
Notez que la compression a réduit la qualité du son et le nombre d'images par seconde.
Le mieux est encore de télécharger le programme complet (avec son code source) pour tester chez soi. Vous pourrez
ainsi apprécier le programme dans les meilleures conditions
Télécharger le projet Code::Blocks complet + l'exécutable Windows (335 Ko)
Il faut impérativement que le fichier "Hype_Home.mp3" soit placé dans le dossier du programme pour
qu'il fonctionne (sinon il s'arrêtera de suite).
Si vous n'avez toujours pas la chanson en question, vous pouvez la télécharger ou bien récupérer une autre
chanson à vous et la renommer en "Hype_Home.mp3".
Idées d'amélioration
Comment améliorer un truc parfait ?
Il est toujours possible d'améliorer un programme. Ici, j'ai par exemples des tonnes d'idées d'extensions qui
pourraient aboutir à la création d'un véritable petit lecteur MP3.
9 sur 11
23/08/2007 02:12
TP : visualisation spectrale du son - Programmation - Lecture du tutorie...
http://www.siteduzero.com/tuto-3-10147-1-tp-visualisation-spectrale-d...
Il serait bien qu'on puisse choisir le MP3 qu'on veut lire. Il faudrait par exemple lister tous les .mp3 présents
dans le dossier du programme. On n'a pas vu comment faire ça, mais vous pouvez le découvrir par vous-même
Indice : utilisez la librairie dirent (il faudra inclure dirent.h). A vous de chercher des informations sur le
net pour savoir comment l'utiliser. L'idéal est d'être capable de lire la doc à ce sujet.
Si votre programme était capable de lire et gérer les playlists, ça serait encore mieux. Il existe plusieurs
formats de playlist, le plus connu est le format M3U.
Exemple de fichier playlist au format M3U :
Code : Autre
#EXTM3U
#EXTINF:0,01 - Home.mp3
01 - Home.mp3
#EXTINF:0,02 - My Innocence.mp3
02 - My Innocence.mp3
#EXTINF:0,03 - Scream.mp3
03 - Scream.mp3
#EXTINF:0,04 - Anybody here.mp3
04 - Anybody here.mp3
#EXTINF:0,05 - Get there.mp3
05 - Get there.mp3
#EXTINF:0,06 - Spirits above.mp3
06 - Spirits above.mp3
Vous pourriez afficher le nom du MP3 en cours de lecture dans la fenêtre (il faudra utiliser SDL_ttf)
Vous pourriez afficher un indicateur pour qu'on sache où en est de la lecture du morceau, comme cela se fait
sur la plupart des lecteurs MP3.
Vous pourriez aussi proposer de modifier le volume de lecture
etc etc...
Bref, il y a beaucoup à faire.
Vous avez la possibilité de créer de beaux lecteurs, il ne tient plus qu'à vous de les coder
S'il y a une chose à retenir de ce TP, c'est que la difficulté quand on programme n'est pas toujours de savoir
quelle
fonction utiliser pour tel effet. La preuve : je vous ai donné toutes les fonctions nécessaires dès le début de ce TP.
Non, la difficulté consiste à réfléchir correctement pour arriver à résoudre un problème. C'est quelque chose que
vous rencontrerez quel que soit le langage utilisé. On dit que c'est un problème d'algorithmique : il faut arriver à
écrire le meilleur code source pour arriver au résultat que l'on veut.
Ici, il y avait 2 problèmes algorithmiques :
Le dessin des barres verticales, qu'il fallait adapter en fonction de la hauteur de la fenêtre. Vous avez dû faire
un petit calcul pour transformer un nombre entre 0 et 1 en un nombre entre 0 et HAUTEUR_FENETRE pour
pouvoir tracer les barres.
Le dégradé du vert au rouge. Il fallait là encore faire quelques calculs pas bien compliqués sur une variable
pour l'adapter en une valeur comprise entre 0 et 255
Lire la solution n'a que peu d'intérêt. D'ailleurs pour être franc, je crois que si j'avais lu cette solution avant d'avoir
réfléchi au problème, ça m'aurait découragé. Il est en effet toujours plus difficile de lire le code source d'un autre
que de l'écrire.
D'où l'intérêt de prendre le temps qu'il faut, mais de le faire soi-même
N'ayez donc pas peur si vous ne comprenez pas instantanément tous les codes sources que vous lisez. Personne ne
peut se vanter de savoir faire ça.
10 sur 11
23/08/2007 02:12
TP : visualisation spectrale du son - Programmation - Lecture du tutorie...
http://www.siteduzero.com/tuto-3-10147-1-tp-visualisation-spectrale-d...
Ce qui compte, c'est d'y arriver tout seul, quel que soit le temps que vous mettez. Au fur et à mesure, vous
deviendrez habitué à ce genre de problèmes d'algorithmique et il vous faudra de moins en moins de temps pour les
résoudre
Auteur : M@teo21
Noter et commenter ce tutorial
Imprimer ce tutorial
11 sur 11
23/08/2007 02:12