Col-Tracker, part XI

La première partie de cette série est disponible ici.

Deux ans plus tard

Et oui, encore un trou de deux ans avec presque aucune évolution dans Col-Tracker.

Bon, j’ai bien fait quelques évolutions mineures sur les retours de mon béta-testeur, et il a pu composer la musique du jeu Muncher Mouse mais pas grand chose de plus n’a changé.

Nous sommes maintenant en 2020 et à la fin de l’année l’applet Flash utilisé par Col-Tracker ne fonctionnera plus (comme tous les autres applets Flash), et je ne suis pas super motivé pour le ré-écrire en Javascript, donc je ferais sûrement un correctif minimal pour que l’éditeur reste utilisable, mais sans possibilité d’écouter les musiques à part en passant par le « ROM player« .

En attendant il vous reste environ un mois si vous voulez l’essayer :

http://www.fantasy-lands.net/Col-Tracker/

Notez qu’une fois votre clavier configuré il faudra appuyer sur « F3 » pour faire apparaître l’applet Flash, puis cliquer sur l’icône « Flash » pour autoriser l’exécution.

La version actuelle de Col-Tracker

Col-Tracker, part X

La première partie de cette série est disponible ici.

Premier utilisateur !

Depuis quelques semaines, j’ai un utilisateur (salut Cyril ;o) ) qui a bien voulu essuyer les plâtres en essayant d’utiliser Col-Tracker pour écrire la musique du prochain jeu de mon ami Youki.

Bon, comme il utilise un MacBook il a fallu que j’ajoute le support des claviers sans pavé numérique, et que je repense les raccourcis claviers (ainsi qu’une interface pour changer de clavier car pour l’instant je faisais ça à la main dans le code) mais ça n’a pas été trop dur.

Ca fait un long moment que je n’ai plus mis ce blog à jour, mais il y a eu quelques évolutions dans Col-Tracker.

D’abord j’ai corrigé le problème du bruit affreux au début du canal 2. En fait il semble que ce soit causé par le fait que le canal commence par une commande « rest ». Ca ne se posait pas sur le canal 3 car comme la pause était beaucoup plus longue, Col-Tracker n’utilisait pas une commande « rest » mais une note traditionnelle avec un volume de 0 (ça prend moins de mémoire que d’utiliser plusieurs « rest » l’un derrière l’autre).

Je n’ai pas trouvé de moyen élégant d’intégrer ça dans mon code, mais je suppose que maintenant que tout fonctionne il devrait être temps de faire un petit refactoring pour profiter du recul acquis après 4 années de développement.

J’ai aussi implémenté un « ROM player« , qui permet en un clic de générer une ROM au format Colecovision contenant la musique prête à être jouée sur un émulateur, afin de vérifier que la tout fonctionne bien.

