Cette page est une liste presque exhaustive des paramètres de contrôle disponibles dans Tidal Cycles. J’ai fait le choix de conserver les paramètres les plus courants et d’éliminer les paramètres les plus obscurs ou utilisés seulement pour des fonctions très facultatives ou aujourd’hui obsolètes. Cette page est constituée à partir des informations glânées sur la documentation officielle. Elle peut servir à se faire une idée de ce que Tidal offre avec une installation normale de SuperDirt (+ sc3plugins).
Général
Nom de la fonction
Type de l’argument
Valeur type
Description
sound
String
“jvbass”
Dossier de sample ou nom du synthétiseur SuperDirt
s
String
“jvbass”
Dossier de sample ou nom du synthétiseur SuperDirt.
n
Double
0-x
Numéro de la sample dans le dossier.
begin
Double
0-1
Début du sample ou 0 est le début du fichier et 1 la fin.
end
Double
0-1
Fin du sample ou 0 est le début du fichier et 1 la fin.
loop
Double
0 ou 1
Nombre d’itérations sur la sample en un cycle.
offset
Double
0-x
Forme de décalage temporel (décalage vers le futur)
cut
Int
0 ou 1
Couper la sample lorsque l’enveloppe se réamorçe. 0 ou 1.
gain
Float
0-x
Volume. 0 : silence. 1: normal. >1 : de plus en plus fort.
pan
Float
0-1
Position stéréo. 0 : gauche, 1 : droite.
orbit
Int
0-9
Choix du canal d’effets (par défaut, 9 orbits sont disponibles).
speed
Float
-x-x
Vitesse de lecture de la sample.
accelerate
Float
-x-x
Effet de rampe sur la vitesse de lecture du sample.
cps
Float
0-x
Change la vitesse de lecture de tout les patterns. Le tempo est exprimé
en cycles par seconde (cps).
nudge
Float
0-x
Change le timing des samples. Moduler ce paramètre permet d’humaniser le
jeu des patterns. Valeurs basses: swing, valeurs hautes : plus étrange.
Envelopes
Nom de la fonction
Type de l’argument
Valeur type
Description
attack
Float
0-x
Durée de l’attaque (durée avant amplitude maximale).
att
Float
0-x
Paramètre utilisé pour l’enveloppe ASR.
decay
Float
0-x
Durée de la chute de l’amplitude jusqu’à zone d’entretien.
sustain
Float
0-x
Durée de la zone d’entretien, niveau d’amplitude stable.
sus
Float
0-x
Durée de la zone d’entretien, niveau d’amplitude stable.
release
Float
0-x
Durée de l’extinction de la note.
Filtres
Nom de la fonction
Type de l’argument
Valeur type
Description
cutoff
Double
0-20000
Fréquence de coupure du filtre passe bas.
lpf
Float
0-20000
Fréquence de coupure du filtre passe bas.
lpq
Float
0-1
Fréquence de résonance du filtre passe bas.
resonance
Float
0-1
Fréquence de résonance du filtre passe bas.
bandf
Float
0-20000
Fréquence de coupure du filtre passe bande.
bpf
Float
0-20000
Fréquence de coupure du filtre passe bande.
bandq
Float
0-1
Fréquence de résonance du filtre passe bande.
bpq
Float
0-1
Fréquence de résonance du filtre passe bande.
hcutoff
Float
0-20000
Fréquence de coupure du filtre passe haut.
hpf
Float
0-20000
Fréquence de coupure du filtre passe haut.
hpq
Float
0-1
Fréquence de résonance du filtre passe haut.
hresonance
Float
0-1
Fréquence de résonance du filtre passe haut.
Notes et fréquences
Nom de la fonction
Type de l’argument
Valeur type
Description
freq
Float
0-20000
Fréquence du synthétiseur ou de la sample.
midinote
Float
0-127
Hauteur de la note MIDI.
note
Float
0-127
Hauteur de la note MIDI (?).
octave
Int
0-10 (?)
Octave de la note.
legato
Float
0-x
Taux de superposition entre deux samples ou notes.
MIDI
Nom de la fonction
Type de l’argument
Valeur type
Description
cc
String
0-x
Spécifier un ccn et un ccv sous la forme ccn:ccv. Quasi-obsolète.
ccn
Float
0-x
Control Number (MIDI)
ccv
Float
0-127
Control Value (MIDI)
midichan
Int
0-15
Sélection du canal MIDI.
modWheel
Float
0-127
Valeur de la roue de modulation MIDI.
portamento
Float
0-127
Valeur du portamento.
progNum
Int
0-127
Program Number ?
dur
Float
0-x
Durée de la note.
expression
Float/Int (?)
0-127
Pédale d’expression (volume).
sustainpedal
Float/Int (?)
0-127
Pédale de soutien.
mtranspose
Int
0-127
Transposition MIDI ?
midicmd
String
“noteon”
“noteon” transforme le pattern en valeurs note on. Autres valeurs :
“touch”, “polytouch”, “bend”…
Delay
Nom de la fonction
Type de l’argument
Valeur type
Description
delay
Float
0-1
wet/dry pour du délai.
delayfeedback
Float
0-1
Valeur de retour du délai, entre 0 et 1.
delayfb
Float
0-1
Valeur de retour du délai, entre 0 et 1.
delaytime
Float
0-1
Intervalle du délai.
delayt
Float
0-1
Intervalle du délai.
lock
Int
0 ou 1
Permet de verrouiller le valeur du délai sur la longueur du cycle.
Distortion et dégradation du signal
Nom de la fonction
Type de l’argument
Valeur type
Description
coarse
Int
0-x
Divise la fréquence d’échantillonage.
1 : normal.
2 : divisé par deux. etc…
crush
Float
0-16
Effet de bit-crushing:
1 : drastique.
16 : presque normal.
distort
Float
0-x
Une distortion très sèche avec beaucoup d’harmoniques.
triode
Float
0-x
Une distortion triode.
krush
Float
0-x
Distortion “krush” importée de Sonic-Pi.
kcutoff
Float
0-20000
Cutoff du “krush”.
shape
Float
0-x
Un type d’amplification particulier.
squiz
Int
0,2-x
Filtre, modulateur en anneau et pitch-shifter. Dégrade
le signal. Passer un multiple de deux comme argument.
Reverb
Nom de la fonction
Type de l’argument
Valeur type
Description
room
Float
0-1
Taille de la pièce.
size
Float
0-1
Métaphore de la “profondeur”, entre 0 et 1.
dry
Float
0-1
Paramètre wet/dry entre 0 (wet) et 1 (dry).
Octaviation
Nom de la fonction
Type de l’argument
Valeur type
Description
octer
Float
?
Harmoniques à l’octave.
octersub
Float
?
Harmoniques à l’octave / 2.
octersubsub
Float
?
Harmoniques à l’octave / 4.
Phaser
Nom de la fonction
Type de l’argument
Valeur type
Description
phaserrate
Float
0-x
Vitesse du phaser.
phasr
Float
0-x
Vitesse du phaser.
phaserdepth
Float
0-x
Profondeur du phaser.
phasdp
Float
0-x
Profondeur du phaser.
Tremolo
Nom de la fonction
Type de l’argument
Valeur type
Description
tremolodepth
Float
0-x
Profondeur de l’effet de trémolo.
tremdp
Float
0-x
Profondeur de l’effet de trémolo.
tremolorate
Float
0-x
Vitesse du trémolo.
tremr
Float
0-x
Vitesse du trémolo.
Leslie
Nom de la fonction
Type de l’argument
Valeur type
Description
leslie
Float
0-x
Dry/Wet de l’effet de cabine leslie.
lrate
Float
0-x
Vitesse de rotation de la cabine.
lsize
Float
0-x
Taille (change l’effet doppler)
Autres effets et divers
Nom de la fonction
Type de l’argument
Valeur type
Description
vowel
String
“a”
Filtre formant. Au choix parmi : “aeiou”.
“~” pour aucun effet.
legato
Float
0-1
Taux de superposition entre deux sons.
waveloss
Int
0-100
Divise un flux audio en petits segments. Ne conserve qu’une
fraction d’entre eux.
xsdelay
Float
?
Délai spectral (???)
tsdelay
Float
?
Délai spectral (???)
freeze
Int
0 ou 1
Gèle l’audio et tente de maintenir le même spectre.
comb
Float
0-x
Le nombre de dents et la profondeur du filtre sont contrôlés
par un seul nombre à virgule.
scram
Float
0-x
Randomise l’ordre des bits dans le signal audio.
smear
Float
0-x
Effet de “smearing”.
binshift
Float
0-x
Stretching et shifting des bits. Tout est contrôlé par un seul
nombre à virgule. Peut s’utiliser comme un pitch-shifter.
hbrick
Float
0-?
Un filtre passe-haut de type spectral.
lbrick
Float
0-?
Un filtre passe-bas de type spectral.
real
Float
?
???
imag
Float
?
???
enhance
Float
?
???
djf
Float
0-1
Un filtre DJ. Passe-bas pour la première moitié, passe-haut
pour le reste.
Cette page recense quelques exemples de patterns simples réalisés à l’aide des samples et des instruments par défaut de Tidal Cycles. Il est donc possible de copier/coller les exemples afin d’expérimenter en les modifiant. Chacune des sections cherche à illustrer l’un des aspects de la syntaxe du langage, tout en limitant le niveau de complexité. Il est recommandé de jouer avec chacun des exemples afin d’acquérir une plus grande familiarité avec le code et sa manipulation en temps réel.
Gymnastique
-- Tempo = CPS (Cycles per second).
setcps 0.8
-- Quelques patterns très simples.
d1 $ s "bd*4"
d2 $ s "~ ~ ~ sd"
d3 $ s "hh cp hh cp"
-- Tidal est un langage très expressif. Il existe beaucoup de manières
-- permettant d'exprimer une même idée. En voici trois :
d1 $ s "[[bd*4],[~ ~ ~ sd],[hh cp hh cp]]"
d1 $ stack [s "bd*4",
s "~ ~ ~ sd",
s "[hh cp]*2"]
d1 $ s "[bd(4,4), sd(1,4), [hh,cp](2,4)]"
d1 $ silence
-- ou bien
hush
Choisir un échantillon sonore ou un synthétiseur
-- Sur la piste 1, je veux jouer "numbers".
d1 $ s "numbers"
-- Sur la piste 1, je veux jouer le premier son du dossier "numbers".
d1 $ n 0 # s "numbers"
-- Ibid avec notation interne au pattern.
d1 $ s "numbers:0"
-- ibid, en alternant entre "0, 1, 2 et 3".
d1 $ n "<0 1 2 3>" # s "numbers"
-- ibid, en jouant deux dossiers de samples en même temps.
d1
$ fast 2 $ n "<0 1 2 3>" # s "[numbers, jazz]"
-- choix pseudo-aléatoire de la sample.
d1 $ fast 8 $ s "808" # n (irand 20)
-- on parcourt alternativement deux dossiers
d1 $ fast 2 $ n (run 4) # cat [s "808", s "jazz"]
-- plusieurs dossiers de sample dans un même pattern
d1 $ s "bass3 jvbass:2"
La représentation du temps privilégie par Tidal est cyclique et non linéaire. Cette idée possède des implications profondes pour la manipulation des patterns et des contenus musicaux.
Représentation cyclique du temps.
Représentation linéaire d’un pattern.
Tout est un pattern
-- Tidal introduit un nouveau type : les patterns.
-- Les patterns remplaçent les chaînes de caractères.
-- La syntaxe des patterns est assez complexe. Essayons d'en avoir une
-- compréhension intuitive avant de l'expliquer plus en détail.
-- un son de grosse caisse.
d1 $ s "bd"
-- Deux sons de grosse caisse répartis sur un cycle.
-- Tidal adopte une représentation cyclique du temps.
d1 $ s "bd bd"
d1 $ s "bd*2"
d2 $ s "hh*4"
-- Deux sons de grosse caisse et charlestons fermées à la noire..
-- Les crochets expriment l'idée de groupe.
-- La virgule l'idée de simultanéité / superposition.
d1 $ s "[bd*2, hh*4]"
d1 $ s "[[bd*2, hh*4], [jvbass]]" -- les groupes peuvent être enchåssés.
-- Il existe une petite arithmétique relative aux répétitions / divisions.
d1 $ s "hh*2"
d2 $ s "hh*4"
d1 $ s "hh/2"
d1 $ s "hh*<2 4 8 16>" -- par "accident", l'arithmétique se patterne...
-- L'exemple donné est ici celui des samples. Tout fonctionne également
-- avec des notes !
d1 $ s "c4*2 ds4/2 g4*2 bf4/4" -- peu lisible mais tout à fait possible.
-- Les patterns permettent une forme élégante de combinatoire :
d1 $ s "<bd hh sn hh>" -- Un seul élément par cycle, en alternance.
d1 $ s "[bd|hh|sn|hh]" -- Choix aléatoire entre quatre samples.
d1 $ s "jvbass? bd" -- 50% de chances de ne pas jouer la note.
d1 $ s "bd(5,4)" -- séquence euclidienne.
-- Il existe d'autres opérateurs plus complexes.
-- Nous les aborderons ultérieurement.
-- Exemple : il existe toute une catégorie d'opérateurs permettant une
-- arithmétique entre patterns (|+ +|, |- -|, |* *|, etc...)
Patterner sons, notes et paramètres
-- Beaucoup de choses peuvent être exprimées en tant que patterns.
-- Dessin manuel d'une enveloppe de volume cyclique.
d1 $ s "hh*8" # amp "0.2 0.4 0.8 0.9 0.5 0.2 0.1"
-- Vitesse de lecture de l'échantillon.
d1 $ s "jvbass*8" # speed "0.2 0.4 0.8 0.9 0.5 0.2 0.1"
-- Exemple complexe : modulations paramétriques multiples
-- 0 et 0.5 peuvent être patternés également !
d2
$ s "[jvbass|amencutup]*8" # speed (range 0 0.5 $ run "<8 5 16>")
# lpf "<400 800 1200 2000 4000 8000>"
-- Exemple complexe : basse "acide" et grosse caisse.
-- Modulation du filtre et de la séquence de note.
d1
$ fast 2
$ note "<c3 f2 g2>*4" |+ note "0 12"
# s "supersaw" # cut 1 # release 0.2
# lpf "<400 500 1000 2000 4000 5000>" # lpq "0.2 0.4 0.5 0.1"
d2
$ s "808bd*2" # amp 2
-- Exemple complexe : courte pièce générative pour cordes pincées
-- avec un message...
do
setcps 0.5
d1
$ slow 2
$ rarely (superimpose ((|+ note "[0,12,-12]") . (# release 4) . (# room 0.8)))
$ superimpose ((fast "<0 1 0 1 0 [1|2]>") . (off "<0.75 0.25 0.5>" (id)))
$ note "c a f e b a b a d a d a g e g e " |+ note 12 # s "pluck"
# release 2 # room 0.5 # dry 0.6 # size 0.7
-- Exemple : nappe de bruits complexe. Beaucoup de variations paramétriques.
d1
$ rarely (slow 4)
$ sometimes (superimpose (# speed 0.0125) . (# amp 1.5))
$ rarely ((fast 4) . (|+ speed (run 8)))
$ s "[hand|gretsch]*8" # n (irand 20) # cut 0 # speed (range 0.8 1 $ rand)
# lpf "<4000 2000 3000 6000 100 400>" # room 0.6 # size 0.6 # dry 0.4
# hpf "[1000|2000|4000|1250|1500]"
# pan (range 0 1 $ rand)
Composition de fonction
-- Chaque pattern constitue une seule et même expression. Tidal procède
-- par composition de fonctions. Il existe, par conséquent, un très grand
-- nombre de fonctions aux effets variés. Voici un inventaire de quelques
-- fonctions courantes :
-- accélérer le pattern
d1 $ fast 2 $ s "jvbass"
-- accélérer le pattern et la vitesse de lecture
d1 $ hurry 2 $ s "jvbass"
-- ralentir le pattern
d2 $ slow 2 $ s "jvbass"
-- renverser le pattern
d1 $ rev 4 $ n "0 1 2 3" # s "numbers"
-- chop | striate | bite | chew pour le découpage des samples.
d1 $ fast 2 $ chop "<2 4 8 16 32 64 128 256 512>" $ s "tabla:4 tabla:2"
-- Il est possible de d´éfinir une probabilité d'application
-- de fonction avec certaines fonctions
-- sometimes | rarely | often | always
d1
$ sometimes (fast 8)
$ s "jvbass*2"
-- Pour une liste plus complète des fonctions, reportez vous à l'une
-- des pages de ce même site.
SuperDirt
-- Tidal Cycles est d'ordinaire couplé à SuperDirt, une extension de
-- SuperCollider pensée pour Tidal. SuperDirt expose de très nombreux
-- paramètres de synthèse accessibles par défaut dans un pattern.
-- appliquer un filtre passe-bas/passe-haut/passe-bande
d1 $ fast 2 $ s "jvbass" # lpf 500 # lpq 0.1
d1 $ fast 2 $ s "jvbass" # hpf 500 # hpq 0.1
d1 $ fast 2 $ s "jvbass" # bpf 500 # bpq 0.1
-- ajouter de la réverbération
d1 $ hurry 2 $ s "jvbass" # room 0.5 # size 0.5 # dry 0.5
-- ajouter du délai
d2 $ fast 2 $ s "jvbass" # delay 0.5 # delaytime 0.5 # delayfeedback 0.6
-- Il est possible de donner une dimension probabiliste
-- à l'application d'un effet.
d2
$ sometimes ((# speed 4) . (# room 0.8))
$ s "hh*8"
Combiner paramètres et fonctions / Apprendre Tidal Cycles
Les exemples précédents illustrent trois caractéristiques essentielles de la syntaxe :
Tidal permet de travailler à l’échelle du son/timbre (outil pour la synthèse / le contrôle paramétrique).
Tidal permet de créer dynamiquement des patterns et de les combiner (outil d’interprétation / instrument).
Par combinaison de fonctions, Tidal organise et structure le jeu musical (outil de composition).
Cette page ne se destine qu’à introduire à la syntaxe de Tidal et omet volontairement un grand nombre de possibilités et de fonctionnalités (mini-notation des accords, des polymètres, arithmétique des patterns, composition de nouvelles fonctions, interface MIDI et I/O en général). Le langage dans son ensemble doit être pensé comme une interface permettant d’organiser des évènements dans le temps. Tidal ne se préoccupe presque pas de la nature des objets séquencés (hormis interface SuperDirt). Il s’agit d’un outil permettant de mettre en forme rapidement (en temps réel ?) une pensée musicale algorithmique. L’apprentissage de Tidal, comme celui d’un instrument, requiert de la patience et de la pratique (au-delà même du seul aspect digital et de la manipulation du texte). La flexibilité de la syntaxe et la possibilité de composer des fonctions / de combiner rapidement plusieurs paramètres en fait un outil particulièrement puissant avec de fortes propriétés d’émergence.
Je travaille en parallèle de ma thèse sur un environnement de live-coding musical nommé Belly. Ayant appris la programmation sur le tard et en autodidacte, la tâche s’avère lente et fastidieuse [1]. Il s’agit d’un client pour SuperDirt en Python. C’est un bon exercice pour comprendre les enjeux de la conception d’un tel système : scheduling temps-réel, manipulation de la syntaxe, couplage avec le moteur audio et avec Emacs. Je posterais le programme et sa documentation lorsque celui-ci atteindra la maturité et la stabilité suffisante pour être utilisé quotidiennement sans trop de heurts. Le but est de se rapprocher, autant que possible, des langages les plus utilisés par la communauté TOPLAP (Tidal Cycles, FoxDot, etc…). Le but est également d’expérimenter avec plusieurs modalités de représentation algorithmique de la notation musicale et de réfléchir sur de potentielles nouvelles notations pour les musiques électroniques et informatiques. J’espère à terme que ces expérimentations mèneront vers un environnement stable que je pourrais utiliser pour enseigner et pratiquer cette approche particulière du jeu et de l’improvisation musicale.
Belly n’est qu’une surcouche logicielle pour SuperCollider et SuperDirt (échantillonnage, synthèse sonore, sorties audios). Le logiciel n’émet donc aucun son : Belly se charge d’organiser la performance en émettant des messages temporels très précis renseignant les différents paramètres et les différents signaux qui composent le jeu musical. Cette architecture est assez commune pour ce type de langages/DSL, ainsi qu’en témoignent Sonic Pi ou Tidal Cycles dont Belly s’inspire très largement. Du fait de la relative jeunesse du programme, je n’ai pas encore précisément décidé du paradigme de programmation attendu de la part de l’utilisateur/musicien : fonctionnel ou impératif. Il s’agit encore d’établir une interface de haut-niveau pour la notation musicale ou pour la manipulation et la description du temps musical. L’idéal serait de programmer entièrement Belly, une seconde fois, dans un langage fonctionnel ou multi-paradigmatique (Common Lisp ?). L’absence de librairies permettant de faciliter la tâche me retient encore de m’y consacrer plus pleinement.
Le programme repose sur un mécanisme très incomplet et approximatif de « récursion temporelle », notion illustrée et largement développée/commentée par Andrew Sorensen [2]. Ce mécanisme ne peut être identique à celui proposé par Sorensen pour au moins une raison. De manière notoire, Python ne supporte pas l’optimisation des fonctions tail recursive qui sont à la base même de ce type particulier de récursion, courant dans des langages tels que Scheme. Racket ou CL. Je souhaite pourtant m’inspirer, autant que possible, des langages fonctionnels ou des langages de type LISP. La sur-représentation du LISP ou des dérivés de SmallTalk dans le milieu de l’informatique musicale ne m’apparaît pas comme une simple coïncidence. Sans doute s’agit-t-il d’une indication du fait que ces langages s’adaptent mieux à certaines contraintes propres au domaine musical : prototypage rapide, hot-reloading, concision et souplesse de la syntaxe, adaptation de cette dernière au domaine (expression musicale, synthèse, composition). La plupart de ces langages proposent une approche in media res de la programmation musicale, permettant la manipulation du programme dans le temps et dans l’action. De manière tout simplement personnelle, j’ai également une préférence esthétique pour l’élégance de ces langages.
Python possède l’une des syntaxes les plus rigides et l’un des interpréteurs les plus contraignants qui soit : espaces signifiants, absence de macros, AST peu déchiffrable, impossibilité de recharger un module, de mettre à jour les instances d’une classe lors d’une redéfinition de l’objet, etc… Pour ces raisons au moins, Belly me semble handicapé par rapport à ce qui peut déjà se faire dans le domaine du live-coding, au travers de langages tels que Clojure ou Haskell. C’est un handicap que j’accepte volontiers, dans la mesure ou je manque encore de pratique et de métier; la programmation n’étant pas mon activité principale ni ma spécialité. Le fait que FoxDot existe reste toutefois la preuve que Python supporte ce type d’applications musicales.
Du point de vue technique
Belly est capable, au travers de SuperDirt, de gérer les entrées et sorties MIDI ou OSC. Cela lui permet de communiquer assez facilement avec l’essentiel des STAN ou des moteurs audios existants. La précision temporelle est tout à fait acceptable, ce qui fait déjà de ce programme un séquenceur efficace pour prototyper et tester plusieurs dispositifs ou instruments simples. De manière détournée, ces deux dernières caractéristiques font de Belly un outil qui peut être employé en dehors de son domaine pour piloter sons, lumières, animations et autres.
L’output du programme est pensé pour être interprété par SuperDirt, le moteur audio par défaut de Tidal Cycles. Tout ce qui est exprimable dans Tidal l’est donc potentiellement avec Belly (manipulation de samples, paramètres de synthèse). Belly est pourtant très loin de permettre la même expressivité que le langage développé par Alex McLean. Pour le moment, Belly reste un DSL très verbeux, peu élégant et peu capable pour ce qui s’agit de représenter la musique et le temps. Il est difficile de faire émerger un sens de la structure, une idée mélodique complexe, ou d’être réellement expressif. J’espère trouver un moyen d’arranger cela au cours des prochains mois. J’ai bon espoir, car le système d’objets de Python est assez flexible, et supporte bien des bizarreries. Les quelques vidéos en annexe de ce post donnent une bonne idée de la syntaxe actuelle, à quelques différences mineures près.
Notes
[1] Sur ce même site, quelques vidéos illustrent un premier essai de langage, très proche de FoxDot, aujourd’hui abandonné.