Go Down

Topic: Petite banque de données musicale (Read 1 time) previous topic - next topic

Matth37

Bonjour, je voulais avoir votre avis sur mon code. Le programme dans son ensemble est assez vaste et fonctionne. Il a pour but d'automatiser l'ouverture/fermeture des portes d'un poulailler. J'ai donc opté pour une approche orienté objet avec les classes suivantes : Bouton, Capteur_Lumiere, Ecran, Led, Porte, Temps et Son.

Je ne détaillerai que la classe Son (les modules étant bien séparés les uns des autres).

Le constructeur me permet de créer un objet hautParleur1 par exemple dans lequel je peux choisir un morceau à charger et un tempo dans un Musique.h.

Je peux ensuite faire grosso modo (v_SON_Lecture()) un hautParleur1.Lecture() qui me permet de lire le tableau en "const int" correspondant au morceau choisi.

Chaque mélodie est un tableau à 2 dimensions dans lequel repose dans chaque bloc la fréquence de la note de base, le rythme et l'octave. Un calcul ensuite me permet de retrouver la fréquence voulue.

J'ai mis 4 mélodies (dont une qui ne compte pas vraiment, c'est juste un test à 3 notes) et c'est très lourd  :o

J'aurai bien voulu stocker ça différemment et charger le tableau au besoin mais j'ai déjà eu un mal de chien à mettre ça en place. Je m'étais embarqué sur un attribut melodie[][3] et je me suis cassé les dents à vouloir absolument intégrer des séries de notes, rythmes en fonction du choix de la musique. Et Monsieur C++ n'aime pas franchement que je déclare mon tableau dans le .h et que je l'initialise dans une fonction de mon .cpp ... J'ai pensé au tableau dynamique type vector par la suite, mais vu que c'est pas implanté nativement...

J'ai fait du javascript récemment et je me demandais s'il n'y avait pas une sorte de format json qui pouvait exister pour arduino ? Si vous avez des idées pour alléger ces séries de valeurs, je suis preneur.

Son.cpp :
Code: [Select]
#include "Son.h"
#include "Arduino.h"
#include "Musique.h"
#include <string.h>

// macro pour compter le nombre de lignes ou de colonnes dans un tableau quelque soit le type
#define COMPTE_LIGNES(tableau)    (sizeof(tableau) / sizeof(*tableau))
#define COMPTE_COLONNES(tableau) (sizeof(tableau) / (sizeof(**tableau) * COMPTE_LIGNES(tableau)))

// Mélodies
const int SON_TEST[3][3]={
 {DON,CROCHE,0},
 {DON,CROCHE,2},
 {DON,NOIRE,3}
};

const int SON_FRENCHCANCAN[44][3]={
 {SON,NOIRE,3},{DON,BLANCHE,3},{REN,CROCHE,3},{FAN,CROCHE,3},
 {MIN,CROCHE,3},{REN,CROCHE,3},{SON,NOIRE,3},{SON,NOIRE,3},
 {SON,CROCHE,3},{LAN,CROCHE,3},{MIN,CROCHE,3},{FAN,CROCHE,3},
 {REN,NOIRE,3},{REN,NOIRE,3},{REN,CROCHE,3},{FAN,CROCHE,3},
 {MIN,CROCHE,3},{REN,CROCHE,3},{DON,CROCHE,3},{DON,CROCHE,4},
 {SIN,CROCHE,3},{LAN,CROCHE,3},{SON,CROCHE,3},{FAN,CROCHE,3},
 {MIN,CROCHE,3},{REN,CROCHE,3},{DON,BLANCHE,3},{REN,CROCHE,3},
 {FAN,CROCHE,3},{MIN,CROCHE,3},{REN,CROCHE,3},{SON,NOIRE,3},
 {SON,NOIRE,3},{SON,CROCHE,3},{LAN,CROCHE,3},{MIN,CROCHE,3},
 {FAN,CROCHE,3},{REN,NOIRE,3},{REN,NOIRE,3},{REN,CROCHE,3},
 {SON,CROCHE,3},{REN,CROCHE,3},{MIN,CROCHE,3},{DON,NOIRE,3}
};