Ca m’a permis grâce à Cyril de découvrir un bug de priorité des canaux dans certains cas… mais il semble s’agir d’un bug du BIOS donc je ne peux pas faire grand chose (en gros il faut changer à la main les priorités des canaux sinon un ou plusieurs d’entre eux restent silencieux). J’ai passé quelques heures à tracer le problème sous le débogueur de mon émulateur, et si toutes les données sont au bon endroit, la routine du BIOS essaie de jouer les notes sur le mauvais canal :o(

Je suis assez tenté de remplacer le BIOS par mes propres routines (ce qui me permettrait d’encoder les musiques de manière plus compacte) mais je crains que ça prenne beaucoup de temps avant d’être stable donc je vais éviter pour l’instant.

La onzième partie de cette série est disponible ici.

Col-Tracker, part IX

La première partie de cette série est disponible ici.

Faire des pauses

En fait, si vous donnez une priorité au canal 1 supérieure à celle du canal 2, le canal 2 ne jouera aucune note, et ainsi de suite… donc ma solution au problème des 0xFF de la semaine dernière ne fonctionne pas.

J’ai donc simplement modifié l’algo de génération des pauses pour le canal 3. En fait ce n’est pas si gênant : le surcoût en mémoire sera juste d’un octet dans les cas où on a une pause de 31, 61 ou 62 frames.

A ce point, tout semble fonctionner parfaitement, y compris le mod de test que j’ai composé spécialement pour inclure tous les cas tordus auxquels je pouvais penser !

…enfin jusqu’à ce que j’essaie d’utiliser le mod généré dans un programme directement sur la Colecovision :

Le mod de test ne contenait que 2 patterns jouant une gamme montante, puis descendante (Do Ré Mi Fa Sol La Si Do Si La Sol Fa Mi Re Do), mais pour rendre ça plus intéressant ça jouait « Do Ré Mi » sur le canal 1, « Fa Sol La » sur le canal 2 et « Si Do » sur le canal 3 :

Premier module de test : Une gamme qui monte et redescend

Le fichier ASM généré contenait exactement ce à quoi je m’attendais, mais à l’exécution il y avait un gros son affreux dès que le canal 2 commençait à jouer des notes :o(

Je suis toujours en train de chercher la cause du problème mais il semblerait que le canal 2 ne puisse pas commencer par une pause (étrangement, ça a l’air de fonctionner pour le canal 3)

La dixième partie de cette série est disponible ici.

Col-Tracker, part VIII

La première partie de cette série est disponible ici.

Le silence c’est compliqué

L’éditeur d’instruments avec stages séparés fonctionne, et on peut maintenant jouer une pattern sur 2 canaux (le 1 et le 2).

Pour le 3ème canal, il reste un problème à cause des silences…

J’ai écrit un algorithme pour générer des silences entre les notes de la façon la plus optimale (c’est à dire qui prend le moins d’octets sur la cartouche de la Colecovision) et ça m’a appris beaucoup sur la façon dont le BIOS décode les notes.

Il y a une commande « rest » qui sert à faire des pauses. Celle-ci utilise 5 bits pour la durée de la pause (en nombre de frames, c’est à dire en 1/50 secondes pour une console PAL et en 1/60 secondes pour NTSC). Je pensais que lorsque ces 5 bits étaient à zéro la pause serait de 32 frames (25=32), mais en fait cela fait une pause de 256 frames ce qui est à la fois surprenant et totalement non-documenté(*).

Petit détail amusant, j’avais constaté ce comportement en regardant les sources de l’applet Flash de Daniel Bienvenu, et je pensais qu’il avait fait une erreur (désolé Daniel :o) ). Heureusement c’était un bug facile à corriger, donc maintenant tout devrait fonctionner, non ?

Non… Ca fonctionne bien sur les canaux 1 et 2, mais pas sur le canal 3.

Le problème vient également de la commande « rest« .
Le format de celle-ci est :  » <nº de canal sur 2 bits> 1 <durée sur 5 bits> « .

Lorsqu’on veut faire une pause de 31 frames sur le canal 3, ça donne « 11111111« , ou 0xFF en hexadécimal. Hors, 0xFF est aussi utiliser pour indiquer qu’un canal n’a aucune note.

J’ai supposé en lisant la documentation technique que ça ne fonctionnait que lorsque 0xFF était au début des données du canal, mais en fait dès qu’un 0xFF est présent dans un canal (à la place d’une note) celui-ci s’arrête.

J’ai d’abord pensé à faire un algorithme différent et un peu moins optimisé pour le canal 3 afin de ne jamais avoir de 0xFF mais j’ai réalisé qu’il me faudrait aussi un algorithme différent pour la canal 0 (celui des bruits blancs)(**).

A la place, j’ai essayé une solution un peu plus exotique : Puisque chaque canal « logique » a une priorité, et peut jouer des notes sur plusieurs canaux « hardware« , je vais générer toutes les pauses sur le canal « hardware » 1.

Si je donne au canal « logique » 1 la priorité la plus grande, quand un des autres canaux va essayer de jouer un « rest« , ils vont être suspendus jusqu’à ce que ce canal « hardware » 1 soit disponible. Ca devrait fonctionner cette fois, non ?

Après un test rapide ça a l’air de fonctionner mais il faut que j’implémente cette solution pour pouvoir tester tous les cas. Ca ne fonctionne pas du tout dans l’applet Flash par contre, mais je peux toujours générer des données différentes pour celle-ci (par exemple en remplaçant « 0xFF » par « 0xF 0xE1 » (pause de 30 frames, puis pause de 1 frame)).

Essayons ! :o)

La neuvième partie de cette série est ici.

(*) En fait, je pense que c’est un effet de bord de la manière dont le code à été écris : La valeur sur 5 bits est copiée dans un registre 8 bits (les 3 bits supérieurs sont mis à zéro), puis une pause d’une frame est effectuée et le registre est décrémenté ; la commande se termine quand le registre contient zéro, mais si on part de zéro, celui-ci sera décrémenté avant le premier test, et contiendra alors 255, ce qui entraîne une durée de 256 frames.

