Attention, ceci est un brouillon !

logo pas beau

Dernière mise à jour : Thu Jan 9 15:40:58 CET 2014

JoyMidi : votre joystick pilote votre tx81z :)

Ce logiciel est une expérimentation pas vraiment terminée, mais je le trouve assez prometteur : il permet de piloter un périphérique MIDI à partir d'une manette de jeu USB. Pour le moment, il n'est testé que sous Linux, mais dès que les principes généraux seront en place, il sera (peut-être) porté dans le poisson piquant.

Il ne connait actuellement que les boutons binaires, c'est à dire que les croix directionelles et les sticks analogiques ne sont pas utilisables. Ce léger inconvénient n'est que provisoire. Il ne peut piloter qu'un seul synthé MIDI sur un seul canal. Ce léger inconvénient n'est pas plus provisoire que le précédent.

L'interactivité n'est pas encore au rendez-vous, sauf pour les vieux qui considèrent que _tout_ peut se faire avec vim. Pratiquement tout le machin se règle par des fichiers de configurations textuels, garantis sans la moindre tache gluante de XML. Il existe plusieurs catégories de fichier, qui sont détaillées plus loin.

Qaund le premier prototype sera opérationnel, je rajouterais la possiblité de surcharger les valeurs déclarées dans ces fichiers par des options de la cli et/ou des variables d'environnement.

les fichiers de configuration

Quelques règles fluctuantes mais néammoins générales : par défaut, les fichiers sont placés dans $HOME/.tth/joymidi/. L'option -i /un/chemin permet de choisir un autre endroit. Cet emplacement pourra peut-être être surchargé par la variable shell JOYMIDI_RC_DIR (si ça marche un jour). Le caractère # introduit les commentaires, si ils sont au début de la ligne. Les lignes vides sont ignorées. Tout le système est case sensitive. Les valeurs numériques peuvent être introduites en décimal, octal ou hexadécimal : 42 042 0x42. Les lignes ne doivent pas dépasser (en gros) 200 caractères.

Nous avons trois (ou plus) catégories de fichiers : le fichier maitre, qui contrôle les aspects généraux du système (son nom est fixé (par dddd) : context.init), les fichiers de description des manettes, et, pour finir, les "pilotes de synthés".

Une des plus grosses difficultés que j'ai rencontré lors de la création de cet engin a été, justement, l'organisation de ces fichiers de configuration. Nous devons prendre en compte plusieurs catégories de choses : le contexte général tout d'abord, puis les manettes de jeu, les synthétiseurs, et les connections entre ces manettes et ces machines à bruit. Je peux vous garantir que ce n'est pas simple, surtout quand on est seul à réfléchir sur la chose\dots.

context.init

Ce fichier contient les réglages généraux du bouzin. Il définit tout un paquet de choses essentielles : comment accéder au baton, par quel moyen causer aux machines cibles,

joydevice
Le périphérique qu'il faudra utiliser pour capter vos mouvements de doigts. Exemple : /dev/input/js0. Exemple à ne pas prendre au pied de la lettre si vous jonglez avec vos ports USB, mais udev peut aider dans ce cas là.
midiout
Le port de sortie, le cable, la prise, le lien physique pour causer à votre tr505. Exemple : /dev/midi. Avec cette option, nous attaquons directement le device-driver, sans passer par des couches plus évoluées. Solution portable, mais rustique.
alsaname
Le nom du client (serveur ?). Avec cette option, c'est la partie sequencer d'ALSA qui est utilisée. Il est donc possible de router les actions sur le joypad vers d'autres applications, ou même vers d'autres machines grace à aseqnet.
midichannel
Le canal MIDI par lequel vous allez causer à votre psr6300. Attention, ce numéro de canal va de 1 à 16, donc il y a des off-by-one qui trainent peut-être dans le soft. Yhbw.
buttonsconf
Chacun des boutons de votre manette est identifié par un numéro, ce qui n'est pas facile à mémoriser. Cette variable fournira donc le nom d'un fichier permettant d'associer un nom à un numéro de bouton (et éventuellement d'autres paramètres).
translation
Le nom du fichier qui contiendra l'assignation de chacune des touches du lolpad vers une des "notes" de votre machin MIDI. La syntaxe est détaillée , et ce n'est pas un cadeau.

