URL: https://linuxfr.org/users/zerodeux/journaux/taptempo-en-une-ligne Title: TapTempo en une ligne Authors: zerodeux Date: 2019年07月19日T00:07:05+02:00 License: CC By-SA Tags: perl, perl5, programmation et taptempo Score: 45 En lisant une [dépêche du moment](https://linuxfr.org/news/debian-10-buster-une-distribution-qui-a-du-chien) je découvre en passant le [logiciel TapTempo](https://linuxfr.org/users/mzf/journaux/un-tap-tempo-en-ligne-de-commande). En lisant la description du comportement, par réflexe je me suis dit "tiens ça doit rentrer dans une ligne un algo de ce genre". ```perl perl -ne 'BEGIN{use Time::HiRes qw/gettimeofday/} push(@t,0+gettimeofday()); shift(@t) if @t>5; printf("%3.0f bpm",60*(@t-1)/($t[-1]-$t[0])) if @t>1' ``` Bon ça ne marque qu'avec la touche **Entrée**, pas avec n'importe quelle touche, mais ça affiche bien le BPM en moyennant les 5 dernières valeurs. Et ça rentre dans un tweet (sans compter l'invocation de l'interpréteur : 138 caractères). Je décompose le mouvement : `perl -ne` : le flag `-e` indique que le code va être passé dans l'argument suivant; le flag `-n` indique que ce code sera exécuté pour chaque ligne reçu via stdin, et dans notre cas la source sera la console et la fin de ligne par défaut le retour chariot. `BEGIN{use Time::HiRes qw/gettimeofday/}` : de loin la partie la plus verbeuse, mais il faut bien appeler les choses par leur nom. Le module `Time::HiRes` et un "Perl core module", donc si vous avez l'interpréteur vous êtes sûr que vous avez ce module (sauf sur les distros qui aiment vous embrouiller comme CentOS/RHEL). Ensuite on importe la fonction qui nous intéresse dans l'espace de nommage de notre programme pour ne pas avoir à l'invoquer avec la syntaxe java-esque `Time::HiRes::gettimeofday`. Notez qu'il manque l'aliasing à la Python pour renommer une fonction importée, j'aurai bien aimé renommer `gettimeofday` en `gtod` (ça existe, mais pas en core module à ma connaissance). Comme le one-liner est invoqué à chaque ligne d'input, on limite l'invocation de cet import à la compilation avec `BEGIN` (oui : à la compilation, pas au début de l'exécution, mais dans ce billet vous avez le droit d'ignorer ce détail). `push(@t,0+gettimeofday())` : j'utilise la liste `@t` sans l'intialiser, c'est MAL mais c'est un one-liner hein, tout est permis. Mais le comportement est défini, je sais que la liste est initialement vide, je gère les risques. On relève l'heure et on l'empile à la fin de la liste. Le `0+` est un hack totalement légal et courant pour forcer le résultat de la fonction à être une valeur numérique. Sinon ça renvoie un tuple, cf. [ligne 12 de l'exemple sur la doc](https://perldoc.perl.org/Time/HiRes.html). `shift(@t) if @t>5` : je limite la taille de la liste à 5 éléments en retirant le premier élément si nécessaire (ma liste est donc utilisée en FIFO, je garde les 5 dernières mesures sur une fenêtre de temps glissante). Notez que l'opérateur de comparaison est numérique (en Perl on donc le pendant alphanumérique qui est `gt`) et force Perl à considérer `@t` comme le nombre d'éléments de la liste au lieu de la liste elle-même. Perl est un langage où le contexte intervient tout le temps et si vous dépassez vos premières impressions (c'est ambigu/magique/nimp), vous pourrez découvrir que c'est un moyen d'expressivité dont on a du mal à se passer dans les autres langages. `60*(@t-1)/($t[-1]-$t[0])` : si vous voulez faire la moyenne des deltas entre chaque mesure successive, vous constaterez facilement que le calcul se résume à faire le delta uniquement entre la première et dernière mesure (et cet algo simple m'arrangeait, même si ergonomiquement on tend à préférer des moyennes exponentiellement lissées comme par ex. la fameuse mesure du **load** Unix). En perl l'index -1 d'une liste permet d'obtenir le dernier élément. Au fait, si on a N échantillons, on a N-1 mesures, d'où le facteur `@t-1`. Pour passer des Hz obtenus naturellement à partir du chronométrage en secondes au BPM, ben on multiplie par 60. `printf("%3.0f bpm",...) if @t>1` : il faut bien afficher le résultat, on le justifie sur 3 colonnes et on demande 0 décimales. Détail amusant, on n'affiche pas le retour chariot car votre console va afficher celui que vous avez saisi, et il y a donc une race condition (mais je vous souhaite bonne chance pour appuyer plus vite sur Entrée que l'interprétation de la ligne par Perl). Il faut au moins deux échantillons pour avoir une mesure, et dans le monde merveilleux des entiers, "avoir au moins deux" peut aussi se dire "avoir strictement plus que un". J'ai pris la notation la plus courte. Voilà. Et du coup faire un one-liner qui donne un journal de 100 lignes, c'est fatiguant en fait. **PS** : merci à [François Mazen](https://linuxfr.org/users/mzf) de m'avoir suggéré d'en faire un journal. Il m'a rappelé qu'il existait des portages Perl de TapTempo : * https://linuxfr.org/users/astaoth/journaux/portage-de-taptempo-en-perl * https://linuxfr.org/users/glaeken/journaux/portage-de-taptempo-en-perl6

AltStyle によって変換されたページ (->オリジナル) /