(**) En effet ce canal ne supporte pas les « Frequence sweep » que j’utilise beaucoup dans les silences car ça permet d’avoir une pause de 4096 frames pour seulement 6 octets.

Col-Tracker, part VII

La première partie de cette série est disponible ici.

Un petit break…

Bon, il semblerait que j’ai encore été distrait par d’autres projets, et le Col-Tracker n’a pas avancé du tout depuis deux ans :o(

Flash est maintenant totalement obsolète, et il est probable qu’une fois terminé Col-Tracker ne fonctionnera que sur Chrome puisque ce dernier a un plug-in Flash intégré (pour l’instant).

La bonne nouvelle est que l’API audio de Javascript semble assez complète pour que je puisse porter la partie « qui joue la musique » si nécessaire, mais je vais essayer de faire ça le plus tard possible car ça me prendrait sans doute quelques mois.

Mon objectif à court terme est d’implémenter l’éditeur d’instrument et de pouvoir enfin jouer une pattern complète (au moins sur une voix).

A dans deux ans ! (non, je déconne (enfin… j’espère ;o) ))

…et ça repart

J’ai passé un peu de temps à rafraîchir ma mémoire sur le format des notes de musiques du BIOS de la Colecovision. Il y a tellement de paramètres que l’éditeur d’instruments va sans doute ressembler à un simulateur de vol. Ca pourrait être un problème pour les nouveaux utilisateurs, mais ça devrait aller si je fournis quelques instruments d’exemple. Ils n’auront qu’à expérimenter en modifiant les différents paramètres jusqu’à obtenir le son qu’ils veulent.

Le principe d’un instrument sera une suite de « stages » qui correspondront à des « notes du BIOS ». Par exemple pour faire une enveloppe de volume avec 4 stages (ADSR : Attack, Decay, Sustain et Release), on aura :

  • Un stage avec un volume partant de zéro et un « volume sweep » positif pour que le volume atteigne son maximum (c’est l’attaque de la note)
  • Un stage partant du volume maximal avec un « volume sweep » négatif pour que le volume atteigne son niveau de maintient
  • Un stage sans effet pour la phase de maintient
  • Un stage avec un « volume sweep » négatif pour que le volume atteigne zéro

Pour la première version chaque stage sera limitée à ce qu’une « note simple » peut faire avec les fonctions du BIOS (par exemple sur la durée maximale des notes) mais je pense pouvoir enlever ces limites plus tard.

Je me suis rendu compte que j’avais totalement oublié de prévoir un moyen d’insérer des silences entre deux stages mais on devrait pouvoir s’en sortir en insérant une note avec un volume à 0 qui sera de toutes façons converti en silence lors de la « compilation » qui transformera le mod en musique compatible pour le BIOS.

J’ai aussi réalisé que le format des notes du 4ème canal (celui qui génère des « bruits blancs ») était suffisamment différent du format des autres notes pour nécessiter des instruments spécifiques, donc j’ai fait le choix d’ignorer ce canal dans un premier temps.

Bon, il est temps de commencer à implémenter l’éditeur de stages pour les instruments (ça ne fait que 4 ans que j’ai commencé ce projet :o) ).

Il y aura une limite de 16 stages par instruments. Ca peut sembler peu mais puisque chaque stage peut prendre jusqu’à 8 octets au format BIOS, utiliser 16 stages prendrait 128 octets (dans le pratique, je pense que 2 ou 3 stages devraient couvrir 99% des besoins).

Je suis sûr qu’il faudra que je change la moitié de ces choix, mais il faut bien commencer quelque part :o)

PS: Je me suis aussi rendu compte que certains des raccourcis claviers affichés dans la ligne de statut ne correspondent plus à l’implémentation courante, mais je suppose que ça ne deviendra pas un problème avant que j’ai des utilisateurs :o)

La huitième partie de cette série se trouve ici.

Col-Tracker, part VI

La première partie de cette série est disponible ici.

Un vrai éditeur de notes

J’ai enfin implémenté la possibilité de saisir des notes dans les patterns !

Je pensais que ce serait une des parties les plus compliquées mais en fait ça s’est révélé bien plus simple que prévu :o)

La principale difficulté venait d’un truc que je n’avais pas prévu : Les évènements claviers de Javascript ne retournent pas de « Code touche » correspondant à la position physique de la touche sur le clavier.

