Arduino et génération musicale.

Musique et Mathématiques … même combat.

Difficile de trouver un domaine qui dans la nature n’est pas plus ou moins intimement mêlé à des propriétés purement mathématiques. Cordes vibrantes et vagues dans l’océan partagent l’ADN d’une variation sinusoïdale. L’escargot avec sa maison dont la courbure calque ses formes sur celles d’une spirale logarithmique. Pourquoi pas des exponentielles tant que vous y êtes ?
Le démonstrateur P23_GENERATEUR_DE_SEQUENCE.ino qui est actuellement intégré dans P24_Complet_avec_6_Items.ino a été volontairement confiné à des ondes dont l’atome est le Hz. C’est un critère bassement comptable qui a engendré une telle censure. Les applications « audibles » sont actuellement tellement variées, qu’il y aura forcément parmi vous certains techniciens qui regrettent intensément d’avoir écarté de PICOSYNTHÉ la faculté de se voir configurable dans le langage des musiciens. Ce chapitre leur est consacré. Le codage en C++ avec des tables de float pour définir des notes de musique est bien trop goinfre en OCTETS. L’approche par calculs est infiniment plus pertinente …

La complicité des mathématiques avec les partitions musicales.

Indépendamment de l’objectif qui vise à faciliter le travail de programmation à ceux qui désirent modifier leur générateur pour y intégrer P25_GENERATEUR_de_TONALITES.ino quitte à sacrifier un ou deux items moins important pour eux, nous allons dans ce chapitre aborder la gestion des notes musicales avec Arduino et faire un petit chemin dans le domaine du calcul exponentiel. Pas question dans ces lignes de traiter « musique » nous serions franchement hors sujet. On va se contenter de ne faire qu’effleurer ce vaste domaine en n’abordant qu’un seul aspect de la sensation auditive : La fréquence des ondes acoustiques propagées par les vibrations de l’air. On va oublier le principal au sens musical : La durée, le timbre, l’attaque et la terminaison ainsi que l’intensité des sons. Comme des sélecteurs par codes musicaux n’utilisent généralement pas les « demi tons », pour compacter un peu le programme nous allons ignorer les dièses et les bémols.
Abordons maintenant l’aspect physicomathématique des sons musicaux. On va se contenter « du juste nécessaire » pour devenir autonome en programmation musicale avec l’ATmega328. Tout son musical (Dans notre cas une note élémentaire.) résulte d’une fréquence fondamentale exprimée en hertz, correspondant à sa hauteur. Deux notes dont les fréquences fondamentales ont un rapport qui est une Puissance de deux (C’est-à-dire la moitié, le double, le quadruple …) donnent des sons « auditivement identiques » auxquels nous affectons un nom conventionnel allant de DO à SI. Ils seront graves ou aigus, mais nous aurons la sensation d’un son totalement analogue. C’est la place occupée par la NOTE dans le spectre audible qui caractérisera l’Indice de cette dernière. Par exemple sur la Fig.57 on peut se faire une idée de la notion de puissance de deux pour le LA si cher aux musiciens. Le LA indice 3 que fait entendre ce bon vieux diapason mécanique correspond à exactement 440Hz. Le plus grave des LA est celui d’indice 0 soit 55Hz. Le DO0 fait 32,70Hz et repéré par l’extrémité droite de la zone coloriée en jaune sur la Fig.57 qui correspond aux infrasons. L’Indice le plus élevé dans la gamme tempérée est 7. Un SI7 fait 7902,13Hz. Cette fréquence donne l’impression d’un ton particulièrement aigu. Inutile de focaliser sur

