Cette page présente les étapes à suivre pour mettre en place un script Mididings dans une configuration de boucles MIDI avec Sequencer64, Carla et un synthétiseur virtuel (ici Fluidsynth), le tout sous LibraZik.
Dans une configuration de séquenceur en looping (live ou non), le logiciel propriétaire Ableton Live a une fonctionnalité appelée Random Follow expliquée par exemple dans cette vidéo , et qui consiste à préparer plusieurs boucles pour la même séquence que le logiciel va choisir aléatoirement, résultant en une suite aléatoire de ces boucles. Ceci peut donner par exemple de la variété dans une séquence de percussions, avec quelques coups supplémentaires de caisse ou de charleston, ou dans une ligne de basse, pour éviter que ce soit trop répétitif et devienne lassant.
Mon looper libre de prédilection, Sequencer64, ne présente pas cette fonction. Je n'ai pas trouvé non plus de greffon LV2 qui fasse ceci (il existe par contre PSI Random MIDI pour remplacer une note par une autre note choisie aléatoirement dans une certaine bande). Je me suis donc tourné vers Mididings pour randomiser les séquences.
Pour ce tuto j'utilise Ray Session et Carla, mais c'est bien sûr transposable sur d'autres outils.
Seq64 est lancé depuis Ray Session, et des synthétiseurs virtuels tels que Fluidsynth ou Helm sont lancés dans Carla en tant que greffons lv2.
En temps normal, chaque séquence de Seq64 peut être connectée à un synthétiseur virtuel pour produire un son (sur l'image ci-dessus par exemple la trompette, le piano et les percus sont jouées par des greffons Fluidsynth hébergés dans Carla).
Pour ce tuto, l'idée est donc de créer plusieurs séquences dans Seq64, qui seront jouées (aléatoirement donc) par le même synthétiseur.
Je me suis donc tourné vers Mididings, qui permet de recevoir des signaux MIDI, de les traiter et de renvoyer un signal différent - ou de lancer une application externe, ou n'importe quelle autre action possible en utilisant les scripts de configuration en Python. J'ai donc imaginé router les 4 séquences de Seq64 vers mididings, qui choisirait aléatoirement quelle séquence laisser ressortir vers le synthétiseur.
Le script aurait donc un nombre maximal d'entrées MIDI pour les séquences (constante NPORTS dans la suite). Chaque séquence serait envoyée sur une Scène différente, et une seule de ces scènes serait renvoyée vers l'unique sortie MIDI du script.
Il reste à identifier un déclencheur pour que Mididings sache à quel moment choisir la scène à activer. Il y a sans doute de meilleures options, mais j'ai choisi d'utiliser le contrôle CC#119 que je n'utilise autrement pas. Une séquence de "contrôle" démarrant avec un signal CC#119 déclencherait le changement de scène de Mididings.
Le début du fichier de configuration mididings définit les entrées et sorties du script. Ici, la fonction
Dans Carla, les entrées et sorties de ce script ressemblent donc à ceci :
On passe ensuite à la création des scènes, qui doit dépendre aussi du nombre d'entrées NPORTS utilisées au-dessus :
Pour sélectionner aléatoirement une scène, on veut d'abord être sûr de ne sélectionner que les scènes qui sont effectivement connectées à une séquence ; et qui reçoivent effectivement un signal. Comme le son ne commence pas forcément au tout début d'une séquence, j'ai décidé d'utiliser aussi le contrôle CC#119 en tout premier signal de chaque séquence - ci-dessous la ligne de basse, avec un CC119 à une vélocité de 64 dès le début :
Dès qu'une des entrées du script mididings détecte un signal CC119, la scène correspondante sera détectée comme active et ajoutée au set ACTIVESCENES :
Le paramètre de la fonction
Nous sommes maintenant prêts à choisir aléatoirement une de ces scènes actives (la fonction
Enfin, le cœur d'un script mididings est définie par la fonction
Les 2 lignes de
La première ligne va donc détecter un signal CC#119 sur n'importe quelle entrée, et appeler la fonction
La deuxième ligne va détecter un signal sur le port 0 (
Pour tester, le moyen le plus simple est de lancer mididings avec ce script en ligne de commande et de vérifier les changements de scènes :
En même temps, lancer
Si tout va bien, il devrait y avoir un message
Pour rendre tout ça un peu plus facile à utiliser dans une session Ray, plutôt que de lancer le script dans un terminal, j'ai écrit un petit script batch qui lance mididings. Il a fallu ajouter une possibilité de détecter un SIGTERM pour que mididings s'arrête lorsqu'on appuie sur Stop dans Ray-Session :
Alors pour expliquer ça rapidement (la logique n'est pas de moi mais je ne retrouve plus le post de forum qui m'a aidé, j'espère que ce que j'explique est correct !), la commande mididings est lancée avec
Grâce à la ligne
Grâce à la ligne
Il ne reste qu'à lancer ce script bash grâce au bouton
J'ai mis en place ce script en pensant avoir par exemple une séquence de contrôle de 2 ou 4 mesures et des séquences d'instruments d'une ou 2 mesures, mais il est bien sûr aussi possible d'envoyer directement une des séquences sur ctrl_in en même temps que sur in_0 pour que la sélection aléatoire soit synchrone avec la longueur de la séquence 1.
Une petite image pour les connexions entre Seq64, mididings, le synthétiseur et jack mixer :
[+]
Table des matières
Introduction
Dans une configuration de séquenceur en looping (live ou non), le logiciel propriétaire Ableton Live a une fonctionnalité appelée Random Follow expliquée par exemple dans cette vidéo , et qui consiste à préparer plusieurs boucles pour la même séquence que le logiciel va choisir aléatoirement, résultant en une suite aléatoire de ces boucles. Ceci peut donner par exemple de la variété dans une séquence de percussions, avec quelques coups supplémentaires de caisse ou de charleston, ou dans une ligne de basse, pour éviter que ce soit trop répétitif et devienne lassant.
Mon looper libre de prédilection, Sequencer64, ne présente pas cette fonction. Je n'ai pas trouvé non plus de greffon LV2 qui fasse ceci (il existe par contre PSI Random MIDI pour remplacer une note par une autre note choisie aléatoirement dans une certaine bande). Je me suis donc tourné vers Mididings pour randomiser les séquences.
Organisation de la session
Pour ce tuto j'utilise Ray Session et Carla, mais c'est bien sûr transposable sur d'autres outils.
Seq64 est lancé depuis Ray Session, et des synthétiseurs virtuels tels que Fluidsynth ou Helm sont lancés dans Carla en tant que greffons lv2.
En temps normal, chaque séquence de Seq64 peut être connectée à un synthétiseur virtuel pour produire un son (sur l'image ci-dessus par exemple la trompette, le piano et les percus sont jouées par des greffons Fluidsynth hébergés dans Carla).
Pour ce tuto, l'idée est donc de créer plusieurs séquences dans Seq64, qui seront jouées (aléatoirement donc) par le même synthétiseur.
Le script mididings
Idée et réflexions préalables
Je me suis donc tourné vers Mididings, qui permet de recevoir des signaux MIDI, de les traiter et de renvoyer un signal différent - ou de lancer une application externe, ou n'importe quelle autre action possible en utilisant les scripts de configuration en Python. J'ai donc imaginé router les 4 séquences de Seq64 vers mididings, qui choisirait aléatoirement quelle séquence laisser ressortir vers le synthétiseur.
Le script aurait donc un nombre maximal d'entrées MIDI pour les séquences (constante NPORTS dans la suite). Chaque séquence serait envoyée sur une Scène différente, et une seule de ces scènes serait renvoyée vers l'unique sortie MIDI du script.
Il reste à identifier un déclencheur pour que Mididings sache à quel moment choisir la scène à activer. Il y a sans doute de meilleures options, mais j'ai choisi d'utiliser le contrôle CC#119 que je n'utilise autrement pas. Une séquence de "contrôle" démarrant avec un signal CC#119 déclencherait le changement de scène de Mididings.
Entrées et sorties
Le début du fichier de configuration mididings définit les entrées et sorties du script. Ici, la fonction
buildportsarray()
utilise une boucle entre 0 et np (=NPORTS) crée une série (array) ["ctrl_in", "in_0", "in_1", .. , "in_4"]
, et le bloc config()
utilise cette série pour créer les ports d'entrée ("ctrl_in" est là pour recevoir le signal de déclencheur) :# The maximum number of input ports (in addition to ctrl_in) NPORTS=5 # Build an array of input ports after the ctrl input def buildportsarray(np): portsarray=["ctrl_in"] for p in xrange(0,np): portsarray.append("in_%d" %p) # %d dans le string pour concaténer "in_" avec la valeur de p return portsarray # Define input and output ports config( #backend='jack-rt', client_name = 'mdd-RandomFollowSeq', in_ports = buildportsarray(NPORTS), out_ports = [ 'out', ] )
Dans Carla, les entrées et sorties de ce script ressemblent donc à ceci :
Préparer les scènes
On passe ensuite à la création des scènes, qui doit dépendre aussi du nombre d'entrées NPORTS utilisées au-dessus :
# Returns a dictionnary of Scenes, one per input port minus the control (first) port def routing_scenes(ports): return dict( (p, Scene("Port %d" % (p+1), PortFilter(p+1) >> Port(1) )) for p in range(1, ports+1) )
Fonctions pour sélectionner une scène aléatoire
Pour sélectionner aléatoirement une scène, on veut d'abord être sûr de ne sélectionner que les scènes qui sont effectivement connectées à une séquence ; et qui reçoivent effectivement un signal. Comme le son ne commence pas forcément au tout début d'une séquence, j'ai décidé d'utiliser aussi le contrôle CC#119 en tout premier signal de chaque séquence - ci-dessous la ligne de basse, avec un CC119 à une vélocité de 64 dès le début :
Dès qu'une des entrées du script mididings détecte un signal CC119, la scène correspondante sera détectée comme active et ajoutée au set ACTIVESCENES :
# Global variable for the scenes that are active, i.e. the ports on which there is a midi signal ACTIVESCENES=set() ACTIVESCENES.add(1) # Activate scenes only once a CC119 is detected def activatescene(ev): newscene=ev.port-1 if 1 <= newscene <= NPORTS+1: if newscene not in ACTIVESCENES: ACTIVESCENES.add(newscene) print("activated scene %d" %newscene + " for port %d" %ev.port)
Le paramètre de la fonction
activatescene()
est ev, qui est l'événement MIDI détecté (voir plus bas) et qui inclut tous les paramètres d'un signal MIDI (NoteOn, NoteOff, Control, Port, etc. comme listés ici
), et la scène activée aura le numéro ev.port-1
(puisque l'input in_0 est sur le port d'entrée 1 mais correspond à la scène 0 !).Nous sommes maintenant prêts à choisir aléatoirement une de ces scènes actives (la fonction
sample()
choisit aléatoirement un élément d'un set) :# Picks a random scene in the set of active scenes def randscene(ev): pickedscene=sample(ACTIVESCENES,1)[0] switch_scene(pickedscene) return ev
note
La fonction
sample()
nécessite d'importer la bibliothèque random
, et la fonction switch_scene()
vient de la bibliothèque mididings.engine
,
qui doivent donc être importées en début de script :from mididings.engine import switch_scene from random import sample
Le cœur du script
Enfin, le cœur d'un script mididings est définie par la fonction
run()
, qui va ici d'abord créer les scènes grâce à la fonction routing_scenes()
définie plus haut, puis effectivement filtrer le signal MIDI entre entrées et sortie dans la section control
.run( # Create scenes for each port scenes=routing_scenes(NPORTS), control = [ # activate a scene once CC119 is detected CtrlFilter(119) >> Call(activatescene), # Call random scene when the control port detects a CC119 PortFilter(0) >> CtrlFilter(119) >> Call(randscene) ] )
Les 2 lignes de
control
vont être actives en parallèle
, mais chaque ligne définit des commandes en série.La première ligne va donc détecter un signal CC#119 sur n'importe quelle entrée, et appeler la fonction
activatescene()
en y passant l'événement MIDI pour paramètre d'entrée comme expliqué plus haut.La deuxième ligne va détecter un signal sur le port 0 (
ctrl_in
), vérifier si c'est un CC#119, et si oui, déclencher le choix aléatoire d'une scène ! Grâce à ce système, la séquence de contrôle peut avoir une longueur différente de celle des séquences, pour par exemple déclencher le choix aléatoire toutes les 2 mesures alors que chaque séquence n'en fait qu'une seule - et donc chaque séquence sera jouée 2 fois de suite avant de changer aléatoirement.Intégration dans Carla et Ray Session
Lancer le script dans le terminal et tester dans Carla
Pour tester, le moyen le plus simple est de lancer mididings avec ce script en ligne de commande et de vérifier les changements de scènes :
> $ mididings -R -f mididings_randomFollowSeq.py switching to scene 1: Port 2
En même temps, lancer
aseqdump
permet de vérifier le signal entrant et le signal sortant :> $ aseqdump Waiting for data at port 131:0. Press Ctrl+C to end. Source Event Ch Data 0:1 Port subscribed 129:0 -> 131:0 0:1 Port subscribed 130:0 -> 131:0 130:0 Control change 0, controller 119, value 64 130:0 Note on 0, note 45, velocity 100 130:0 Note off 0, note 45, velocity 64 130:0 Note on 0, note 43, velocity 100 130:0 Note off 0, note 43, velocity 64 130:0 Note on 0, note 41, velocity 100 130:0 Note off 0, note 41, velocity 64 130:0 Note on 0, note 40, velocity 100 130:0 Note off 0, note 40, velocity 64 130:0 Control change 0, controller 119, value 64 130:0 Note on 0, note 45, velocity 100 130:0 Note off 0, note 45, velocity 64
Si tout va bien, il devrait y avoir un message
switching to scene X: Port Y
chaque fois que ctrl_in reçoit un CC#119 ! (même si c'est la même scène plusieurs fois de suite !)Intégrer à Ray Session
Pour rendre tout ça un peu plus facile à utiliser dans une session Ray, plutôt que de lancer le script dans un terminal, j'ai écrit un petit script batch qui lance mididings. Il a fallu ajouter une possibilité de détecter un SIGTERM pour que mididings s'arrête lorsqu'on appuie sur Stop dans Ray-Session :
#!/bin/bash _term() { echo "Caught SIGTERM!" kill -TERM "$child" 2>/dev/null # Kills the child process if it is still running } trap _term SIGTERM # if the shell receives SIGTEM, the function _term is a trap handler before exiting # ending the command with & will background it into the shell's job control system mididings -R -f /home/zig/Software/mididings/mididings_randomFollowSeq.py & child=$! # The child signal's PID wait "$child" # waits for the job to finish, or for a signal
Alors pour expliquer ça rapidement (la logique n'est pas de moi mais je ne retrouve plus le post de forum qui m'a aidé, j'espère que ce que j'explique est correct !), la commande mididings est lancée avec
&
pour "sortir" de ce script, et le PID de mididings est enregistré dans la variable child
.Grâce à la ligne
wait "$child"
, si $child
s'arrête, ce script s'arrêtera.Grâce à la ligne
trap _term SIGTERM
, la fonction _term
sera appelée si le script reçoit le signal SIGTERM
- par exemple si Ray Session l'arrête - et tuera le processus $child
c'est-à-dire mididings !Il ne reste qu'à lancer ce script bash grâce au bouton
Exécutable
dans Ray Session, et de l'enregistrer comme application par un clic droit et "Save as Application Template".Détails à l'utilisation
J'ai mis en place ce script en pensant avoir par exemple une séquence de contrôle de 2 ou 4 mesures et des séquences d'instruments d'une ou 2 mesures, mais il est bien sûr aussi possible d'envoyer directement une des séquences sur ctrl_in en même temps que sur in_0 pour que la sélection aléatoire soit synchrone avec la longueur de la séquence 1.
Une petite image pour les connexions entre Seq64, mididings, le synthétiseur et jack mixer :
Liens et commentaires
- Ray Session
- Carla
- Mididings et sa doc très bien faite
- Le fil de forum dans lequel j'ai réfléchi à ça
[+]