Comme je voulais permettre de jouer sur deux octaves en utilisant le clavier selon les mêmes touches que la plupart des logiciels de musiques de l’Amiga, cela donnait pour le premier Octave A, Z, E, R, T, Y pour Do, Ré, Mi, Fa, Sol, La… sur un clavier Français mais pour un clavier Anglais c’était Q, W, E, R, T, Y pour ces mêmes notes.

Les raccourcis claviers de Col-Tracker en AZERTY et QWERTY

J’ai donc du ajouter une fonction de configuration permettant à l’utilisateur de choisir son clavier, et une couche d’abstraction qui me renvoie directement le code correspondant à la note (au lieu de recevoir un code « A » ou « Q » pour la touche correspondant au premier Do, je reçois « K_C » (« Keyboard, note C » ; « C » correspond au Do en notation anglo-saxonne, qui est celle utilisée par les Trackers). L’avantage est que je n’ai pas besoin de me soucier du clavier de l’utilisateur une fois la configuration effectuée.

L’inconvénient par contre est qu’il faudra sans doute que je supporte plein de claviers différents, mais pour l’instant je me limite à l’AZERTY et au QWERTY puisque ce sont les deux seuls dont je dispose.

Je suis content d’avoir pensé dès le début à intégrer une ligne de statut pour afficher les raccourcis claviers car … il y en a beaucoup. Voici le contenu de cette ligne quand l’éditeur de patterns à le focus clavier :

Use Piano key shortcuts for notes, Keypad 0-9 for changing octave, Keypad / and * for changing instrument, Keypad +/- for changing volume, Ctrl + previous keys to edit current note and Shift+keypad +/- for detuning the current note

Je ne me serais jamais souvenu de tout ça :o)

J’ai légèrement modifié la gestion des volumes sonores des notes pour une meilleure lisibilité : Au lieu d’avoir un pourcentage entre 0% et 200%, j’affiche maintenant un pourcentage qui varie entre -99 et + 99.

Dans la pratique, c’est quasi pareil, mais c’est beaucoup plus intuitif (je pense) pour les utilisateurs.

Export en local

C’est très pratique de sauver toutes les données dans le LocalStorage HTML5 du navigateur, mais je me suis dit qu’il serait quand même pratique (et plus sûr) de pouvoir sauver sur le disque local de l’utilisateur. J’ai donc ajouté une fonction d’import/export qui permet cela.

  • Pour l’export il suffit d’appuyer sur le bouton « Export Mod« , « Export Pattern » ou « Export Instr.« 
  • Pour l’import, il suffit de glisser-déposer le fichier sauvé précédemment dans le Col-Tracker

Il y avait une petite difficulté dans le fait que l’accès en écriture au disque local via Javascript ne fonctionne que sur Chrome pour l’instant. J’ai donc contourné la difficulté en envoyant les données à écrire à un script PHP qui les renvoie telles quelles mais avec les entêtes HTTP demandant au navigateur de les sauver sur le disque (comme quand vous cliquez sur un fichier ZIP ou BIN dans une page web).

J’ai décidé également de ne pas compresser ces fichiers d’export car il pourrait être pratique de les éditer en local sur le PC avant de les renvoyer dans Col-Tracker.

La septième partie de cette série se trouve ici.

Col-Tracker, part V

La première partie de cette série est disponible ici.

Compression

Grace à la sérialisation de ma classe de base « Bindable » et à la nouvelle API LocalStorage d’HTML 5, il a été plutôt facile d’ajouter de la persistance, permettant à l’utilisateur de sauver dans son navigateur (et de manière persistante) ses instruments, patterns ou même mods complets.

Il reste cependant un petit problème : JSON est très verbeux, et la sérialisation d’un mod complet (même vide) prend… 3,9 millions de caractères ! D’autant plus que comme Javascript utilise UTF16 pour son encodage interne des caractères, ça prend 7,8 Mo !

Ca ne devrait même pas fonctionner puisque LocalStorage est limité par défaut à 5 Mo par site web (d’après ce que j’ai lu, ça ne fonctionnerait probablement pas sur Chrome… C’est une chance que je développe sur Firefox ;o) ).

En cherchant un peu, j’ai trouvé la librairie LZString qui a été écrite justement dans ce but (compresser les chaînes de caractères stockées dans le LocalStorage du navigateur). Ca a l’air de fonctionner mais compresser une chaîne de 3,9 millions de caractères prend un peu de temps.