un indice huit qui positionnerait les sept notes entre 8372.02Hz et 15804.26Hz car rares sont les instruments de musique qui en fondamental génèrent de telles vibrations … sans compter qu’avec ces fréquences on pénètre dans le monde silencieux des ultrasons. (Quand notre oreille est neuve, on entend certaines de ces notes, mais passé les cinquante printemps, la notion d’ultrasons devient de plus en plus restrictive !)
Dans la musique dite occidentale, les degrés de hauteurs sont au nombre de douze. Sept d’entre eux sont considérés comme les principaux et sont par convention [DO, RÉ, MI, FA, SOL, LA SI]. L’intervalle compris entre deux gammes d’indice voisin s’appelle une octave.
Les cinq degrés « intercalés » entre les notes ajoutent des dièses et des bémols. Ces nuances comme on va le voir au chapitre suivant ne sont pas réparties « graduellement » ce qui va compliquer un peu la programmation. En revanche, ce qui simplifie grandement le codage, c’est que mathématiquement on peut facilement trouver une équation qui lie un degré à sa base dans l’octave considéré.
Dans la gamme tempérée, la formule permettant de déterminer la fréquence d’une note QRG par rapport à une note de départ QRGDepart est :

Dans cette formule, N est le nombre de demi-tons au-dessus de la note de référence QRGDepart.

Un tout petit chouilla de mathématiques.

x– Oupssssss ! C’est quoi cette formule avec un N/12 écrit en petit et en haut ?
x– J’y pige rien du tout Môamôa !

Rassurez-vous, ce n’est pas si compliqué qu’il n’y paraît, avec quelques exemples on va comprendre, et surtout c’est facile à programmer.
ZEN, restons ZEN … on va y arriver.
Quand on écrit un nombre N en « hauteur », on veut simplement préciser que la base ne sera pas multipliée par ce nombre, mais élevée à la puissance. C’est à dire que l’on va multiplier N fois ce nombre initial par lui-même. Cet opérande N est nommé l’exposant. Exemple :
5 * 4 = 20 > On a ici décrit une multiplication.
5 4 = 5 * 5 * 5 * 5 = 625 > On a ici décrit une puissance > Calcule 5 à la puissance 4.
Cas particulier : Le Carré 5 2 = 5 * 5 = 25.
Cas particulier : Le Cube 5 3 = 5 * 5 * 5 = 125.

– Fastoche non ?
– Ouaissss, mais dans le calcul encadré on divise par 12, tu peux me détailler le calcul ?
– Oui je le peux, par exemple pour une base correspondant au SOL3 à générer ça donne :

• La NOTE de départ d’un calcul sera pour nous toujours le DO du même indice, ainsi l’entier N sera toujours positif. Mathématiquement ce n’est pas
x   impératif, mais « programmatiquement » ce choix arbitraire nous simplifie l’écriture des instructions et surtout reste compatible avec le type byte.

– OUF, c’est assez compliqué comme ça.
– J’en conviens un tantinet. Voyons la suite du calcul :

• Un SOL dans une gamme tempérée occupe le degré 7, car la référence se jalonne sur zéro. Dans notre cas, le calcul de l’exposant devient :
x   N/12 = 7/12 = 0.5833333.
• Le SOL3 = DO3 * 2 7/12 = 261,63 * 2 7/12 = 392,00Hz.
Pour effectuer ce calcul, on multiplie 0.5833333 fois 261,63 par lui même. On dit simplement que l’on a élevé 261,63 à la puissance 0.5833333. Il ne s’agit que d’un calcul particulier, comme multiplier, diviser, extraire une racine carrée etc. Pour chacune de ces opérations typiques les mathématiciens ont développé des protocoles que nous utilisons « manuellement » ou inscrits en binaire dans une calculatrice. On se doute que pour le calcul des puissances, il suffit sur la calculatrice d’appuyer sur la touche [Puissance] au lieu de +, de * ou de /. Au même titre que le C++ de l’IDE met à notre disposition les opérateurs *, /, +, – etc, il nous fournit la fonction pow() qui sera chargée de ce type de calculs. C’est une fonction, c’est à dire qu’elle retourne une valeur et son appel peut être disposé dans le code à tout endroit devant « contenir » une constante ou une variable.

Calcul de puissances avec le C++ de l’IDE.

