begin process at 2012 05 27 18:50:00
  Trouver un code source :
 
dans
 
Accueil > 

Code

 > 

Multimédia

 > MOTEUR DE SON UTILISANT FMOD (C++) (WAV-MIDI-MP3-ETC...)

MOTEUR DE SON UTILISANT FMOD (C++) (WAV-MIDI-MP3-ETC...)


 Information sur la source

Note :
9,5 / 10 - par 4 personnes
9,50 / 10

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10
Catégorie :Multimédia Niveau :Débutant Date de création :08/05/2004 Date de mise à jour :08/05/2004 02:19:23 Vu / téléchargé :11 593 / 720

Auteur : metalmigoule

Ecrire un message privé
Commentaire sur cette source (10)
Ajouter un commentaire et/ou une note

 Description

Ce petit moteur sonore est vraiment le B-A BA de ce
que l'on peut faire avec Fmod.

Il est réalisé en C/C++ mais d'autres
langages aurais aussi bien pu faire l'affaire ...

Il va sagir d'initialiser/désinitialiser Fmod,
de pouvoir ajouter/retirer des sons stockés à l'intérieur
d'un vector (utilisé pour l'occasion comme un petit tableau dynamique),
et de pouvoir les jouer et les stopper quand on le désire.

Donc en résumé, tout ça restera très basique : pas de son 3D, pas d'effets ou de fioritures...
Ce tut est donc réservé aux débutants (dont je fais partie ;-)) désirant avoir une première approche évoluée de ce que peut apporter la prise en charge du son dans un prog...


J'ai réalisé ce SoundEngine sous Visual C++ 6, donc je ne peux
expliquer comment régler l'environnement que sur VS.

Mais la doc de Fmod étant très complète, je vous propose d'aller y jeter
un oeil si vous êtes allergiques à Microsoft, tout sera expliqué en détail pour les autres EDI.  

Donc pour commencer vous n'aurez besoin de 3 choses :
- la librairie fmodvc.lib à inclure dans le projet (spécifique ici à VS6 !)
- le fichier d'entête fmod.h
- la dll de Fmod : fmod.dll à mettre soit dans le
répertoire de l'exécutable, soit dans system32
Vous trouverez tout ça en téléchargeant l'api Fmod sur le site de Fmod (http://www.fmod.org)

Après, c'est que du code, mais rien de bien méchant vous allez voir.