Voyons un exemple :

# --------------------------------
#   primary initialisation file
# --------------------------------

joydevice      /dev/input/js0
midiout        /dev/midi
alsaname       joymidi

# warning: numbering of midi channel start at ONE !
midichannel    10

buttonsnames   thrustmaster.init
translation    drumtracks.init

Dans le cas où midiout et alsaname sont tous deux présents, (en principe) c'est le dernier rencontré qui décide de la sortie à utiliser.

D'autres informations de contrôle vont peut-être arriver un de ces jours dans ce fichier, par exemple le volume général envoyé avec chaque note on, ou bien une transposition de toutes les notes... La limite est l'imagination.

buttons.conf

Comme vu précedemment, les boutons sont identifiés par des numéros. Ce n'est pas très facile à manipuler, nous allons donc associer un nom à chacun de ces codes. Ces noms devront être constitués uniquement de lettres, de chiffres et du _, en tenant compte de la casse. Les codes numériques des boutons peuvent être trouvés avec le dumpeur adéquat. Voyons rapidement un petit exemple :

# les boutons du gadget 
button		wtf		1
button		omg		2	65
button		osef		3	%50

# la croix directionnelle 
axis		up_down		5
axis		left_right	4	

Le premier champ est le type de bouton : button désigne un bouton binaire (on/off) et axis désigne un bouton analogique. Le second champ est le nom que vous allez assigner à ce bouton ou ce valuateur. Le troisième est le numéro par lequel le bouton est connu du système. Il y a un outil pour découvrir ces numéros.

Les éventuels champs supplémentaires n'ont pas encore de destination précise. Je pense, entre autre, au volume. Dans cet exemple, il peut être absolu et dans l'intervalle [0..127], ou, si précédé d'un %, le pourcentage du volume par défaut (actuellement figé à 127 par dddd). A ce jour (19 mai 2010), ce n'est pas implémenté.

boombox.init

Actuellement, le format de ce(s) fichier(s) est en pleine crise d'incertitude quasi quantique. Comme le reste. Le 7 mai, j'ai rajouté la description des chargements de sysex sur la machine cible. Et à partir de maintenant, l'ordre des instructions dans ce fichier aura une importance. La seconde version est donc de ce genre :

# configuration du machin MIDI quelconque
asciiupload sysex-tx81z.ascii

# translation pour un machin MIDI quelconque
keys
wtf	0x55
omg	42
6	51
osef	88	c=12
.

La première section contient des instructions pour éventuellement changer la configuration du synthé au bout du fil, par exemple pour splitter un tx81z (au hasard :) en 8 sons monophoniques. J'envisage plusieurs options possibles : fichiers sysex en ascii ou en binaire, ordres MIDI en program change, setup du volume, du pitch-bend; vous voyez le genre, et en prime, la description de ces ordres :

asciiupload filename
Envoi d'un fichier éditable avec vim et dont la structure est en cours de définition. Fonction pas écrite.
binupload filename
Envoi d'un fichier brut de décoffrage, un binaire obscur tel que ce que l'on obtient avec un dumpeur de sysex. Fonction pas écrite.
programchange nnn
Envoi d'un ordre de changement de programme désigné par son numéro. Fonction pas écrite.