Élever à une puissance exige de préciser à la fonction pow() deux opérandes : La BASE et l’EXPOSANT. Par exemple, le volume d’un cube s’écrira :
VOLUME = pow(COTE, 3); car nous savons que pour trouver le volume d’un cube, il suffit d’élever la valeur de son coté au cube, d’où cette terminologie de cube quand on doit multiplier trois fois une entité par elle même. Pour inscrire dans le programme l’instruction qui va calculer la valeur d’une fréquence, il suffit d’écrire : Frequence_desiree = DOde calcul * pow(2, Position/12);

Cette équation constitue la trame du calcul, car le DOde calcul sera fonction de l’Indice désiré et devra être déterminé pour se « loger » dans cette équation.
Le tableau donné ci-dessous présente les fréquences relatives à DOde calcul en fonction de l’Indice. Remarquez au passage que dans la colonne coloriée en jaune on retrouve la fréquence de 261.63 utilisée dans le calcul présenté ci-dessus. Vous pouvez également vérifier que chaque note s’obtient en multipliant la précédente par deux. Dans le programme il serait donc parfaitement judicieux d’employer un calcul élémentaire à partir de la constante 32,70. Le code en serait certainement moins volumineux. Ce n’est toutefois pas le choix qui a été fait, car les calculs diminuent la précision sur les fréquences car on perd les décimales. Pour ne pas cumuler deux approximations, le choix consiste à définir ces valeurs dans un tableau de constantes :

dans un tableau de constantes :
Avant de détailler le calcul réellement effectué pour déterminer la valeur de Frequence_desiree, voyons au préalable la façon dont sera mémorisée une séquence musicale, car on n’enregistre plus des valeurs de fréquences, mais des NOTEs associées à des Indices.

Organisation des données.

Inévitable recommencement, la mise en place des données et surtout de leur stockage en mémoire doit systématiquement engager une recherche d’optimisation en taille. Plus la donnée sera économe en nombre d’OCTETs, outre l’occupation de RAM, plus ses chargements et déplacement dans le microcontrôleur seront rapides. Chaque note sera représentée dans un byte dont la valeur sera comprise entre Ordre = 0 et 6 : 0 pour le DO, 1 pour le RE, 2 pour le MI … 6 pour le SI.
Tout aussi économe, l’Indice va varier entre 0 et 7 et sera également indiqué par un byte.
Une séquence complète sera donc logée dans un « tableau double ». Au moment de générer ou d’afficher une tonalité, un pointeur global PTR sera indexé sur la position concernée. Toutes les procédures de servitude seront assujetties à PTR pour effectuer un travail quelconque relatif à la tonalité en cours de traitement. La Fig.58 résume la technique de stockage et de traitement d’une séquence.

Dans cet exemple, le nombre de notes dans une séquence est de 4. Pour optimiser la taille occupée dans la RAM par les variables, il y a superposition d’identificateurs. Le nombre de notes contenues dans une séquence est préservé dans Tmp_INF. Le nombre maximal de tonalités possibles est précisé dans la directive #define NB_Tonalite qui ici vaut10. Vous pouvez sans grande pénalité l’augmenter à convenance puisque chaque note ajoutée ne prendra que deux OCTETs de plus.

Calcul de la fréquence en fonction de la NOTE à générer.

Deux aspects indépendants viennent compliquer la programmation du calcul de la fréquence. La première difficulté résulte du filtrage à effectuer dans ce calcul pour « sauter » les divers demi-tons que nous éliminons volontairement du processus. (Justification : Lors de la saisie on divise par deux le nombre des valeurs à échantillonner avec le bouton rotatif, car sauf cas particulier les codeurs musicaux n’emploient pas les dièses et les bémols.) La deuxième complication vient du fait que la fonction pow(BASE, EXPOSANT) les deux données numériques peuvent être quelconques et en particulier des fractionnaires. Le résultat retourné est un double. De plus pow() ne s’utilise qu’avec des variables de type float. Si on propose des int, long, etc, le résultat sera erroné. Dans la syntaxe décrite en ligne il est suggéré de transposer type « à la volée », mais les essais personnels avec les exemples suggérés n’ont pas fonctionné. Il semble donc impératif d’affecter aux paramètres et d’utiliser dans la formule de calcul que le type float. C’est cet aspect un peu indigeste de l’IDE qui impose dans la formule codée une variable Pointeur.
Examinons le tableau de la Fig.59 qui détaille dans sa première colonne comment sont réparties les 12 degrés d’une gamme tempérée. On remarque qu’un demi-ton peut être vu comme de degré inférieur augmenté d’un incrément, ou le degré supérieur diminué d’un écart. Seuls le RE et le LA ne satisfont pas à ce critère. Dans le tableau de la Fig.59 seules les lignes avec une note principale coloriée en bleu foncé seront retenues, les autres seront filtrés. Dans le programme, la ligne (1) donne à Pointeur la

