# FoxDot Introduction # ===================== ++Part 1: Les bases++ == :::warning Pour exécuter le code dans FoxDot, placez votre curseur texte sur la ligne de code et appuyez sur Ctrl+Enter ou Cmd+Enter sous MacOS. ::: :::warning Pour commencer à faire du son dans FoxDot, nous attribuons à un "Player" un instrument numérique utilisant : ::: ```python= p1 ``` :::warning p1 est le nom de notre "player", et les flèches (>>) sont utilisées pour lui donner des instructions. La première instruction est "commencez à jouer de l'instrument 'pads'". Ces instruments sont appelés "SynthDefs" - pour voir la liste des SynthDefs disponibles ::: ```python= print(SynthDefs) ``` :::warning Pour l'instant, nous nous contenterons d'utiliser l'instrument "pads". La plupart des instructions sont placées entre parenthèses, mais certaines actions sont effectuées à l'aide de fonctions. Par exemple, pour arrêter un player, nous "appelons" la fonction d'arrêt en tapant le nom, puis un point, suivi du nom de l'action et ensuite entre parenthèses. Les players ont tous des noms à deux caractères - si nous utilisons un nom à trois caractères, nous obtenons une erreur ::: ```python= foo >> pads() ``` :::warning Pour modifier le comportement de "p1", nous pouvons lui donner des instructions entre parenthèses : ::: ```python= p1 >> pads() p1 >> pads(2) p1 >> pads([0,2,4]) p1.stop() ``` :::warning La première instruction est la tonalité des notes - il peut s'agir d'une valeur unique ou d'une liste de valeurs entre crochets. 0 fait référence à la *première* note de la gamme Si nous utilisons des parenthèses rondes au lieu de parenthèses carrées, cela permet de jouer les notes ensemble ::: ```python= p1 >> pads((0,2,4)) p1 >> pads([0,1,2,(3,5,7)]) p1.stop() ``` :::warning Le fait de placer une liste à l'intérieur d'une autre liste alterne la valeur utilisée ::: ```python= p1 >> pads([0,2,[4,7]]) p1.stop() ``` :::warning Après avoir défini la tonalité, nous utilisons des arguments pour donner d'autres instructions - comme les durées ::: ```python= p1 >> pads([0,1,2,3], dur=1) p1 >> pads([0,1,2,3], dur=1/2) p1 >> pads([0,1,2,3], dur=[1,1/2]) p1.stop() ``` ```python= print(Player.get_attributes() ``` :::warning Les arguments utiles sont "amp", "dur", "sus", "pan", "oct" [la liste de l'ensemble des arguments](https://foxdot.org/docs/player-attributes/) ::: ```python= p1 >> pads([0,1,2,3], dur=[1,1/2,1/2], amp=[1.5,0.5], sus=2, pan=[-1,1], oct=[5,5,5,(4,6)]) ``` :::warning Jouons avec des sons de percussions. Pour déclencher les samples, nous utilisons un instrument spécial appelé "play". et au lieu de donner une liste de tons à jouer, nous lui donnons une chaîne de caractères entre guillemets ::: ```python= d1 >> play("x-o-") d1.stop() ``` :::warning Chaque caractère est associé à un dossier de samples. "x" est une grosse caisse, "-" est un charley et "o" est une caisse claire. Pour sélectionner un fichier différent dans le dossier, nous utilisons le mot-clé "sample" : ::: ```python= d1 >> play("x-o-", sample=1) d1 >> play("x-o-", sample=2) d1 >> play("x-o-", sample=[0,1,2]) d1.stop() ``` :::warning Il peut aussi s'agir d'une liste de numéros ! Nous pouvons rendre notre motif de percussions plus complexe en utilisant des crochets ::: ```python= d1 >> play("x-o[--]") d1 >> play("x-o(-o)") d1 >> play("x-o{-o*}") d1.stop() ``` :::warning Les crochets jouent plusieurs samples dans l'espace d'un temps : ::: ```python= d1 >> play("x-o[--]") d1 >> play("x-o[---]") d1 >> play("x-o[-------]") d1.stop() ``` :::warning Les parenthèses rondes alternent le son utilisé : ::: ```python= d1 >> play("x-o(-o)") d1 >> play("x-o(-[-o])") d1 >> play("x-o(-[-(-o)])") d1.stop() ``` :::warning Et Les parenthèses bouclées {} sélectionnent un sample au hasard pour plus de variété ::: ```python= d1 >> play("x-o{-o}") d1 >> play("x-o{-[--]o}") d1.stop() ``` :::warning Tout comme avant, nous pouvons utiliser les arguments : ::: ```python= d1 >> play("x-(-[-o])", dur=[3/4,3/4,1/2], pan=[-1,1]) ``` :::warning Vous pouvez également modifier la vitesse de lecture de l'audio ::: ```python= d1 >> play("x-(-[-o])", dur=[3/4,3/4,1/2], pan=[-1,1], rate=1) d1 >> play("x-(-[-o])", dur=[3/4,3/4,1/2], pan=[-1,1], rate=2) d1 >> play("x-(-[-o])", dur=[3/4,3/4,1/2], pan=[-1,1], rate=0.5) d1 >> play("x-(-[-o])", dur=[3/4,3/4,1/2], pan=[-1,1], rate=-1) d1 >> play("x-(-[-o])", dur=[3/4,3/4,1/2], pan=[-1,1], rate=[1,2,0.5,-1]) d1.stop() ``` :::warning Pour jouer des choses en même temps, il suffit d'utiliser plusieurs players. ::: ```python= p1 >> pads([0,2,4,9,7], dur=1/4) d1 >> play("x-x-") d2 >> play(" * ") ``` :::warning Pour tout arrêter, appuyez sur "Cmd+." ou lancez la ligne de code ci-dessous. ::: ```python= Clock.clear() ``` *** ++Part 2: Composer un morceau++ === :::warning Les gammes ! Jusqu'à présent, nous n'avons utilisé que la majeure qui est la valeur par défaut, mais nous pouvons en utiliser tout un tas et même composer la nôtre ! Pour voir la liste des gammes, utilisez : ::: ```python= print(Scale.names()) ``` :::warning Utilisons la gamme "dorian" ! ::: ```python= Scale.default = "dorian" ``` :::warning Tout le timing est géré par "Clock" et nous pouvons changer le tempo si nous le voulons ::: ```python= Clock.bpm = 144 ``` :::warning Commençons par un rythme de base du drum ::: ```python= d1 >> play("x ") ``` :::warning Ajouter une ligne de basse ::: ```python b1 >> sawbass([0,-1,3], dur=[4,4,8]) ``` :::warning Ajoutons quelques accords - nous pouvons nous assurer qu'ils s'accordent avec la basse en réglant la hauteur relative à la hauteur de la basse, b1, en utilisant l'opérateur d'addition (+). ::: ```python= p1 >> star(b1.pitch) p1 >> star(b1.pitch + (0,2,4)) p1 >> star(b1.pitch + (0,2,4), dur=[3/4, 3/4, 1/2]) ``` :::warning Créez votre propre mélodie pour l'accompagner - lancez un SynthDef ::: ```python= print(SynthDefs) # par exemple blip p2 >> blip([0,7,6,4,2], dur=1/2, sus=1) ``` :::warning Ajoutons des percussions. ::: ```python= d1 >> play("x-") d2 >> play(" * ") ``` :::warning Qu'arrive-t-il à nos accords si nous changeons la basse ? ::: ```python= b1 >> sawbass([2,3,4,6], dur=4) ``` *** ++Part 3: Algorithmic music++ == :::warning Parfois, nous voulons donner des instructions aux players qui n'arrivent pas tout de suite. On peut utiliser la fonction "every" pour dire "tous les 8 temps, fais qqchose". Par exemple : ::: ```python= p1 >> pads([0,1,2,3,4,5,6,7]) p1.every(8, "reverse") p1.stop() ``` :::warning Tous les 8 temps, le player commence à jouer les notes dans l'ordre décroissant puis change à nouveau tous les 8 temps. On peut aussi "mélanger" l'ordre des notes ! ::: ```python= p1 >> pads([0,1,2,3,4,5,6,7]) p1.every(8, "shuffle") p1.stop() ``` :::warning Au lieu de tout mettre sur une nouvelle ligne, il est possible de "chaîner" ces fonctions ensemble : ::: ```python= p1 >> pads([0,1,2,3]).every(4, "reverse") p1 >> pads([0,1,2,3]).every(4, "reverse").stop() ``` :::warning Une autre fonction intéressante est le "stutter" ("bégaiement"), qui joue de multiples sons. Après "stutter", nous pouvons fournir plus d'arguments entre parenthèses comme nous l'avons fait avec le SynthDef : ::: ```python= d1 >> play("x-o-").every(4, "stutter") d1 >> play("x-o-").every(4, "stutter", 4) d1 >> play("x-o-").every(4, "stutter", 16) ``` :::warning Nous pouvons utiliser des mots-clés comme nous l'avons fait ci-dessus avec "stutter", pour changer la façon dont la fonction fonctionne ::: ```python d1 >> play("x-o-").every(4, "stutter", 4, pan=[-1,1]) d1 >> play("x-o-").every(4, "stutter", 4, dur=3) d1.stop() ``` :::warning Pour les players "mélodiques" (où nous jouons des notes), nous pouvons utiliser une fonction sympa appelée "offadd" qui jouera une nouvelle note sur le décalage, quelques ton plus haut que l'original Tous les 3 temps, jouez une note sur le temps mort qui est 4 ::: ```python= x1 >> blip([0,2,3,4]).every(3, "offadd", 4) ``` :::warning Vous pouvez "enchaîner" plus d'une fonction répétée, ::: ```python= x1 >> blip([0,2,3,4]).every(3, "offadd", 4).every(7, "stutter", 4) ``` :::warning Essayez de changer certains des mots-clés ::: ```python= x1 >> blip([0,2,3,4]).every(3, "offadd", 4).every(7, "stutter", 4, dur=3, pan=[-1,1], oct=6) ``` :::warning Enchaînez autant de fonctions différentes que vous le souhaitez ! ::: ```python= x1 >> blip([0,2,3,4]).every(3, "offadd", 4).every(7, "stutter", 4, dur=3, pan=[-1,1], oct=5).every(8, "reverse") ``` *** ++Part 4: Ajout et enchaînement des effets++ = :::warning Nous pouvons aussi ajouter des effets aux players et les séquencer comme nous l'avons fait avec les durées et les intensités. Nous pouvons ajouter une réverbération en spécifiant la taille de la pièce et le pourcentage de la réverb ::: ```python= p1 >> blip(dur=4, sus=1, room=1, mix=0.5) p1 >> blip(dur=1, sus=1, room=[0,0.25,0.5,1], mix=[0, 0.1, 0.3, 0.5]) p1.stop() ``` :::warning Vous trouverez ci-dessous d'autres effets à essayer. vous pouvez les appliquer à d'autres SynthDefs [Voici la liste et le détails de chacun](https://foxdot.org/docs/player-effects/) ::: ```python= print(FxList) ``` :::warning High Pass Filter - laisse seulement les fréquences *supérieures* à cette valeur dans le signal ::: ```python= d1 >> play("x-o-") d1 >> play("x-o-", hpf=500) d1 >> play("x-o-", hpf=5000) d1 >> play("x-o-", hpf=[0,100,250,500,1000,2000,4000,8000]) d1.stop() ``` :::warning Low pass filter - ne laisse que les fréquences *en dessous* de cette valeur dans le signal ::: ```python= d1 >> play("x-o-") d1 >> play("x-o-", lpf=5000) d1 >> play("x-o-", lpf=500) d1 >> play("x-o-", lpf=[50,100,200,400,800,1600,3200,6400]) d1.stop() ``` :::warning Chop - découpe le signal en "x" parties ::: ```python= p1 >> pluck([0,4], dur=4, chop=4) p1 >> pluck([0,4], dur=4, chop=8) p1 >> pluck([0,4], dur=4, chop=320) p1.stop() ``` :::warning Que se passe-t-il lorsque vous utilisez un sustain "sus" différent de la durée ? ::: ```python= p1 >> pluck([0,4], dur=[3/4,3/4,1/2], chop=4) p1 >> pluck([0,4], dur=[3/4,3/4,1/2], chop=4, sus=2) p1.stop() ``` :::warning Shape - distorsion de la forme des ondes ::: ```python= b1 >> bass(dur=8) b1 >> bass(dur=8, shape=0.5) b1 >> bass(dur=8, shape=[0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0]) ``` *** ++Part 5: Les Patterns++ == :::warning Python utilise des "listes" pour stocker de multiples données mais elles ne sont pas souvent manipulées d'une manière qui soit utile pour créer de la musique intéressante.,C'est pourquoi FoxDot utilise le type de données appelé Pattern qui est une extension des "listes" Pour créer une Pattern simple, il suffit de mettre un "P" majuscule devant une liste ::: ```python= l = [0, 1, 2, 3] p = P[0, 1, 2, 3] print(l, type(l)) print(p, type(p)) ``` :::warning Maintenant, nous pouvons faire des choses intéressantes avec le "p" que nous ne pouvons pas faire avec le "l". Par exemple, si nous voulons doubler toutes les valeurs de "l", le moyen le plus court est de le faire de cette manière : ::: ```python= print([x * 2 for x in l]) ``` :::warning C'est un peu lourd, surtout par rapport à la façon dont nous le faisons avec les patterns : ::: ```python= print(p * 2) ``` :::warning Nous pouvons faire toutes les opérations arithmétiques que nous voulons, et même utiliser des listes/patterns : ::: ```python= print(P[0, 1, 2, 3] * [1, 4]) ``` :::warning Les listes sont également accompagnées de toute une série de fonctions utiles pour manipuler l'ordre, etc. [Voci la liste](https://foxdot.org/docs/pattern-methods/) ::: ```python= print(p.reverse()) print(p.rotate()) print(p.palindrome()) print(p.stretch(6)) ``` :::warning Nous pouvons les chaîner ensemble : ::: ```python= print(p.reverse().palindrome().rotate() * 2) ``` :::warning Vous pouvez même "remplir automatiquement" un pattern avec des chiffres si vous vous sentez paresseux. C'est très similaire à la fonction 'range' en Python où vous spécifiez le début,la fin, et l'orde des nombres que vous voulez : ::: ```python= print(P[0:10]) print(P[10:0:-1]) print(P[0:10:2].shuffle()) ``` :::warning Pour plus d'informations sur les méthodes Pattern, consultez ::: ```python= help(Pattern) ``` :::warning Réalisons quelques exemples plus utiles puis voyons comment nous pouvons les utiliser : Pour joindre deux ou plusieurs patterns ensemble, utilisez le symbole de la "barre | " de cette façon : On obtient 0-4 en série, puis dans un ordre aléatoire ::: ```python= print(P[:4] | P[:4].shuffle()) ``` :::warning Pour créer des groupes de valeurs, comme des accords, dans les Patterns, vous pouvez utiliser le symbole &. pour regouper deux patterns en un seul groupe de patterns - ne vous inquiétez pas s'ils sont de tailles différentes ::: ```python= print(P[:4] & P[9, 11]) ``` :::warning Pour obtenir un sous-ensemble d'un pattern, nous pouvons utiliser l'indexation Python normale. Par exemple, si vous voulez juste un élément d'un pattern, nous mettons des crochets à la fin du pattern et le numéro de l'article que nous voulons ::: ```python= evens = P[2, 4, 6, 8] print(evens[2]) ``` :::warning Vous obtenez 6 pour l'index 2, car les index commencent à 0 ! ::: :::warning Pour obtenir un sous-ensemble, vous pouvez utiliser la méthode que nous avons fait pour générer une série ! ::: ```python= print(evens[0:3]) ``` :::warning Nous obtenons les trois premiers éléments de la liste ::: :::warning Même si l'éventail dépasse la fin du pattern, nous obtiendrons la taille que nous avons demandée ::: ```python= print(evens[0:6]) ``` :::warning Créons une mélodie soignée en utilisant un pattern ::: ```python= p1 >> blip(P[:10:2][:8].rotate(-3), dur=1/2, sus=2) ``` :::warning Combinez avec un pattern "PStep" ::: ```python= p1 >> blip(P[:10:2][:8].rotate(-3) + PStep(8,[0,3]).rotate(), dur=1/2, sus=2) p1.stop() ``` :::warning Alors, qu'est-ce que le PStep ? Eh bien, il existe dans FoxDot des fonctions qui permettent de générer des patterns pour vous permettre d'économiser de la frappe. Examinons quelques modèles utiles : ::: ```python= print(PStep(5,4,0)) # Pattern de longueur 5, se terminant par un 4, rempli de 0 print(PDur(3,8)) # Rythme euclidien, 3 pulsations sur 8 temps print(PSine(8)) # valeur n représentant une onde sinusoïdale ``` :::warning Mettons-les en pratique ::: ```python= p1 >> blip(P[:10:2][:8].rotate(-3) + PStep(8,[0,3]).rotate() | P[[9,11]], dur=PDur(3,8), sus=2, pan=PSine(16).shuffle()) d1 >> play("Xs") b1 >> dbass([0, 2, 3, 4], dur=8) Clock.clear() ``` :::warning Les fonctions de Pattern, telles que "palindrome" et "trim", peuvent être appelées régulièrement, tout comme les fonctions de Player comme "stutter" pour créer des modèles qui changent au fil du temps ! ::: ```python= p1 >> blip(P[:10:2], dur=PDur(5,8)*2, sus=2, oct=PStep(7,5,6)).every(6, "reverse").often("trim", 3).every(9, "stutter", 4, dur=3) d1 >> play("Xs") b1 >> dbass([0, 2, 3, 4], dur=8) Clock.clear() ``` :::warning Il existe aussi des patterns "infinis" qui continuent à générer des valeurs pour vous. Ils ont très utile lorsqu'on utilise des éléments de hasard. Générer des entiers aléatoires entre 0 et 8 en utilisant "PRand". ::: ```python= p1 >> blip(PRand(0, 8)) p1.stop() ``` :::warning Générer des valeurs aléatoires à partir d'une liste ::: ```python= p1 >> blip(PRand([0, 2, 4])) p1.stop() ``` :::warning Générer des valeurs flottantes dans une palette en utilisant PWhite ::: ```python= p1 >> blip(pan=PWhite(-1, 1), amp=PWhite(0, 1)) p1.stop() ``` :::warning Un bon exemple de combinaison d'indexation et de valeurs aléatoires pour créer des rythmes intéressants : ::: ```python= d1 >> play("x-o ") p1 >> blip(dur=1/4, amp=PRand([0,1])[:8]) Clock.clear() ``` *** ++Part 6: Utiliser le temps++ == :::warning Jusqu'à présent, nous avons utilisé des listes de numéros pour des choses comme les tonalités et les durées mais que faire si nous voulons que les valeurs changent en fonction du temps plutôt que de la séquence ? Voici un exemple : ::: :::warning Utilisons une basse pour jouer ces notes pendant 8 temps chacune ::: ```python= b1 >> bass([0, 3], dur=8) ``` :::warning Et si nous voulons changer la durée mais continuer à jouer les notes pendant 8 temps chacun ? ::: ```python= b1 >> bass([0, 3], dur=PDur(3,8)) b1.stop() ``` :::warning Et bien ça ne marche pas. C'est pour ça que nous utilisons un outil appelé "var" qui signifie "variable" et qui varie en fonction du rythme : ::: ```python= b1 >> bass(var([0, 3], dur=8), dur=PDur(3,8)) b1.stop() ``` :::warning Il a joué chaque tonalité pendant 8 temps, même si les durées étaient inférieures à 8. On crée un "var" en utilisant le code - var(Liste de valeurs, dur=duration) ::: ```python= b1 >> bass(var([0, 3], dur=8), dur=PDur(3,8)) ``` :::warning Remarquez la différence entre changer la durée dans la basse et la durée dans le var ::: ```python= b1 >> bass(var([0, 3], dur=8), dur=PDur(5,8)) b1 >> bass(var([0, 3], dur=[6, 2]), dur=PDur(5,8)) b1.stop() ``` :::warning Ils sont particulièrement utiles pour créer des séquences d'accords. Utilisons-les dans notre morceau de tout à l'heure : Voici notre basse pour commencer : ::: ```python= b1 >> sawbass([0,-1,3], dur=[4,4,8]) ``` :::warning Créons un var appelé "chords" pour que nous puissions l'utiliser dans plusieurs players : ::: ```python= var.chords = var([0,-1,3], dur=[4,4,8]) b1 >> sawbass(var.chords, dur=1) ``` :::warning Nous pouvons maintenant changer la durée comme nous voulons... ::: ```python= b1 >> sawbass(var.chords, dur=PDur(3,8)*2) ``` :::warning ...et d'autres instructions pour créer des patterns intéressants ! ::: ```python= b1 >> sawbass(var.chords, dur=PDur(3,8)*2, oct=[5,5,[6,4],5], pan=[0,[-1,1]]) + [0,0,4,0,7] ``` :::warning Nous pouvons utiliser la variable "var.chords" comme une seule note dans une liste : ::: ```python= p1 >> blip([var.chords,2,3,4], sus=2) ``` :::warning Écoutez la première note de la séquence, elle change avec les accords. On peut continuer d'ajouter toutes sortes de fonctions à la séquence pour la rendre plus intéressante ::: ```python= p1 >> blip([var.chords,2,3,4], sus=2).every(3, "offadd", 4) p1 >> blip([var.chords,2,3,4], sus=2).every(3, "offadd", 4).every(7, "stutter", 4, dur=3, pan=[-1,1], oct=6) p1 >> blip([var.chords,2,3,4], sus=2).every(3, "offadd", 4).every(7, "stutter", 4, dur=3, pan=[-1,1], oct=6).every(8, "reverse") ``` :::warning Cette fois, nous utiliserons plutôt "var.chords" que "b1.pitch" lors de l'ajout (0, 2, 4). ::: ```python= p2 >> star(var.chords + (0, 2, 4), dur=PDur(3,8)) ``` :::warning Que se passe-t-il si nous utilisons b1.pitch ? ::: ```python= p2 >> star(b1.pitch + (0, 2, 4), dur=PDur(3,8)) ``` :::warning Introduisons à nouveau des percussions ! ::: ```python= d1 >> play("x-") d2 >> play(" H ") ``` :::warning Utilisons un nouveau "var" pour appliquer un filtre passe-haut sur les drums pour la dernière mesure d'un cycle de 8 mesures Réglez le filtre sur 0 pour 28 temps (7 mesures x 4 temps) et ensuite sur 8000 pour 4 temps (1 mesure x 4 temps) ::: ```python= var.filter = var([0,8000], dur=[28,4]) d1 >> play("x-", hpf=var.filter) d2 >> play(" H ", hpf=var.filter) ``` :::warning Essayez d'ajouter vos éléments - voyez s'il y a d'autres façons intéressantes de combiner la variable "var.chords". ::: :::warning Essayez d'appliquer le "var.filter" à p1, p2 et b1. Essayez d'utiliser des crochets et .every pour rendre les sons de percussion plus complexes Que se passe-t-il lorsque vous changez "var.chords" ? ::: ```python= var.chords = var([2,3,4,6], dur=4) ``` *** ++Part 7: PGroups et patterns complexes++ == :::warning Jusqu'à présent, nous avons fait référence à des chiffres entre parenthèses comme celui-ci : (0, 2, 4) comme des groupes de valeurs. FoxDot les traite comme un type de données appelé "PGroup" qui est un type de pattern. Regardez le code ci-dessous ::: ```python= print(P[0, 1, 2, (3, 4)]) ``` :::warning Nous obtenons P[0, 1, 2, P(3, 4)] - le dernier élément est un PGroup. Comme avec les patterns, nous pouvons simplement mettre un "P" devant les parenthèses pour convertir en PGroup et faire des trucs sympas avec ::: ```python= print(P(0, 1, 2, 3, 4).reverse()) print(P(0, 1, 2, 3, 4).shuffle()) ``` :::warning En plus de jouer des notes ensemble comme ça : ::: ```python= p1 >> pads(P(0, 2, 4, 6), dur=4) p1.stop() ``` :::warning Les PGroups peuvent également être utilisés pour jouer des notes en succession rapide en mettant des symboles différents entre le "P" et les parenthèses : ::: ```python= p1 >> pads(P(0, 2, 4, 6), dur=4) p1 >> pads(P*(0, 2, 4, 6), dur=4) p1 >> pads(P*(0, 2, 4, 6), dur=2) p1.stop() ``` :::warning Vous remarquez la différence ? Le P* joue toutes les notes sur toute la durée de la note, tout comme les crochets dans le synthétiseur "play". Vous pouvez utiliser le symbole + pour répartir les notes sur le sustain d'une note par opposition à la durée, ce qui peut être utile lorsque vous utilisez des durées variables : ::: ```python= p1 >> pluck(P*(0, 4), dur=PDur(3,8), sus=1) p1 >> pluck(P+(0, 4), dur=PDur(3,8), sus=1) p1 >> pluck(P+(0, 4), dur=PDur(3,8), sus=2) p1.stop() ``` :::warning Nous utilisons un de ces PGroups lorsque nous utilisons la fonction "offadd" avec un Pattern qui nous permet de spécifier les durées entre les notes en utilisant le symbole ^ et la durée comme dernière valeur du groupe : ::: ```python= print(P[0, 1, 2, 3].offadd(4)) p1 >> pluck(P^(0, 2, 4, 0.5), dur=4) # retard de 0,5 battement p1 >> pluck(P^(0, 2, 4, 0.75), dur=2) # retard de 0,75 battement p1 >> pluck([P*(0, 3), P^(0, 2, 4, 0.75)], dur=2) # Combinaison de plusieurs PGroups p1.stop() ``` :::warning Donc P[:4].offadd(4) est la même chose que P[:4] + P^(0, 4, 0.5) ! ::: ```python= p1 >> pluck(P[:4].offadd(4)) p1 >> pluck(P[:4] + (P^(0,4,0.5))) p1.stop() ``` :::warning Ils sont utiles pour créer des variations de rythme sans avoir à créer un argument "dur" complexe. par exemple pour créer la mélodie simple ci-dessous : ::: ```python= p1 >> pluck([[0, P*(0, 0)], 2, -3, 2]) ``` :::warning Sinon nous devrions faire ce-ci : ::: ```python= p1 >> pluck([0, 2, -3, 2, 0, 0, 2, -3, 2], dur=P[1,1/2,1].stutter([4,2,3])) p1.stop() ``` *** ++Part 8: Séquences de samples avancés++ == :::warning Créons un rythme de percussion très simple ::: ```python= d1 >> play("xs", sample=2) d2 >> play(" * ", sample=2) d3 >> play("(+ )+( [( +)+])", sample=2) Clock.clear() ``` :::warning Nous avons dû utiliser trois players différents pour ce qui n'est qu'une séquence de percussion. Si cela peut faciliter le changement d'arguments, comme la durée ou l'amplitude de certaines parties de la séquence, il peut aussi être utile de traiter la séquence dans son ensemble. Nous pouvons "superposer" plusieurs chaînes d'échantillons en plaçant les séquences les unes à côté des autres mais en les entourant de flèches <> comme cela : ::: ```python= d1 >> play("<xs>< * ><(+ )+( [( +)+])>", sample=2) d1.stop() ``` :::warning Assurez-vous qu'il n'y a pas d'espaces entre les différents modèles ! Vous pouvez également utiliser ces parenthèses pour jouer des samples ensemble dans une séquence, comme celle-ci : ::: ```python= d1 >> play("x-<*><o>-") ``` :::warning Bien qu'il soit parfois plus facile de les diviser en séquences séparées : ::: ```python= d1 >> play("<x-*->< o >") d1.stop() ``` :::warning Les séquences n'ont pas besoin d'être de la même longueur, alors essayez plusieurs séquences de longueurs différentes ! ::: :::warning Vous pouvez considérer chaque séquence comme des couches superposées qui sont regroupées à l'aide de PGroups. Si vous souhaitez modifier les arguments ou les effets d'une couche individuelle, nous devons utiliser des PGroups pour le faire. Ainsi, si nous avons 3 couches et que nous voulons fixer le sample de la première couche à 2 mais les autres à 0, nous pourrions utiliser un code qui ressemble à ceci : ::: ```python= d1 >> play("<xs>< * ><(+ )+( [( +)+])>", sample=P(2, 0, 0)) d1.stop() ``` :::warning De même, si je veux régler le panoramique stéréo de la dernière couche pour alterner à gauche puis à droite (c'est-à-dire -1 et 1), alors je pourrais utiliser un code qui ressemble à ceci : ::: ```python= d1 >> play("<xs>< * ><(+ )+( [( +)+])>", sample=P(2, 0, 0), pan=P(0, 0, [-1, 1])) d1.stop() ``` :::warning Tout cela est très utile quand on veut utiliser "every" avec une séquence plus complexe : ::: ```python= d1 >> play("<xs>< * ><(+ )+( [( +)+])>", sample=P(2, 0, 0), pan=P(0, 0, [-1, 1])).every([12,4], "trim", 3) d1.stop() ``` :::warning Lorsque vous créez une séquence complexe, vous pourriez vouloir utiliser un sample spécifique avec une valeur séparée au reste de la séquence. Par exemple, si vous voulez que le sample "*" soit 2 mais que les autres soient 0, vous pourriez le faire de cette façon : ::: ```python= d1 >> play("x-*-", sample=[0,0,2,0]) d1.stop() ``` :::warning Mais que se passe-t-il lorsque vous changez la séquence ? ::: ```python= d1 >> play("x-*(-[-*])", sample=[0,0,2,0]) ``` :::warning Vous devez ensuite mettre à jour les arguments du sample en fonction de cela : ::: ```python= d1 >> play("x-*(-[-*])", sample=[0,0,2,[0,(0,2)]]) d1.stop() ``` :::warning C'est un peu ennuyeux. Vous pouvez en fait spécifier le numéro du sample pour un caractère spécifique en le mettant entre les barres || avec le numéro que vous voulez : ::: ```python= d1 >> play("x-|*2|-") d1 >> play("x-|*2|(-[-|*2|])") d1.stop() ``` :::warning Vous pouvez également utiliser des séquences / patterns de cette manière ! ::: ```python= d1 >> play("x-o|n[01]|") d1 >> play("x-|o(02)|-") d1 >> play("x-|o(0[20])|-") d1 >> play("x-o|a{0123}|") d1.stop() ``` ++Part 9: Utilisation de samples longs (fichiers wav)++ == :::warning Pour pouvoir utiliser un fichier wav long, il faut le placer dans un répertoire spécifique : ::: 1. dans FoxDot, ouvrir "Help&Settings">"Open Samples Folder": ![](https://i.imgur.com/L01Sysr.png) 2. Placer le fichier wav dans le sous-répertoire "_loop_": ![](https://i.imgur.com/6nepJnc.png) :::warning Ensuite, pour "jouer" ce fichier wav dans FoxDot , il faut utiliser le player 'loop". Ici 'dur=1' précise que l'on veut un extrait d'une durée d'un temps musical du fichier wav (ici appelé 'foxdot.wav'). Rappelons qu'avec le bpm à 120, un temps musical (beat) vaut 0.5 seconde. ::: ```python= s1 >> loop('foxdot',dur=1) ``` :::warning Nous pouvons aussi indiquer une liste ‘[2,1]’ qui précise les emplacements des extraits (dont la durée reste fixée dans l’attribut ‘dur’) que l’on souhaite lire. Le premier élément ‘2’ précise que l’on va commencer par lire l’extrait d’un temps musical qui démarre au 3ième temps musical dans le fichier wav (notons que les indices de liste démarrent à 0, et donc 2 fait référence au 3ième temps). Le deuxième élément ‘1’ précise que l’on va lire l’extrait (toujours d’une durée fixée dans l’attribut ‘dur’) qui démarre au 2ième temps musical dans le fichier wav. ::: ```python= s1 >> loop('foxdot',[2,1],dur=1) ``` :::warning Evidemment nous pouvons faire de cette liste une Pattern et lui appliquer toutes les méthodes habituelles : https://foxdot.org/docs/pattern-methods/ ::: ```python= s1 >> loop('foxdot',P[2,3,8,1].stutter(3),dur=1) ``` :::warning Si nous voulons lire la totalité du sample, il ne suffit pas d’augmenter la valeur de l’attribut ‘dur’ pour qu’elle coresponde à la durée du sample. La valeur de l’attribut ‘dur’ correspond à la durée de la boucle ‘loop’. Donc chaque modification de la ligne devra attendre la fin de la boucle pour être prise en compte. Ce ci pose naturellement des problèmes de réactivité pour l’aplication d’effets sur un sample de plusieurs secondes ou minutes. Pour remédier à ce problème nous allons découper le sample en une suite de boucles qui s’enchaînent les unes après les autres. Sur le même principe que celui de la liste nous allons enchainer les emplacements d’extraits (dont la durée est fixée dans l’attribut ‘dur’) de 0 (départ) jusqu’à la fin du sample. Ici le sample ‘foxdot’ dure 5 secondes, nous avons vu qu’avec un bpm à 120, un temps musical (beat) vaut 0.5 seconde, il nous faut donc 10 temps musicaux. ::: ```python= print(P[:11]) P[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] s1 >> loop('foxdot',P[:11],dur=1) ``` :::warning Nous pouvons également y préciser le point de départ du sample, ici le temps ‘3’ ::: ```python= print(P[3:11]) P[3, 4, 5, 6, 7, 8, 9, 10] s1 >> loop('foxdot',P[3:11],dur=1) ``` :::warning Si vous voulez lancer un sample long quand vous le souhaitez et être certain qu’il démarre bien au début, vous devez insérer votre liste dans une var, puis indiquer le nombre de fois où chaque valeur de la liste sera jouée, ici ‘1’ (une fois) et enfin lui indiquer à quel moment la liste doit démarrer, ici ‘ start=nextbar’. ::: ```python= s1 >> loop('foxdot', var(P[:11],1,start=nextbar)) ``` :::warning Nous pouvons aussi lui indiquer de s’arreter à la fin du sample c’est à dire à la fin de la liste pour qu’il soit lu qu’une seule fois. Ici la valeur ‘11’ placé dans ‘after()’ correspond au dernier temps musical ::: ```python= s1 >> loop('foxdot', var(P[:11],1,start=nextbar)).after(11, "stop") ``` ++Part 10 : Séquencer l'exécution d'instructions FoxDot++ == :::warning On illustre ici comment préparer des séquences d'instruction qui vont être exécutées selon un échéancier choisi. Il y a deux phases principales : la déclaration des séquences, l'échéancement des séquences. ::: ## Déclaration des séquences Voici un exemple : ```python= def sequence(f): f() return f @sequence def sequence1(): s1>>play("g", sample=2,rate=[1,2]) @sequence def sequence2(): s1.pitch="ggGG" s2 >> sinepad(P[2,4,3,0]+var([0,2],8), tremolo=[2,4], dur=[1,1/2]) @sequence def sequence3(): s3 >> prayerbell([2,6],dur=var([1/4,1],[1,3]),sus=0.1) s2.amp= var([1,0.5],4) Clock.clear() ``` :::warning a) Les trois premières lignes sont des instructions Python à copier tel quel (pour les programmeurs: déclaration d'une fonction 'sequence' dont on va modifier le comportement à l'aide d'un décorateur). ::: :::warning b) On déclare ensuite ci-dessus 3 séquences (on peut en faire autant que l'on veut). La première séquence correspond au code :-1: ::: ```python= @sequence def sequence1(): s1>>play("g", sample=2,rate=[1,2]) ``` :::danger Ce qu'il faut en retenir: - il faut commencer par une ligne avec @sequence (pour les programmeurs: on déclare un décorateur de la fonction 'sequence') - il faut ensuite une ligne pour déclarer le nom de la séquence, ici appelée 'sequence1' (pour les programmeurs : c'est le nom de la fonction décorant la fonction 'sequence'). Cette ligne doit commencer par 'def' et se terminer avec ':', et on doit ajouter '()' collé au nom choisi pour la séquence. - puis on met des lignes FoxDot en les indentant (une tabulation pour débuter la ligne). Dans cet exemple, il y a une seule ligne FoxDot qui déclare le player "s1" de type "play", mais on peut mettre autant de lignes (toutes indentées) que nécessaires ::: :::warning Notons que dans la deuxième séquence (appelée sequence2) et que je prévois être exécutée après sequence1, je modifie un attribut d'un player qui a été lancé dans sequence1 et je démarre un nouveau player de type sinepad: ::: ```python= def sequence2(): s1.pitch="ggGG" s2 >> sinepad(P[2,4,3,0]+var([0,2],8), tremolo=[2,4], dur=[1,1/2]) ``` :::warning c) On termine la déclaration des séquences par la ligne ::: ```python= Clock.clear() ``` :::warning d) Une fois la déclaration des séquences saisies sur FoxDot, il faut la charger en mémoire : il faut faire interpréter toutes ces lignes d'un coup (utiliser typiquement Ctrl + Return). ::: ## Echéancement des séquences :::warning Une fois que l'on a chargé en mémoire les séquences (étapes d) ci-dessus), on peut échéancer l'exécution de ces séquences. Par exemple: ::: ```python= start = Clock.mod(4) - 0.1 Clock.schedule(sequence1, start) Clock.schedule(sequence2, start + 8) Clock.schedule(sequence3, start + 16) ``` :::warning Ces lignes doivent être interprétées dans FoxDot en même temps (typiquement avec un Ctrl + Return). Ce qu'il faut en retenir : - la première ligne récupère l'instant de démarrage de la prochaine mesure (dans 4 temps musicaux) et le stocke dans la variable 'start' - la deuxième ligne planifie l'exécution de la première séquence (appelée 'sequence1') au début de la prochaine mesure (c'est-à-dire à l'instant stocké dans la variable 'start') - la troisème ligne planifie l'exécution de la deuxième séquence (appelée 'sequence2') 8 temps musicaux après le début de la prochaine mesure (c'est-à-dire à l'instant 'start + 8') - la quatrième ligne planifie l'exécution de la troisième séquence (appelée 'sequence3') 16 temps musicaux après le début de la prochaine mesure ::: ++Part 11 : Construire Accords & Mélodies++ == ## Les gammes :::warning Une règle simple à retenir pour construire vos accords et mélodies avec FoxDot ::: :::danger **La gamme détermine les notes contenues dans les accords et les mélodies utilisés.** <iframe width="560" height="315" src="https://www.youtube.com/embed/erWFq3c5YFk" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe> ::: :::warning Pour connaitre toutes les gammes proposées dans Foxdot ::: ```python= print(Scale.names()) ``` :::warning Pour connaitre les notes contenues dans une gamme, ici la gamme chromatic ::: ```python= print(Scale.chromatic) P[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] ``` | 0 | 1| 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10| 11| |-----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|------------|------------|------------| |Do | Do# | Ré | Ré# | Mi | Fa | Fa# | Sol | Sol# | La | La# | si | :::warning Structure des touches : * **Les touches blanches** sont les notes naturelles : Do, Ré, Mi, Fa, Sol, La, Si. * **Les touches noires** sont les notes avec des altérations (dièse ou bémol) : (Do#) ou (Ré♭), (Ré#) ou (Mi♭), (Pas de touche noire entre Mi et Fa), (Fa#) ou (Sol♭), (Sol#) ou (La♭), (La#) ou (Si♭), (Pas de touche noire entre Si et Do). ::: :::warning Il faut savoir que toutes les notes de la gamme chromatic sont séparées d’un demi ton chacune. ::: ![](https://i.imgur.com/yCTYJKh.png) ![](https://i.imgur.com/4D1F1Py.png) :::warning À noter que les dièses et les bémols sont les mêmes notes mais changent de nom en fonction de la note qui les précède. Le dièse (noté #) réhausse la note qu'il précède d'un demi-ton. Le bémol (noté b) abaisse la note qu'il précède d'un demi-ton. C’est à dire que Do# est précédé du Do mais le Do# devient un Reb si il est précédé d’un Re. ::: Voilà l’ensemble des gammes proposées dans FoxDot avec leurs notes associées.![](https://i.imgur.com/zVd5xz5.jpg) :::info <u> **Étape 1** : Qu'est-ce qu'une Scale (gamme) </u> ? Une "scale" ou gamme est un ensemble organisé de notes que l'on utilise pour composer ou improviser de la musique. Imaginez cela comme un nuancier musical : chaque gamme propose une série de notes qui s'harmonisent entre elles et qui créent un certain "mood". Une gamme est définie par l'espacement entre ses notes. <u>Exemple</u> : La gamme la plus courante est la gamme majeure. Elle commence par une note de base (la tonique) et suit une structure spécifique pour atteindre l’octave (la même note que celle de départ, mais plus haute). <u>**Étape 2** : Structure d'une gamme</u> Une gamme n'est pas simplement une liste de notes au hasard. Elle suit un schéma précis de "tons" et de "demi-tons" (écart entre deux notes). Voici la structure de deux gammes courantes : **Gamme majeure** (par exemple en Do majeur : Do - Ré - Mi - Fa - Sol - La - Si - Do) : ton, ton, demi-ton, ton, ton, ton, demi-ton. **Gamme mineure** naturelle (par exemple en Do mineur : Do, Ré, Mi♭, Fa, Sol, La♭, Si♭, Do) : ton, demi-ton, ton, ton, demi-ton, ton, ton. **Ton** : Deux touches sur un clavier (par exemple, de Do à Ré). **Demi-ton** : Une touche sur un clavier (par exemple, de Mi à Fa). <u>**Étape 3** : Interpréter ces listes de notes</u> Dans FoxDot et Renardo, les notes sont généralement interprétées comme des "degrés" dans une gamme plutôt que des notes spécifiques. Cela signifie que vous pouvez choisir une gamme (par exemple, majeure ou mineure) et FoxDot/Renardo se chargera de jouer les notes correspondantes. ```python= Exemple : p1 >> pluck([0,1,2,3,4,5,6], scale=Scale.minor) ``` Ici, les nombres 0,1,2,3,4,5,6 sont des "degrés" de la gamme mineure. Ils ne représentent pas directement des notes spécifiques, mais FoxDot/Renardo les convertira en notes de la gamme mineure que vous avez choisie. Si votre base est "Do", alors ces degrés joueront Do, Ré, Mi♭, Fa, Sol, La♭, Si♭. Ces notes suivent bien le schéma : ton - demi-ton - ton - ton - demi-ton - ton - ton, de la gamme mineure naturelle. **Règle de la gamme mineure naturelle :** <u>**ton**</u> : distance de 2 demi-tons (deux touches sur un piano, par exemple de Do à Ré). <u>**demi-ton**</u> : distance d'un demi-ton (une touche sur un piano, par exemple de Mi à Fa). Pour la gamme Do mineur naturel, en partant de la tonique Do, voici les intervalles entre les notes, appliqués successivement selon le schéma : 1. Do → Ré (ton, 2 demi-tons) 2. Ré → Mi♭ (demi-ton, 1 demi-ton) 3. Mi♭ → Fa (ton, 2 demi-tons) 4. Fa → Sol (ton, 2 demi-tons) 5. Sol → La♭ (demi-ton, 1 demi-ton) 6. La♭ → Si♭ (ton, 2 demi-tons) 7. Si♭ → Do (ton, 2 demi-tons) ```python= Exemple : pluck([0,2,4,5,7], scale=Scale.minor) ``` Les chiffres 0, 2, 4, 5, 7 représentent effectivement des degrés ou positions dans la gamme mineure que tu as choisie. Voici le détail : * 0 correspond à la première note de la gamme (tonique). * 2 correspond à la troisième note de la gamme.(tierce) * 4 correspond à la cinquième note de la gamme.(quinte) * 5 correspond à la sixième note de la gamme. * 7 correspond à la huitième note (ou la même note que la première, mais une octave plus haute). Il existe beaucoup de gammes, par exemple : **Gamme pentatonique** (5 notes) majeure : ton, ton, 1,5 ton, ton, 1,5 ton mineure : 1,5 ton, ton, ton, 1,5 ton, ton **Gamme hexatonique** (6 notes) 1,5 ton, ton, demi-ton, demi-ton, 1,5 ton, ton **Gammes heptatonique** (7 notes) majeure : ton, ton, demi-ton, ton, ton, ton, demi-ton. mineure : ton, demi-ton, ton, ton, demi-ton, ton, ton. **Gamme octotonique** (8 notes) (demi-ton/ton) : demi-ton, ton, demi-ton, ton, demi-ton, ton, demi-ton, ton (ton/demi-ton) : ton, demi-ton, ton, demi-ton, ton, demi-ton, ton, demi-ton **Gamme chromatique** : demi-ton entre chaque note | 0 | 1| 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10| 11| |-----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|------------|------------|------------| |Do | Do# | Ré | Ré# | Mi | Fa | Fa# | Sol | Sol# | La | La# | si | Les notions de "**majeur**" et "**mineur**" sont spécifiques aux gammes diatoniques, qui sont basées sur un schéma précis de tons et de demi-tons. Ces gammes ont des relations harmoniques très claires constituées par la 1ère, 3ème, et 5ème notes de la gamme : <u>Gamme majeure</u> : (1)tonique (la fondamentale), (3)tierce majeure, (5)quinte juste <u>Gamme mineure</u> : (1)tonique (la fondamentale), (3)tierce mineure, (5)quinte juste **Les accords parfaits** majeurs ou mineurs sont directement dérivés des gammes et sont les accords les plus fondamentaux en harmonie tonale. Chaque degré d'une gamme peut théoriquement donner un accord, mais le 1er degré (la fondamentale), le 3ème degré (la tierce), et le 5ème degré (la quinte) constituent l'accord parfait de cette gamme, aussi appelé accord tonique. **Pour changer la tonique** : Tu peux utiliser le paramètre root pour choisir une nouvelle note de base. Par exemple, si tu veux que la tonique soit (La), tu fais : python p1 >> pluck([0, 2, 4, 5, 7], scale=Scale.minor, root=9) Par défaut, root=0 et signifie que la tonique est (Do). Si tu veux changer cette tonique : * root=0 correspond à (Do) * root=2 correspond à (Ré) * root=4 correspond à (Mi) * root=5 correspond à (Fa) * root=7 correspond à (Sol) * root=9 correspond à (La) Exemple avec la gamme blues et une tonique différente : Si tu veux jouer une gamme blues avec G (Sol) comme tonique, tu peux faire : python p1 >> pluck([0, 3, 5, 6, 7, 10], scale=Scale.blues, root=7) Ici, root=7 signifie que la tonique de la gamme est G (Sol). Les degrés de la gamme seront donc transposés à partir de cette note. ::: ## Les accords <iframe width="560" height="315" src="https://www.youtube.com/embed/A6VoJv7bP5Q" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe> :::warning On désigne par « accord » la combinaison d’au moins trois notes différentes, d'une même gamme, jouées simultanément. **les accords permettent de créer la partie accompagnement**. Chacune des trois notes de l’accord possède un nom qui lui est propre : • La première note de l’accord s’appelle **la fondamentale** • La deuxième note de l’accord s’appelle **la tierce** • Et la troisième note de l’accord s’appelle **la quinte** la fondamentale donne son nom à l’accord. Par exemple si la fondamentale de votre accord est un **Do**, alors vous êtes en présence d’un accord de **Do**, si c’est un **La**, alors vous êtes en présence d’un accord de **La**, etc. Chaque note de l’accord doit être séparée par **un intervalle de tierce** (c’est-à-dire un intervalle de trois notes). <u>Exemples</u>: **Un accord de Do majeur** : Do/Mi/Sol : **deux tons / un ton et demi** **Un accord de La mineur** : La/Do/Mi : **un ton et demi / deux tons** Pour les deux accords : **1ere note** (la fondamentale), **3ème note** (la tierce), et la **5ème note** (la quinte) L’ intervalle de tierce peut être **majeur** ou **mineur** Une **tierce majeure** sera composée de **deux tons** : exemple Do/Mi/Sol Une **tierce mineure** sera composée d’**un ton et demi** : exemple La/Do/Mi ![](https://i.imgur.com/djP76VA.png) ::: :::warning Je commence par choisir une gamme, par exemple ::: ```python= print(Scale.aeolian) P[0, 2, 3, 5, 7, 8, 10] ``` | <b><span style="color:red;">0</span></b> | 1 | <b><span style="color:red;">2</span></b> | <b><span style="color:red;">3</span></b> | 4 | <b><span style="color:red;">5</span></b> | 6 | <b><span style="color:red;">7</span></b> | <b><span style="color:red;">8</span></b> | 9 | <b><span style="color:red;">10</span></b> | 11 | |-----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|------------|------------|------------| | <b><span style="color:red;">Do</span></b> | Do# | <b><span style="color:red;">Ré</span></b> | <b><span style="color:red;">Ré#</span></b> | Mi | <b><span style="color:red;">Fa</span></b> | Fa# | <b><span style="color:red;">Sol</span></b> | <b><span style="color:red;">Sol#</span></b> | La | <b><span style="color:red;">La#</span></b> | Si | :::warning Ainsi je dispose de ces notes [0, 2, 3, 5, 7, 8, 9, 11] pour composer mes accords et mes lignes mélodiques. ATTENTION Lorsque vous composez avec une gamme vous ne devez pas utiliser les valeurs de la liste données par print(Scale....) qui définissent les notes de la gamme. Vous devez utiliser les valeurs qui définissent l'ordre des notes dans la gamme. Commençons par un accord qui suit la règle de l’intervalle de tierce. ::: ```python= Scale.default = Scale.aeolian m1 >> piano(P[(0,2,4)],dur=1,oct=4) ``` :::warning Ensuite nous pouvons lui ajouter une ligne mélodique qui utilisent les notes proposées dans la même gamme. En jouant sur la durée et l’octave des notes pour apporter du rythme. ( **None** est une note silencieuse pour créer une pause dans la ligne) ::: ```python= Scale.default = Scale.aeolian m1 >> pbass(P[(0,2,4),None,(0,2,4),(0,2,4)],dur=[1,3,1,1],oct=[4], sus=1, root=[0,2,3,2]) m2 >> sawbass([0,2,5,8,5,None,5,8,5,8,7,8,5,8,11,8,5,None],dur=0.25,oct=4) m3 >> play ("x.x.Xs",sample= [0,2]) ```