const int SON_MARCHE_IMPERIALE[44][3]={
 {SON,NOIRE,3},{SON,NOIRE,3},{SON,CROCHE,3},{RED,CROCHEPOINTEE,3},
 {LAD,DOUBLECROCHE,3},{SON,NOIRE,3},{RED,CROCHEPOINTEE,3},{LAD,DOUBLECROCHE,3},
 {SON,BLANCHE,3},{REN,NOIRE,4},{REN,NOIRE,4},{REN,NOIRE,4},
 {RED,CROCHEPOINTEE,4},{LAD,DOUBLECROCHE,3},{FAD,NOIRE,3},{RED,CROCHEPOINTEE,3},
 {LAD,DOUBLECROCHE,3},{SON,BLANCHE,3},{SON,NOIRE,4},{SON,CROCHEPOINTEE,3},
 {SON,DOUBLECROCHE,3},{SON,NOIRE,4},{FAD,CROCHEPOINTEE,4},{FAN,DOUBLECROCHE,4},
 {MIN,DOUBLECROCHE,4},{RED,DOUBLECROCHE,4},{MIN,CROCHE,4},{SIL,DEMISOUPIR,0},
 {SON,CROCHE,3},{REN,NOIRE,4},{DON,CROCHEPOINTEE,4},{SIN,DOUBLECROCHE,3},
 {LAD,DOUBLECROCHE,3},{LAN,DOUBLECROCHE,3},{LAD,CROCHE,3},{SIL,DEMISOUPIR,0},
 {RED,CROCHE,3},{SON,NOIRE,3},{RED,CROCHEPOINTEE,3},{LAD,DOUBLECROCHE,3},
 {SON,NOIRE,3},{RED,CROCHEPOINTEE,3},{LAD,DOUBLECROCHE,3},{SON,BLANCHE,3}
};

const int SON_FIREWORKS[72][3]={
 {REN,NOIRE,3},{SON,CROCHE,3},{SON,CROCHE,3},{SON,CROCHE,3},
 {SON,CROCHE,3},{SON,DOUBLECROCHE,3},{LAN,DOUBLECROCHE,3},{SIN,DOUBLECROCHE,3},
 {LAN,DOUBLECROCHE,3},{SON,CROCHE,3},{SON,DOUBLECROCHE,3},{LAN,DOUBLECROCHE,3},
 {SIN,CROCHE,3},{SIN,CROCHE,3},{SIN,CROCHE,3},{SIN,CROCHE,3},
 {SIN,DOUBLECROCHE,3},{DON,DOUBLECROCHE,4},{REN,DOUBLECROCHE,4},{DON,DOUBLECROCHE,4},
 {SIN,CROCHE,3},{SIN,DOUBLECROCHE,3},{DON,DOUBLECROCHE,4},{REN,CROCHE,4},
 {REN,CROCHE,4},{REN,CROCHE,4},{REN,CROCHE,4},{REN,BLANCHE,4},
 {SIL,DEMISOUPIR,0},{SON,CROCHE,4},{REN,CROCHE,4},{SIN,CROCHE,3},
 {SIL,DEMISOUPIR,0},{SON,CROCHE,4},{REN,CROCHE,4},{SIN,CROCHE,3},
 {SIL,DEMISOUPIR,0},{REN,NOIRE,4},{REN,NOIRE,4},{MIN,DOUBLECROCHE,4},
 {REN,DOUBLECROCHE,4},{DON,CROCHE,4},{SIN,CROCHE,3},{LAN,BLANCHE,3},
 {SIL,DEMISOUPIR,0},{REN,CROCHE,4},{REN,CROCHE,4},{MIN,DOUBLECROCHE,4},
 {REN,DOUBLECROCHE,4},{DON,CROCHE,4},{SIN,CROCHE,3},{LAN,CROCHEPOINTEE,3},
 {SIN,DOUBLECROCHE,3},{LAN,CROCHEPOINTEE,3},{SIN,DOUBLECROCHE,3},{LAN,DOUBLECROCHE,3},
 {SIN,DOUBLECROCHE,3},{LAN,DOUBLECROCHE,3},{SIN,DOUBLECROCHE,3},{LAN,DOUBLECROCHE,3},
 {SIN,DOUBLECROCHE,3},{LAN,DOUBLECROCHE,3},{SIN,DOUBLECROCHE,3},{LAN,CROCHEPOINTEE,3},
 {LAN,DOUBLECROCHE,3},{SIN,DOUBLECROCHE,3},{DON,DOUBLECROCHE,4},{REN,DOUBLECROCHE,4},
 {MIN,DOUBLECROCHE,4},{DOD,CROCHEPOINTEE,4},{REN,DOUBLECROCHE,4},{REN,BLANCHE,4}
};


