fred voisin’s website

computer music producer, since 1989

refonte de la librairie « Morphologie » (1)

12 fév. 2009

Propositions apparaissant pendant la réécriture du code de la librairie « Morphologie » selon les directives que nous nous sommes fixées en janvier.

Etat général du code

La librairie Morphologie, développée à l’IRCAM en 1997 par Jacopo Baboni-Schilingi et Frédéric Voisin, est un ensemble d’outils destinés à l’analyse et la génération de séquence musicales. Dès son origine, elle a été conçue et présentée (notamment au sein du groupe de recherche musicale PRISMA) comme un programme de recherche musicale susceptible d’évolution.
Ainsi, depuis la première version, de grosses différences sont apparues selon les différentes versions des uns et des autres, selon les problématiques apparues et les réponses apportées, mais aussi à la suite de l’évolution des environnements de Patchwork (IRCAM, utilisé jusqu’après 1998), OpenMusic (IRCAM) et plus récemment PWGL (Sibelius Academy in Finland), des différentes versions de LISP (MCL de Digitool ou LispWorks) utilisées pour ces environnements de composition assistée par ordinateur.

Après avoir décidé d’une mise à jour de Morphologie qui comprenne les avancées les plus importantes de ses utilisateurs, voici donc quelques détails de la première étape de la refonte du code.
Le code source sera disponible dès que possible à l’adresse : http://common-lisp.net/project/morphologie/

version PWGL

Dans la dernière version courante pour PWGL (celle de Jacopo), on trouve indistinctement 389 fonctions (defun, defmethod et define-box, 2 defparameter et 1 defclass) :