valeur mémorisée dans la séquence et indexée par PTR. Par exemple si dans la cellule indexée par PTR la valeur est 3, Pointeur vaudra 3.0 ce qui mathématiquement parlant est strictement identique. Il semble à première lecture que créer une variable locale pour y mettre la même valeur est un peu gneugneu. Pourtant, si dans le calcul de la ligne(4) vous remplacez Pointeur par PTR, le résultat sera erroné. Et oui … le coté pointilleux de la fonction pow() qui ne veut manipuler que des float. De toute façon il aurait été obligatoire de créer une variable locale pour préserver PTR, car le traitement des lignes (2) et (3) ne doit pas le modifier. La subtilité de programmation réside ici dans l’adoption d’un float alors que PTR et de type byte. La ligne de code (2) effectue le filtrage de la zone jaune, alors que (3) se charge de la plage rose. Avouez que pour générer toutes les fréquences des NOTEs musicales, la fonction codée en C++ reste étonnamment compacte. Et encore, si vous désirez la totalité des 96 degrés, on peut encore enlever les deux lignes (2) et  (3). C’est pas génial la physicomathématicoinformatique ?

Les faiblesses du démonstrateur.

Les  fréquences sont générées avec la partie entière résultant du calcul. Par exemple un MI2 sera de 164Hz alors qu’en théorie il serait de 164,81Hz. Certaines notes sont ainsi très légèrement « dégradées », avec un effet de plus en plus dérisoire quand l’indice augmente.
Le but étant principalement d’aborder la génération musicale sur Arduino et le calcul exponentiel, le démonstrateur P25_GENERATEUR_de_TONALITES.ino n’est absolument pas optimisé en code, un gain de consommation mémoire étant largement possible. En contrepartie, ce petit programme permet d’aborder en détail le traitement musical avec l’IDE et fournit des protocoles d’exploitation parfaitement opérationnels. Ainsi, pour ceux qui désireront modifier leur PICOSYNTHÉ le travail de développement se limitera à une adaptation d’insertion … et d’optimisation. Le listage inclus une foule de remarques qui aident à en comprendre la structure.

Mais aussi sa force et surtout sa convivialité.