C_SON::C_SON(byte b_pinSon,byte b_choixMusique,int i_tempo)
{
 b_SON_pinSon = b_pinSon;
 b_SON_choixMusique=b_choixMusique;
 i_SON_tempo=i_tempo;
 pinMode(b_SON_pinSon, OUTPUT);
}

int C_SON::i_SON_CalculFrequence(int i_frequenceOrigine,int i_octaveSouhaite){
 return i_frequenceOrigine*pow(2,i_octaveSouhaite);
}

void C_SON::v_SON_Lecture(){
 int i_melodie[100][3];
 float f_tempo=0;
 int lignes=0;
 if(b_SON_choixMusique==TEST){
 lignes=COMPTE_LIGNES(SON_TEST);
 i_melodie[lignes][3];
 memcpy(i_melodie, SON_TEST, sizeof(SON_TEST));
 }
 else if(b_SON_choixMusique==MARCHE_IMPERIALE){
 lignes=COMPTE_LIGNES(SON_MARCHE_IMPERIALE);
 i_melodie[lignes][3];
 memcpy(i_melodie, SON_MARCHE_IMPERIALE, sizeof(SON_MARCHE_IMPERIALE));
 }
 else if(b_SON_choixMusique==FRENCHCANCAN){
 lignes=COMPTE_LIGNES(SON_FRENCHCANCAN);
 i_melodie[lignes][3];
 memcpy(i_melodie, SON_FRENCHCANCAN, sizeof(SON_FRENCHCANCAN));
 }
 else if(b_SON_choixMusique==FIREWORKS){
 lignes=COMPTE_LIGNES(SON_FIREWORKS);
 i_melodie[lignes][3];
 memcpy(i_melodie, SON_FIREWORKS, sizeof(SON_FIREWORKS));
 }
 f_tempo=(1000.0*60.0)/float(i_SON_tempo);

 for (int n=0;n<lignes;n++){ // boucle de lecture du tableau
    char note = i_melodie[n][0]; // on récupère la fréquence de base dans le tableau
    char octave= i_melodie[n][2]; // on récupère l'octave
    int frequence=i_SON_CalculFrequence(note,octave); //on calcule la bonne fréquence
 Serial.println(frequence);
 float duree=f_tempo*i_melodie[n][1]/32;// on multiplie la duree de base par la valeur de duree du tableau
 Serial.println(duree);
 tone (b_SON_pinSon,frequence); //on joue la note
    delay(duree);
    noTone(b_SON_pinSon);//on arrete la note
    delay(10);// petite attente pour avoir l'impression d'attaquer la note
  }
}

void C_SON::v_SON_SetMelodie(byte b_choixMusique,int i_tempo){
 b_SON_choixMusique=b_choixMusique;
 i_SON_tempo=i_tempo;
}


Son.h :
Code: [Select]
#ifndef DEF_SON
#define DEF_SON
#include "Arduino.h"

class C_SON
{
 protected:
 byte b_SON_pinSon=HIGH; // numero de pin
 bool bo_SON_etatSon=false; // etat (si allume alors true)
        int i_SON_tempo;
 byte b_SON_choixMusique;

  public:
  C_SON();
  C_SON(byte b_pinSon, byte b_choixMusique,int i_tempo);
 int i_SON_CalculFrequence(int i_frequenceOrigine,int i_octaveSouhaite);
 void v_SON_Lecture();
 void v_SON_SetMelodie(byte b_choixMusique,int i_tempo);
};

#endif



Musique.h :
Code: [Select]
// liste musiques disponibles
#define TEST 0
#define MARCHE_IMPERIALE 1
#define FRENCHCANCAN 2
#define FIREWORKS 3

// Liste des notes
#define SIL 0
#define DON 65
#define DOD 69
#define REN 74
#define RED 78
#define MIN 83
#define FAN 87
#define FAD 93
#define SON 98
#define SOD 104
#define LAN 110
#define LAD 117
#define SIN 123

// liste des rythmes
#define QUINTUPLECROCHE 1
#define QUADRUPLECROCHE 2
#define TRIPLECROCHE 4
#define DOUBLECROCHE 8
#define CROCHE 16
#define CROCHEPOINTEE 24
#define NOIRE 32
#define NOIREPOINTEE 48
#define BLANCHE 64
#define BLANCHEPOINTEE 96
#define RONDE 128

// liste des rythmiques de silences
#define TRENTEDEUXIEMEDESOUPIR 1
#define SEIZIEMEDESOUPIR 2
#define HUITIEMEDESOUPIR 4
#define QUARDESOUPIR 8
#define DEMISOUPIR 16
#define SOUPIR 32
#define DEMIPAUSE 64
#define PAUSE 128

// Tempo
#define LENTO 60
#define ANDANTE 80
#define MODERATO 100
#define ALLEGRO 120
#define PRESTO 150
#define PRESTISSIMO 200

J-M-L

#1
Aug 31, 2018, 11:49 pm Last Edit: Aug 31, 2018, 11:51 pm by J-M-L
déjà si vous utilisiez des bytes au lieu des int vous diviserez par 2 la place requise... (si tout tient sous 255)

ensuite si vous utilisez une indirection pour chaque élément (par exemple pour les tempo 0 = LENTO, 1 = ANDANTE, 2 = MODERATO, 3 = ALLEGRO, ....) vous n'auriez que 6 valeurs pour le tempo, ce qui tient sur 3 bit... en prenant une approche similaire vous pouvez condenser fortement le stockage de la musique (structure de champs de bits)
Hello - Please do not PM me for help,  others will benefit as well if you post your question publicly on the forums.
Bonjour Pas de messages privés SVP, postez dans le forum directement pour que ça profite à tous

hbachetti

Salut

Pas mal ce petit exercice.
J'ai essayé de faire quelque chose du même genre il y a quelque temps, mais n'ayant pas de connaissances musicales, c'est difficile pour moi de transcrire une partition.

Personnellement je ferais ceci :

Code: [Select]

struct note
{
  byte base;
  byte tempo;
  byte oct;
};

const struct note SON_TEST[] = {
  {DON, CROCHE, 0},
  {DON, CROCHE, 2},
  {DON, NOIRE, 3}
};

// et ainsi de suite ...



Ensuite tu peux gagner un peu de RAM en pile avec un pointeur, sans recopie dans la variable i_melodie.
Et aussi tenir compte des silences :

Code: [Select]

void C_SON::v_SON_Lecture() {
  struct note *i_melodie;
  float f_tempo = 0;
  int lignes = 0;
  if (b_SON_choixMusique == TEST) {
    lignes = COMPTE_LIGNES(SON_TEST);
    i_melodie = SON_TEST;
  }
  else if (b_SON_choixMusique == MARCHE_IMPERIALE) {
    lignes = COMPTE_LIGNES(SON_MARCHE_IMPERIALE);
    i_melodie = SON_MARCHE_IMPERIALE;
  }
  else if (b_SON_choixMusique == FRENCHCANCAN) {
    lignes = COMPTE_LIGNES(SON_FRENCHCANCAN);
    i_melodie = SON_FRENCHCANCAN;
  }
  else if (b_SON_choixMusique == FIREWORKS) {
    lignes = COMPTE_LIGNES(SON_FIREWORKS);
    i_melodie = SON_FIREWORKS;
  }
  f_tempo = (1000.0 * 60.0) / float(i_SON_tempo);

  Serial.print("lines: ");
  Serial.println(lignes);
  for (int n = 0; n < lignes; n++) { // boucle de lecture du tableau
    char note = i_melodie[n].base; // on récupère la fréquence de base dans le tableau
    char octave = i_melodie[n].oct; // on récupère l'octave
    int frequence;
    // gérer les silences
    if (note != SIL) {
      frequence = i_SON_CalculFrequence(note, octave); //on calcule la bonne fréquence
    }
//    Serial.println(frequence);
    float duree = f_tempo * i_melodie[n].tempo / 32; // on multiplie la duree de base par la valeur de duree du tableau
//    Serial.println(duree);
    // gérer les silences
    if (note != SIL) {
      tone (b_SON_pinSon, frequence); //on joue la note
    }
    delay(duree);
    // gérer les silences
    if (note != SIL) {
      noTone(b_SON_pinSon);//on arrete la note
    }
    delay(10);// petite attente pour avoir l'impression d'attaquer la note
  }
}


Tu peux aussi simplifier comme ceci :

Code: [Select]


// Liste des notes
// ...
#define FIN 255

const struct note SON_TEST[] = {
  {DON, CROCHE, 0},
  {DON, CROCHE, 2},
  {DON, NOIRE, 3},
  FIN
};

  // la boucle for devient :
  for (int n = 0; i_melodie[n].base != FIN; n++) { // boucle de lecture du tableau



La macro COMPTE_LIGNES et la variable lignes deviennent inutiles.

Ainsi modifié le code l'occupation en mémoire sur une NANO est :
Le croquis utilise 5644 octets (18%) de l'espace de stockage de programmes. Le maximum est de 30720 octets.
Les variables globales utilisent 337 octets (16%) de mémoire dynamique, ce qui laisse 1711 octets pour les variables locales. Le maximum est de 2048 octets.

Ce n'est pas si lourd sauf si tu envisages de créer une bibliothèque de mélodies conséquente.
Sinon, une MEGA pourrait convenir, ou mieux : un stockage sur microSD.

J'ai essayé french cancan. En tout cas les notes sont justes.

@+
Linux is like a wigwam: no Windows, no Gates, and an Apache inside ...

Christian_R

Pourquoi ne pas ajouter une petite carte SD pour stocker les données de notes, et mettre juste le code dans la mémoire de l'arduino ?
Christian

hbachetti

#4
Sep 01, 2018, 02:09 pm Last Edit: Sep 01, 2018, 04:49 pm by hbachetti
Pour mes besoins personnels, je viens de le faire.
J'utilise un lecteur SD classique (SPI).

Code: [Select]

#include "Arduino.h"
#include <string.h>
#include <SPI.h>
#include <SD.h>

#ifndef DEF_SON
#define DEF_SON
#include "Arduino.h"

class C_SON
{
  protected:
    byte b_SON_pinSon; // numero de pin
    int i_SON_tempo;
    byte b_SON_choixMusique;

  public:
    C_SON();
    C_SON(byte b_pinSon, byte b_choixMusique, int i_tempo);
    int i_SON_CalculFrequence(int i_frequenceOrigine, int i_octaveSouhaite);
    void v_SON_Lecture();
    void v_SON_SetMelodie(byte b_choixMusique, int i_tempo);
  private:
    bool readMelody(char *name, struct note *melody);
};

#endif

// liste musiques disponibles
#define TEST 0
#define MARCHE_IMPERIALE 1
#define FRENCHCANCAN 2
#define FIREWORKS 3

// Liste des notes
#define SIL 0
#define DON 65
#define DOD 69
#define REN 74
#define RED 78
#define MIN 83
#define FAN 87
#define FAD 93
#define SON 98
#define SOD 104
#define LAN 110
#define LAD 117
#define SIN 123
#define FIN 255

// liste des rythmes
#define QUINTUPLECROCHE 1
#define QUADRUPLECROCHE 2
#define TRIPLECROCHE 4
#define DOUBLECROCHE 8
#define CROCHE 16
#define CROCHEPOINTEE 24
#define NOIRE 32
#define NOIREPOINTEE 48
#define BLANCHE 64
#define BLANCHEPOINTEE 96
#define RONDE 128

// liste des rythmiques de silences
#define TRENTEDEUXIEMEDESOUPIR 1
#define SEIZIEMEDESOUPIR 2
#define HUITIEMEDESOUPIR 4
#define QUARDESOUPIR 8
#define DEMISOUPIR 16
#define SOUPIR 32
#define DEMIPAUSE 64
#define PAUSE 128

// Tempo
#define LENTO 60
#define ANDANTE 80
#define MODERATO 100
#define ALLEGRO 120
#define PRESTO 150
#define PRESTISSIMO 200

#define MAX_SIZE  201

struct note
{
  byte base;
  byte tempo;
  byte oct;
};

struct note melody[MAX_SIZE];

C_SON::C_SON(byte b_pinSon, byte b_choixMusique, int i_tempo)
{
  b_SON_pinSon = b_pinSon;
  b_SON_choixMusique = b_choixMusique;
  i_SON_tempo = i_tempo;
  pinMode(b_SON_pinSon, OUTPUT);
}

int C_SON::i_SON_CalculFrequence(int i_frequenceOrigine, int i_octaveSouhaite) {
  return i_frequenceOrigine * pow(2, i_octaveSouhaite);
}

bool C_SON::readMelody(char *name, struct note *melody)
{
  int i = 0;

  File f = SD.open(name);
  if (f == 0) {
    Serial.println("Read file failed");
    return false;
  }
  while (f.available() && i < MAX_SIZE) {
    melody[i].base = f.read();
    melody[i].tempo = f.read();
    melody[i++].oct = f.read();
  }
  Serial.print(i);
  Serial.print(" notes from");
  Serial.println(name);
  melody[i].base = FIN;
  f.close();
  return true;
}

void C_SON::v_SON_Lecture() {
  float f_tempo = 0;
  bool play = false;

  if (b_SON_choixMusique == MARCHE_IMPERIALE) {
    play = readMelody("/ZIC/MARCHE~1.ZIC", melody);
  }
  else if (b_SON_choixMusique == FRENCHCANCAN) {
    play = readMelody("/ZIC/FRENCH~1.ZIC", melody);
  }
  else if (b_SON_choixMusique == FIREWORKS) {
    play = readMelody("/ZIC/FIREWO~1.ZIC", melody);
  }
  f_tempo = (1000.0 * 60.0) / float(i_SON_tempo);

  if (play) {
    for (int n = 0; melody[n].base != FIN; n++) { // boucle de lecture du tableau
      char note = melody[n].base; // on récupère la fréquence de base dans le tableau
      char octave = melody[n].oct; // on récupère l'octave
      int frequence;
      if (note != SIL) {
        frequence = i_SON_CalculFrequence(note, octave); //on calcule la bonne fréquence
      }
      //    Serial.println(frequence);
      float duree = f_tempo * melody[n].tempo / 32; // on multiplie la duree de base par la valeur de duree du tableau
      //    Serial.println(duree);
      if (note != SIL) {
        tone (b_SON_pinSon, frequence); //on joue la note
      }
      delay(duree);
      if (note != SIL) {
        noTone(b_SON_pinSon);//on arrete la note
      }
      delay(10);// petite attente pour avoir l'impression d'attaquer la note
    }
  }
}

void C_SON::v_SON_SetMelodie(byte b_choixMusique, int i_tempo) {
  b_SON_choixMusique = b_choixMusique;
  i_SON_tempo = i_tempo;
}

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  if (!SD.begin(10)) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    while (1);
  }
  Serial.println("card initialized.");
}

void loop() {
  C_SON son = C_SON(9, MARCHE_IMPERIALE, ALLEGRO);
  son.v_SON_Lecture();
  delay(2000);
  son.v_SON_SetMelodie(FRENCHCANCAN, PRESTO);
  son.v_SON_Lecture();
  delay(2000);
  son.v_SON_SetMelodie(FIREWORKS, ALLEGRO);
  son.v_SON_Lecture();
  delay(2000);
}


Il peut lire des fichiers jusqu'à 200 notes.

Code: [Select]
#define MAX_SIZE  201
Facilement modifiable ... mais on pourra difficilement aller plus loin avec une NANO.

Le petit programme C qui permet de générer les fichiers son est attaché.
Compilé avec GCC sous LINUX, mais facilement adaptable sous WINDOWS.

Il ne reste plus qu'à ...

@+
Linux is like a wigwam: no Windows, no Gates, and an Apache inside ...

J-M-L

#5
Sep 01, 2018, 02:47 pm Last Edit: Sep 01, 2018, 02:48 pm by J-M-L
si on pousse un peu plus loin le concept:

Liste des notes:
Code: [Select]
#define SIL 0
#define DON 65
#define DOD 69
#define REN 74
#define RED 78
#define MIN 83
#define FAN 87
#define FAD 93
#define SON 98
#define SOD 104
#define LAN 110
#define LAD 117
#define SIN 123
-->il y en a 13 donc tient sur 4 bits

Liste des rythmes:
Code: [Select]
#define QUINTUPLECROCHE 1
#define QUADRUPLECROCHE 2
#define TRIPLECROCHE 4
#define DOUBLECROCHE 8
#define CROCHE 16
#define CROCHEPOINTEE 24
#define NOIRE 32
#define NOIREPOINTEE 48
#define BLANCHE 64
#define BLANCHEPOINTEE 96
#define RONDE 128
-->il y en a 11 donc tient sur 4 bits

Liste des rythmiques de silences:
Code: [Select]
#define TRENTEDEUXIEMEDESOUPIR 1
#define SEIZIEMEDESOUPIR 2
#define HUITIEMEDESOUPIR 4
#define QUARDESOUPIR 8
#define DEMISOUPIR 16
#define SOUPIR 32
#define DEMIPAUSE 64
#define PAUSE 128
-->il y en a 8 donc tient sur 3 bits

Liste des Tempo
Code: [Select]
#define LENTO 60
#define ANDANTE 80
#define MODERATO 100
#define ALLEGRO 120
#define PRESTO 150
#define PRESTISSIMO 200
-->il y en a 6 donc tient sur 3 bits

donc au total 4 + 4 + 3 + 3 = 14 bits --> tient sur 2 octets (et on peut prendre 4 bits pour chaque pour simplifier)

==> en utilisant un champs de bit dans la structure et des index dans un tableau pour les valeurs associées, on peut tout stocker sur 2 octets au lieu de 3. il faudra les 4 tableaux bien sûr en mémoire (peuvent être en mémoire PROGMEM) ce qui permet quand même un gain intéressant sur la longueur des musique
Hello - Please do not PM me for help,  others will benefit as well if you post your question publicly on the forums.
Bonjour Pas de messages privés SVP, postez dans le forum directement pour que ça profite à tous

hbachetti

D'après CECI, je vous livre une nouvelle version avec la marseillaise.
Dur dur, c'est bourré de notes pointées.  :(

@+
Linux is like a wigwam: no Windows, no Gates, and an Apache inside ...

hbachetti


J'ai un peu bossé. Lecture en boucle des fichiers situés dans un répertoire "/ZIC" d'une microSD.
Et un bouton sur D8 pour passer au morceau suivant.

Code: [Select]


#include "Arduino.h"
#include <string.h>
#include <SPI.h>
#include <SD.h>

// Liste des notes
#define SIL 0
#define DON 65
#define DOD 69
#define REN 74
#define RED 78
#define MIN 83
#define FAN 87
#define FAD 93
#define SON 98
#define SOD 104
#define LAN 110
#define LAD 117
#define SIN 123
#define FIN 255

// liste des rythmes
#define QUINTUPLECROCHE 1
#define QUADRUPLECROCHE 2
#define TRIPLECROCHE 4
#define DOUBLECROCHE 8
#define CROCHE 16
#define CROCHEPOINTEE 24
#define NOIRE 32
#define NOIREPOINTEE 48
#define BLANCHE 64
#define BLANCHEPOINTEE 96
#define RONDE 128