Heureusement il devrait être possible d’améliorer un peu ces performances. La dé-sérialisation d’un objet s’effectue de la manière suivante :

  • D’abord je crée une nouvelle instance, initialisée avec la valeur par défaut de chaque propriété
  • Puis j’appelle la méthode fromBytes() en lui passant la chaîne de caractère correspondant à la sérialisation de l’objet sauvegardé
  • La méthode fromBytes() remplace la valeur des propriétés présentes dans sérialisation

Il devrait donc être possible de ne sérialiser que les propriétés qui ne sont pas égales à leur valeur par défaut. Faire ce tri n’est pas trivial, mais par contre il y a un moyen très simple de savoir si un objet est égal à sa valeur par défaut : En utilisant la valeur sérialisée d’un objet « neuf » (c’est ce que j’utilise pour permettre la fonction « reset » (utilisée par les boutons « Delete » et « Cut » de l’interface pour réinitialiser un objet)).

Une simple comparaison de chaîne permet donc de savoir si un objet (instrument, note, etc…) est un objet par défaut, et si c’est le cas il suffit de sauvegarder la chaîne « {} » (JSON pour un objet vide) au lieu de sa sérialisation complète.

Ca devrait fonctionner, être rapide, et économiser beaucoup de mémoire.

J’ai fait un test avec un mod presque vide (seulement deux patterns et deux instruments, et le résultat de la sérialisation est réduit à 4531 caractères (ou 9 Ko), soit 800 fois plus court que la version précédente :o)

On pourrait s’arrêter là, mais LZString ne devrait pas avoir de problème à manipuler des chaînes de cette taille, donc essayons de rajouter une étape de compression après la sérialisation : Le mod de test se sérialise maintenant en 383 caractères, soit moins de 1 Ko (10400 fois plus court que la version de départ)

Je pense que je vais m’arrêter là pour la partie sérialisation car maintenant nous avons des tailles de fichier plus qu’acceptables :o)

La sixième partie de cette série est disponible ici.

Col-Tracker, part IV

La première partie de cette série est disponible ici.

Ecrivons un peu de code

Les trois premières parties de cette série décrivent ce que j’ai fait en 2013, mais j’avais été pris par d’autres projets, et tout est resté en l’état pendant 2 ans. J’ai eu beaucoup de mal à me replonger dans le projet car je ne me souvenais plus des détails ; c’est une des raisons pour lesquelles j’ai commencé à écrire ce blog, afin d’avoir une documentation technique à peu près à jour si je devais suspendre le projet de nouveau (en plus de garder la motivation en donnant un peu plus de visibilité au projet).

Nous voilà donc revenu au présent. Je suis motivé à bloc, et j’espère bien finir ce projet (ou au moins avancer suffisaient pour qu’il soit utilisable).

Pour l’instant j’ai la vue principale du projet, mais rien ne fonctionne vraiment à part le bouton pour montrer/masquer l’applet Flash.