Seule façon de savoir si une publicité est mensongère, c’est encore d’acheter le produit pour le tester. En ce qui vous concerne, le coût ne sera pas bien élevé puisqu’il suffit de téléverser P25_GENERATEUR_de_TONALITES.ino sur Arduino pour expérimenter les divers protocoles d’exploitation. Bien que le petit programme expérimental puisse nous fournir la valeur de la fréquence en fonction de la NOTE jouée et de son Indice, le tableau donné dans le chapitre Calcul de puissances avec le C++ de l’IDE nous précise l’intégralité des valeurs théoriques. Ainsi, vous pourrez évaluer la très faible diminution de précision due à la perte des décimales, mais surtout ce tableau permet de disposer des informations bien utiles quand on veut élaborer un jeu d’essais destiné à valider le programme. Au passage, remarquez que la fonction de calcul des fréquences remplace un tableau de 49 long soit 196 OCTETs. Sans compter qu’à la place de la fonction de calcul il aurait aussi été obligatoire d’ajouter une ou des procédures d’extraction des valeurs. Le LA présente la particularité d’avoir des fréquences entières pour tous les Indices. Donc sa génération sera d’une précision maximale. La page d’ouverture montrée sur la Fig.60 respecte l’allure des autres fonctions de PICOSYNTHÉ. On retrouve le TITRE en jaune, et deux zones distinctes dans l’encadré bleu. Pour savoir dans quelle mode se trouve l’Exploitation, l’index latéral se positionne soit à droite au milieu de la zone du haut, soit au centre de celle du bas. Le capteur rotatif n’a aucune raison de modifier les données de la zone du haut. Dans ce mode, tourner le bouton provoquera des BIPs sonores d’erreur. La touche FC- court déclenche la séquence musicale consignée. Sur un RESET la séquence est constituée d’une octave en Indice 3 complétée à la fin par un DO d’Indice 4. Quand on clique sur le bouton poussoir central du capteur rotatif, l’index passe dans la zone du bas.  Dans ce cas, on peut vérifier une à une les notes consignées. La Fig.61 témoigne de la clarté de l’affichage qui dans ce cas précise la nature de la NOTE, son Indice, mais aussi dans l’encadré jaune la valeur de sa fréquence. Cette
dernière comparée à celles du tableau donné ci-dessus permet de valider le traitement du calcul de la fréquence détaillé dans les pages précédentes. Dans cet exemple, la tonalité n°2 de la séquence est un MI d’Indice 5 assez aigu. Dans ce mode, la touche FC- court déclenche la génération de cette note pendant la durée mémorisée. Avec un délai de 20mS, nous n’entendrons pas grand chose. La sortie du mode vérification réaffiche le TITRE de la fonction.
Conservant le protocole de saisie d’une séquence de CODE, la touche FC+ court efface l’écran, génère un BIP d’alerte et affiche le message de demande de confirmation Changer de code ?. Si l’on accepte, de façon banale le logiciel commence par quémander le nombre de tonalités qui seront intégrées dans la séquence codée. Naturellement, il y aura limitation à dix éléments si vous avez exagéré. (Voir la Fig.62 pour laquelle on désire synthétiser une séquence Baudot à cinq BITs)
Toujours aussi banale est la page suivante dans laquelle on va définir la durée d’une tonalité, dont la valeur sera limitée entre 1mS et 1000mS. Tout dépassement de la valeur 1000 sera « raboté ».
Ensuite, on entre dans une boucle qui va ouvrir autant de pages qu’il y a de tonalités à produire dans la séquence du code à générer. La Fig.64 est relative à la tonalité n°2. Tourner le capteur rotatif fait recirculer les notes de DO à SI dans ordre montant ou dans l’ordre inverse en fonction du sens de rotation. FC+ court augmente de un l’Indice avec recirculation en permutation circulaire, alors que FC- court le diminue. Consigner dix notes avec un tel protocole est très rapide, je crois difficile de faire plus simple.
Notez au passage que parfois certains systèmes de codage utilisent des durées très courtes. Dans ce cas, pour nous les humains la séquence sera pratiquement inaudible.
– Et si l’on désire des notes de « silence » dans la séquence ?
Ce n’est pas prévu dans le démonstrateur, car je ne connais pas d’application codée intercalant des silences. Dans ce cas, consignez les notes, relevez les fréquences, puis passez en fonction P23_GENERATEUR_DE_SEQUENCE.ino dans lequel les passages silencieux seront remplacés par des fréquences élevées largement positionnées dans le spectre ultrasonore. Notre appareil de mesurage permet vraiment beaucoup de possibilités …

Une fausse bonne idée.

Construire une stratégie de traitement informatique à partir d’une formule de base d’un phénomène quelconque à simuler n’a rien d’illogique. Il est du reste plutôt sain de traduire en « binaire » les comportements naturels que l’on cherche à copier pour en extraire la quintessence. Toutefois, il peut arriver que des cas singuliers, des propriétés particulières puissent conduire à une approche élégante et plus avantageuse que chercher par des « équations de base » à copier la nature. Le bénéfice que nous allons tirer de cette expérience résulte de la façon dont le compilateur génère le code. Chaque fois que l’on écrit une ligne d’instruction, il la décortique. Puis en fait l’inventaire des procédures à aller chercher dans sa bibliothèque. Si par exemple il rencontre une ligne d’instruction du genre Y = X * 3 / (2 + 5); le compilateur déduit qu’il faudra que le code objet soit pourvu de l’opérateur *, de l’opérateur / et enfin de l’acolyte addition +. Il compare alors cette liste avec celle des séquences de code déjà intégrées au programme, car rencontrées dans le source qui précède. Si jusqu’à cette ligne * n’a jamais été rencontré, alors le « paquet d’octets » relatifs à cette fonction sera ajouté au programme, et la liste des « déjà présents » sera mise à jour. Par ce mode de fonctionnement, le compilateur n’encombre la mémoire que si une fonction est réellement invoquée, et cette dernière ne sera copiée dans le code qu’une seule fois.

