Jouer de la musique
Ah, enfin on y vient. Il va y avoir de l'ambiance. 
Voilà, on va tenter de faire jouer un morceau de musique à IRBOT en plus de
tout ce qu'il doit déjà faire.
On aurai pu utiliser un générateur de mélodie tout fait, tel que l'UM66T-20L
par exemple. Mais c'est beaucoup plus amusant d'écrire son propre générateur
de mélodie, d'autant plus qu'on a un microcontrôleur à notre disposition.
Dans le post précédent, on a vu comment générer une tonalité précise (le
Bip) à l'aide de la fonction son (val, durée) qui
utilise le générateur de fréquence PWM.
Eh ben, pour jouer de la musique on va simplement appeler le fonction son() pour
chaque note de la partition musicale.
Tout d'abord, on définie la gamme des notes de 2 octaves dans un tableau
statique. Un tableau statique a l'avantage d'être stocké dans la mémoire
flash. Il n'utilise pas de RAM. La RAM est précieuse, il faut l'économiser.
Voici la définition du tableau des notes
// NOTE FREQUENCE ---> val=5000000/(frequence*16)
// Octave0 Octave1
const int C_NOTE[2] ={ 149, 74};
const int Db_NOTE[2] ={ 140, 70};
const int D_NOTE[2] ={ 133, 66};
const int Eb_NOTE[2] ={ 125, 62};
const int E_NOTE[2] ={ 118, 59};
const int F_NOTE[2] ={ 111, 55};
const int Gb_NOTE[2] ={ 105, 52};
const int G_NOTE[2] ={ 99, 49};
const int Ab_NOTE[2] ={ 94, 47};
const int A_NOTE[2] ={ 88, 44};
const int Bb_NOTE[2] ={ 83, 41};
const int B_NOTE[2] ={ 79, 39};
Comme précedemment, val est calculée à l'aide de la
formule val= 5000000 / (frequence *16 )
149 correspond à une fréquence de 2093 Hz, le Do.
Voilà, on a notre tableau des notes, il ne reste plus qu'à faire un tableau de
la partition de notre mélodie.
J'ai choisi Joyeux Anniversaire, c'est peut-être
pas très original, vous avez surement mieux à me proposer.
Le tableau de la partition, également stocké en mémoire flash.
#define TAILLE_JOYEUX 25
const struct PARTITION // DUR = temps / 24ms
{
int NOTE;
int DUR;
} JA [TAILLE_JOYEUX] = {
C_note[0],15, C_note[0],4, D_note[0],21, C_note[0],21, F_note[0],21, E_note[0],37,
C_note[0],15, C_note[0],4, D_note[0],21, C_note[0],21, G_note[0],21, F_note[0],37,
C_note[0],15, C_note[0],4, C_note[1],21, A_note[0],21, F_note[0],21, E_note[0],21,
D_note[0],37,
Bb_note[0],15, Bb_note[0],4, A_note[0],21, F_note[0],21, G_note[0],21, F_note[0],50};
Le tableau de la partition est un tableau à 2 dimensions : note
et durée
La note pointe sur le tableau des notes. La durée est exprimée en fraction de
24ms (des essais ont révélé ce chiffre). La durée est variable et correspond
aux blanches, noires etc ... de la partition pour ceux qui ont des notions de
solfège.
Voilà, on a notre tableau des notes et le tableau de la partition. Il ne reste
plus qu'à créer un séquenceur qui va dérouler la partition.
Comme d'habitude, on va utiliser la routine d'interruption qui est appelée
toutes les 20ms (environ).
On y rajoute notre bout de programme qui fait office de séquenceur.
if (MUSIQUE) {
if (!TONE) { // si pas de son en cours
son(JA[IX_NOTE].NOTE, JA[IX_NOTE].DUR);
CPT_PAUSE=3; // 3*24ms
MUSIQUE=0;
if(++IX_NOTE==TAILLE_JOYEUX) {
IX_NOTE=0;
CPT_PAUSE=82; // pause 2"
}
}
}
else {
if (CPT_PAUSE) {
if (!--CPT_PAUSE) MUSIQUE=1;
}
}
IX_NOTE est l'index de la partition, il est incrémenté à chaque note jouée.
Avant de jouer la note suivante,on attend que la note en cours soit terminée.
Et on met une pause de 75ms (environ) entre 2 notes.
Lorqu'on arrive en fin de partition, on recommence au début.
On appelle donc la fonction son() avec les paramètres
de chaque note.
La fonction son pour rappel
int1 son(int val, int duree) {
if (TONE) return 1;
TONE=1;
CPT_TONE=duree;
setup_ccp1(CCP_PWM); // Configure CCP1 en PWM
setup_timer_2(T2_DIV_BY_16, val, 1); // définie la période
set_pwm1_duty(25);
}
Voilà, c'est donc le génrateur PWM qui émet soigneusement la bonne fréquence
vers le buzzer.
Prochain post : la vidéo
On va encore rajouter un petit plus. On a une touche HP sur
notre télécommande qui ne sert à rien. 
Autant la rajouter à notre prog. Premier appui sur HP, on coupe la musique,
deuxième appui on remet.
Voici le petit bout de prog à rajouter dans la fonction switch pour prendre en
compte la touche HP.
case 13: // Touche HP
if (MUSIQUE || CPT_PAUSE) {
MUSIQUE=0;
CPT_PAUSE=0;
setup_ccp1(CCP_OFF);
}
else {
MUSIQUE=1;
CPT_PAUSE=3;
IX_NOTE=0;
}
delay_ms(100); // car la télécommande envoie plusieurs trame
return;
Et pour clore ce post, la vidéo de démonstration de la
musique (1,3M)
http://pro.wanadoo.fr/yves.heilig/Forum/IRBOT/Videos/irbot_musique.avi
Si vous avez des idées sur des mélodies originales, faites le moi savoir.