La seconde section débute par le mot clef keys et se termine par un . seul sur sa ligne. Rassurez-vous, ça va être plus simple qu'un sendmail.cf (loulz). Le premier champ est soit un nom de touche tel que déclaré dans buttons.conf, soit un numéro de touche qu'il faut détecter avec dump_my_joy. Le second champ est le code MIDI de la note, exprimée en décimal, en octal (0nnn) ou en hexadécimal (0xnn), qui sera éventuellement modifié quand la fonctionnalité detune sera implémentée. Quand à l'éventuel troisième champ, il permettra par exemple de surcharger le numéro de canal déclaré dans context.init.

Je vais essayer de fournir, dans la mesure des machines que j'ai sous la main, ou dont j'ai la documentation, des exemples crédibles de fichier de branchement directement utilisables.

envoyer des bytes

Certaines des machines que nous joystickons peuvent être configurées à distance. Il juste suffit de leur envoyer les bons octets : changement de programme, sysex, que sais-je encore ?

Pendant que je confectionne le code, je vais tenter de mettre au point un exemple pour le tx81z : avoir plusieurs sons différents, ce qui va probablement impliquer de pouvoir envoyer les noteon/off sur plusieurs canaux différents ?

# nous allons supposer (dddd) que la tx81z est sur le canal 1, et lui
# envoyer un 'program change' pour le 109 (qui pulse bien)
0xc0 109