Pour calculer la fréquence d’une note, la belle formule encadrée dans le chapitre La complicité des mathématiques avec les partitions musicales fait appel à la fonction puissance. Pour évaluer le coût en octets de cette séquence de programme, il suffit de compiler une première fois P25_GENERATEUR_de_TONALITES.ino qui aboutit à un code objet de 15680 octets. Puis, on place en remarque la ligne de calcul contenant le pow(). On recompile pour s’apercevoir que le code maigrit brusquement à 14150 octets. Il est facile d’en déduire que la simple écriture de pow() dans le source engendre une facture salée de 1500 octets pour ces « trois petites lettres ». C’est qu’élever une valeur à une puissance quelconque impose une quantité de calculs et de comparaisons notables, nous entrons avec cette fonction dans du calcul « transcendant ». Il se trouve que l’on peut allègrement se passer de ce luxe si l’on oublie la formule fondamentale et que l’on focalise notre attention sur :

Deux notes dont les fréquences fondamentales ont un rapport qui est une Puissance de deux (C’est-à-dire la moitié, le double, le quadruple …) donnent des sons « auditivement identiques » auxquels nous affectons un nom conventionnel allant de DO à SI.

Cette phrase est directement recopiée depuis le chapitre cité, strictement sans modification. Comme dans un contrat d’assurance, ce n’est pas ce qui est écrit en gros qu’il faut analyser avec attention, mais les plus petites lignes en polices de 4 avec des mots inconnus ! Dans notre cas, c’est la remarque qui était ajoutée en gris pour ne pas trop empiéter sur le texte de base qui est importante.
Et oui, la puissance de deux peut être remplacée par une simple multiplication ou division, et ces opérateurs sont gratuits puisque ajoutés au code depuis des chapitres et des chapitres.

CONCLUSION : Au lieu de partir des DO et calculer les écarts par les puissances, on va baser le traitement sur une gamme complète. On peut choisir l’Indice 0 et multiplier par deux les fréquences autant de fois que nécessaire pour changer d’Indice, ou se baser sur la gamme Indice 7 et en diviser à convenance par deux les fréquences relatives aux sept notes. C’est cette deuxième technique qui sera utilisée, car elle procure une plus grande précision vers les tonalités aigües.
Dans P25_GENERATEUR_de_TONALITES.ino les modifications à apporter sont vraiment mineures. Le démonstrateur P26_Une_gamme_bien_temperee.ino en apporte la preuve. Le tableau comportant les DO est remplacé par

x                   long GAMME_indice_sept[7] = {4186, 4699, 5274, 5588, 6272, 7040, 7902} ;

contenant les valeurs des fréquences des sept notes de la gamme Indice 7. Par rapport aux données du tableau proposé ci-avant on observera que l’on a arrondi la fréquence, par exemple 6272 est légèrement plus précise que 6271 qui était obtenu par l’ancien calcul. C’est du gagne petit, mais il vaut toujours mieux un petit plus qu’un grand moins quand on change de stratégie. On gagne également un emplacement dans le tableau, soit quatre octets. Tout bon ça !
C’est surtout la procédure de calcul des fréquences qui va bénéficier d’une sacré cure de jouvence. Entièrement listée ci-dessous on constate qu’elle se résume maintenant à peu de chose :

