24 Janvier 2014


Leçon 7 : les notes de musique


pas FB

les fonctions musicales

la fonction tone()

Cette fonction permet d'envoyer un signal périodique qui peut jouer des notes de musique si on l'envoie sur un haut-parleur.
sa syntaxe est
      tone(broche, frequence, durée);

la fonction notone()

Cette fonction est nécessaire pour libérer la broche qui vient de jouer.
Tant qu'elle n'est pas appelée, on ne peut pas jouer de note sur une autre broche.

la fonction delay()

Vous la connaissez déjà.
On l'appelle entre chaque note pour qu'elles ne soient pas "collées".
Pour simplifier, on lui donnera la valeur 600 dans le 1er programme.
Dans les suivants on fera varier cette valeur en fonction de la durée de la note précédente.

montage

Plusieurs broches conviennent mais une seule à la fois. Impossible de jouer un morceau à plusieurs voix.
On utilisera la broche 8 d'Arduino en mettant un haut-parleur de 8 ohms entre cette broche et la masse.

programmation

fréquence des notes

Dans la gamme 3, la fréquence du DO est 262, celle du RÉ 294, celle du MI 330.
on choisira des durées de 400 ms pour les noires.
calculez les autres durées.
Vous en savez maintenant assez pour programmer ce morceau.

au Clair de la Lune



listes de notes et de durées

les listes

On ne passe pas les notes une par une mais on passe au programme l'adresse d'une liste de notes.
On lui passe aussi l'adresse d'une liste de durées.

passage de paramètre

Quand nous passons un paramètre à une fonction, nous pouvons le faire de 2 manières :
      en lui passant une valeur, par exemple un entier
      en lui passant l'adresse qui contient cette valeur.
cette seconde manière utilise un pointeur.
    int a est une variable
    int* b est un pointeur sur l'adresse de la variable b.

premier programme avec liste

Remarquez la manière de déclarer un tableau initialisé de constantes.


      //       clair_de_lune.ino
     
      const int clairLune[] = {262, 262, 262, 294, 330, 294, 262, 330, 294, 294, 262 } ;
      const int dureeLune[] = {400, 400, 400, 400, 800, 800, 400, 400, 400, 400, 1200 };
      void jouer(int* , int* , int );       // déclaration de fonction
     
      void setup() {
            pinMode( 8 , OUTPUT );
            jouer(clairLune, dureeLune, 11); // Au clair ... Pierrot,
            delay(800);                                   // pause
            jouer(clairLune, dureeLune, 11); // Prête-moi ... un mot.
      }
     
      void loop() {
            //rien si on ne veut pas jouer en continu
      }
     
      void jouer(const int* listeNotes, const int* dureesNotes, int nbNotes) {
           for (int numNote = 0; numNote < nbNotes; numNote++) {
                  int duree = dureesNotes[numNote];
                  tone(8, listeNotes[numNote], duree);
                  delay(duree * 1.3);
            }
            noTone(8);       // libère la sortie 8
      }




La partie importante de cette séance n'est pas la manière de jouer une note mais le passage de paramètres à la fonction jouer().





31 Janvier 2014

utilisation d'un fichier .h

Dans les programmes utilisant l'afficheur, nous avions appelé le fichier LiquidCrystal.h avec la directive #include
Ce fichier contenait des définitions vraies pour tous les afficheurs et son rôle était de nous éviter de les réécrire dans chaque programme.
J'en ai écrit un pour éviter de répéter les fréquences des notes et leurs durées.
Son principe est simple : il permet au compilateur de savoir par exemple que "DO" veut dire "262 hertz" ou que "N" veut dire 400ms.
On l'appelle en écrivant en tête du programme #include mesnotes.h
Il faut aussi copier ce programme dans le même répertoire que le programme principal. Nous n'avions pas eu besoin de recopier LiquidCrystal.h parce qu'il était compris dans le programme Arduino.
Nous allons en faire l'expérience avec Frère Jacques.