Je vais commencer par permettre l’édition des instruments, patterns et du Mod lui-même (dans un premier temps, on ne pourra éditer que leurs propriétés (nom, nombre de notes, durée, vitesse, etc…) car un éditeur permettant de saisir des notes dans une pattern par exemple demandera un peu plus de travail.

J’ai décidé d’utiliser la librairie Javascript Lineage pour avoir un modèle objet de base (classes, polymorphisme, etc…) sans trop de problèmes [Note de 2020: Si cette librairie était très utile en 2015, les versions modernes de Javascript supportent enfin une implémentation utilisable du modèle objet « classique », donc elle n’est plus nécessaire de nos jours. Si vous voulez programmer « orienté objet » en Javascript, utilisez simplement les fonctions intégrées au langage].

La première étape a été de créer une classe de base pour les objets « bindables« . Ce que je veux dire par « bindable » est qu’il est possible d’assigner un contrôle (champ de saisie, case à cocher, etc…) à chaque propriété de l’objet :

  • Quand on « bind » une instance de la classe, tous les contrôles affichent la valeur correspondante à ses propriétés
  • Quand l’utilisateur modifie ces valeurs en utilisant les contrôles, les propriétés correspondantes de l’instance sont modifiées

Puisque j’aurai sans doute besoin de sérialiser ces objets à un moment ou à un autre, j’ai ajouté deux méthodes toBytes() et fromByte() pour sérialiser et désérialiser les instances de ces objets.
J’ai passé un petit moment à essayer d’implémenter une solution « super-optimisée » avant de réaliser qu’utiliser JSON me faciliterait la vie, donc l’implémentation par défaut de ces deux méthodes se contente d’utiliser JSON (on pourra toujours surcharger cette implémentation dans certaines classes si nécessaire).

Ca se présente plutôt bien pour l’instant, mais il manque une couche supplémentaire à mon « framework »…

Un manager pour les lier tous[*]

Maintenant que j’arrive simplement à « binder » une instance d’objet à des contrôles, je me suis rendu compte que dans la pratique j’avais surtout des listes d’objets, et que je devais changer l’instance « bindée » chaque fois que l’utilisateur sélectionne un nouvel objet.

Je pourrais faire ça à la main, mais pourquoi ne pas aller plus loin et implémenter une classe « BindableManager » qui se chargerait de ça ?

Finalement ça c’est avéré plutôt simple, et j’ai maintenant un manager pour chaque liste d’objet qui permet d’associer un tableau d’objets « bindables » à un contrôle de liste, et qui met à jour les contrôles chaque fois que l’utilisateur change l’objet sélectionné.

Le « BindableManager » se charge également de modifier le tableau d’objets quand l’utilisateur modifie certaines propriétés, et met à jour le contrôle de liste quand le nom de l’objet à été édité.

J’ai fais une petite concession pour simplifier le code : chaque liste contient exactement 256 objets. Je ne pense pas que limiter un morceau de musique à 256 patterns (et 256 instruments) soit un gros handicap, et une fois le morceau exporté vers la Colecovision seuls les objets réellement utilisés seront inclus donc ce n’est pas un problème.

Un bonus inattendu à été la possibilité d’implémenter un copier/couper/coller (ainsi qu’un « reset » pour réinitialiser une instance) simplement en utilisant la sérialisation.

Bref, le projet a plutôt bien avancé après cette première séance de codage.

La cinquième partie de cette série est disponible ici.

[*] La version anglaise de ce titre « A manager to bind them all » sonnait beaucoup mieux (surtout pour les fans de Tolkien ;o) )

Col-Tracker, part III

La première partie de cette série est disponible ici.

Quelles fonctionnalités pour Col-Tracker ?

Avant de penser à l’interface utilisateur j’ai passé un bon moment à lire toute la documentation dont je disposais sur les routines du BIOS de la Colecovision utilisées pour la musique.

Puisqu’il n’était pas possible de changer la forme d’onde (seules les ondes « carrées » sont disponibles ; pas de triangle, sinusoïdales ou dents de scie), j’ai décidé d’être aussi flexible que possible pour le contrôle du volume, afin de simuler des enveloppes.

De plus, non seulement chaque instrument aura un (ou plusieurs) volume(s) propre(s), mais il sera possible de modifier ce volume pour chaque note, pattern, ou même au niveau du morceau de musique entier.

Cela permettra par exemple de jouer une pattern avec un volume plus faible que le reste du morceau sans avoir à modifier tous les instruments un par un.

Ca parait simple d’expliquer le principe général, mais la spécification détaillée a été plus compliquée… Au début je voulais juste remplacer les volumes des instruments à chaque niveau, mais ça n’avait pas beaucoup de sens de forcer (par exemple) toutes les notes d’une pattern à avoir le même volume.