Source

  • 1. Création d'une classe intermédiaire, la classe Son
  • INTERFACE
  • class Son
  • {
  • public:
  • Son() {}
  • ~Son() {}
  • //format
  • int format;
  • FSOUND_STREAM * stream;
  • FSOUND_SAMPLE * sample;
  • FMUSIC_MODULE * module;
  • //charge un fichier son
  • BOOL Charger(char *fichAdr, int format);
  • void Liberer(void);
  • //joue et un stoppe le son
  • BOOL Jouer(void);
  • void Stopper(void);
  • };
  • Vous vous demandez sûrement quels sont les formats de sons évoqués ci-dessus. C'est tout simple. On peut disinguer 3 grandes sortes de sons :
  • - les gros fichiers WAV/MP3/etc... stockés en stream
  • - les petits fichiers WAV/MP3/etc... stockés en sample
  • - les fichiers MIDI/etc... stockés en modules
  • Remarque : c'est à l'utilisateur lui-même de savoir à l'avance quel format de fichier va être chargé
  • Remarque : un petit point important : Fmod est séparé en deux plus petites api, FSound et FMusic. Chacune est spécialisée dans le traitement d'une famille de son. FSound pour les stream et sample et FMusic pour les modules.
  • Pour chaque son il y a donc un pointeur vers chacune de ces structures.
  • On définit pour cela quelques constantes qui vont être passées en argument lors du chargement des sons :
  • //gros mp3/wav -> loop
  • #define STREAM_TYPE 0
  • //petits mp3/wav -> joués une fois
  • #define SAMPLE_TYPE 1
  • //midi et autres -> loop
  • #define MODULE_TYPE_MUSIC 2
  • //midi et autres -> joués une fois
  • #define MODULE_TYPE_SOUND 3
  • Les autres fonctions parlant d'elles-même, passons à la réalisation.
  • Nous n'allons exposer ici que la méthode de chargement. Etant la plus "complexe" (^_^ toute proportion gardée), elle va nous permettre de poser quelques bases :
  • REALISATION
  • /* Charge un son en fonction du format spécifié*/
  • BOOL Son::Charger(char *fichAdr, int format)
  • {
  • BOOL result = TRUE;
  • //on stocke le format du son
  • this->format = format;
  • //on charge suivant le format
  • switch(format)
  • {
  • //stream
  • case STREAM_TYPE:
  • stream = NULL;
  • stream = FSOUND_Stream_OpenFile(fichAdr, FSOUND_LOOP_NORMAL, 0);
  • if(stream == NULL)
  • result = FALSE;
  • break;
  • //sample
  • case SAMPLE_TYPE:
  • sample = NULL;
  • sample = FSOUND_Sample_Load(FSOUND_FREE, fichAdr, FSOUND_LOOP_OFF, 0);
  • if(sample == NULL)
  • result = FALSE;
  • break;
  • //module loop
  • case MODULE_TYPE_MUSIC:
  • module = NULL;
  • module = FMUSIC_LoadSong(fichAdr);
  • FMUSIC_SetMasterVolume(module, 160);
  • if(module == NULL)
  • result = FALSE;
  • break;
  • //module simple
  • case MODULE_TYPE_SOUND:
  • module = NULL;
  • module = FMUSIC_LoadSong(fichAdr);
  • FMUSIC_SetMasterVolume(module, 160);
  • FMUSIC_SetLooping(module,FALSE);
  • if(module == NULL)
  • result = FALSE;
  • break;
  • //si aucun init fail
  • default:
  • result = FALSE;
  • break;
  • }
  • return result;
  • }
  • Remarque : j'ai choisi de régler du volume des sons de type module juste après leur chargement.
  • Il faut savoir que pour ce type de fichiers particulier, le volume se règle individuellement pour chaque module (de 0 à 255 - 160 étant un bon compromis).
  • On aurais aussi bien pu régler tout ça par la suite, mais autant le faire depuis le début....
  • Ce qu'il faut bien remarquer dans cette méthode est le passage en paramètre du format du son. Comme je l'ai évoqué plus haut, c'est donc à l'utilisateur de savoir quel sont il va charger au moment de l'appel de la procédure.
  • J'ai également fait un choix (contestable, mais se révèlant après expérience plutôt concluant) : les répétitions.
  • C'est-à-dire le nombre de fois qu'un son va être joué d'affilé : les stream et les modules de type musique sont répétées à l'infini, tandis que les sample et les modules de type son ne sont joués qu'une fois.
  • On aurais très bien pu complexifier cette fonction de chargement pour la rendre plus "customisable"... Mais le principal caractère de ce moteur étant son accessibilité, je n'ai rien inplémenté de tel.
  • Excepté ces petits détails, aucune difficulté (consultez la doc de Fmod pour les méthodes de chargement (d'ailleurs très simples à utiliser)).
  • Le reste des méthodes, Jouer/Stopper et Liberer ne necessitent pas selon moi de longues explications si l'on à compris comment était réalisée la méthode Charger.
  • A noter tout de même que la fonction Charger ne libére rien au moment de charger un son. Pensez donc bien à libérer un son avant de vouloir le recharger à partir d'un autre fichier.
  • Voilà les autres fonction.
  • /* Libère le son*/
  • void Son::Liberer(void)
  • {
  • //si c'est une stream ou un module on libère
  • if(format == STREAM_TYPE)
  • {
  • FSOUND_Stream_Close(stream);
  • stream=NULL;
  • }
  • else if(format == MODULE_TYPE_MUSIC
  • || format == MODULE_TYPE_SOUND)
  • {
  • FMUSIC_FreeSong(module);
  • module=NULL;
  • }
  • }
  • /* Joue le son en fonction du format*/
  • BOOL Son::Jouer(void)
  • {
  • //on joue suivant le type de format
  • switch(format)
  • {
  • //stream (loop)
  • case STREAM_TYPE:
  • if(FSOUND_Stream_Play(FSOUND_FREE, stream) == -1)
  • return FALSE;
  • break;
  • //sample
  • case SAMPLE_TYPE:
  • if(FSOUND_PlaySound(FSOUND_FREE, sample) == -1)
  • return FALSE;
  • break;
  • //module (loop)
  • case MODULE_TYPE_MUSIC:
  • if(FMUSIC_PlaySong(module) == NULL)
  • return FALSE;
  • break;
  • //module
  • case MODULE_TYPE_SOUND:
  • if(FMUSIC_PlaySong(module) == NULL)
  • return FALSE;
  • break;
  • default:
  • break;
  • }
  • return TRUE;
  • }
  • /* Stope la lecture en cours d'une stream ou d'un module*/
  • void Son::Stopper(void)
  • {
  • //si c'est une stream ou un module on stoppe
  • if(format == STREAM_TYPE)
  • FSOUND_Stream_Stop(stream);
  • else if(format == MODULE_TYPE_MUSIC
  • ||format == MODULE_TYPE_SOUND)
  • FMUSIC_StopSong(module);
  • }
  • 2. La classe SoundEngine
  • Voilà comment elle se présente :
  • INTERFACE
  • class SoundEngine
  • {
  • public :
  • vector<Son> sons;
  • SoundEngine() {}
  • ~SoundEngine() {}
  • /* Initialise tout :
  • * mixRate = frequence de sortie
  • * maxChannels = nombre de sons pouvant être traité à la fois
  • */
  • BOOL Initialiser(int mixRate, int maxChannels);
  • //On désinitialise tout
  • BOOL Desinitialiser(void);
  • /* Charge un nouveau son :
  • * fichAdr = adresse du fichier son
  • * format = stream/sample/module (voir constantes)
  • */
  • BOOL AjouterSon(Son son);
  • BOOL AjouterSon(Son son, int index);
  • BOOL AjouterSon(char *fichAdr, int format);
  • BOOL AjouterSon(char *fichAdr, int format, int index);
  • //Retire un son, soit à un index donné, soit le dernier chargé
  • BOOL RetirerSon(void);
  • BOOL RetirerSon(int index);
  • //Joue le son
  • BOOL Jouer(int index);
  • //Stoppe le son
  • BOOL Stopper(int index);
  • };
  • On peut distinguer 3 types de méthodes :
  • - Initialisation : Initialiser/Desinitialiser
  • - Stockage : AjouterSon/RetirerSon
  • - Rendu : Jouer/Stopper
  • Pour stocker les sons j'utilise un vector de Son Pour ceux qui ne savent pas ce que c'est qu'un vector, c'est en fait une fonctionnalité faisant partie de la stl - bibliothèque de classes container - permettant en autres de créer de tableaux dynamique efficacement. Il permet d'éviter l'enchainement des new et delete en cascade et ainsi pas mal de problèmes ^_^.
  • Allez faire un tour sur la page des liens si vous voulez en savoir plus.
  • REALISATION
  • Bon, voilà le code :
  • /*Initialisation*/
  • BOOL SoundEngine::Initialiser(int mixRate, int maxChannels)
  • {
  • //On definit le volume des mp3 et wave
  • FSOUND_SetVolume(FSOUND_ALL,160);
  • return FSOUND_Init(mixRate, maxChannels, FSOUND_INIT_USEDEFAULTMIDISYNTH );
  • }
  • Remarque : on règle ici le volume des stream et des sample (map3 et wav principalement). Le volume de ces format ne sont pas réglés individuellement pour chaque son, comme pour les modules, mais globalement. A noter que cette fonctionalité est utilisable à n'importe quel moment dans un programme.
  • /*Desinitialisation*/
  • BOOL SoundEngine::Desinitialiser(void)
  • {
  • BOOL init = TRUE;
  • try
  • {
  • //on stoppe et libère les sons
  • for(int i=0; i<sons.size(); i++)
  • {
  • sons.at(i).Stopper();
  • sons.at(i).Liberer();
  • }
  • }
  • catch(...)
  • {
  • init = FALSE;
  • }
  • //on ferme Fmod
  • FSOUND_Close();
  • return init;
  • }
  • Remarque : attention à ne pas l'oublier, la bonne libération des objets peut éviter bien des soucis par la suite (surtout sous Win9x...)
  • /*Ajoute un son dans le vector - Ver1*/
  • BOOL SoundEngine::AjouterSon(Son son)
  • {
  • //on le range dans le vector
  • sons.push_back(son);
  • return TRUE;
  • }
  • /*Ajoute un son dans le vector - Ver2*/
  • BOOL SoundEngine::AjouterSon(Son son, int index)
  • {
  • //si l'index dépasse la capacité du vector
  • if(index < 0 || index > sons.size() - 1)
  • return FALSE;
  • vector<Son>::iterator it;
  • it = sons.begin();
  • it += index;
  • //on le range dans le vector à l'index indiqué
  • sons.insert(it, son);
  • return TRUE;
  • }
  • /*Ajoute un son dans le vector - Ver3*/
  • BOOL SoundEngine::AjouterSon(char *fichAdr, int format)
  • {
  • Son temp;
  • if(!temp.Charger(fichAdr, format))
  • return FALSE;
  • //on le range dans le vector
  • sons.push_back(temp);
  • return TRUE;
  • }
  • /*Ajoute un son dans le vector - Ver4*/
  • BOOL SoundEngine::AjouterSon(char *fichAdr, int format, int index)
  • {
  • Son temp;
  • //si l'index dépasse la capacité du vector
  • if(index < 0 || index > sons.size() - 1)
  • return FALSE;
  • //on charge un objet temporaire
  • if(!temp.Charger(fichAdr, format))
  • return FALSE;
  • vector<Son>::iterator it;
  • it = sons.begin();
  • it += index;
  • //on le range dans le vector à l'index indiqué
  • sons.insert(it, temp);
  • return TRUE;
  • }
  • Remarque : 4 versions pour une même méthode. On peut ainsi ajouter des sons directement à partir d'une classe Son mais également en fournissant simplement le chemin d'accès au fichier ainsi que son format. Il est également possible de choisir où ce son sera stocké dans le vector.
  • /*Retire un son du vector - Ver1*/
  • BOOL SoundEngine::RetirerSon(void)
  • {
  • //on retire le dernier son chargé
  • sons.pop_back();
  • return TRUE;
  • }
  • /*Retire un son du vector - Ver2*/
  • BOOL SoundEngine::RetirerSon(int index)
  • {
  • //si l'index dépasse la capacité du vector
  • if(index > sons.size() - 1 || index < 0)
  • return FALSE;
  • vector<Son>::iterator it;
  • it = sons.begin();
  • it += index;
  • //on retire le son à l'index indiqué
  • sons.erase(it);
  • return TRUE;
  • }
  • Remarque : 2 versions pour cette méthode. Cela va permettre de pouvoir retirer un son à n'importe quel endroit du vector.
  • /*Joue le son situé à l'index indiqué*/
  • BOOL SoundEngine::Jouer(int index)
  • {
  • //si l'index dépasse la capacité du vector
  • if(index > sons.size() - 1 || index < 0)
  • return FALSE;
  • sons[index].Jouer();
  • return TRUE;
  • }
  • /*Stoppe le son indiqué*/
  • BOOL SoundEngine::Stopper(int index)
  • {
  • //si l'index dépasse la capacité du vector
  • if(index > sons.size() - 1 || index < 0)
  • return FALSE;
  • //on joue le son
  • sons[index].Stopper();
  • return TRUE;
  • }
  • Remarque : Pour jouer et stopper les sons, on utilise directement
  • la fonction contenue dans la classe Son, après avoir bien
  • sur testé la validité de l'index fournis en paramètre.
  • Voilà, c'est tout pour la création du SoundEngine.
  • Si vous avez des questions n'hésitez pas à me contacter.
  • Passons maintenant à son utilisation au sein de votre programme.
  • 3. Utilisation
  • Tout d'abord, vous devez déclarer une variable
  • de type SoundEngine (ici globale mais on peut adapter).
  • //variable de type SoundEngine
  • SoundEngine soundEngine;
  • //Viens ensuite l'initialisation :
  • //fréquence à 44khz et 32 cannaux
  • soundEngine.Initialiser(44000, 32);
  • //On peut maintant ajouter des sons :
  • //ajout de sons avec une classe Son déjà déclarée
  • Son temp;
  • temp.Charger("grosMP3.mp3", TYPE_STREAM);
  • soundEngine.AjouterSon(temp);
  • temp.Liberer();
  • temp.Charger("petitWAV.wav", TYPE_SAMPLE);
  • soundEngine.AjouterSon(temp, 1);
  • temp.Liberer();
  • temp.Charger("midiMusique1.mid", MODULE_TYPE_MUSIC);
  • soundEngine.AjouterSon(temp);
  • temp.Liberer();
  • temp.Charger("midiSon1.mid", MODULE_TYPE_SOUND);
  • soundEngine.AjouterSon(temp);
  • temp.Liberer();
  • //ajout de sons par chemin d'accés
  • soundEngine.AjouterSon("petitMP3.mp3", SAMPLE_TYPE);
  • soundEngine.AjouterSon("grosWAV.wav", STREAM_TYPE);
  • soundEngine.AjouterSon("midiMusique1.mid", MODULE_TYPE_MUSIC);
  • soundEngine.AjouterSon("midiSon1.mid", MODULE_TYPE_SOUND, 0);
  • //Par exemple.
  • //On peut maintenant les jouer/stopper.
  • ...
  • //jouera midiSon1.mid
  • soundEngine.Jouer(0);
  • //jouera grosMP3.mp3
  • soundEngine.Jouer(1);
  • ...
  • //arretera la lecture
  • soundEngine.Stopper(0);
  • //arretera la lecture
  • soundEngine.Stopper(1);
  • ...
  • //jouera grosWAV.wav
  • soundEngine.Jouer(6);
  • ...
  • //arretera la lecture
  • soundEngine.Stopper(6);
  • //A la fin de votre programme il ne vous restera plus qu'à désinitialiser :
  • //désinitialise Fmod et libère tous les sons chargés
  • soundEngine.Desinitialiser();
  • Voilà c'est tout !
  • Si vous voyez des erreurs, prévenez-moi je corrigerais tout ça dès que je pourrais.
  • Si vous avez des conseils concernant ce SoundEngine, n'hésitez pas non plus à me contacter ;-).
  • J'ai fournit une archive contenat le fichier d'entête et de réalisation.
  • Bonne lecture. Fab
1. Création d'une classe intermédiaire, la classe Son


INTERFACE

class Son 
{
      public:
      Son() {}
      ~Son() {}

      //format
      int format;
      FSOUND_STREAM * stream;
      FSOUND_SAMPLE * sample;
      FMUSIC_MODULE * module;

      //charge un fichier son
      BOOL Charger(char *fichAdr, int format);
      void Liberer(void);

      //joue et un stoppe le son
      BOOL Jouer(void);
      void Stopper(void);
};


Vous vous demandez sûrement quels sont les formats de sons évoqués ci-dessus. C'est tout simple. On peut disinguer 3 grandes sortes de sons :
- les gros fichiers WAV/MP3/etc... stockés en stream
- les petits fichiers WAV/MP3/etc... stockés en sample
- les fichiers MIDI/etc... stockés en modules


Remarque : c'est à l'utilisateur lui-même de savoir à l'avance quel format de fichier va être chargé

Remarque : un petit point important : Fmod est séparé en deux plus petites api, FSound et FMusic. Chacune est spécialisée dans le traitement d'une famille de son. FSound pour les stream et sample et FMusic pour les modules.


Pour chaque son il y a donc un pointeur vers chacune de ces structures. 

On définit pour cela quelques constantes qui vont être passées en argument lors du chargement des sons :

//gros mp3/wav -> loop
#define STREAM_TYPE    0
//petits mp3/wav -> joués une fois
#define SAMPLE_TYPE    1
//midi et autres -> loop
#define MODULE_TYPE_MUSIC    2
//midi et autres -> joués une fois
#define MODULE_TYPE_SOUND   3


Les autres fonctions parlant d'elles-même, passons à la réalisation.

Nous n'allons exposer ici que la méthode de chargement. Etant la plus "complexe" (^_^ toute proportion gardée), elle va nous permettre de poser quelques bases :




REALISATION

/* Charge un son en fonction du format spécifié*/
BOOL Son::Charger(char *fichAdr, int format)
{
      BOOL result = TRUE;

      //on stocke le format du son
      this->format = format;

      //on charge suivant le format
      switch(format)
      {
            //stream
            case STREAM_TYPE:
            stream = NULL;
            stream = FSOUND_Stream_OpenFile(fichAdr,                   FSOUND_LOOP_NORMAL, 0);
            if(stream == NULL)
                  result = FALSE;
            break;

            //sample
            case SAMPLE_TYPE:
            sample = NULL;
            sample =                   FSOUND_Sample_Load(FSOUND_FREE, fichAdr,             FSOUND_LOOP_OFF, 0);
            if(sample == NULL)
                  result = FALSE;
            break;

            //module loop
            case MODULE_TYPE_MUSIC:
            module = NULL;
            module = FMUSIC_LoadSong(fichAdr);
            FMUSIC_SetMasterVolume(module, 160);
            if(module == NULL)
                  result = FALSE;
            break;

            //module simple
            case MODULE_TYPE_SOUND:
            module = NULL;
            module = FMUSIC_LoadSong(fichAdr);
            FMUSIC_SetMasterVolume(module, 160);
            FMUSIC_SetLooping(module,FALSE);
            if(module == NULL)
                  result = FALSE;
            break;

            //si aucun init fail
            default:
            result = FALSE;
            break;
      }

      return result;
}


Remarque : j'ai choisi de régler du volume des sons de type module juste après leur chargement. 
Il faut savoir que pour ce type de fichiers particulier, le volume se règle individuellement pour chaque module (de 0 à 255 - 160 étant un bon compromis).
On aurais aussi bien pu régler tout ça par la suite, mais autant le faire depuis le début.... 

Ce qu'il faut bien remarquer dans cette méthode est le passage en paramètre du format du son. Comme je l'ai évoqué plus haut, c'est donc à l'utilisateur de savoir quel sont il va charger au moment de l'appel de la procédure.

J'ai également fait un choix (contestable, mais se révèlant après expérience plutôt concluant) : les répétitions.
C'est-à-dire le nombre de fois qu'un son va être joué d'affilé : les stream et les modules de type musique sont répétées à l'infini, tandis que les sample et les modules de type son ne sont joués qu'une fois.
On aurais très bien pu complexifier cette fonction de chargement pour la rendre plus "customisable"... Mais le principal caractère de ce moteur étant son accessibilité, je n'ai rien inplémenté de tel.

Excepté ces petits détails, aucune difficulté (consultez la doc de Fmod pour les méthodes de chargement (d'ailleurs très simples à utiliser)).

Le reste des méthodes, Jouer/Stopper et Liberer ne necessitent pas selon moi de longues explications si l'on à compris comment était réalisée la méthode Charger.

A noter tout de même que la fonction Charger ne libére rien au moment de charger un son. Pensez donc bien à libérer un son avant de vouloir le recharger à partir d'un autre fichier.

Voilà les autres fonction.

/* Libère le son*/
void Son::Liberer(void)
{
      //si c'est une stream ou un module on libère
      if(format == STREAM_TYPE)
      {
            FSOUND_Stream_Close(stream);
            stream=NULL;
      }
      else if(format == MODULE_TYPE_MUSIC 
             || format == MODULE_TYPE_SOUND)
      {
            FMUSIC_FreeSong(module);
            module=NULL;
      }
}

/* Joue le son en fonction du format*/
BOOL Son::Jouer(void)
{
      //on joue suivant le type de format
      switch(format)
      {
            //stream (loop)
            case STREAM_TYPE:
            if(FSOUND_Stream_Play(FSOUND_FREE,                                                       stream) == -1)
                  return FALSE;
            break;

            //sample
            case SAMPLE_TYPE:
            if(FSOUND_PlaySound(FSOUND_FREE,                                                       sample) == -1)
                  return FALSE;
            break;

            //module (loop)
            case MODULE_TYPE_MUSIC:
            if(FMUSIC_PlaySong(module) == NULL)
                  return FALSE;
            break;

            //module
            case MODULE_TYPE_SOUND:
            if(FMUSIC_PlaySong(module) == NULL)
                  return FALSE;
            break;

            default:
            break;
      }

      return TRUE;
}

/* Stope la lecture en cours d'une stream ou d'un module*/
void Son::Stopper(void)
{
      //si c'est une stream ou un module on stoppe
      if(format == STREAM_TYPE)
            FSOUND_Stream_Stop(stream);
      else if(format == MODULE_TYPE_MUSIC
              ||format == MODULE_TYPE_SOUND)
            FMUSIC_StopSong(module);
} 





2. La classe SoundEngine

Voilà comment elle se présente :

INTERFACE

class SoundEngine
{
      public :
      vector<Son> sons;

      SoundEngine() {}
      ~SoundEngine() {}

      /* Initialise tout : 
      * mixRate = frequence de sortie
      * maxChannels = nombre de sons pouvant être          traité à la fois
      */
      BOOL Initialiser(int mixRate, int maxChannels);

      //On désinitialise tout
      BOOL Desinitialiser(void);

      /* Charge un nouveau son :
      * fichAdr = adresse du fichier son
      * format = stream/sample/module (voir constantes) 
      */
      BOOL AjouterSon(Son son);
      BOOL AjouterSon(Son son, int index);
      BOOL AjouterSon(char *fichAdr, int format);
      BOOL AjouterSon(char *fichAdr, int format, int                                      index);

      //Retire un son, soit à un index donné, soit le dernier       chargé
      BOOL RetirerSon(void);
      BOOL RetirerSon(int index);

      //Joue le son
      BOOL Jouer(int index);

      //Stoppe le son
      BOOL Stopper(int index);
};


On peut distinguer 3 types de méthodes :

- Initialisation : Initialiser/Desinitialiser
- Stockage : AjouterSon/RetirerSon
- Rendu : Jouer/Stopper

Pour stocker les sons j'utilise un vector de Son Pour ceux qui ne savent pas ce que c'est qu'un vector, c'est en fait une fonctionnalité faisant partie de la stl - bibliothèque de classes container - permettant en autres de créer de tableaux dynamique efficacement. Il permet d'éviter l'enchainement des new et delete en cascade et ainsi pas mal de problèmes ^_^.
Allez faire un tour sur la page des liens si vous voulez en savoir plus.


REALISATION

Bon, voilà le code :

/*Initialisation*/
BOOL SoundEngine::Initialiser(int mixRate, int                                                 maxChannels) 
{
      //On definit le volume des mp3 et wave
      FSOUND_SetVolume(FSOUND_ALL,160);

      return FSOUND_Init(mixRate, maxChannels, FSOUND_INIT_USEDEFAULTMIDISYNTH );
}


Remarque : on règle ici le volume des stream et des sample (map3 et wav principalement). Le volume de ces format ne sont pas réglés individuellement pour chaque son, comme pour les modules, mais globalement. A noter que cette fonctionalité est utilisable à n'importe quel moment dans un programme.


/*Desinitialisation*/
BOOL SoundEngine::Desinitialiser(void)
{
      BOOL init = TRUE;

      try 
      {
            //on stoppe et libère les sons
            for(int i=0; i<sons.size(); i++)
            {
                  sons.at(i).Stopper();
                  sons.at(i).Liberer();
            }
      }
      catch(...) 
      {
            init = FALSE;
      }

      //on ferme Fmod
      FSOUND_Close();

      return init;
}

Remarque : attention à ne pas l'oublier, la bonne libération des objets  peut éviter bien des soucis par la suite (surtout sous Win9x...)



/*Ajoute un son dans le vector - Ver1*/
BOOL SoundEngine::AjouterSon(Son son)
{
      //on le range dans le vector
      sons.push_back(son);

      return TRUE;
}


/*Ajoute un son dans le vector - Ver2*/
BOOL SoundEngine::AjouterSon(Son son, int index)
{
      //si l'index dépasse la capacité du vector
      if(index < 0 || index > sons.size() - 1)
            return FALSE;

      vector<Son>::iterator it;
      it = sons.begin();
      it += index;

      //on le range dans le vector à l'index indiqué
      sons.insert(it, son);

      return TRUE;
}


/*Ajoute un son dans le vector - Ver3*/
BOOL SoundEngine::AjouterSon(char *fichAdr, int format)
{ 
      Son temp;

      if(!temp.Charger(fichAdr, format))
            return FALSE;

      //on le range dans le vector
      sons.push_back(temp);

      return TRUE;
}

/*Ajoute un son dans le vector - Ver4*/
BOOL SoundEngine::AjouterSon(char *fichAdr, int                                                     format, int index)
{
      Son temp;

      //si l'index dépasse la capacité du vector
      if(index < 0 || index > sons.size() - 1)
            return FALSE;

      //on charge un objet temporaire
      if(!temp.Charger(fichAdr, format))
            return FALSE;

      vector<Son>::iterator it;
      it = sons.begin();
      it += index;

      //on le range dans le vector à l'index indiqué
      sons.insert(it, temp);

      return TRUE;
}

Remarque : 4 versions pour une même méthode. On peut ainsi ajouter des sons directement à partir d'une classe Son mais également en fournissant simplement le chemin d'accès au fichier ainsi que son format. Il est également possible de choisir où ce son sera stocké dans le vector.



/*Retire un son du vector - Ver1*/
BOOL SoundEngine::RetirerSon(void)
{
      //on retire le dernier son chargé
      sons.pop_back();

      return TRUE;
}

/*Retire un son du vector - Ver2*/
BOOL SoundEngine::RetirerSon(int index)
{
      //si l'index dépasse la capacité du vector
      if(index > sons.size() - 1 || index < 0)
            return FALSE;

      vector<Son>::iterator it;
      it = sons.begin();
      it += index;

      //on retire le son à l'index indiqué
      sons.erase(it);

      return TRUE;
}


Remarque : 2 versions pour cette méthode. Cela va permettre de pouvoir retirer un son à n'importe quel endroit du vector.



/*Joue le son situé à l'index indiqué*/
BOOL SoundEngine::Jouer(int index)
{
      //si l'index dépasse la capacité du vector
      if(index > sons.size() - 1 || index < 0)
            return FALSE;

      sons[index].Jouer();

      return TRUE;
}

/*Stoppe le son indiqué*/
BOOL SoundEngine::Stopper(int index)
{
      //si l'index dépasse la capacité du vector
      if(index > sons.size() - 1 || index < 0)
            return FALSE;

      //on joue le son
      sons[index].Stopper();

      return TRUE;
}


Remarque : Pour jouer et stopper les sons, on utilise directement 
la fonction contenue dans la classe Son, après avoir bien
 sur testé la validité de l'index fournis en paramètre.

Voilà, c'est tout pour la création du SoundEngine. 
Si vous avez des questions n'hésitez pas à me contacter.

Passons maintenant à son utilisation au sein de votre programme.

 


3. Utilisation


Tout d'abord, vous devez déclarer une variable 
de type SoundEngine (ici globale mais on peut adapter).


//variable de type SoundEngine
SoundEngine soundEngine;

//Viens ensuite l'initialisation :
//fréquence à 44khz et 32 cannaux
soundEngine.Initialiser(44000, 32);

//On peut maintant ajouter des sons :
//ajout de sons avec une classe Son déjà déclarée
Son temp;
temp.Charger("grosMP3.mp3", TYPE_STREAM);
soundEngine.AjouterSon(temp);

temp.Liberer();
temp.Charger("petitWAV.wav", TYPE_SAMPLE);
soundEngine.AjouterSon(temp, 1);

temp.Liberer();
temp.Charger("midiMusique1.mid", MODULE_TYPE_MUSIC);
soundEngine.AjouterSon(temp);

temp.Liberer();
temp.Charger("midiSon1.mid", MODULE_TYPE_SOUND);
soundEngine.AjouterSon(temp);

temp.Liberer();

//ajout de sons par chemin d'accés
soundEngine.AjouterSon("petitMP3.mp3", SAMPLE_TYPE);
soundEngine.AjouterSon("grosWAV.wav", STREAM_TYPE);
soundEngine.AjouterSon("midiMusique1.mid", MODULE_TYPE_MUSIC);
soundEngine.AjouterSon("midiSon1.mid", MODULE_TYPE_SOUND, 0);


//Par exemple.
//On peut maintenant les jouer/stopper.


...
//jouera midiSon1.mid
soundEngine.Jouer(0);
//jouera grosMP3.mp3
soundEngine.Jouer(1);
...
//arretera la lecture
soundEngine.Stopper(0);
//arretera la lecture
soundEngine.Stopper(1);

...
//jouera grosWAV.wav
soundEngine.Jouer(6);
...
//arretera la lecture
soundEngine.Stopper(6);




//A la fin de votre programme il ne vous restera plus qu'à désinitialiser :

//désinitialise Fmod et libère tous les sons chargés
soundEngine.Desinitialiser();

 

 

 

Voilà c'est tout !
Si vous voyez des erreurs, prévenez-moi je corrigerais tout ça dès que je pourrais.

Si vous avez des conseils concernant ce SoundEngine, n'hésitez pas non plus à me contacter ;-).

J'ai fournit une archive contenat le fichier d'entête et de réalisation.

Bonne lecture. Fab



 Fichier Zip

Les Membres Club peuvent télécharger directement un fichier contenu dans le zip sans télécharger le zip en entier !

Télécharger le zip


 Sources du même auteur

Source avec Zip Source avec une capture C++ D3D9 DÉMO D'UN DÉBUT DE MOTEUR 3D

 Sources de la même categorie

Source avec Zip ADAPTER LES TEMPS DE SUBTITLES DE SOUS TITRAGE ENTRE DEUX LA... par berrami
Source avec Zip Source avec une capture DÉTECTION DE VISAGE (YEUX, NEZ, BOUCHE) AVEC OPENCV EN TEMPS... par MadM@tt
Source avec Zip Source avec une capture GÉNÉRATEUR FM EXPÉRIMENTAL par tontonCD
Source avec Zip LECTEUR MULTIMÉDIA par omegatou
Source avec Zip IMPLÉMENTATION D'UN ALGORITHME DE COMPRESSION/DECOMPRESSION ... par eemikhm

Commentaires et avis

Commentaire de LordBob le 08/05/2004 09:28:00

je trouve que ta source c'est une bonne idée, elle a un petit aspect utile et surtout elle permet de bien apprendre a se servir de FMOD !!!
mais un petit truc que tu pourrais faire, sur le site, dans la partie source, tu fait une sorte d'explication de ta source, je pense que ca serait bien si tu l'inserais dans ton zip...
voila sinon continue ta source, rend la plus puissance et continue a posté les mises a jour sur cppfrance...

Commentaire de djl le 08/05/2004 09:51:55

et change aussi qq truc pour la rendre plus c++: utilise bool plutot que BOOL, ne met pas void en parametre à une fonction sans parametre (ca concerne juste le c pour differencier prototype et declaration), remplace tes #define par une enum pour tes constante...
tu peux aussi utiliser 0 à la place de NULL

Commentaire de Funto66 le 08/05/2004 11:08:48

Elle est sympa ta source ;)
djl &gt;&gt; là je suis pas d'accord, faut laisser NULL au lieu de 0, c'est plus explicite, ça revient au même et c'est défini dans la bibliothèque standard.
Par contre je suis d'accord pour remplacer les BOOL par des bool ^^

Aussi, j'ai pas trop regardé mais il me semble que l'on est obligés d'appeler les fonctions son.Liberer() avant un son.Charger() et qu'on doit aussi appeler engine.Desinitialiser().
C'est là que tu pourrais profiter de la puissance du C++ : il faudrait créer des destructeurs qui appelleraient ces méthodes, et ne pas être obligé de libérer un son avant d'en charger un autre : pour ça, la fonction Liberer() serait appelée dans Son::Charger(), seulement si un son était déjà chargé auparavant bien sûr ^^

Voilà, bonne prog.

Commentaire de djl le 08/05/2004 11:33:09

ok, mais NULL n'est pas defini dans la lib standard du c++ mais dans celle du c

"In C++, a literal zero is most appropriate for use as a null pointer
constant" (cpptips)

et stroustrup dit : "If you feel you must define NULL, use const int NULL =  0;"
et pas #define NULL ((void *)0)

Commentaire de Funto66 le 08/05/2004 12:27:45

Oui c'est vrai c'est dans la lib du C.
Mais dans tous les cas je reste persuadé qu'il faut utiliser NULL si on veut que le code soit clair.
En fait, pour l'idée de Stroustrup, faudrait faire un
#ifdef NULL
#undef NULL
extern const int NULL = 0;
#endif

et dans un fichier *.cpp :
const int NULL = 0;

Personnellement, je ne vois pas trop ce qu'il y a de mal à utiliser le NULL de base...j'ai jamais eu de problème avec.

Commentaire de xarier le 08/05/2004 12:51:59

bien bien :) mais je pense qu'il faut ajouter la gestion de la frequence et la 3d et aussi la rapidité de lecture c ta besoin d'aide : je suis la :)

Commentaire de alexis779 le 02/12/2004 18:06:38

C'est du beau travail, mais j'y ai trouvé 2 petites coquilles :
Dans l'utilisation (paragraphe 3), il est écrit :
temp.Charger("grosMP3.mp3", TYPE_STREAM);
et plus bas :
temp.Charger("petitWAV.wav", TYPE_SAMPLE);
Mais il faut mettre STREAM_TYPE et SAMPLE_TYPE à la place de TYPE_STREAM et TYPE_SAMPLE, pour qu'elles soient en accord avec les déclarations des variables dans SoundEngine.h.
Voilà c'est tout.

Une dernière chose : le moteur est compatible avec la dernière version de FMod, c'est qui n'est pas toujours le cas des codes que l'on trouve actuellement :
On voit souvent fsound_stream_openfile à la place de fsound_stream_open.
Bravo.

Commentaire de benefy le 01/04/2005 15:22:20

Juste une petite remarque à propos de la classe SoundEngine: elle reste limitée du fait qu'il n'est pas possible d'en instancier plusieurs, l'initialisation de FMOD ne pouvant pas se faire 2 fois de suite.
Par contre, connais-tu un moyen d'utiliser FMOD sur 2 périphériques son différents en même temps ?
Par exemple, jouer un son sur une carte son et en jouer un autre en même temps sur une deuxième carte son ?

Commentaire de ryosaebafr2000 le 16/06/2005 14:19:59

salut

g telechargé la derniere version (3.74) de fmod mais apparement
la fonction "FSOUND_Stream_OpenFile" ne semble pas fonctionner car g le message d erreur suivi à la compilation :
" Undefined symbol '_FSOUND_Stream_OpenFile@12' referenced in "simplest.c". "
Pourtant, il ne pose aucun probleme pour lire les MODULES (s3m,mod,it,midi etc) avec la fonction "FMUSIC_LoadSong"

ce qui est bizarre c que dans la doc, la fonction FSOUND_Stream_OpenFile n'existe pas mais est remplacée par FSOUND_Stream_Open et que dans "fmod.h", c'est le prototype FSOUND_Stream_OpenFile qui apparait...

Quelqu'un peut il me venir en aide, PLEASE!!!

PS : si vous connaissez, je suis sous Labwindows CVI 7.0 (code en C pur)

Commentaire de Kirua le 11/12/2005 00:43:58

Regarde, tu peux remplacer ça:

#             //module (loop)
#             case MODULE_TYPE_MUSIC:
#             if(FMUSIC_PlaySong(module) == NULL)
#                   return FALSE;
#             break;
#  
#             //module
#             case MODULE_TYPE_SOUND:
#             if(FMUSIC_PlaySong(module) == NULL)
#                   return FALSE;
#             break;

par ça:

#             //module
#             case MODULE_TYPE_MUSIC:
#             case MODULE_TYPE_SOUND:
#             if(FMUSIC_PlaySong(module) == NULL)
#                   return FALSE;
#             break;


à part ça, merci pr le code, je vois mieux comment fmod est hiérarchisé !

 Ajouter un commentaire




Nos sponsors


Sondage...

Comparez les prix

CalendriCode

Mai 2012
LMMJVSD
 123456
78910111213
14151617181920
21222324252627
28293031   

Consulter la suite du CalendriCode

A découvrir



 
Développement réalisé par Nicolas SOREL (Nix) avec l'aide de : Cyril DURAND et Emmanuel (EBArtSoft), Merci à Vincent pour ses précieux conseils.
CodeS-SourceS.com© Toute reproduction même partielle est interdite sauf accord écrit du Webmaster
CodeS-SourceS.com© est une marque déposée tous droits réservés

Google Coop CodeS-SourceS Google Coop CodeS-SourceS
Temps d'éxécution de la page : 8,876 sec (3)

Nous contacter | Annoncer sur CodeS-SourceS | Mentions légales