# 2 - Players ### 2.1. Attributs du Player Introduction Les objets Players de FoxDot sont assignés à des SynthDefs qui prennent divers arguments dans un ensemble de parenthèses pour manipuler les séquences jouées. Vous avez probablement déjà vu dur et pan, mais que pouvons-nous utiliser d'autre ? Il y a beaucoup d'options, qui sont divisées en deux groupes : les attributs et les effets. Les attributs sont des éléments qui affectent quelle note est jouée à quel moment et les effets sont des éléments qui modifient la façon dont le son, sonne ! Vous pouvez voir une liste de tous les mots-clés possibles en évaluant le code suivant ``` >>> print(Player.get_attributes() ('degree', 'oct', 'dur', 'delay', 'blur', 'amplify', 'scale', 'bpm', 'sample', 'sus', 'fmod', 'pan', 'rate', 'amp', 'vib', 'vibdepth', 'slide', 'sus', 'slidedelay', 'slidefrom', 'bend', 'benddelay', 'coarse', 'striate', 'pshift', 'hpf', 'hpr', 'lpf', 'lpr', 'swell', 'bpf', 'bpr', 'bits', 'amp', 'crush', 'dist', 'chop', 'tremolo', 'echo', 'decay', 'spin', 'cut', 'room', 'mix', 'formant', 'shape') ``` Gardez à l'esprit qu'un SynthDef de SuperCollider peut prendre des arguments de mots-clés spécifiques qui ne sont pas listés ci-dessus. Vous pouvez définir les valeurs d'un attribut ou d'un effet d'un Player en les spécifiant comme argument de mot-clé à l'intérieur d'un appel SynthDef comme ceci : `p1 >> pluck([0, 1, 2, 3], dur=1/2, sus=2)` Vous pouvez également définir la valeur directement dans les attributs de l'objet du Player : ``` p1 >> pluck() p1.degree = [0, 1, 2, 3] p1.dur = 1/2 p1.sus = 2 ``` Cette section présente les différents mots-clés d'attributs à l'aide d'exemples de code. Si vous souhaitez en savoir plus sur les effets, vous trouverez plus d'informations dans la section suivante. Attributs Ce sont les valeurs des mots-clés qui sont utilisées par FoxDot pour décider quelle note ou quel sample sera joué à quel moment. Dans le désordre, ce sont : degree, oct, dur, scale, amp, amplify, bpm, sample, et delay. Nous allons maintenant étudier chacun d'entre eux en profondeur avec quelques exemples de code **Hauteur / Note** Mot-clé : **`degré`** La hauteur est parfois appelée "degré de la gamme" et fait référence à l'indice de la gamme que nous devons utiliser pour créer une note - ainsi, pour jouer la première note d'une gamme, vous utilisez la valeur de degré 0. Il n'est pas nécessaire de spécifier ce degré par son nom, car il s'agit toujours du premier argument utilisé. Voici un exemple de code qui joue les quatre premières notes de la gamme par défaut (do majeur). ``` p1 >> pluck([0, 1, 2, 3]) ``` **Octave** Mot-clé : **`oct`** C'est l'octave dans laquelle vous voulez jouer une note. Par défaut, il s'agit de 5, de sorte que la note que vous jouez lorsque vous démarrez un objet Player "vierge" est le do moyen. Une octave est (généralement) composée de 12 demi-tons, de sorte que la 5e octave commence au 60e demi-ton. Nous ajoutons cette valeur à notre hauteur (que nous obtenons en utilisant le degré) pour obtenir la valeur de la note finale. Un nombre plus petit correspond à une note plus basse et un nombre plus grand à une note plus haute : ``` p1 >> pluck(oct=[4, 5, 6]) ``` **Durée** Mot-clé : **`dur`** Il s'agit de la durée d'une note. Les durées ne peuvent pas être négatives et doivent contenir au moins un nombre non nul. Une durée peut être de n'importe quel type tant qu'elle peut être représentée par une valeur à virgule flottante. Les durées suivantes sont toutes valides : ``` # Valeur unique pour toutes les notes p1 >> pluck([0, 1, 2, 3], dur=1/2) # Une liste de durées peut être constituée d'entiers, de fractions ou de valeurs à virgule flottante. p1 >> pluck([0, 1, 2, 3], dur=[1, 1/2, 0.5]) p1 >> pluck([0, 1, 2, 3], dur=[0.1, 0.3, 0.43, 0.17]) ``` Vous pouvez "sauter" une note en réglant sa durée sur zéro ou la "mettre en sourdine" en utilisant un objet de repos dont la durée est indiquée entre parenthèses : ``` # Sauter toutes les 3 notes p1 >> pluck([0, 1, 2, 3], dur=[1, 1, 0]) # Repos toutes les 3 notes pendant 2 temps p1 >> pluck([0, 1, 2, 3], dur=[1, 1, rest(2)]) ``` **Gamme** Mot-clé : **`scale`** Comme son nom l'indique, ce mot-clé définit l'échelle de l'objet Player. Il doit s'agir d'une liste, d'un motif ou d'un objet Scale (qui est une sous-classe de Pattern). Pour voir une liste des échelles, vous pouvez évaluer le code suivant : ``` >>> print(Scale.names()) ['aeolian', 'chinese', 'chromatic', 'custom', 'default', 'diminished', 'dorian', 'dorian2', 'egyptian', 'freq', 'harmonicMajor', 'harmonicMinor', 'indian', 'justMajor', 'justMinor', 'locrian', 'locrianMajor', 'lydian', 'lydianMinor', 'major', 'majorPentatonic', 'melodicMajor', 'melodicMinor', 'minor', 'minorPentatonic', 'mixolydian', 'phrygian', 'prometheus', 'romanianMinor', 'yu', 'zhi'] ``` Par défaut, FoxDot utilise la gamme "majeure". Pour passer à la gamme mineure, par exemple, vous pouvez utiliser le mot-clé scale et la gamme Scale.minor comme suit : ``` # Joue la gamme majeure par défaut p1 >> pluck([0, 2, 4, 6, 7]) # Passage à la gamme mineure p1 >> pluck([0, 2, 4, 6, 7], scale=Scale.minor) ``` Si vous souhaitez modifier l'échelle pour tous les joueurs, vous pouvez définir la valeur Scale.default : ``` # Démarrage d'un lecteur dans la gamme par défaut (Majeure) p1 >> pluck([0, 2, 4, 6, 7]) # Changer la gamme par défaut en Dorian Scale.default = Scale.dorian # Vous pouvez spécifier l'échelle par défaut sous la forme d'une chaîne de caractères Scale.default = "dorian" ``` **Volume** Mots-clés : **`amp`, `amplify`** C'est l'amplitude d'une note, ou son volume/son intensité. Les valeurs sont généralement comprises entre 0 et 1, mais vous pouvez définir des valeurs plus importantes pour rendre une note encore plus forte, mais attention à ne pas être trop fort ou vous pourriez endommager vos oreilles / haut-parleurs ! `p1 >> pluck([0, 1, 2], dur=[1, 1/2, 1/2], amp=[1, 0.5, 1/3])` Nous pouvons créer des motifs assez rythmiques en utilisant l'amp avec des valeurs de 0 : ``` p1 >> pluck( dur=1/4, amp=[1, 1/2, 1/2, 1, 0, 1, 0, 1, 1/2, 1/2, 1, 0, 1, 1/2, 1/4, 1] ) ``` Mais que se passe-t-il si nous voulons jouer ce rythme toutes les deux mesures ? Une solution serait d'ajouter manuellement un grand nombre de 0 à la séquence ou d'utiliser un objet Pattern et sa méthode stutter, mais nous pouvons également utiliser un autre argument de mot-clé conçu à cette fin : amplify. Avant qu'un son ne soit déclenché par un Player, la valeur de l'amp est multipliée par amplify, ce qui permet d'utiliser des éléments tels que TimeVar pour définir une amplitude à 1 ou 0 (c'est-à-dire activée ou désactivée) pendant un certain temps : ``` p1 >> pluck( dur=1/4, amp=[1, 1/2, 1/2, 1, 0, 1, 0, 1, 1/2, 1/2, 1, 0, 1, 1/2, 1/4, 1], amplify=var([1,0],[6,2]) ) ``` Cette fonction est utile si vous souhaitez activer ou désactiver plusieurs lecteurs en même temps : ``` p1 >> pluck(dur=1/4, amp=[1, 1/2, 1/2, 1, 0, 1, 0, 1, 1/2, 1/2, 1, 0, 1, 1/2, 1/4, 1]) p2 >> bass(var([0, 3], 8), dur=1/2) p1.amplify = p2.amplify = var([1,0],4) ``` La dernière ligne est assez maladroite, vous pouvez donc utiliser un objet Group à la place (voir ici) pour plus d'informations : ``` p1 >> pluck(dur=1/4, amp=[1, 1/2, 1/2, 1, 0, 1, 0, 1, 1/2, 1/2, 1, 0, 1, 1/2, 1/4, 1]) p2 >> bass(var([0, 3], 8), dur=1/2) Group(p1, p2).amplify = var([1,0],4) ``` **Tempo** Mot clé: **`bpm`** Si vous voulez qu'un objet Player joue à un tempo différent, vous pouvez utiliser l'attribut bpm. Voici les battements par minute. Le tempo global de l'horloge peut être réglé en changeant son attribut bpm en utilisant par exemple Clock. bpm = 140 (voir ici pour plus d'informations). ``` # Joue au tempo Clock.bpm (par défaut 120) p1 >> pluck([0, 1, 2, 3]) # Forcer le Player à utiliser 100 bpm p2 >> bell([4, 5, 7], bpm=100) # Il jouera toujours à 100 bpm même si Clock.bpm est modifié Clock.bpm = 200 ``` **Samples** Mot-clé : **`sample`** Ce mot-clé n'est utilisé qu'avec le Player de samples, appelé play. Ce SynthDef prend une chaîne comme premier argument (connue sous le nom de "chaîne de lecture") au lieu d'une liste de valeurs de hauteur et joue des échantillons audio stockés sur votre ordinateur portable en fonction du caractère de la chaîne. Chaque caractère est associé à un dossier d'échantillons et, par défaut, il joue le premier échantillon de ce dossier. Pour jouer un autre échantillon, utilisez le mot-clé sample : ``` # Samples par défaut p1 >> play("x-o-") # Une autre série de samples p1 >> play("x-o-", sample=1) # Peut être une liste de valeurs p1 >> play("x-o-", sample=[0, 1, 2]) ``` Les valeurs doivent être des nombres entiers. Si un dossier contient 3 échantillons et que vous utilisez la valeur 4, l'objet lecteur reviendra en boucle au premier fichier du dossier et le lira, il n'est donc pas nécessaire de savoir exactement combien d'échantillons se trouvent dans un dossier. **Retarder un son** Mot-clé : **`delay`** En musique (et particulièrement en musique électronique), le délai fait souvent référence à une sorte d'effet d'écho où un son est rejoué peu de temps après avoir commencé, mais un peu plus silencieusement. Dans FoxDot, cependant, il s'agit littéralement d'une durée, en battements, pour retarder l'exécution d'un son. Ici, nous retarderons chaque troisième note d'un demi-battement : `p1 >> pluck([0, 1, 2, 3], delay=[0, 0, 0.5])` Si vous souhaitez jouer la note et la jouer avec un retard, vous pouvez utiliser un tuple ou un PGroup dont la première valeur est 0, ce qui signifie qu'il n'y a pas de retard. La deuxième valeur indique la durée du retard de la deuxième note : ``` # bégaiement" toutes les trois notes p1 >> pluck([0, 1, 2, 3], delay=[0, 0, (0, 0.5)]) # Retarder une note pour qu'elle soit jouée *après* la suivante p1 >> pluck([0, 1, 2, 3], delay=[0, 0, (0, 1.5)]) ``` **Clé musicale** Mot clé : **`root`** Tout comme vous pouvez utiliser une échelle différente de Scale. default à partir d'un Player, vous pouvez également utiliser une note racine différente (plus d'informations ici). Il doit s'agir d'un nombre ou d'une séquence de nombres et non d'un nom de note, par exemple "C#" ``` # Changer la racine tous les 8 temps p1 >> blip([0, 7, 6, 4, 2], dur=1/4, sus=2, root=var([0, 2], 8)) ``` ### 2.2. Effets du Player Introduction Les effets peuvent être ajoutés à un lecteur de la même manière que ses attributs sont modifiés; en utilisant des arguments de mots-clés. Tout comme pour les attributs Player, il peut s'agir d'une valeur unique ou d'une séquence. Cette page contient des descriptions des différents effets disponibles dans FoxDot et comment les appliquer. La plupart des effets sont appliqués en utilisant une seule valeur, comme pan, mais certains ont un seul effet «parent» et un ou plusieurs effets «enfants». Un exemple est slide, qui est le parent, et slidedelay est l'enfant. Si l'effet parent est fixé à 0, l'effet n'est pas appliqué. Les valeurs enfant de 0 sont toujours appliquées si le parent n'est pas nul ``` # Effet de Slide ajouté p1 >> pluck(dur=4, slide=1, slidedelay=0.5) # Effet de Slide non ajouté p1 >> pluck(dur=4, slide=0, slidedelay=0.5) # Effet de Slide ajouté avec 0 delay p1 >> pluck(dur=4, slide=1, slidedelay=0) ``` **Sustain** Mots clés : **`sus`, `blur=1`** L’argument du mot-clé sus est utilisé pour définir le “sustain” d’une note, c’est-à-dire la durée du son de la note. Par défaut, il s’agit de la durée de la note (définie à l’aide du mot-clé dur) et d’une valeur mesurée en termes de “battements”. Le code suivant jouera une répétition d'une note à 1 temps avec un demi-temps sustain: ``` # Durée d'un temps, demi-temps p1 >> pluck(dur=1, sus=1/2) ``` Utilisez blur pour créer un effet «legato» (un mot qui signifie «attaché ensemble» en italien). Il s'agit d'un terme musical qui fait référence à la façon dont les notes se succèdent en douceur, ou se confondent. La valeur sus est multipliée par la valeur actuelle du blur, de sorte que le code suivant double la longueur du sustain de toutes les autres notes: ``` # Double la longueur de chaque note p1 >> pluck(dur=PDur(3,8), blur=[1, 2]) ``` **Stereo** Mots clés : **`pan`** Panning (en audio) est la distribution du son sur plusieurs haut-parleurs. Actuellement FoxDot n'utilise que deux canaux de sortie (pour les haut-parleurs gauche et droit) mais il est prévu d'étendre cela à plusieurs haut-parleurs. Pour modifier le panoramique d'un son, utilisez le panoramique et définissez la valeur entre -1 (gauche dure) et 1 (droite dure). Une valeur panoramique de 0 envoie le signal audio des deux haut-parleurs de manière égale. ``` # Alternez entre la gauche, le centre et la droite p1 >> cueillette(pan = [-1, 0, 1]) # Joue deux notes en même temps, mais avec des haut-parleurs différents p1 >> cueillette((0, 4), pan=(-1,1)) # Déplacer graduellement le panoramique du son de gauche à droite en utilisant un "linvar" p1 >> pluck([0, 2, 4, 7], dur=1/4, pan=linvar([-1,1],8)) ``` **Modificateur de fréquence** Mots clés : **`fmod`** Cela ajoute une valeur à la fréquence utilisée pour générer une note, mais seulement dans l'un des canaux. Par exemple, si vous démarrez un Player sans instructions, vous jouerez continuellement une note sur le do moyen, qui est de 261,6 Hz, à travers les deux canaux du haut-parleur. En utilisant fmod = 10, la note sera jouée à 261,6 Hz sur un canal et à 271,6 Hz sur l'autre. Cela crée une «dissonance» ou un son «atonal» perceptible parce que les fréquences sont si proches les unes des autres. L'utilisation d'une valeur plus petite, comme 2, crée une sorte d'effet flanger : ``` # Effet flanger simple p1 >> pluck(fmod = 2) Varier l'effet avec le temps p1 >> pluck(fmod=linvar([-10,10],8), dur=1/4, sus=1) ``` **Vibrato** Mots clés: **`vib`, `vibdepth = 0,02`** Vibrato est un terme musical qui fait référence à une modulation continue de la hauteur, c'est-à-dire changeant dans le temps. Vous pouvez définir la vitesse du vibrato d'une note en utilisant le mot-clé vib et la profondeur (la taille de la modulation) du vibrato en utilisant le mot-clé vibdepth. La profondeur par défaut est de 0,02, ce qui signifie que le vibrato fluctue entre +/- la fréquence de la note multipliée par 0,02. Vous pouvez aussi penser qu'elle fluctue entre 99% et 101% de la valeur de fréquence. ``` p1 >> pads(dur=4, vib=4) p1 >> pads(dur=4, vib=4, vibdepth=0.1) p1 >> pads(dur=4, vib=4, vibdepth=1) ``` **Slide** Mots clés : **`slide`, `slidedelay = 0`** Ceci est utilisé pour changer la fréquence d’une note au fil du temps. La fréquence “slide” à (1 + n) * freq où n est la valeur fournie au mot-clé 'slide'. Par exemple, une valeur slide de 1 fera glisser la fréquence à deux fois sa valeur originale (une octave vers le haut). Une valeur slide de -1 glissera à une fréquence de 0. Par défaut, l'effet slide commence immédiatement après le début de la note. Pour retarder le début du slide, vous pouvez utiliser le mot-clé slidedelay. Il doit s'agir d'une valeur comprise entre 0 (le début de la note) et 1 (la fin de la note). ``` Faites glisser une octave vers le haut p1 >> pluck(dur=4, slide=1) # Déplacer à 0 p1 >> pluck(dur=4, slide=-1) # Retarder l'effet du slide pour commencer à mi-chemin de la note p1 >> pluck(dur=4, slide=0. 5, slidedelay=0. 5) ``` **Slide from** Mots clés: **`slidefrom`, `slidedelay = 0`** Semblable au slide, cet effet change également la fréquence d’une note au fil du temps, mais vous indiquez où le slide commence. La fréquence “slides” de (1 + n) * freq où n est la valeur fournie au mot-clé slidefrom et se termine à la fréquence de la note. Par exemple, une valeur slidefrom de 1 fera glisser la fréquence du double de sa valeur initiale (une octave vers le haut). Une valeur slidefrom de -1 glisse à partir d'une fréquence de 0. Par défaut, l'effet de slide commence immédiatement après le début de la note. Pour retarder le début du slide, vous pouvez utiliser le mot-clé slidedelay. Il doit s'agir d'une valeur comprise entre 0 (le début de la note) et 1 (la fin de la note). ``` # Glisse d'une octave vers le haut p1 >> pluck(dur=4, slidefrom=1) # Glisse à partir de 0 p1 >> pluck(dur=4, slidefrom=-1) # Retarder l'effet de slide pour commencer à mi-chemin de la note p1 >> pluck(dur=4, slidefrom=0. 5, slidedelay=0. 5) ``` **Pitch bend** Mots clés : **`bend`, `benddelay = 0`** Autre effet semblable au slide, le pitch bend change la fréquence d'une note au fil du temps mais revient également à sa fréquence d'origine à la fin de la note. En dehors de cela, il fonctionne exactement de la même manière que le slide. ``` bend de 1 une octave de haut en arrière p1 >> pluck(dur=4, bend=1) # Bend à 0 et retour à nouveau p1 >> pluck(dur=4, bend=-1) # Retarder l'effet de bend pour commencer à mi-chemin de la note p1 >> pluck(dur=4, slide=0. 5, bend=0. 5) ``` **Chop** Mots clés : **`chop`** Cela “couper” le signal audio en “n” parties, où “n” est la valeur que vous fournissez à l'argument du mot-clé. Il utilise le sustain de la note (fixé à l'aide du sus) pour déterminer la taille des parties, de sorte que vous pouvez également combiner chop et sus pour créer des effets intéressants. ``` # Couper un son en 4 parties p1 >> pluck([0,1,2,3], dur=4, chop=4) # Si la durée varie, la taille de la coupe variera aussi p1 >> pluck([0,[4,6,7]], dur=PDur(3,8), chop=4) # Changer une seule valeur pour "sus" égalise les tailles et crée un bel effet d'écho de chevauchement p1 >> pluck([0,[4,6,7]], dur=PDur(3,8), chop=4, sus=2) ``` **Coarse** Mots clés : **`coarse`** C’est similaire au chop mais diffère en ce sens que le signal audio n’est pas « coupé », mais la fréquence de contrôle (la fréquence des notes / la fréquence de lecture des samples) l’est. Cela peut être utile dans plusieurs situations. La première concerne la lecture de samples en utilisant le synthétiseur play: Utiliser chop ne joue essentiellement que la moitié de l'audio, l'autre moitié étant muette par l'effet "chop". L'utilisation du coarse mettra essentiellement le son en pause et le reprendra après un léger retard. Il le fait en fixant la vitesse de lecture à 0 alors que chop mettrait l'amplitude à 0. Écoutez la différence en exécutant le code ci-dessous dans FoxDot: ``` # Utilisez chop c1 >> play("C", dur=4, chop=16, coarse=0) # Utiliser coarse c1 >> play("C", dur=4, coarse=16, chop=0) ``` Une autre utilisation de coarse serait pour quand vous obtenez des sons de coupure lors de l'utilisation de chop. Cela se produit quand une amplitude passe à 0 très rapidement et sonne comme un minuscule “pop”. Exécutez ces lignes de code dans FoxDot et écoutez les différences: ``` b1 >> bass(dur=2, chop=4, coarse=0) b1 >> bass(dur=2, coarse=4, chop=0) ``` La ligne utilisant coarse = 4 sonne un peu plus propre. Malheureusement, cela n’arrive pas toujours et l’effet coarse ne s’applique pas toujours à certains synthés, par exemple le klank. **High-pass filter** Mots clés : **`hpf`, `hpr = 1`** Un son non trivial est constitué d’une combinaison d’ondes sonores vibrant à différentes fréquences et amplitudes, dont certaines peuvent être « filtrées » à partir d’un signal à l’aide d’un filtre. Ceci est souvent connu sous le nom de synthèse soustractive. Un filtre passe-haut supprimera les parties d'un signal qui sont en dessous d'une certaine fréquence et ne laisse passer que les fréquences qui sont supérieures au seuil. Ceci peut être appliqué dans FoxDot simplement en définissant la valeur hpf (abréviation de filtre passe-haut) : ``` # Réglez la coupure du filtre passe-haut à 2000 Hz d1 >> play("x-o-", hpf=2000) # Définir la coupure pour qu'elle change au fil du temps en utilisant un linvar d1 >> play("x-o-", hpf=linvar([0,2000],32)) ``` Vous pouvez également définir la résonance passe-haut pour le filtre en utilisant le mot-clé hpr. Ceci est parfois appelé « rq » ou « hpq ». Lorsque cette valeur diminue, les harmoniques proches de la valeur de coupure sont amplifiées – une valeur proche de 0 sonnera comme une onde sinusoïdale oscillant à la valeur définie en utilisant hpf. Méfiez-vous des valeurs très petites et très grandes car vous pourriez obtenir des sons très forts! ``` # Réglez la coupure du filtre passe-haut à 2000 Hz d1 >> play("x-o-", hpf=2000) # Réglez la résonance à 0,2 - entendez-vous la différence? d1 >> play("x-o-", hpf=2000, hpr=0. 2) # Définir la résonance de coupure *et* pour changer au fil du temps en utilisant linvar d1 >> play("x-o-", hpf=linvar([0,2000],32), hpr=linvar([1,0. 1],28)) ``` **Low-pass filter** Mots clés : `lpf`, `lpr = 1` Tout comme le filtre passe-haut ne permet que les fréquences d'un signal audio au-dessus d'une certaine limite, le filtre passe-bas ne permet que les fréquences d'un signal audio au-dessous d'une certaine limite. La résonance passe-bas, lpr, fonctionne de la même manière que la résonance passe-haut. ``` # Réglez la coupure du filtre passe-bas à 400 Hz d1 >> play("x-o-", lpf=400) # Changer la résonance - pouvez-vous entendre la différence? d1 >> play("x-o-", lpf=400, lpr=0. 2) # Utiliser un linvar pour faire varier les deux valeurs dans le temps d1 >> play("x-o-", lpf=linvar([500,5000],32), lpr=linvar([1,0. 1],28)) ``` **Bitcrush** Mots clés: **`crush`, `bits = 8`** Le bitcrushing est un effet de distorsion créé en réduisant à la fois la fréquence d'échantillonnage d'un signal audio et la bande passante. Une valeur de crush de 1 réduira le débit binaire du signal à la valeur de bits, qui est 8 par défaut. Chaque incrément à écraser par la suite réduit de moitié la fréquence d'échantillonnage du signal (à partir de 44,1 KHz). L'effet bitcrush nécessite l'installation des plugins SC3 pour fonctionner. ``` # Appliquer l'effet de crush de bits d1 >> play("X O ", crush=4) # Réduire le nombre de bits pour plus de distorsion d1 >> play("X O ", crush=4, bits=4) # Ou réduire la fréquence d'échantillonnage pour un style de distorsion différent! d1 >> play("X O ", crush=32, bits=8) ``` **Distortion** Mots clés : **`dist`** Cela nécessite l'installation des plugins SC3. Cette valeur doit être comprise entre 0 et 1 et fausse le signal audio. ``` # Ajoute une distorsion aux Players sample et synthé d1 >> play("x * ", dist=0. 2) p1 >> dirt([0,5], dist=0,3, dur=8) + (0,4) ``` **Wave-shape distortion** Mots clés : **`shape`** Il s’agit d’un autre type de distorsion qui affecte la forme d’onde du signal audio. Cette valeur doit être comprise entre 0 et 1, mais des valeurs plus grandes sont également acceptées (attention avec les écouteurs!). Cet effet de distorsion ne nécessite aucune installation supplémentaire. ``` # Ajoute une distorsion aux joueurs sample et synthé d1 >> play("x * ", shape=0.5) p1 >> dirt([0,5], shape=0.5, dur=8) + (0,4) ``` **Overdrive distortion** Mots clés : **`drive`** Une distorsion créée en amplifiant le son puis en le coupant à une amplitude beaucoup plus «normale». Les valeurs doivent être comprises entre 0 et 1, mais des valeurs plus grandes sont acceptées. ``` # Ajouter overdrive distortion p1 >> dirt(dur=1/2, drive=1) ``` **Reverb** Mots clés : **`room`, `mix = 0. 1`** Utilisez le mot-clé room pour ajouter une réverbération à un son. Cela émule l'effet de jouer le son dans une pièce et peut être sur une échelle de sec (0% de mélange du son réverbéré) à humide (100% de mélange du son réverbéré). Le mot-clé room définit la taille de la room à émuler la réverbération, et mix est le pourcentage de mix sous forme de fraction (0,1 = 10%). ``` # Emuler jouer les sons dans une petite pièce p1 >> play("x o ", room=0. 25) # Emuler jouer les sons dans une pièce plus grande p1 >> play("x o ", room=0. 8) # Rends le signal plus "humide" p1 >> play("x o ", room=0. 8, mix=0. 8) ``` **Echo** Mots clés: **`echo`, `echotime = 1`** Cet effet est souvent appelé Comb Delay mais l'appliquer à un seul son lui donnera l'effet d'écho dans une pièce. Utilisez le mot-clé echo pour définir la durée (en battements) entre chaque son répété. Le code suivant joue une seule note en répétition mais nous l'entendons résonner après 1 temps. `p1 >> blip(dur=4, echo=1)` Note : Vous pouvez parfois avoir besoin d'ajouter une réverbération en utilisant l'argument room pour entendre l'effet echo. En effet, un son est arrêté par SuperCollider une fois qu'il est détecté comme étant silencieux. Si l’écho se produit après une période de silence, vous devrez ajouter une réverbération pour garder le son «vivant». Voici un exemple : ``` Nous n'entendons aucun effet d'écho d1 >> play("x-o-", dur=1, echo=0. 75) Ajoutez la réverbération et nous l'entendons d1 >> play("x-o-", dur=1, echo=0. 75, room=0. 5) ``` Par défaut, vous n'entendrez probablement qu'un seul écho du son original. Pour entendre plus d'échos, augmentez la durée de l'écho: ``` # N'entendez qu'un seul écho p1 >> blip(dur=4, echo=1) # Maintenant nous entendons plusieurs p1 >> blip(dur=4, echo=1, echotime=8) # Nous pouvons utiliser echo pour rendre les boucles de batterie plus intéressantes aussi d1 >> play("(x )( x)o ", room=0. 1, echo=0. 75/2, echotime=4) ``` :::warning Attention à utiliser trop d'écho sur trop de joueurs car il utilise une grande quantité de CPU et peut provoquer le plantage de SuperCollider. ::: **Pan spin** Keywords: **`spin`** Cet effet balaie continuellement le son de gauche à droite, et encore, 'n' nombre de fois, où 'n' est la valeur donnée au mot-clé spin. Cela dépend du sustain de la note (donné en utilisant le mot-clé sus). ``` # Déplacez le pan de gauche à droite 4 fois sur 4 temps p1 >> pads(dur=4, spin=4) # Déplacez le pan de gauche à droite 4 fois sur 1 temps p1 >> pads(dur=4, sus=1, spin=4) ``` **Cut** Mots clés : **`cut`** Pour arrêter un son brusquement (au lieu d'utiliser un sus plus court), vous pouvez utiliser le mot-clé cut. Ceci est particulièrement utile lors de la lecture de sample car sus n'a aucun effet sur le son lui-même. La durée à laquelle le son est arrêté correspond à la valeur de coupure en proportion de la valeur de sus, c'est-à-dire qu'une coupure de 0,5 arrêtera le son à mi-chemin. ``` Arrête un son immédiatement au lieu de sa décomposition naturelle p1 >> pads(dur=4, cut=0,75) # Raccourcir les samples à un dixième de leur longueur normale d1 >> play("x-o-", cut=0. 1) ``` **Formant filtter** Mots clés : **`formant`** Cela utilise la classe Formlet de SuperCollider pour ajouter un filtre de résonance très simple au son, pas différent de l’effet « vowel » de TidalCycles. Les valeurs doivent être comprises entre 1 et 7. ``` # Boucle à travers les différents niveaux, nous pouvons appliquer le filtre p1 >> pluck(formant=P[:8]) ``` **Tremolo** Mots clés : **`tremolo`** Tremolo est la modulation d'amplitude, qui se fait en FoxDot en utilisant une onde sinusoïdale. Cela oscille l’amplitude d’une note ‘n’ fois par temps, où ‘n’ est l’entrée donnée à l’argument tremolo. `p1 >> pads(dur=4, tremolo=2)` **Pitch shift** Mots clés : `pshift` Le décalage la hauteur d'une note par nombre de demi-tons vers le haut ou vers le bas. Cela fonctionne aussi pour les samples utilisés par le play SynthDef. ``` # Décaler la hauteur d'un synthé p1 >> pads(pshift=[0,1,2,3]) # Décaler la hauteur d'un échantillon p2 >> play("C", dur=2, pshift=[0,1,2,3]) Peut être utilisé pour faire des accords p2 >> play("C", dur=2, pshift=[0, (0,4,7)], sample=3) ``` **Glide** Mots clés: **`glide`, `glidedelay = 0. 5`** Glide, souvent appelé glissando, est très similaire à l’effet « slide », sauf que vous spécifiez le nombre de demi-tons à glisser au lieu du multiplicateur de fréquence. À l'avenir, cela pourrait être remplacé par le nombre d'étapes dans l'échelle de cohérence. ``` # Glisser vers et depuis la 5ème note de la gamme (7ème demi-ton) p1 >> pluck([0, 4], dur=4, glide=[7,-7]) ``` ### 2.3. Manipulation algorithmique L'un des avantages du codage en direct est que vous pouvez planifier des événements pour se produire, ou se répéter, dans le futur. Cela vous permet de continuer à coder pendant que des fonctions répétées sont appelées et d'ajouter de la variété à votre musique. Cette section est un examen approfondi de la façon dont chaque méthode du Player est implémentée et comment vous pouvez combiner plusieurs instances de celui-ci pour créer de la musique complexe à partir de motifs simples. Regardons d’abord un exemple simple qui inverse une séquence tous les 8 temps: ``` p1 >> pluck([0, 1, 2, 3, 4, 5, 6, 7]).every(8, "reverse") ``` Le premier argument est le nombre de battements entre chaque appel d'une méthode et le second argument est le nom de la méthode elle-même sous forme de chaîne de caractères. La raison pour laquelle on utilise le nom de la méthode sous forme de chaîne plutôt qu'une fonction est que Python peut vérifier si la méthode est valide à l'aide de la fonction getattr et soulever une erreur si ce n'est pas le cas. En exécutant le code print(getattr(p1, "reverse")), vous obtiendrez quelque chose de similaire à `<bound method="" player. reverse="" of="" >`. Ce qui se passe alors, en substance, c'est que l'horloge d'ordonnancement exécute getattr(p1, "reverse"). __call__() tous les 8 temps. Vous pouvez utiliser une liste de durées pour programmer des appels de méthodes à des intervalles irréguliers, comme suit : ``` p1 >> pluck([0, 1, 2, 3, 4, 5, 6, 7]).every([6, 2], "reverse") ``` Le code ci-dessus appellera la méthode inverse après 6 battements, puis 2 battements après cela, puis encore 6 battements après cet appel, répétant ceci jusqu'à l'arrêt. Vous pouvez aussi utiliser un objet Pattern ou PatternGenerator tel que PRand pour appeler des méthodes à des moments non prédéterminés : ``` p1 >> pluck([0, 1, 2, 3, 4, 5, 6, 7]).every(PRand([2, 4, 8]), "reverse") ``` Si vous essayez de spécifier plusieurs appels de la même méthode, vous constaterez que seul le dernier mis à jour est planifié. Si vous voulez utiliser plus d'un appel répété à la même méthode, vous pouvez utiliser le mot-clé ident et lui donner un nom ou un numéro pour le différencier: ``` # Appelle "reverse" tous les 8 battements *et* tous les 5 battements d1 >> pluck([0, 1, 2, 3, 4, 5, 6, 7]).every(8, "reverse").every(5, "reverse", ident=1) ``` Les méthodes de joueur qui peuvent être utilisées avec chaque efficace sont reverse, rotate, shuffle, jump, and stutter. **Le mot-clé cycle** Parfois, il peut être utile de programmer une méthode pour le même point dans un cycle de N-battements, par exemple le bégaiement du son sur le 6ème temps de tous les 8 cycles de temps. Vous pouvez le faire en spécifiant simplement la longueur du cycle comme argument de mot-clé: ``` p1 >> play("x-o-").every(6, "stutter", cycle=8) ``` Plutôt que d’appeler le stutter tous les 6 battements, il est appelé tous les 8 battements (la taille du cycle) mais décalé de 6 battements. L’une des méthodes les plus utiles qui peuvent être appelées en utilisant 'every' est la méthode de stutter. Ceci lit le dernier événement envoyé à SuperCollider plusieurs fois sur une durée spécifiée. Vous pouvez également spécifier des attributs/effets à attacher aux événements tels que pan ou shape en utilisant des arguments de mots clés. Vous pouvez spécifier le nombre de fois qu’un événement est bégaié simplement en fournissant un entier à chaque appel en suivant le nom de la méthode sous forme de chaîne. La valeur par défaut est 2, ce qui signifie que vous entendrez 1 événement supplémentaire – 2 moins l’événement déjà joué. En utilisant une valeur de 4, vous jouerez 3 événements supplémentaires (vous comprenez l’idée). Par défaut, les événements seront bégaiés pendant la durée de l’événement, mais vous pouvez également bégaier les événements sur une période donnée en fournissant un mot clé dur : ``` # Jouer l'événement 4 fois tous les 6 battements sur 1/2 battements d1 >> play("x-o-", dur=1/2). every(6, "bug", 4) # Jouer l'événement 4 fois tous les 6 battements sur 3 battements d1 >> play("x-o-", dur=1/2). every(6, "bug", 4, dur=3) # Vous pouvez aussi spécifier le nombre d'événements à bégayer en utilisant le mot-clé 'n' d1 >> play("x-o-", dur=1/2). every(6, "bug", dur=3, n=4) ``` Tout comme vous fournissez des arguments de mots clés pour contrôler le son de vos synthés, vous pouvez faire de même avec "stutter" pour contrôler le son en cours de lecture. Il peut s’agir d’une liste ou d’un modèle de valeurs qui sont données à chaque événement bégaié à son tour,c'est à dire qui ne sont pas joués en même temps : ``` # Stutter 8 fois avec vitesse de lecture croissante d1 >> play("x-o-").every(4, "stutter", 8, rate=[1,2,3,4,5,6,7,8]) # Stutter 4 fois avec déplacement alterné et taux supérieur d1 >> play("x-o-").every(4, "stutter", 4, dur=3, pan=[-1, 1], rate=2) # Vous pouvez toujours utiliser des tuples / PGroups pour ajouter des effets simultanés d1 >> play("x-o-").every(4, "stutter", 4, dur=1, pan=(-1,1), rate=(4, 1/2)) ``` Notez que lorsque vous utilisez une liste de valeurs, seules les n premières valeurs seront utilisées (où n est le nombre de fois que vous bégayez). Utilisation des méthodes Pattern En plus de reverse, rotate, shuffle, jump et stutter, vous pouvez également programmer n'importe quelle méthode appartenant à la classe Pattern pour qu'elle soit appelée sur n'importe quel attribut d'un joueur. Le comportement est légèrement différent de celui lors de la planification des méthodes de lecture dans la mesure où au lieu d'être appelé tous les n battements, il est appelé puis désappelé pour ainsi dire. Il est probablement préférable de le démontrer avec un exemple : ``` # Appelle la méthode "trim" sur l'attribut degré d1 >> play("x-o-").every(4, "trim", 3) ``` Le motif « x-o- » est coupé à juste « x-o » après 4 temps, puis revient à « x-o- » après les 4 temps suivants. Par défaut, la méthode est appelée sur l'attribut degré (qui est la hauteur pour la plupart des synthés et la chaîne de caractères pour le synthétiseur play) – vous pouvez spécifier un attribut différent en préfixant le nom de la méthode avec le nom de l'attribut puis un « ». ainsi: ``` # Coupez le motif d'octave à 3 tous les 4 temps p1 >> pluck(oct=[4,5,6,7]).every(4, "oct.trim", 3) ``` Les arguments qui seraient fournis à la méthode pattern sont donnés après le nom de la méthode. Par exemple, la méthode de pattern offadd, qui superpose un pattern avec lui-même mais avec une valeur ajoutée et retardée d'une durée, prend 2 arguments ; la valeur à ajouter et le temps de retard (la valeur par défaut est 0,5). Voici quelques exemples sur la façon de l’utiliser avec chaque : ``` # Jouer une note 2 crans plus haut en retardant 1/2 temps p1 >> pasha([0, 4], dur=[3/4, 3/4, 1/2]).every(3, "offadd", 2) # Jouez une note 4 crans plus haut retardée de 3/4 de temps p1 >> pasha([0,1,3,4], dur=1/2).every(5, "offadd", 4, 3/4) ``` Important : vous pouvez utiliser n'importe quelle méthode de la classe Pattern, que vous pouvez voir en exécutant help(Pattern) ou en consultant la page de documentation. **L'objet Cycle** Cela peut créer une certaine confusion avec le mot-clé cycle, mais l'objet Cycle peut être utilisé pour alterner les valeurs utilisées par chaque méthode. Par exemple, vous voulez bégayer un player toutes les 4 fois tous les 4 battements mais plus de 3 battements la première fois et 2 battements la suivante. Comment tu fais ça? Voici comment vous pourriez penser que cela fonctionnerait : `p1 >> play("x-o-").every(4, "stutter", 4, dur=[3, 2])` Malheureusement, cela générerait une erreur car la méthode bégaiement essaierait d'utiliser la liste comme durée alors qu'elle devrait être une valeur unique. Au lieu de cela, vous pouvez utiliser un objet Cycle, qui alterne les valeurs utilisées comme suit : `p1 >> play("x-o-").every(4, "stutter", 4, dur=Cycle([3, 2]))` ### 2.4. Jouer des Samples Il existe actuellement deux synthés spéciaux dans FoxDot pour lire l'audio stocké dans un fichier ; play et loop. Ici, nous allons les examiner de manière plus approfondie : Le synthétiseur play **Bases** Les bases du synthétiseur play ont été brièvement abordées dans la section d'introduction des objets Player, mais seront revisitées ici. Contrairement aux autres synthés de FoxDot, le premier argument doit être une chaîne de caractères plutôt que des chiffres. Cela permet de coder davantage d'informations dans la chaîne. Chaque personnage fait référence à un ensemble d'échantillons tels que des grosses caisses, des charleys, des caisses claires et d'autres sons. La séquence la plus basique que vous créez est un battement de batterie disco : `p1 >> play("x-o-")` Vous pouvez utiliser différents types de parenthèses pour ajouter plus d'informations à la séquence. Mettre deux caractères ou plus entre parenthèses alternera le son à jouer sur chaque boucle de la séquence : ``` # Simple pattern p1 >> play("(x-)(-x)o-") # parenthèses imbriquées pour plus de variété p1 >> play("(x-)(-(xo))o-") ``` Mettre plusieurs caractères entre crochets les jouera successivement en l'espace d'une étape : ``` # Joue un triplet sur le quatrième temps p1 >> play("x-o[---]", dur=1) # Peut être utilisé dans les parenthèses p1 >> play("(x-)(-[-x])o-") # Peut contenir des parenthèses p1 >> play("x-o[-(xo)]") ``` Vous pouvez également utiliser des accolades pour choisir un échantillon au hasard et ajouter une certaine variété à votre séquence : ``` # Choisir au hasard un sample à la quatrième étape p1 >> play("x-o{-ox}") # Peut contenir [crochets] p1 >> play("x-o{[--]ox}") # Peut être placé entre crochets p1 >> play("x-o[-{ox}]") ``` **Le mot-clé sample** Chaque caractère se rapporte à un dossier de fichiers classés par ordre alphabétique. Pour sélectionner un fichier différent, utilisez le mot-clé sample. `p1 >> play("x-o-", sample=1)` Comme avec tout autre argument de mot-clé, cela peut être une liste, ou même un tuple, de valeurs. ``` p1 >> play("x-o-", sample=[0, 1, 2]) p1 >> play("x-o-", sample=(0, 3)) ``` Le sample pour un caractère individuel peut être spécifié à partir de la chaîne elle-même en entourant le caractère avec un "|" et le numéro spécifique comme ceci : ``` # Joue sample=2 pour le caractère 'o' p1 >> play("x-|o2|-") # Remplacera le mot-clé sample p1 >> play("x-|o2|-", sample=3) ``` Cette syntaxe peut contenir n’importe lequel des parenthèses utilisés précédemment sur le caractère et sur les nombres : ``` # Changer le numéro du sample p1 >> play("x-|o(12)|-") # Alterner le caractère du sample p1 >> play("x-|(o*)2|-") # Lecture de plusieurs samles différents en une seule étape p1 >> play("x-|o[23]|-") # Lecture d’un sample aléatoire p1 >> play("x-|o{1[23]}|-") ``` **Séquences de superposition** Vous pouvez également utiliser les signes < et > pour superposer plusieurs séquences simultanément. Commençons par deux séquences séparées, puis assemblons-les en une seule ligne de code. ``` p1 >> play("x-o-") p2 >> play(" + + [ +]") ``` Nous pouvons mettre chaque séquence entre les caractères « <>» dans une seule séquence et les faire jouer en même temps: ``` # Superposez les deux séquences p1 >> play("<x-o->< + + [ +]>") # Équivalent à : p1 >> play(P["x-o-"].zip(P[" + + [ +]"])) ``` Chaque « séquence » se rapporte à l’indice d’un groupe de sorte que, pour un groupe de valeurs données à un objet Player, chaque « séquence » est affectée seulement par une de ces valeurs données. Voici un exemple qui le démontre le mieux : ``` # Panoramique de chaque séquence vers les canaux gauche et droit p1 >> play("<x-o->< + + [ +]>", pan=(-1, 1)) # Modifier les samples utilisés dans la première séquence p1 >> play("<x-o->< + + [ +]>", sample=(2, 0)) ``` Soyez prudent lorsque vous combinez plusieurs séquence avec certaines fonctions comme offadd car cela crée de nouvelles séquence s’ils n’existent pas, ou les affecte s’ils existent. Le code suivant n’affectera que la deuxième séquence et, par conséquent, la premiere séquence n’est pas affecté : ```p1 >> play("<x-o->< + + [ +]>", sample=(2, 0)).every(4, "sample.offadd", 2) ``` **Le synth loop ** C’est toujours une fonctionnalité assez expérimentale de FoxDot et est certainement sujette à changement, mais jetons un coup d’œil aux bases. Le synthé loop est conçu pour vous permettre de lire des fichiers audio plus longs (>1 sec) et de les manipuler. Pour commencer, indiquez simplement le nom de fichier que vous voulez lire et la durée que vous voulez lire en battements : ``` p1 >> loop("path/to/my/my_file.wav", dur=32) ``` Vous pouvez placer les fichiers dans un dossier spécial situé dans FoxDot/snd/_loop_/ qui peut être ouvert en allant dans “Help & Settings”, puis dans “Open Samples Folder” dans le menu FoxDot. Vous n’avez pas besoin de fournir le chemin complet (ou l’extension) pour les fichiers de ce dossier : ``` p1 >> loop("my_file", dur=4) ``` Pour voir tous les fichiers dans ce dossier, exécutez `print(Samples.loops)`. Si vous voulez jouer avec l’ordre de lecture, vous pouvez fournir un argument de position après le nom du fichier que FoxDot parcourra en fonction de la durée. ``` # Lire les 4 premiers battements du sample dans l’ordre p1 >> loop("my_file", P[:4], dur=1) Jouer les 4 premiers battements dans un ordre aléatoire p1 >> loop("my_file", P[:4].shuffle(), dur=1) ``` Si vous connaissez le bpm du fichier audio et souhaitez le lire au tempo actuel, vous pouvez fournir au lecteur un argument tempo. Par exemple, my_file pourrait être un battement de batterie à 135 bpm, mais le tempo actuel est de 120, je peux ajuster le tempo de my_file à l’horloge comme suit : ``` # Quatre premiers battements en un seul temps p1 >> loop("my_file", P[:4], dur=1, tempo=135) # Les 4 premiers battements en 1/2 temps p1 >> loop("my_file", P[:8]/2, dur=1/2, tempo=135) ``` Vous pouvez lire le fichier entier au tempo actuel en fournissant un argument beat_stretch avec une valeur non nulle (telle que 1 ou True) et vous n’avez pas besoin de connaître le tempo au préalable. `p1 >> loop("my_file", dur=4, beat_stretch=True)` Le temps d’étirement de l’audio de cette façon va changer la hauteur, donc si l’audio est lancé, vous pouvez souhaiter l’étirer sans perdre cette information. Ceci est possible en utilisant l’argument striate. Cela coupe le fichier en un grand nombre de petits segments et les lit de manière étalée sur la durée – cela va lire le fichier audio entier. Plus le fichier audio est volumineux, plus le nombre que vous souhaitez utiliser est important. En utilisant l’exemple ci-dessus, vous pouvez utiliser une valeur de striate de 100-200 pour une lecture plus fluide : ``` # Étirer le fichier en utilisant 100 segments p1 >> loop("my_file", dur=4, striate=100) # Étirer le fichier en utilisant 10 segments p1 >> loop("my_file", dur=4, striate=10) ``` Notez : vous pouvez rencontrer des changements de hauteur à des tempos plus rapides. Tous les effets de FoxDot Player peuvent être utilisés avec le synthé loop, alors expérimentez et découvrez ce qui fonctionne le mieux pour votre audio. Par exemple, l’utilisation d’un "slide" avec des valeurs négatives peut recréer l’effet « dj scratching » du hip-hop de la vieille école, car il ralentit le taux de lecture à 0 puis de nouveau : `p1 >> loop("my_file", P[:8]/2, dur=1/2, slide=[0,0,-2])` **Le synth stretch ** Cet ajout récent à FoxDot vous permet de lire un fichier audio entier sans perdre d’informations de hauteur – que le tempo soit plus rapide ou plus lent. Il suffit de fournir le nom du fichier de la même manière que le synthé loop et de définir la durée de lecture du fichier sur et au loin : ``` # Lecture du fichier entier en 4 temps p1 >> stretch("my_file", dur=4) ``` ### 2.5. Les clés de Player Introduction Les clés de Player sont le moyen le plus simple de créer des relations entre vos objets Player. Ils vous permettent de partager des données de manière réactive et dynamique et sont particulièrement utiles si vous collaborez lorsque vous utilisez l’interface Troop. Ils sont accessibles comme tout attribut d’objet Python, en tapant le nom de l’objet, un point, puis le nom de l’attribut par exemple p1.pitch. La chose intéressante à propos des clés de Player est que, si le Player d’origine est mis à jour, de même que la clé de Player, de sorte que vous n’avez pas à vous soucier de mettre à jour les valeurs nulle part ailleurs. Ceux-ci fonctionnent pour n’importe quel attribut d’un joueur, par exemple degré, ampli, sus, pan ou toute autre chose. Ce n’est pas tout à fait la même chose que copier et coller la valeur Pattern car il utilisera toujours la valeur la plus à jour détenue par cet attribut. Prenons un exemple : ``` p1 >> pads([0, 4, 5, 3], dur=4) p2 >> pluck(p1.degree, dur=1/2) ``` Le Pattern utilisé par p1 est P[0, 4, 5, 3] mais la durée est de 4 battements pour chaque note. Après avoir utilisé p1.degree, le Player p2 jouera le même pitch, en changeant seulement la valeur lorsque le pitch de p1 change. Essentiellement, p2 jouera chaque hauteur 8 fois. Pour accéder directement au motif, vous devez lire les données du dictionnaire attr comme suit : ``` p1 >> pads([0, 4, 5, 3], dur=4) p2 >> pluck(p1["degree"], dur=1/2) ``` Remarque : si p1 est mis à jour, la hauteur de p2 ne sera pas mise à jour jusqu’à ce que la ligne de code soit re-exécutée lors de l’utilisation du dictionnaire attr. **Alias** La clé de player utilise deux alias pour récupérer la valeur de degré d’un player. Vous pouvez utiliser . pitch pour les synthés et . char pour le synthé play, qui le rend plus facile de comprendre quelle valeur vous obtenez réellement. **Maths and Logic** Vous pouvez effectuer n’importe quelle opération mathématique sur une clé de Player disponible en Python : | Symbol | Name | Description | | -------- | -------- | -------- | |+ |Addition | | |- |Subtraction | | / |Division | | |* |Multiplication | | |** |Power | | |^ |Power | | |// |Floor division | Retourne le résultat entier de la division | |% |Modulo division | Retourne le reste de la division | |== |Equal to |Teste si la clé de Player est égale à la valeur donnée, retourne 1 si True et 0 si False | |!= |Not equal to | Teste si la clé de Player n’est pas égale à la valeur donnée, renvoie 1 si Vrai et 0 si Faux | |> |Greater than | Teste si la clé de Player est supérieure à la valeur donnée, renvoie 1 si True et 0 si False | |< |Less than | Teste si la clé de Player est inférieure à la valeur donnée, renvoie 1 si True et 0 si False | |>= |Greater than or equal to | Teste si la clé de Player est supérieure ou égale à la valeur donnée, renvoie 1 si Vrai et 0 si Faux | |<= |Less than or equal to | Teste si la clé de Player est inférieure ou égale à la valeur donnée, renvoie 1 si vrai et 0 si faux | **Methods** **`.transform(func)`** Le comportement d’une clé de Player est similaire à celui du TimeVar. Il s’agit essentiellement d’un nombre/chaîne qui change au fil du temps, mais toute transformation effectuée, telle que la multiplication par deux, sera également vraie chaque fois que la valeur change. ``` >>> p1 >> pads([0, 4, 5, 3], dur=4) >>> a, b = p1.pitch, p1.pitch * 2 >>> print(a, b) 4, 8 >>> print(a, b) 5, 10 ``` Au fur et à mesure que le temps change, le pitch du Player et toute opération arithmétique sur celui-ci créent une nouvelle clé de Player qui contient des informations sur l’original et la transformation. De cette façon, il retourne toujours la transformation de la valeur correcte. Les choses se compliquent lorsque nous voulons utiliser une fonction personnalisée sur notre clé de Player. Disons que nous voulons transformer notre clé de Player en un 5 lorsqu’elle est impaire et un 3 lorsqu’elle est pair. Voici une fonction qui vous permettra de le faire : ```python >>> def odd_test(num): return 5 if num % 2 == 1 else 3 >>> p1 >> pads([0, 1, 2, 3], dur=4) >>> a, b = p1.pitch, odd_test(p1.pitch) >>> print(a, b) 0, 3 >>> print(a, b) 1, 3 >>> print(a, b) 2, 3 ``` Remarquez quelque chose. Nous avons toujours obtenu 3, même si la valeur de la clé de player était odd. Pour appliquer une fonction (par opposition à une opération mathématique), vous devez utiliser la méthode de transformation et fournir la méthode avec la fonction pour la transformer. Il ne devrait prendre qu’un seul argument d’entrée : ``` >>> p1 >> pads([0, 1, 2, 3], dur=4) >>> p2 >> pluck(p1.pitch.transform(odd_test), dur=1/2) >>> print(p1.pitch, p2.pitch) 0, 5 >>> print(p1.pitch, p2.pitch) 1, 3 ``` **`.map(mapping_dict, default=0)`** Au lieu de définir une fonction pour retourner certaines valeurs comme ci-dessus, nous pouvons fournir un mappage sous la forme d’un dictionnaire Python. Les mappages peuvent être des valeurs ou des fonctions individuelles. Si la valeur d’une clé de Player n’est pas dans le dictionnaire, la valeur par défaut est retournée. ``` >>> p1 >> pads([0, 4, 5, 3], dur=4) >>> p2 >> pluck(p1.pitch.map({4: 1, 3: 0}, default=2)) >>> print(p1.pitch, p2.pitch) 0, 2 >>> print(p1.pitch, p2.pitch) 4, 1 >>> print(p1.pitch, p2.pitch) 5, 2 >>> print(p1.pitch, p2.pitch) 3, 0 ``` Voici comment vous pouvez implémenter la transformation odd_test en utilisant map et une fonction lambda : ``` p1 >> pads([0, 4, 5, 3], dur=4) p2 >> pluck(p1.pitch.map({lambda x: x % 2 == 1: 5}, default=3) ``` **`.accompany(rel=[0, 2, 4])`** Retourne une clé de Player qui, lorsque la clé de Player source change de valeur, se déplace vers la valeur la plus proche qui est +/- les valeurs en relation c'est à dire [0, 2, 4]. Lorsqu’il est utilisé avec . pitch, il se déplace vers la valeur de pitch la plus proche qui complète la troisième ou cinquième au-dessus ou en dessous de la note. ``` p1 >> pads([0, 4, 5, 3], dur=4) p2 >> pluck(p1.pitch.accompany()) ``` **Exemples utiles** Créez une séquence d’accords en fonction de la hauteur d’un Player : ``` p1 >> bass([0, 4, 5, 3], dur=4) p2 >> pluck(p1.pitch + (0, 2, 4), dur=1/2) ``` Utilisez le pitch d’un Player dans une séquence : ``` p1 >> bass([0, 4, 5, 3], dur=4) p2 >> pluck([p1.pitch, 7, 6, 7], dur=1/2) ``` Inverser l’amplitude d’un Player : ``` p1 >> play("x-o-", amp=[1,1,0,1,0,1,0], dur=1/4) p2 >> play("*", amp=p1.amp != 1, dur=1/4) ``` Harmoniser et associer deux Players à des canaux opposés : ``` p1 >> pluck([0, 2, 6, 3, 2, 4, 1, -2], dur=1/2, pan=[-1, 0.5, 0.25, -0.5, 0]) p2 >> blip(p1.pitch + 2, dur=1/2, pan=p1.pan * -1) ``` Utilisez l’indexation pour accompagner la note racine d’une séquence d’accords : ``` p1 >> pluck([0, 4, 5, 3], dur=4) + (0, 2, 4) p2 >> blip(p1.pitch[0].accompany()) ``` ### 2.6. Groups Introduction Parfois, il est utile d’appliquer des effets à plusieurs objets du Player à la fois. C’est là que l’objet du groupe entre en jeu! Créez un objet de groupe, qui peut être traité comme un simple objet Player. Les effets peuvent être appliqués comme suit : ``` # Adoucir plusieurs joueurs à la fois Group(p1, p2, p3).amp = 0.25 ``` Les groupes peuvent être affectés à une variable à utiliser à plusieurs reprises ``` my_group = Group(p1, p2, p3) my_group.amp = 1/2 my_group.hpf = 500 ``` **Methods** **`.stop()`** Arrête tous les Players du groupe. `Group(p1, p2, p3).stop()` **`.solo()`** Mute tous les autres Players, c'est à dire que seuls les joueurs du groupe peuvent être entendus. `Group(p1, p2, p3).solo() ` **`.only()`** Arrête tous les Players qui ne font pas partie du groupe `Group(p1, p2, p3).only()` **Groupes par défaut** Il existe déjà plusieurs objets de groupe dans FoxDot pour certains ensembles d’objets de Player en fonction du nom de la variable, se terminant par le suffixe « _all ». Donc, pour chaque caractère, p. ex., « a », il y a un groupe appelé a_all qui contient a1, a2, a3, …, a9. Donc, si vous organisez vos Players par nom variable, il est facile d’appliquer des effets ou de les arrêter tous en même temps : ``` d1 >> play("x-o-") d2 >> play(" * * *") ``` ``` p1 >> pads([0, 4, -2, 3], dur=4) p2 >> pluck([0, 1, 3, 4], dur=1/4) ``` ``` # Apply a filter p_all.hpf = 500 ``` ``` # Arrêter uniquement les joueurs commençant par 'd’ d_all.stop() ``` Vous pouvez accéder à un groupe de tous les Players actifs à l’aide de la fonction Master() qui renvoie un objet Groupe. ``` d1 >> play("x-o-") p1 >> pluck([0, 2, 4, 2]) ``` ``` # Applies the filter to all Players Master().hpf = 500 ``` ``` # Stop everything Master().stop() ``` ### 2.7. Fondamentales et Gammes **Modifier la fondamentale** Pour changer la fondamentale (ou tonique) de la musique dans FoxDot, il suffit de changer la valeur de la variable Root.default : «Root.default = 2» Lorsque vous démarrez FoxDot, il est automatiquement défini sur 0, ce qui est la fondamentale de C. Définir la valeur Root.default sur un nombre indique le nombre de demi-tons pour déplacer la fondamentale. Donc, pour faire de la musique avec une fondamentale de D, vous définissez la valeur sur 2. Cette valeur peut être un entier, une valeur flottante, un TimeVar ou une chaîne. Vous pouvez utiliser une chaîne pour définir explicitement la fondamentale comme suit : `Root.default = "D"` Vous pouvez spécifier les dièses et les bémols en utilisant respectivement les caractères « # » et « b » : ``` Root.default = "D#" Root.default = "Db" ``` Vous pouvez définir explicitement la racine d’un objet Player à l’aide du mot-clé root. Remarque : cela ne peut pas être une chaîne de caractères. ``` # Forcer le joueur à entrer la touche D p1 >> pluck([0, 2, 4], root=2) # Signalera une erreur p1 >> pluck([0, 2, 4], root="D") ``` **Mise à jour de la Gamme** Au démarrage de FoxDot, la gamme est automatiquement définie sur la gamme majeure. Pour afficher toutes les gammes intégrées disponibles, exécutez les opérations suivantes : `print(Scale.names())` Cela renvoie une liste qui ressemble à ceci : ``` ['aeolian', 'altered', 'bebopDom', 'bebopDorian', 'bebopMaj', 'bebopMelMin', 'blues', 'chinese', 'chromatic', 'custom', 'default', 'diminished', 'dorian', 'dorian2', 'egyptian', 'freq', 'halfDim', 'halfWhole', 'harmonicMajor', 'harmonicMinor', 'hungarianMinor', 'indian', 'justMajor', 'justMinor', 'locrian', 'locrianMajor', 'lydian', 'lydianAug', 'lydianDom', 'lydianMinor', 'major', 'majorPentatonic', 'melMin5th', 'melodicMajor', 'melodicMinor', 'minMaj', 'minor', 'minorPentatonic', 'mixolydian', 'phrygian', 'prometheus', 'romanianMinor', 'susb9', 'wholeHalf', 'wholeTone', 'yu', 'zhi'] ``` Pour afficher les demi-tons utilisés par une gamme particulière, par exemple locrian, vous pouvez exécuter print(Scale.locrian), qui renverra un objet Pattern. Comme pour la fondamentale, vous pouvez mettre à jour la gamme en modifiant la valeur Scale.default. Il peut s’agir du nom d'une gamme sous forme de chaîne, de l’objet Scale, par exemple Scale.locrian, ou d’un Pattern de valeurs de demi-tons à utiliser. ``` Scale.default = "minor" Scale.default = Scale.minor Scale.default = P[0, 2, 3, 5, 7, 8, 10] ``` **Tuning** Vous pouvez également modifier le réglage de la gamme en utilisant Scale.default.set() à la place et fournir un argument de mot-clé tuning. Les types de réglage actuellement disponibles sont les suivants : | FoxDot Syntax | Description | | -------- | -------- | | Tuning.ET12 | [12-tone equal tempered (default)](https://en.wikipedia.org/wiki/Equal_temperament) | | Tuning.just | [Just intonation](https://en.wikipedia.org/wiki/Just_intonation) | | Tuning.bohlen_pierce | [Bohlen Pierce Scale](https://en.wikipedia.org/wiki/Bohlen%E2%80%93Pierce_scale) | Comme mentionné, pour utiliser un autre type de réglage, vous devez utiliser . set() avec la gamme par défaut : Scale.default.set("major", tuning=Tuning.just) Vous pouvez créer votre propre système d’accordage en fournissant une liste de nombres qui divisent la gamme de telle sorte que le dernier nombre est égal au premier nombre une octave plus haut, par exemple, le système d’accordage de 12 tons tempérés égaux utiliserait les nombres [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]. ``` Scale.default.set( [0, 2, 3, 5, 6, 9, 10], tuning=[0, 0.9, 2.1, 2.9, 4.1, 4.9, 6.1, 6.9, 8.1, 8.9, 10.1, 10.9, 12] ) ``` ### 2.8. Valeurs constantes **Définir une valeur constante** **“const(value)”** Une constante est une valeur immuable, c’est-à-dire qu’elle ne peut pas être manipulée au moyen d’opérations mathématiques. Pour en créer un, il suffit d’utiliser le constructeur const et la valeur que vous voulez garder constante : ``` >>> value = const(10) >>> print(value + 4) 10 >>> print(value * 100) 10 >>> print(value / 99) 10 ``` Ceux-ci peuvent être vraiment utiles pour déplacer des séquences entières de valeurs sauf une ou deux : `p1 >> pluck([0, 4, const(7), const(6)], dur=1/2) + var([0, -2, -4])` Les constantes peuvent également être utilisées dans un PGroup pour créer des notes constantes dans des séquences d’accords en mouvement : `p1 >> pluck(var([0, -3, -2, -4], 4), dur=1/2) + (0, 2, const(4))`