Après avoir essayé plusieurs solutions, je suis parti sur un système à base de pourcents :

  • Les instruments sont toujours définis avec une valeur native entre 0 (silence) et 15 (volume maximum)
  • Les autres niveaux (note, pattern et morceau) seront défini avec une valeur entre 0 et 200 correspondant à un pourcentage du volume du niveau précédent (entre 0% (silence) et 200% (deux fois plus fort au maximum, car on ne peut toujours pas aller au delà de 15). Ces autres niveaux ont un volume par défaut de 100% ce qui correspond à « aucune modification »

Je ne suis pas sûr du tout qu’augmenter le volume donne toujours des bons résultats, mais on verra bien quand ce sera implémenté (et il n’est pas impossible que ce soit pratique pour des effets sonores comme un laser ou une explosion).

J’ai aussi décidé d’ajouter un paramètre « detune » (désaccorder) à chaque note afin de permettre d’obtenir presque toutes les fréquences possibles (je ne suis pas assez bon musicien pour savoir dans quels cas c’est utile, mais j’ai vu cette option dans d’autres Trackers, et ça n’a pas l’air trop compliqué à implémenter).

Il y aura aussi une colonne « Effet » permettant de saisir 6 caractères afin de permettre des améliorations futures.

Une chose à prendre en compte avec la Colecovision est qu’il y a deux versions : NTSC et PAL. Ces deux versions sont cadencées à des vitesses légèrement différentes, et ça implique qu’il faut utiliser deux formules différentes pour convertir les fréquences sonores en paramètres pour le chip sonore.

Col-Tracker permettra de générer des musiques pour les deux versions, mais j’ai ajouté un troisième réglage « Mixte ». Avec cette option, au lieu de choisir entre PAL et NTSC quel système jouera les notes justes et quel système sera légèrement désaccordé, on utilisera une formule à mi-chemin entre les deux. Cela signifie que les deux systèmes PAL et NTSC seront légèrement désaccordés, mais pas autant que si le compositeur avait choisi l’autre système comme cible. Encore une fois, je ne suis pas sûr du tout que cette option soit vraiment utile, mais on verra ça une fois que Col-Tracker sera suffisamment avancé pour jouer de la musique :o).

Un problème potentiel est que je ne suis pas sûr du tout de pouvoir rejouer une musique coupée en patterns. J’ai quelques idées pour y arriver, mais si ça ne fonctionnait pas je pourrais toujours dérouler les patterns dans une seule longue liste de notes. J’espère quand même que ça fonctionnera car ça réduira la taille mémoire des morceaux, ce qui est bien pratique car les cartouches Colecovision ont une taille maximale de 32Ko (à moins de faire du « bank swapping« , mais autant éviter si on peut s’en passer).

La quatrième partie de cette série est disponible ici.

Col-Tracker, part II

La première partie de cette série est disponible ici.

Première maquette de l’interface utilisateur

Avant d’aller plus loin, je devais décider à quoi l’application allait ressembler. Je n’avais pas utilisé de Sound-Tracker depuis plus de 10 ans, donc j’ai commencé par une petite recherche d’images des différentes versions disponibles sur Amiga.

La bonne surprise a été que l’interface originale sur Amiga était très simple (bien plus que dans mes souvenirs) et qu’il n’y a pas beaucoup d’informations affichées en même temps (probablement à cause de la résolution graphique de l’époque).

J’ai rapidement fait une maquette en HTML avec la plupart des éléments que je voulais, et l’applet Flash de Daniel Bienvenu que je comptais utiliser, avec un peu de code pour l’afficher ou la masquer (en pratique, il n’y a pas besoin de la voir mais ça peut être pratique pour déboguer).

La seule chose qui manquait (enfin, la seule dont je m’étais aperçu) était un moyen de composer la musique en choisissant une liste de « patterns », mais je trouverai une solution plus tard (si le projet arrive jusque là :o) ).

Puisque mon éditeur allait utiliser beaucoup de raccourcis claviers, j’ai décidé d’ajouter une barre de statut affichant tous les raccourcis actifs, en fonction de l’élément sélectionné, ainsi qu’un clavier de piano affichant les touches du clavier correspondant à chaque note.

Première maquette. Rien ne fonctionnait à part le bouton « Show/Hide player » (Cliquez pour voir en plein écran)

Structure des morceaux de musique

Si vous n’êtes pas familiers avec Sound-Tracker ou ses nombreux clones, cet écran doit vous sembler un peu confus. Pas de panique, voici quelques détails sur les objets qui composent un morceau de musique (ou un « Mod » comme on disait à l’époque) :

  • Le morceau de musique (ou Mod) est composé de plusieurs « patterns » (je n’ai pas trouvé de bonne traduction en Français).
  • Chaque pattern contient une liste de notes à jouer pour chaque canal sonore (nous en avons ici 4, comme la Colecovision) et quelques paramètres propres comme je nombre de notes et la vitesse de défilement (les notes sont jouées de haut en bas)
  • Chaque note contient un ton (do, ré, ré#, etc…) et un instrument (et d’autres paramètres que je ne détaillerais pas ici car… ils ne sont pas encore implémentés :o) )
  • Les instruments permettent de définir comment chaque note sera jouée (par exemple le volume, la durée, ou via une combinaison des vibratos ou une enveloppe de volume)

La troisième partie de cette série est disponible ici.