En ligne (1) on déclare une variable locale qui va servir au calcul de la fréquence.  La ligne (2) très naturelle va chercher la valeur de la fréquence correspondant à la NOTE désirée. Comme l’indique l’identificateur du tableau, cette valeur correspond à l’Indice 7. Toute aussi évidente l’instruction (3) saisit dans le CODE musical mémorisé l’Indice souhaité pour la tonalité pointée par PTR. C’est la ligne (4) qui se charge de diviser par deux autant de fois qu’il le faudra  cette valeur pour aboutir à la NOTE d’Indice souhaité. Certains vont objecter qu’il aurait été possible d’initialiser à 7 la valeur du compteur I directement dans sa déclaration en ligne (1). Généralement j’évite cette façon de coder, je préfère pour des raisons de lisibilité effectuer l’initialisation dans la ligne de code directement concernée. Le résultat compilé est identique, mais pour comprendre un programme je crois que c’est plus avantageux. Faites chauffer le compilateur. Le code dégringole à 14210 octets et ne réserve plus que 507 emplacements pour les données dynamiques soit un gain de 1470 octets pour le programme et une économie de quatre octets pour les données. Yesssssss !

De la bonne volonté, mais … peut mieux faire !

Jamais content les clients, vous leur faites une promo à 1470 octets de moins et ils en veulent plus. (Des efforts, pas des octets !) Bien qu’une optimisation à outrance va à l’inverses de la clarté en lecture du source, quand on veut gaver la mémoire d’instructions, chaque cas particulier peut être exploité pour minimiser le code. Décaler à droite n’est pas spécialement évocateur pour comprendre la genèse de nos notes musicales, mais si l’on a bien présent à l’esprit qu’un SHIFT revient à multiplier ou diviser par deux, pomponner encore un peu notre procédure peut compléter le régime amaigrissant. Si dans la ligne (4) on remplace la division par deux / 2 par un décalage d’une position à droite, ce qui revient au même mathématiquement, l’écriture devient :

x                        I = 7;  while(I != Indice) {Frequence_desiree = Frequence_desiree >> 1; I–;} }

La compilation dégénère à 14182 soit 28 octets de remise supplémentaire. Notre programme, suite à toutes ces améliorations devient moins luxueux qu’à l’origine, et l’on peut envisager sérieusement d’en ajouter la fonction dans le MENU de base de PICOSYNTHÉ.

La morale de ce chapitre est facile à déduire : On se précipite trop souvent sur les solutions évidentes, alors qu’une analyse plus fouillée peut conduire à de réels bénéfices. À bon entendeur …

Pour « faire joujou » avec la fonction de génération de nombres aléatoires, en tournant le capteur rotatif quand on est en mode exploitation, après confirmation avec FC+ court, on déclenche la génération d’un CODE totalement aléatoire, tant au point de vue du nombre de tonalités incluses, de la durée des tonalités musicales, que de celui des notes affectées. N’y voir qu’un petit exercice de style, qui se limite à une petite récréation durant laquelle on fait appel à la fonction random(MAX) qui génère un entier compris entre 0 et MAX bornes comprises. Toute rotation du bouton quand l’index est dans la zone du haut demande confirmation. Si on accepte, la séquence actuelle est remplacée par un CODE chaque fois différent. On remarque en ligne (1) que la

séquence de Demande de confirmation fait l’objet d’une procédure indépendante. La ligne (2) se charge de calculer le nombre de tonalités qui vont constituer le code. Comme ce dernier ne peut être nul, random va calculer un entier aléatoire compris entre 0 et le maximum possible moins un. Ainsi, dans notre cas la valeur retournée sera comprise entre 0 et 9. Le -1 est compensé par un + 1 avec au final Tmp_INF qui sera compris entre 1 et 10. La particularité de la ligne (3) réside dans le random(100,300) à qui on impose également la limite inférieure. Par choix, les durées seront donc arbitrairement comprises entre 0,1 et 0,3S. L’instruction (4) va compter pour générer Tmp_INF tonalités différentes. (5) pour sa part calcule des entiers entre 0 et 7 pour positionner les Indices, et (6) s’occupe de calculer des entiers compris entre 0 et 6 pour conditionner les NOTEs. Enfin (7) se charge de restituer l’écran complet sur lequel nous pouvons immédiatement voir les changements Nbr, ΔT etc.