Ah oui, mais non..., ça ne va pas marcher ;( car quand le soft démarre, on n'a pas encore fait le aconnect 128:0 24:0 qui 'branche' le joystick sur la machine. Big L00z3, et là, sur le coup, je ne vois aucun moyen de régler le problème, à part passer directement par le lien physique ? Ou alors, peut-être il y a ce qu'il faut dans ALSA pour qu'une application détecte qu'un client s'est mis à l'écoute. Piste à creuser.

installer la chose

C'est très rudimentaire : il faut lire le Makefile, essayer de le comprendre, taper des commandes ésotériques dans le xterm, interpréter les messages d'erreur, toussa... Mais dans l'ensemble, sur un Linux classique, ça passe comme un spam au smtp. À condition d'avoir une installation complète d'alsa, avec tout ce qu'il faut pour compiler & linker un programme. Les bubuntistes comprendront.

Dans le Makefile, il y a quelques indications complémentaires sur ce qu'il est possible de modifier à la compilation, eg: le niveau de verbosité des messages de debug. Vous avez aussi un README.txt qui contient des explications approximatives.

L'étape suivante est l'identification des codes que la kernelle vous renvoie à chaque fois que vous appuyez sur la gachette. Pour ça, le petit proggy dump_my_joy peut vous aider. Compilez le, lancez le, et essayez de comprendre les chiffres. Vous allez voir, c'est assez simple. Chaque action sur votre bouton de joie est décodée par la kernelle (merci Ingrid) et renvoyée au logiciel sous la forme d'un assemblage de chiffres, décrits de cette façon :

struct js_event {
        __u32 time;     /* event timestamp in milliseconds */
        __s16 value;    /* value */
        __u8 type;      /* event type */
        __u8 number;    /* axis/button number */
	};

Tout cela semble diablement technique (recette !), et assez éloigné du MIDI. Détrompez vous : il y a quelques analogies, qui sont en fait à l'origine de ce merveilleux progiciel.

Dump my Joy, please...

Après compilation par un trivial make dump_my_joy, vous pouvez le lancer dans un xterm avec l'option -n. Il va commencer par analyser une partie des fichiers de configuration, puis se mettre à lire votre manette et afficher ce qu'il en pense.

Tout d'abord, on voit défiler quelques lignes de technobabage racontant l'initialisation du bouzin, et ensuite, quand vous tripotez la manette, arrive un truc dans ce genre :

   time     type   numbt   value
252205792      1     4         1
252205912      1     4         0
252206400      1     6         1
252207104      1     4         1
252207632      1     9         1
252208056      1     8         1
252209904      1     8         0
252209904      1     9         0
252209936      1     4         0
252209936      1     6         0

Le time, pour le moment, osef. Le type indique sur quel genre de contrôle vous venez d'agir : la valeur 1 est celle qui nous intéresse, elle correspond à un bouton. Un 2 indiquera une croix directionnelle ou un stick analogique, non traités dans cette première version. Le numbt est le numéro du bouton concerné, et finalement la value, elle, nous indique ce qui vient de se passer. : 1 signifie "enfoncé" et 0, "relaché". Ça y est, vous saisissez l'analogie avec noteon/noteoff du MIDI ?

Tout cela n'est pas très clair ? Essayez donc d'enlever l'option -n, et recommencez l'expérience. Voici un affichage qui vous permettra de debbuger facilement votre fichier joypad.init. Pour découvrir les autres options c'est simplement -h.

Hacking the thing ?

N'y songez même pas pour le moment : ya que des bugs. Je ne sais tellement pas comment construire la chose, que le code est en permanente fluctuation. Par contre, les remarques (même désobligeantes) et les suggestions (même trollisantes) sont acceptables; ceux qui savent sauront comment me joindre.

Il y a quand même les classiques fichiers README, BUGS, TODO et CHANGES. Ah, mais... il y a aussi un Makefile, aussi gruik que le reste ! Peut-être un volontaire pour écrire les manpages ?

Debugging the thing (with ALSA)

Première méthode :
lancer joymidi avec les bonnes options, puis utiliser aseqdumap -l pour repérer le port utilisé. Ensuite, aseqdump -p nnn:0 décode ce qui sort du machin :

tth@lol:~/Devel/MIDI/JoyMidi$ aseqdump -l | grep tth
128:0    joymidi                        tth was here !
tth@lol:~/Devel/MIDI/JoyMidi$ aseqdump -p 128:0
Waiting for data. Press Ctrl+C to end.
Source_ Event_________________ Ch _Data__
128:0   Note on                 0  70 100
128:0   Note on                 0  67 100
128:0   Note off                0  70   0
128:0   Note off                0  67   0

Bien entendu, aseqdump -p joymidi fera (en principe), la même chose, si vous n'utilisez pas le potentiel surchargement du nom.

Deuxième méthode :
La première méthode a quand même un biais: aseqdump interprète ce qu'envoie joymidi, et peut éventuellement rater quelques octets mal sentis. Un autre outil du kit ALSA, amidi, peut en théorie montrer exactement ce qui arrive. Mais son utilisation est moins immédiate. Première etape : lancer amidi dans un xterm avec les bonnes options.

xtermA$ amidi -p virtual -d

Deuxième étape : faire la connexion entre joymidi et amidi grace à aconnect. (C'est là que ça n'est pas encore évident pour moi ;)

xtermB$ aconnect -io
client 128: 'joymidi' [type=user]
    0 'tth was here !  '
client 129: 'Client-129' [type=user]
    0 'Virtual RawMIDI '
xtermB$ aconnect 128 129

Et maintenant, dans le premier xterm, on peut contempler les octets envoyés par votre glorieux baton de joie :

90 46 64
80 46 00
90 43 64
80 43 00
90 44 64
80 44 00
90 45 64
80 45 00

Voilà, j'espère avoir fait le tour des méthodes de debugging appliqués à la manette de jeu qui se prend pour un clavier MIDI.

Command line options

Ce gadget de musimatique propose deux binaires utilisables à partir de la cli. Chacun d'entre eux prend des options sur la ligne, et j'essaye de garder une bonne cohérence entre les deux. Demander gentiment avec -h vous donnera quelque chose dans ce genre :

tth@lol:~/Devel/MIDI/JoyMidi$ ./dump_my_joy -h
dump_my_joy options:
  -v : increment verbose level
  -h : get more help (if available)
  -i : set the locations of init files
  -d : use an alternate joy device
  -n : display just the numbers

Voyons cela plus en détails pour certains de ces demandes :

-v
Plus vous rajoutez de -v, plus le logiciel sera bavard. Je pense, pour le futur, ajouter un machin pour n'afficher que des trucs sélectionnés.
-i
-i permet de choisir l'emplacement dans lequel sera lu le premier fichier d'initialisation: context.init. Par defaut, ce sera ~/.tth/joymidi/. A partir de ce moment, l'endroit où seront cherchés les autres fichiers est un peu quantique. Je pense que le code doit être affiné, tel un bon Maroilles.
-n
Pour empécher la traduction en termes humainement compréhensible des valeurs numériques transportées par les petits lutins qui courent sur les bus ethérés de la machinerie logicielle.

Une manette, plusieurs prises

Vous avez peut-être remarqué que le chemin vers le joypad change parfois selon la prise USB sur laquelle il est branché. Il est probablement possible de régler ce léger souci par une règle udev bien sentie. D'autre part, est-il possible d'utiliser joymidi avec plusieurs manettes ? Oui, je pense, il doit suffire de construire plusieurs répertoires avec les bons fichiers et de lancer deux instances de joymidi avec l'option -i foo/ ou -i bar/. Pas encore testé.
Please add more doc here...

Interaction avec ALSA

Tout nouveau, tout pas beau. Je ne suis qu'un noobz en programmation ALSA, et la doc est, comment dire, plutôt faite pour ceux qui savent déja. Ceci dit, avec les exemples fournis, et les trucs qu'on trouve dans le grand Ternet mondial, on s'en sort à peu près.

tth@lol:~/Devel/MIDI/JoyMidi$ aseqdump -l
 Port    Client name                Port name
  0:0    System                     Timer
  0:1    System                     Announce
 14:0    Midi Through               Midi Through Port-0
 16:0    SB Live 5.1                EMU10K1 MPU-401 (UART)
 24:0    UM-3EX                     UM-3EX MIDI 1
 24:1    UM-3EX                     UM-3EX MIDI 2
 24:2    UM-3EX                     UM-3EX MIDI 3
 24:3    UM-3EX                     UM-3EX Control
128:0    joymidi                    tth was here !

Donc voilà, si tout est correctement configuré, notre manette apparait bien dans la liste des périphériques ALSA. Bonne nouvelle, puisque nous allons pouvoir examiner le code MIDI généré. Hop, voilà ce que ça donne :

tth@lol:~/Devel/MIDI/JoyMidi$ aseqdump -p joymidi
Waiting for data. Press Ctrl+C to end.
Source_ Event_________________ Ch _Data__
128:0   Note on                 0  68 100
128:0   Note off                0  68   0
128:0   Note on                 0  67 100
128:0   Note off                0  67   0
128:0   Note on                 0  33 100
128:0   Note on                 0  67 100
128:0   Note off                0  67   0
128:0   Note off                0  33   0

La suite, tonton !

Ne soyez pas impatient, le code est en train de se mettre en place, et le tarball contient déja un peu de grain à moudre. Rappelons toutefois que c'est un brouillon que vous êtes en train de lire. Néammoins, aller jeter un petit regard salace sur contexte.h peut vous apprendre plein de choses.

Ensuite, je prépare calmement un bon hack hardware, que je vous proposerais bientôt, pour brancher un machin élégant (ou steampunk ?) en amont de ce logiciel. Actuellement, j'en suis à l'erreur 404. Et pour finir, quelques exemples d'utilisation avec midish sont en train de voir le jour.

The end, my friends

Donc voilà, il reste un gazillion de choses à faire pour que joymidi soit enfin prêt pour le primetime. En attendant, les dinos ayant tous les droits, je vous recolle la somptueuse gif animée :

logo pas beau, mais qui clignote avec vigueur :)

Ce logiciel est généreusement offert par le dino reconnu tth à tous les gens qui aiment faire librement du bruit avec des machines du siècle dernier. La license (must legalize) sera probablement un truc dans le genre de la dwtfywl; ou pire. Les costumes sont de Paul Boyé et les décors de Donald Portnawak.