~: grep \(def PWGL/morphologie/src/morphologie.lisp | wc -l
~: 389

où 140 fonctions sont prévues pour l’interface graphique (beaucoup trop !) :

~: grep \(define PWGL/morphologie/src/morphologie.lisp | wc -l
~: 140

parmi lesquelles seulement 38 apparaissent dans le menu.

Ainsi, nombre de fonctions auxquelles l’utilisateur ne doit en principe pas avoir un accès direct par l’interface graphique sont pourtant déclarées en tant que méthodes à usage graphique (« define-box »), ce qui empêche la lisibilité du code source. Ceci est valable également pour la version OpenMusic (« om::defmethod ! »).

version OpenMusic

  • la version Morphologie2 est la version la plus complète des versions pour OpenMusic ;
  • la version Morphologie2.1 ajoute une méthode « list » pour les fonctions « class-1 », « euclidian-d » et « resemblance-match », supprime une méthode aux fonctions « min-flex-max » et « sempre-su », mais surtout ne contient pas les fonctions ajoutées par Paolo Aralla (outre les références d’icônes et quelques changements très mineurs de documentation ou de noms de variables (cf. version2 vs version2.1)

La version Morphologie2 pour OpenMusic comprend 381 fonctions (defun, defmethod et 2 defparameter, 1 defclass et 1 defpackage) :

~: grep \(def OM/Morphologie2/Morphologie2\ sources/morphologie2.lisp | wc -l
~: 253

auxquelles il faut ajouter 128 fonctions graphiques om::defmethod pour OpenMusic :

~: grep \(om::defmethod OM/Morphologie2/Morphologie2\ sources/morphologie2.lisp | wc -l
~: 128

(253 + 128 = 381)

  • versions OpenMusic vs. PWGL

Si certaines différences entre les versions OpenMusic et PWGL proviennent de lignes comptées pour le mot « (default » (cf. « grep \(def ... ») et ne sont pas pertinentes, d’autres viennent de la définition des menus pour PWGL (dans OM, les menus étant définis dans un autre fichier lisp) : la structure du code, où sont imbriqués fonctions du noyau du code et fonctions de l’interfaces graphiques, diffère sensiblement entre les versions actuelles.

liste des fonctions GUI version OM
liste des fonctions GUI version PWGL

différences fonctions GUI OM / PWGL

Ainsi, grosso modo, dans la version PWGL le même fichier du code source contient à la fois les fonctions, graphiques ou non et la définition des menus dans le même fichier source, tandis que dans la version OpenMusic les menus sont définis dans un fichier séparé.

Et quelques inconsistances, où certaines fonctions « graphiques » propres à un environnement sont absentes sous ce nom dans l’autre :

  • les méthodes « list-modulo », « posn-match » sont communes à PWGL et OM et sont pourtant redéfinies ;
  • les méthodes « g-min », « g-max » sont retrouvées dans la version PWGL alors qu’elles y sont déjà définies, mais pourtant pas (au moins sous la forme de fonction GUI) dans la version OM où elles ne sont pas définies ;
  • les fonctions l-nth, permut-circ définies dans dans la version PWGL n’existent pas dans OpenMusic 6.0.x ;
  • permut-circn est définie en interne dans OM mais pas dans PWGL ;
  • etc.
  • les fonctions « list ! », « mat-trans », « group-list », « sort-list » et « flat-once » définies dans le fichier « utils.lisp » de la version PWGL doivent réintégrer le fichier principal ;
  • etc.

Il faut donc revoir l’ensemble du code source en detail et, pour réécrire le code, je propose :

1. structurer le code source

  • distinguer fonctions et algorithmes de la partie du code destinée à l’interface graphique (GUI) OM, PWGL afin de permettre l’utilisation de la librairie dans tout environnement informatique common-lisp (unix/linux notamment) ;
  • réécriture et optimisation en common-lisp ;
  • rassembler et structurer le code en trois fichiers de code source :
    > un fichier « load » pour l’initialisation et la configuration de la librairie selon l’environnement OM, PWGL, Unix/Linux ;
    > un fichier morphologie-cl.lisp qui réuni l’ensemble du noyau de la librairie en common-lisp ;
    > un fichier morphologie-gui.lisp qui réuni le code concernant les interfaces graphiques, « boxes » et définition des menus, des différents environnements possibles (PWGL, OM, linux...) ;
  • restructurer et documenter le code common-lisp :
    > organiser les différentes fonctions du code common-lisp selon leur fonctionnalité (analyse, classification, génération, etc.) ;
    > suppression des fonctions redondantes ;
    > documentation (systématiquement trilingue ???)
    > dans le fichier morphologie-cl.lisp, signaler les fonctions prévues pour la partie utilisateur (liste, signe...)
    > restructurer les menus de l’interface utilisateur ;
  • normalisation de la dénomination des fonctions et de variables :
    pour les fonctions principales et destinées à l’utilisateur (GUI), mais aussi le nom des fonctions intermédiaires qui sont parfois obscures.
    De même le nom des variables (on trouve par exemple « list », « liste », « lista », « seq »...).
    Le code étant trilingue, des noms fondés dur des racines latines (plutôt que l’esperanto ou du frenglitalien ;)) serait un bon dénominateur commun !
  • gestion des warnings et des messages d’erreurs selon le contexte (common-lisp, OM, PWGL, ...) :
    faire une fonction de signalement des erreurs et avertissements variant selon le contexte (OM, PWGL, console, terminal)
  • je propose donc, pour assurer la portabilité de l’essentiel du code source de Morphologie, de réécrire et valider son noyau (morphologie-cl.lisp) en common-lisp sous GNU/Linux (SBCL par exemple) compatible avec les autres LISP, et d’implémenter ensuite les seules fonctions utilisateur (menus et « boites » (morphologie-gui.lisp) pour chacun des environnements pévus (OM, PWGL, Mac OSX, Microsoft-Windows). On distinguera donc les fonctions « internes », fixes et propres au noyau common-lisp, des fonctions de menu destinées spécifiquement à l’utilisateur et variant donc selon les environnements. Cela suppose donc qu’à chaque fonction du menu corresponde une (et une seule) fonction common-lisp et que la fonction de menu ne fasse appel qu’à une (et une seule) fonction common-lisp : ceci permettra aux utilisateurs ne disposant pas d’environnement graphique de pouvoir utiliser la librairie en utilisant les mêmes noms de fonctions.

2. todo

  • « ptrn-find » = « ptrn-recogn » + méthodes : homogénéïser (redondant)
  • renommer « structure-1 » par « struct-contrastive » ?
  • renommer « structure-2 » par « struct-réduite » ?
  • distances, ressemblances : redéfinir les méthodes et renommer
  • débugguer « multi-distance »
  • « ins-ptrn » : bug dans PWGL (reprendre depuis la version OM)
  • renommer « min-flex-max » par « primitives »
  • renommer « direct-analysis » par « directions »
  • optimiser « find-permut » et renommer par « permut-positions »
  • optimiser analyse contrastive (depuis version LispMe)
  • renommer « contrast-lev1 » par « enum »
  • renommer « contrast-all-lev » par « enum-recurs »
  • renommer « new-old-analysis » par « activation » ?
  • fonction « energie »
  • revoir fonctions d’entropie
  • version « draw-prim-tree » sans interface graphique (caractères terminal)
  • les fonctions de distances, ressemblance et de Prim dans le menu « Classification »
  • chemin le plus court de prim-tree : version non graphique
  • ajouter code SOM dans classification
  • à terme : versions graphiques de prim-tree (linux, OM, PWGL)
  • autres corrections mineures dues à la refonte (cf. 1.)
  • ...

3. changements effectués (work in progress)

  • suppression de la fonction « rispero » redondante avec « scom » (trouver nom plus explicite ?)
  • « ptrn-smooth » renommé par « remove-local-dup » et optimisé :
    dans SBCL linux PPC 1.6 GHz,
    ancienne version (non récursif) :
    (time (remove-local-dup (loop for i from 0 to 10000 collect (random 4))))
    Evaluation took:
     0.936 seconds of real time
     0.833 seconds of user run time
     0.003 seconds of system run time
     0 calls to EVAL
     0 page faults and
     196,688 bytes consed.

nouvelle version (récursif) :

(time (remove-local-dup (loop for i from 0 to 10000 collect (random 4))))
Evaluation took:
 0.002 seconds of real time
 0.002 seconds of user run time
 0.0 seconds of system run time
 0 calls to EVAL
 0 page faults and
 131,072 bytes consed.
  • « primo-passo » optimisé
  • « dist-1 » renommé « edit-dist1 »
  • « dist-2 » renommé « edit-dist2 »
  • « distance » renommé « edit-dist » (qui donnera la foncton GUI « edit-distance » ?)
  • renommé fonction internes « dist-2-ldl » et « dist-2-ldl » par « edit-dist-ldl1 » et « edit-dist-ldl2 » par soucis de cohérence des noms
  • renommé la fonction interne « ldl-dist » par « multi-edit-distance »
  • renommé les fonctions de menu « multi-distance » par « edit-distance-multi »
  • dans les fonctions distance « internes », subsitué les arguments optionnels par des arguments en mot-clefs (&key, plus commode en common-lisp pour combiner les variantes des fonctions et insensible à l’ordre des arguments)
  • dans les fonctions de distance d’édition, l’argument scale est soit ’nil (non-normalisé), soit ’t (normalisé)
  • intégration des fonctions du fichier de la version PWGL utils.lisp dans les fonctions internes (morphologie-cl.lisp)
  • « mat-trans » renommé « mat-transpos » (la fonction est réécrite et permet de résoudre conflit avec OM et il s’agît bien d’une trqnsposiytion de matrice
  • « sort-list » renommé « deep-sort-list » (d’après suggestion Killian Sprotte)
  • « flat-once » renommé « flat-1 » (évite conflit qvec OM)
  • ajouté fonction « message » pour remplacer les messages en « (format t ...) »
  • supprimé la fonction « mini » et « maxi » (remplacés par apply ’min ou ’max)
  • réécriture de « euclidian-d » (optimisation, suppression du format array inutile) et renommé « euclidian-distance »
  • ptrn-smooth réécrit et renommé « remove-local-dup »
  • corrigé et optimisé numtochar26 et num->char (avant limité à 676, étendu aux entiers de 0 a l’infini)
  • rationalisé fonctions de conversion nombres vers caractères alpha, conservé une seule fonction principale num->char
  • ...

à suivre...