L’ajout de cette fonction dans le programme complet n’est raisonnable que si elle s’accompagne d’une optimisation à outrance, car le code commence à encombrer sérieusement les lieux. Les possibilités graphiques de l’écran OLED permettent d’envisager avec optimisme la fonction WOBULATEUR, mais il ne faut pas se leurrer, cette dernière sera gloutonne en ressources, il faut impérativement se montrer avare tout au long du développement logiciel. Probablement que nous n’aurons pas le loisir d’agrémenter notre appareil d’un LOGO, alors ÉCONOMISONS UN MAX ! La compilation de P26_Une_gamme_bien_temperee.ino montre que le petit amusement de génération aléatoire de séquences codées consomme la bagatelle de 500 octets. Pour le programme complet cette plaisanterie est évidemment totalement exclue. Dans la stricte inclusion de cette dernière fonction dans P27_COMPLET_avec_7_Items.ino, on constate à la compilation que le corps du programme augmente de 1716 octets. Ce n’est pas négligeable, mais d’autres items du MENU se sont avérés plus gourmands. Par contre, les données dynamiques s’étirent de 118 emplacements ce qui fait beaucoup. Avant d’envisager le développement d’un WOBULATEUR hypothétique, il faut obligatoirement soumettre le programme actuel à une cure de désintoxication. On se doute que nous allons ressortir les méthodes déjà employées au cours de nos didacticiels.

Préparer l’avenir : OPTIMISATIONNERunMAX !

Gouverner c’est prévoir, et si parfois les mesures prises sont impopulaires, seul l’avenir peut en démontrer le bienfondé. Dans cet ordre d’idées, nous allons supposer que la place disponible après optimisation sera suffisante pour contenir à la fois la fonction WOBULATEUR et la possibilité de faire afficher notre LOGO. C’est un pari sur l’avenir. L’enjeu n’est toutefois pas primordial. La seule pénalité sera d’avoir consacré un peu de temps à l’affichage du dessin. S’il faut éliminer la séquence d’affichage de la SALAMANDRE, ce ne sera pas pour autant un drame. Par ailleurs, cette décision présente l’avantage d’organiser dès ce stade l’occupation de l’EEPROM. Si d’aventure on devait faire de la place, la bestiole resterait sagement dans sa cage binaire, n’occupant que 120 octets en mémoire non volatile, il sera inutile de l’effacer car pour notre application nous n’utiliserons probablement pas les 1024 emplacements disponibles.

Première étape : Loger le LOGO en EEPROM.                                             .
Il suffit de réutiliser P11_Ecriture_LOGO_en_EEPROM.ino qui va se charger de cette phase. Ainsi PICOLAB et PICOSYNTHÉ présenteront une apparence homogène.  ATTENTION : Quand on réutilise le programme pour écrire le LOGO en EEPROM il faut penser à modifier la sortie #define broche_SDA 6 qui devient #define broche_SDA 8.

Deuxième étape : Inscrire les textes en EEPROM.                                             .
Nous avons déjà constaté que c’est l’un des moyens les plus radicaux pour faire des économies. Dans cette optique, activez le programme utilitaire P28_Ecrire_les_textes_en_EEPROM.ino dans l’IDE.

Troisième étape : Utiliser le LOGO et les textes.                                             .
Quand on insère dans P29_COMPLET_avec_LOGO.ino la séquence d’affichage du LOGO, le programme enfle de 330 octets. Ensuite on ajoute la procédure d’affichage des textes EEPROM et on modifie les séquences concernées. Le gain en taille programme et surtout en variables dynamiques est substantiel. Pour compléter la cure d’amaigrissement, on optimise encore quelques séquences ici et là. Au final le bilan est assez inespéré. Le programme diminue de 406 octets et la RAM dynamique de 270, très largement de quoi compenser notre LOGO. Chic chic chic …

>>> Page suivante.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *