utilitaire pour la fonction tone().

Salut les arduinos,
Après quelques testes avec les buzzers de mon starter kit, j'ai remarquer que l'on pouvait utiliser la fonction tone() et envoyer le résultat sur le port du buzzer si celui est apte PWM.
J'ai donc effectuer quelques recherche sur la fréquence des sons et je vous présente ici le fruit de mes recherche sous formes d'un petit jeu de fonctions pour buzzer ou autre composant sonore, je souhaite de tout cœur que quelqu'un de plus calé que moi en musique me corrige si mes fonctions ne sont pas exactes.

Considérons la gamme chromatique:

L'octave (l'octave correspond a un doublement de la fréquence) est divisée en intervalles égaux de 12 demi-tons. Cette gamme bien tempéré a été imaginée par le musicien J.S Bach

Et le LA de référence donner par un diapason dont la fréquence est de 440 Hz.

#define NOTE_A 110  //A (LA) octave 1

#define BUZZER 3

enum { A_1=NOTE_A,            // A 1 ==  110 Hz (LA  110 Hz)
       A_2=NOTE_A*2,          // A 2 ==  220 Hz (LA  220 Hz)
       A_3=NOTE_A*2*2,        // A 3 ==  440 Hz (LA  440 Hz) // tuning fork tone.
       A_4=NOTE_A*2*2*2,      // A 4 ==  880 Hz (LA  880 Hz)
       A_5=NOTE_A*2*2*2*2     // A 5 == 1760 Hz (LA 1760 Hz)
       } ;                    // A (LA) octaves frequency values.



void setup() {
  Serial.begin(9600) ;
  print_menu() ;  
}

void loop() {
  if ( Serial.available() ) {
    byte resp =Serial.read() ;
    if (resp == '0' ) {
     print_menu() ;
    } 
    else if (resp == '1')  {
      Serial.println("Octave 1") ;
      Serial.println(A_1) ;
      Serial.println() ;
      enumerate_note(BUZZER,1500,A_1) ;
      Serial.println() ;
      Serial.println("Octave 2") ;
      Serial.println(A_2) ;
      Serial.println() ;
      enumerate_note(BUZZER,1500,A_2) ;
      Serial.println()    ;
      Serial.println("Octave 3") ;
      Serial.println(A_3) ;
      Serial.println()    ;
      enumerate_note(BUZZER,1500,A_3) ;
      Serial.println() ;
      Serial.println("Octave 4") ;
      Serial.println(A_4) ;
      Serial.println() ;
      enumerate_note(BUZZER,1500,A_4) ;
      Serial.println() ;
      Serial.println("Octave 5") ;
      Serial.println(A_5) ;
      Serial.println() ;
      enumerate_note(BUZZER,1500,A_5) ;
    }
    else if (resp == '2') {
     play_octaves(BUZZER,1500) ; 
   }
  }
}

void print_menu(void) {
  Serial.println("0) Print menu.") ;
  Serial.println("1) enumerate notes.") ;
  Serial.println("2) Play Octaves.") ;
}

unsigned int get_range(unsigned int A) {
  unsigned int a[6]={0,110,220,440,880,1760} ;  // A frequencies in Hz (exclude 0: value for the subtraction in case of A == 110 ) 
  unsigned int idx ;
  for (idx=0 ; idx < 6 ; idx++) {
    if ( a[idx] == A ) {
     break ;
    }
  } 
  --idx ;
  unsigned int range_of_values=A-a[idx] ; // Intervalle computing:    (LA octave x) - (LA octave x-1)    
  return range_of_values ;
}  

void play_octaves(byte pin,unsigned long timer) {
  tone(pin,A_1,timer) ;
  delay(timer) ;
  tone(pin,A_2,timer) ;
  delay(timer) ;
  tone(pin,A_3,timer) ;
  delay(timer) ;
  tone(pin,A_4,timer) ;
  delay(timer) ;
  tone(pin,A_5,timer) ;
  delay(timer) ;
}

void enumerate_note(byte pin,unsigned long timer,unsigned int A) {

  byte offset=3 ;  // the reference A have index 9 so: DO == 3 (12-9) == 3.
  
  char *notes[12]={"do","do#","re","re#","mi","fa","fa#","sol","sol#","la","la#","si"} ; //12 semi-secondes per octave
 
 
  unsigned int range=get_range(A) ;
  
  double interval=range/12.0 ; // 12 semi-secondes per octave at equal interval.
  byte c=0 ;
  while (offset < 15) {
    unsigned int note=(offset*interval)+range ; // Computing note.
    Serial.println("-----") ;
    Serial.println(notes[c]) ;
    Serial.println(note) ;
    tone(pin,note,timer) ;
    delay(timer) ;
    offset += 1 ;
    c++ ;
  }

}
  

void play_note(byte pin,unsigned long timer,byte note_idx,unsigned int A) {
  
  // parameter note_idx must be an integer respresenting the index from the note in range (0-11) :
  // C,   cis|des,         D,   dis|es,             E,   F,    fis | ges,         G,    gis|as,             A,     ais|b,              H.  [anglophone representation]                                    
  // DO,  DO #|RE Bemol,  RE,   RE # | RE Bemol,   MI,   FA,   FA # | SOL Bemol, SOL,   SOL # | LA Bemol,  LA,     LA # | SI Bemol,   SI.  [French representation]
  // from Octave basis parameter A
  
  unsigned int range=get_range(A) ;
  
  double interval=range/12.0 ; // 12 semi-secondes per octave at equal interval.
  
  unsigned int note=((note_idx+3)*interval)+range ;
  tone(pin,note,timer) ;
  delay(timer) ;
}  

void play_frequency(byte pin,unsigned long duree,unsigned int frequency) {
  /* Frequencies from 16 Hz to 17 KHz are human audible. */ 
  /* Ultrasound > (20 KHz == 20 000 Hz) */ 
  tone(pin,frequency,duree) ;
}

Merci de bien vouloir me corriger si mes fonctions ne sont pas exactes, a vrai dire je ne connais rien a la musique et aux notes, j'ai simplement fait quelques recherches d'ou mes calcules.

PS: Je me demande qui a traduit la documentation de mon starter-kit car la différence entre un buzzer actif et un buzzer passif y est expliquer mais n'importe comment et de manière incompréhensible, après mes essaies les deux buzzers donnent des résultats semblable, Ce qui ne devrai pas être le cas, car il devrai y avoir une différence ...???

malheureusement,

double interval=range/12.0 ;

est archi faux. les fréquences des notes suis cette suite mathématique :

Fn+1 = Fn x racine_douzième(2). On ne parle donc plus d'intervalle, mais de rapport. la suite que tu as écrite serait Fn+1 = Fn + (range/12), ais si tu la joue, tu verras que c'est pas très agréable à l'oreille...

http://forum.arduino.cc/index.php?topic=158784.msg1401830#msg1401830

Cette suite donne des fréquences qui demandent bien plus de précision que le +/-1Hz de la fonction tone() (qui elle-même n'est pas des plus juste dans ses calculs). Dans le lien que je t'ai donné, je parle justement d'un code que j'ai fait pour faire un petit synthé avec un arduino. Je dois utiliser une table de temps, et c'est le seul moyen pour être assez précis dans les fréquences générées. il faut que je finalise ce code pour vous le mettre en ligne.

Merci pour la correction dans mes recherches je suis tomber sur le rapport:

Rapport de fréquence de 2 demis-ton successifs dans la gamme chromatique:
la formule étant écrite bizarrement:
__
12 /
1 : / 2 = 1 : 1,059463

Je n'ai pas compris le 12 écrit au dessus de la racine carré,
ni les deux points (un rapport ???).

OU:

Rapport de fréquence entre deux tons entiers:
__
6 /
1 : / 2 = 1 : 1,222462

Je n'ai pas compris le 6 écrit au dessus de la racine carré,
ni les deux points (un rapport ???).

Ca serai sympa de m'expliquer le sens de cette notation que je n'ai pas trouver dans mes bouquins de math.

PS: Je suppose que la premère formule correspond a ce que tu a écrit:

Fn+1 = Fn x racine_douzième(2).

C'est effectivement racine douzième, de la même manière qu'on écrit la racine cubique par exemple Racine cubique — Wikipédia

Arguino:
Rapport de fréquence de 2 demis-ton successifs dans la gamme chromatique:
la formule étant écrite bizarrement:
__
12 /
1 : / 2 = 1 : 1,059463

Je n'ai pas compris le 12 écrit au dessus de la racine carré,
ni les deux points (un rapport ???).

__
12 /
1 : / 2 = 1 : 1,059463

c'est la même chose que
1 1
_________ = ________
__ 1,059463
12 /
/ 2