Frère Jacques avec #include


      //       frereJacques.ino
     
      #include "mesNotes.h"
     
      int frereJacques1[] = {FA4, SOL4, LA4, FA4, FA4, SOL4, LA4, FA4, LA4, LAdi4, DO5, LA4, LAdi4, DO5 } ;
      int dureeJacques1[] = {N, N, N, N, N, N, N, N, N, N, B, N, N, B };
      void jouer(int* , int* , int );
     
      void setup() {
            jouer(frereJacques1, dureeJacques1, 14);
      }
     
      void loop() {
            //rien si on ne veut pas jouer en continu
      }
     
      void jouer(int*listeNotes, int*dureesNotes, int nbNotes) {
            for (int numNote = 0; numNote < nbNotes; numNote++) {
                  int duree = dureesNotes[numNote];
                  tone(8, listeNotes[numNote], duree);
                  // On sépare les notes d'un intervale égal à 1,3 fois la note jouée.
                  int pause = duree * 1.30;
                  delay(pause);
            }
            noTone(8);       // libère sortie 8
      }

cliquez sur cette ligne pour récupérer le fichier mesNotes.h

choix de l'air à jouer

On va utiliser le moniteur série pour choisir l'air à jouer : Frère Jacques quand on envoie J ou bien La Truite quand on envoie T .


      #include "mesNotes.h"
     
      int frereJacques1[] = {FA4, SOL4, LA4, FA4, FA4, SOL4, LA4, FA4, LA4, LAdi4, DO5, LA4, LAdi4, DO5 } ;
      int frereJacques2[] = {DO5, RE5, DO5, LAdi4, LA4, FA4, DO5, RE5, DO5, LAdi4, LA4, FA4, FA4, DO4, FA4, 0, FA4, DO4, FA4 } ;
      int laTruite1[] = {SOL4, DO5, DO5, MI5, MI5, DO5, SOL4, SOL4, SOL4, SOL4, RE5, DO5, SI4, LA4, SOL4 };
      int laTruite2[] = {SOL4, DO5, DO5, MI5, MI5, DO5, SOL4, DO5, SI4, LA4, SI4, DO5, FAdi4, SOL4};
      int dureeJacques1[] = {N, N, N, N, N, N, N, N, N, N, B, N, N, B };
      int dureeJacques2[] = {300, D, C, C, N, N, 300, D, C, C, N, N, N, N, N, N, N, N} ;
      int dureelaTruite1[] = {C, C, C, C, C, N, C, C, 300, D, D, D, D, D, N } ;
      int dureelaTruite2[] = {C, C, C, C, C, N, C, C, D, D, C, C, N } ;
      int i, recu[20];
     
      void jouer(int* , int* , int );
     
      void setup()      {
            Serial.begin(9600);
            Serial.print("envoyez J pour Frere Jacques ou T pour La Truite");
      }
     
      void loop()      {
            i = 0 ;
            while ( Serial.available()>0 ) {
                  recu[i] = Serial.read();
                  i++;
                  delay(100);
            }
            if (i>0)       {
                  switch (recu[0])       {
                        case 'j' :
                        case 'J' :
                              jouer(frereJacques1, dureeJacques1, 14);
                              jouer(frereJacques2, dureeJacques2, 19);
                              break;
                        case 't' :
                        case 'T' :
                              jouer(laTruite1, dureelaTruite1, 15);
                              jouer(laTruite2, dureelaTruite2, 14);
                              break;
                  }
            }
      }
     
      void jouer(int*listeNotes, int*dureesNotes, int nbNotes)       {
           for (int numNote = 0; numNote < nbNotes; numNote++)      {
                  int duree = dureesNotes[numNote];
                  tone(8, listeNotes[numNote],duree);
                  // On sépare les notes d'un intervale égal à 1,3 fois la note jouée.
                  int pause = duree * 1.30;
                  delay(pause);
            }
            noTone(8);       // libère sortie 8
      }

Maintenant, il ne vous reste plus qu'à traduire chaque symphonie de Beethoven en langage Arduino. :)



haut de la page


flèche gauche Retour à la leçon 6 : sorties PWM           Page Suivante : révision sur les fonctions flèche droite