// liste des rythmiques de silences
#define TRENTEDEUXIEMEDESOUPIR 1
#define SEIZIEMEDESOUPIR 2
#define HUITIEMEDESOUPIR 4
#define QUARDESOUPIR 8
#define DEMISOUPIR 16
#define SOUPIR 32
#define DEMIPAUSE 64
#define PAUSE 128

// Tempo
#define LENTO 60
#define ANDANTE 80
#define MODERATO 100
#define ALLEGRO 120
#define PRESTO 150
#define PRESTISSIMO 200

#define MAX_SIZE  201
#define BUTTON  8

struct note
{
  byte base;
  byte tempo;
  byte octave;
};

class MusicPlayer
{
  protected:
    byte m_speakerPin; // numero de pin
    int m_tempo;
    byte m_track;

  public:
    MusicPlayer();
    MusicPlayer(byte speakerPin);
    bool openDir(char *name);
    void playNext(int tempo);
  private:
    File m_musicDir;
    struct note melody[MAX_SIZE];
    int getFrequency(int frequency, int octave);
    bool readMelody(File &f, struct note *melody);
};

MusicPlayer::MusicPlayer(byte speakerPin)
{
  m_speakerPin = speakerPin;
  pinMode(speakerPin, OUTPUT);
}

bool MusicPlayer::openDir(char *name)
{
  Serial.print(F("open "));
  Serial.println(name);
  m_musicDir = SD.open(name);
}

int MusicPlayer::getFrequency(int frequency, int octave) {
  return frequency * pow(2, octave);
}

bool MusicPlayer::readMelody(File &f, struct note *melody)
{
  int i = 0;

  while (f.available() && i < MAX_SIZE) {
    melody[i].base = f.read();
    melody[i].tempo = f.read();
    melody[i++].octave = f.read();
  }
  Serial.print(i);
  Serial.print(F(" notes from "));
  Serial.println(f.name());
  melody[i].base = FIN;
  f.close();
  return true;
}

void MusicPlayer::playNext(int tempo) {
  float ftempo = 0;
  bool play = false;

  if (m_musicDir == 0) {
    Serial.println(F("must open a directory first"));
    return;
  }
  File f =  m_musicDir.openNextFile();
  if (f == 0) {
    m_musicDir.rewindDirectory();
    f =  m_musicDir.openNextFile();
  }
  Serial.print(F("reading: "));
  Serial.println(f.name());
  play = readMelody(f, melody);
  ftempo = (1000.0 * 60.0) / float(tempo);

  if (play) {
    for (int n = 0; melody[n].base != FIN; n++) { // boucle de lecture du tableau
      char note = melody[n].base; // on récupère la fréquence de base dans le tableau
      char octave = melody[n].octave; // on récupère l'octave
      int frequence;
      if (note != SIL) {
        frequence = getFrequency(note, octave); //on calcule la bonne fréquence
      }
      //    Serial.println(frequence);
      float duree = ftempo * melody[n].tempo / 32; // on multiplie la duree de base par la valeur de duree du tableau
      //    Serial.println(duree);
      if (note != SIL) {
        tone (m_speakerPin, frequence); //on joue la note
      }
      delay(duree);
      if (note != SIL) {
        noTone(m_speakerPin);//on arrete la note
      }
      delay(10);// petite attente pour avoir l'impression d'attaquer la note
      if (digitalRead(BUTTON) == LOW) {
        break;
      }
    }
  }
  f.close();
}

MusicPlayer player = MusicPlayer(9);

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  pinMode(BUTTON, INPUT_PULLUP);
  if (!SD.begin(10)) {
    Serial.println(F("Card failed, or not present"));
    // don't do anything more:
    while (1);
  }
  Serial.println(F("card initialized."));
  player.openDir("/ZIC");
}

void loop()
{
  player.playNext(ALLEGRO);
  delay(2000);
}


Prochaine étape : il faudrait quelqu'un de courageux pour écrire un logiciel de reconnaissance de partition musicale  ;D

@+

Linux is like a wigwam: no Windows, no Gates, and an Apache inside ...

Go Up