test ajout des articles
This commit is contained in:
@@ -1,7 +1,24 @@
|
||||
/* Write your global styles here, in PostCSS syntax */
|
||||
@tailwind base;
|
||||
|
||||
|
||||
|
||||
@layer utilities {
|
||||
/* Hide scrollbar for Chrome, Safari and Opera */
|
||||
.no-scrollbar::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
/* Hide scrollbar for IE, Edge and Firefox */
|
||||
.no-scrollbar {
|
||||
-ms-overflow-style: none; /* IE and Edge */
|
||||
scrollbar-width: none; /* Firefox */
|
||||
}
|
||||
}
|
||||
|
||||
@layer base {
|
||||
.inline-picture {
|
||||
@apply w-24 inline;
|
||||
}
|
||||
a {
|
||||
@apply text-orange-300;
|
||||
}
|
||||
@@ -25,6 +42,7 @@
|
||||
}
|
||||
pre {
|
||||
@apply bg-base-300 border-white border-l-2 my-4 px-2 py-2 pl-4
|
||||
overflow-x-scroll no-scrollbar
|
||||
}
|
||||
ul {
|
||||
@apply my-2
|
||||
|
||||
@@ -13,6 +13,13 @@
|
||||
"image": "https://wiki.fuz.re/lib/exe/fetch.php?media=wiki:logo.png",
|
||||
"link": "https://wiki.fuz.re/doku.php?id=evenements:creative_coding"
|
||||
},
|
||||
{
|
||||
"name": "Creative Coding Bordeaux",
|
||||
"place": "Bordeaux",
|
||||
"description": "Creative Coding Bordeaux est un groupe destiné au partage des idées, techniques et passions autour de l'art algorithmique",
|
||||
"image": "https://secure.meetupstatic.com/photos/event/b/7/a/2/clean_515327010.webp",
|
||||
"link": "https://www.meetup.com/fr-FR/creative-coding-bordeaux/"
|
||||
},
|
||||
{
|
||||
"name": "Digital Audio Community",
|
||||
"place": "Lyon",
|
||||
|
||||
@@ -19,6 +19,22 @@ export const fetchMarkdownGuides = async () => {
|
||||
};
|
||||
})
|
||||
);
|
||||
|
||||
return allGuides;
|
||||
};
|
||||
|
||||
export const fetchMarkdownArticles = async () => {
|
||||
const alLArticleFiles = import.meta.glob('/src/routes/articles/*.md');
|
||||
const iterableArticleFiles = Object.entries(alLArticleFiles);
|
||||
// Also return the content
|
||||
const allArticles = await Promise.all(
|
||||
iterableArticleFiles.map(async ([path, resolver]) => {
|
||||
const { metadata } = await (resolver() as Promise<{ metadata: any }>);
|
||||
const articlePath = path.slice(11, -3);
|
||||
return {
|
||||
meta: metadata,
|
||||
path: articlePath,
|
||||
};
|
||||
})
|
||||
);
|
||||
return allArticles;
|
||||
};
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
<a href="/membres" class="text-gray-100 hover:text-orange-300 flex md:hidden">Membres</a>
|
||||
<a href="/outils" class="text-gray-100 hover:text-orange-300 flex md:hidden">Outils</a>
|
||||
<a href="/guides" class="text-gray-100 hover:text-orange-300 flex md:hidden">Guides</a>
|
||||
<a href="/articles" class="text-gray-100 hover:text-orange-300 flex md:hidden">Articles</a>
|
||||
<a href="/reseaux" class="text-gray-100 hover:text-orange-300 flex md:hidden">Réseaux</a>
|
||||
<a href="/ressources" class="text-gray-100 hover:text-orange-300 flex md:hidden">Ressources</a>
|
||||
<a href="/presse" class="text-gray-100 hover:text-orange-300 flex md:hidden">Presse</a>
|
||||
@@ -79,6 +80,9 @@
|
||||
<li class="text-xl ml-0">
|
||||
<a class="text-white hover:text-orange-300" href="/guides">Guides</a>
|
||||
</li>
|
||||
<li class="text-xl ml-0">
|
||||
<a class="text-white hover:text-orange-300" href="/articles">Articles</a>
|
||||
</li>
|
||||
<li class="text-xl ml-0">
|
||||
<a class="text-white hover:text-orange-300" href="/reseaux">Réseaux</a>
|
||||
</li>
|
||||
|
||||
11
src/routes/api/articles/+server.ts
Normal file
11
src/routes/api/articles/+server.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { fetchMarkdownArticles } from '$lib/utils';
|
||||
import { json } from '@sveltejs/kit';
|
||||
|
||||
export const GET = async () => {
|
||||
const allPosts = await fetchMarkdownArticles();
|
||||
|
||||
const sortedArticles = allPosts.sort((a, b) => {
|
||||
return new Date(b.meta.date).getTime() - new Date(a.meta.date).getTime();
|
||||
});
|
||||
return json(sortedArticles);
|
||||
};
|
||||
@@ -3,11 +3,8 @@ import { json } from '@sveltejs/kit';
|
||||
|
||||
export const GET = async () => {
|
||||
const allPosts = await fetchMarkdownGuides();
|
||||
|
||||
const sortedGuides = allPosts.sort((a, b) => {
|
||||
return new Date(b.meta.date).getTime() - new Date(a.meta.date).getTime();
|
||||
});
|
||||
|
||||
console.log(sortedGuides)
|
||||
return json(sortedGuides);
|
||||
};
|
||||
|
||||
23
src/routes/articles/+page.svelte
Normal file
23
src/routes/articles/+page.svelte
Normal file
@@ -0,0 +1,23 @@
|
||||
<script lang="ts">
|
||||
export let data;
|
||||
import Info from "$lib/components/Info.svelte";
|
||||
</script>
|
||||
|
||||
<h1>Articles</h1>
|
||||
|
||||
<Info info="Dada." markdown=false />
|
||||
|
||||
<h2>Articles publiés</h2>
|
||||
|
||||
<ul>
|
||||
{#each data.articles as post}
|
||||
<li class="px-4 pb-4 my-4 rounded-lg bg-base-300 dark:bg-base-300 hover:bg-base-200 hover:dark:bg-base-200 border-1 border-color-base-100">
|
||||
<h2>
|
||||
<a href={post.path}>
|
||||
{post.meta.title}
|
||||
</a>
|
||||
</h2>
|
||||
<p class="pt-2">Publié le : {post.meta.date} par {post.meta.author}</p>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
5
src/routes/articles/+page.ts
Normal file
5
src/routes/articles/+page.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export const load = async ({ fetch }) => {
|
||||
const response = await fetch(`/api/articles`);
|
||||
const articles = await response.json();
|
||||
return { articles };
|
||||
};
|
||||
14
src/routes/articles/[slug]/+page.svelte
Normal file
14
src/routes/articles/[slug]/+page.svelte
Normal file
@@ -0,0 +1,14 @@
|
||||
<script>
|
||||
export let data;
|
||||
</script>
|
||||
|
||||
<article>
|
||||
<h1>{data.title}</h1>
|
||||
<div class="pt-4 flex justify-between mb-12">
|
||||
<p class="inline font-bold">Publié le : {data.date}</p>
|
||||
<p class="inline font-bold">Auteur : {data.author}</p>
|
||||
</div>
|
||||
<div class="px-12 content-center">
|
||||
<svelte:component this={data.content} />
|
||||
</div>
|
||||
</article>
|
||||
11
src/routes/articles/[slug]/+page.ts
Normal file
11
src/routes/articles/[slug]/+page.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
export async function load({ params }) {
|
||||
const articles = await import(`../${params.slug}.md`);
|
||||
const { title, date, author } = articles.metadata;
|
||||
const content = articles.default;
|
||||
return {
|
||||
title,
|
||||
date,
|
||||
author,
|
||||
content
|
||||
};
|
||||
}
|
||||
8
src/routes/articles/articles.svelte
Normal file
8
src/routes/articles/articles.svelte
Normal file
@@ -0,0 +1,8 @@
|
||||
<script>
|
||||
export let title;
|
||||
export let date;
|
||||
</script>
|
||||
|
||||
<article>
|
||||
<slot />
|
||||
</article>
|
||||
87
src/routes/articles/ordinateur_crier.md
Normal file
87
src/routes/articles/ordinateur_crier.md
Normal file
@@ -0,0 +1,87 @@
|
||||
---
|
||||
title: Les ordinateurs peuvent-t-ils crier ?
|
||||
date: '2023-12-23'
|
||||
author: Raphaël Forment et Rémi Georges
|
||||
---
|
||||
|
||||
## À propos
|
||||
|
||||
<br>
|
||||
|
||||
Cet article était initialement publié dans la revue [Bugne Bugne](https://www.instagram.com/bugne_bugne/), une _"Revue lyonnaise dédiée aux musiques électroniques et aux enjeux politiques et sociaux de la fête, indépendante et non-lucrative ✊"_. L'objectif de cet article était de présenter le _live coding_ à un large public et de parler des concerts que nous organisons à Lyon. Je reprends ici l'intégralité du texte et je rajoute des liens supplémentaires pour enrichir la chose :)
|
||||
|
||||
<br>
|
||||
|
||||
J'ai pris la liberté de rajouter tout un tas de liens divers qui apportent
|
||||
souvent un contrepoint décalé au texte.
|
||||
|
||||
## Introduction
|
||||
|
||||
|
||||
Quelques personnes en Europe et dans le monde pratiquent le _live coding_. Nous sommes [quelques centaines ou quelques milliers](https://solstice.toplap.org). _Live coder_, cela consiste à improviser de la musique directement au travers de langages de programmation, sur scène, devant tout le monde, avec [les _bugs_, les _crashs_, etc](https://academic.oup.com/edited-volume/28278/chapter-abstract/214421107?redirectedFrom=fulltext). que cela implique. Tout au long de la performance, les _live coders_ éditent du code et le soumettent à l'ordinateur. Ils découvrent le résultat en même temps que le public et sont pareillement surpris ou inquiets de ce qu'ils entendent.
|
||||
|
||||
<br>
|
||||
|
||||
_Live coder_, cela veut tout et rien dire et personne ne semble souhaiter définir le terme précisément. On peut [programmer et modifier des synthétiseurs en temps réel](https://www.youtube.com/watch?v=KwvqoH4LPKM), créer des séquences musicales, [des visuels](https://www.youtube.com/watch?v=cw7tPDrFIQg), etc. On peut allumer des ampoules en rythme ou [broder un pull](https://slab.org/2021/03/28/research-products/) sur scène, la seule limite restant le _crash_ et la capacité technique de faire ce que l'on veut. Le _live coding_ peut mobiliser toutes les ressources de l'ordinateur, pour le meilleur comme pour le pire. Certains aiment programmer de la musique, d'autres aiment programmer des visuels. Faites cela de manière conjointe, et vous obtenez une **Algorave**, une [algorithmic rave party](https://algorave.org). L'idée derrière ce terme était, [à l'origine](https://www.nime.org/proceedings/2014/nime2014_426.pdf), de faire de la musique de club au travers du code, de faire danser les gens sur des algorithmes. Ca ne ressemble pas du tout à de la musique de club, mais cela reste dansant quand même. C'est une musique à part, avec ses propres sonorités et ses gestes musicaux particuliers.
|
||||
|
||||
|
||||
<br>
|
||||
|
||||
_Live coder_, cela ne signifie pas nécessairement programmer quelque chose pour arriver à une fin. Il n'y a pas de patron pour surveiller que vous terminiez votre programme dans les temps. _Live coder_, c'est surtout programmer sans but, errer dans un système musical et chercher ce qui sonne bien, ce qui sonne mal, et aussi pas mal chercher ce que l'on veut réellement faire. C'est un peu du jazz d'ordinateur. C'est une conversation à la fois avec votre ordinateur et avec votre propre capacité ou incapacité à vous exprimer musicalement au travers du code.
|
||||
|
||||
|
||||
## Renouer avec l’ordinateur
|
||||
|
||||
Il y a [longtemps que les gens font ça](https://github.com/philburk/hmsl), mais originellement, tout le monde s'en fichait. Il y a quelques décennies, il était normal d'utiliser des langages de programmation pour créer de la musique. C'était souvent la seule interface dont on disposait pour dialoguer avec la machine, pour composer, pour contrôler des synthétiseurs, des échantillonneurs, des machines, etc. L'apparition des [interfaces graphiques](https://www.youtube.com/watch?v=yJDv-zdhzMY) a aussi introduit le fait de cliquer partout, puis les fenêtres, puis tout un tas d'idées et de concepts dont on n'avait pas vraiment besoin pour faire de la musique. En bref, les interfaces graphiques ont rompu quelque chose d'important dans la manière dont on approche l'interaction avec l'ordinateur.
|
||||
|
||||
<br>
|
||||
|
||||
Les ordinateurs sont faits pour manger du texte, des nombres, des instructions. Ils sont ridiculement petits, puissants et versatiles. Ce sont des calculatrices qui [calculent vite](https://www.youtube.com/watch?v=MbIiAr5dt24). Ils sont partout et sont d'ailleurs [faits pour être emportés partout](https://web.archive.org/web/20120216040047/http://pbup.goto10.org/). On passe déjà notre vie avec. Le seul problème est que l'on ne les utilise pas comme des ordinateurs. On ne les utilise pas non plus, d'ailleurs, comme des instruments de musique et les musiciens passent généralement beaucoup de temps et [consacrent beaucoup d'énergie](https://www.nime.org/) à éviter de se confronter à [la vrai nature](https://www.youtube.com/watch?v=tDacjrSCeq4) de l'ordinateur.
|
||||
|
||||
<br>
|
||||
|
||||
Parlons un petit peu des métaphores. Ouvrez n'importe quel logiciel de production musicale (Ableton, Fruity Loops, Pro Tools). Regardez un peu ce que l'on vous montre à l'écran. Les logiciels pour créer de la musique sont remplis de métaphores étranges que personne n'a jamais réellement souhaité. On édite des mélodies MIDI sur des [piano rolls](https://www.youtube.com/watch?v=EO2CO0X-bAQ) comme si l'on manipulait un [piano mécanique avec des rouleaux](https://www.youtube.com/watch?v=9CnkYvikIFg). On montre un studio d'enregistrement avec des [tranches de console et des potentiomètres](https://www.reaper.fm/) alors qu'on a juste un clavier et une souris. Les synthétiseurs virtuels ont [des boutons et des potentiomètres qu'on ne peut pas pousser](https://www.arturia.com/products/analog-classics/cmi-v/sounddesign). Vous ne pouvez cliquer que sur un bouton à la fois, et les contrôleurs sont pénibles à utiliser. Les synthétiseurs virtuels ont des lumières tristes qui ne brillent même pas et ils peuvent planter tout comme Word ou Excel. Il y a quelque chose qui coince. Il fallait initialement vendre ces logiciels aux musiciens et on leur a vendu ce qu'ils connaissent le mieux. C'est tout pareil que votre bureau avec ses dossiers, ses fichiers, etc. Votre bureau n'existe pas, et les dossiers ne sont pas des dossiers en carton jaune moche que vous rangez dans une armoire.
|
||||
[Les platines sont devenues des instruments](https://www.youtube.com/watch?v=wl1ZrEza7uY) lorsque les musiciens ont commencé à s'intéresser à leurs qualités musicales. De même, l'ordinateur peut devenir un instrument de musique si l'on s'intéresse [à ses qualités intrinsèques](https://www.youtube.com/watch?v=kPRA0W1kECg) : l'idée n'est pas d'éviter ce qu'il est vraiment, mais de [chercher ses qualités](https://thirtydollar.website/) dans le domaine musical.
|
||||
|
||||
<br>
|
||||
|
||||
<blockquote class="pl-8 text-2xl">
|
||||
<em>I'm the operator with my pocket calculator I am adding, and subtracting... I'm controlling, and composing! By pressing down a special key, It plays a little melody.</em>
|
||||
</blockquote>
|
||||
|
||||
<br>
|
||||
|
||||
Pourtant, il est toujours possible de programmer sa musique. On peut même faire la même chose qu'avant, mais en [beaucoup mieux](https://www.youtube.com/watch?v=WtwneW2s2bo), on peut faire la même chose que nos ancêtres, mais en temps réel. On peut tout programmer si on essaie vraiment. C'est super amusant mais c'est aussi devenu bizarre. Plus personne ne fait ça, à tel point que programmer son ordinateur en direct est devenu un parti pris. Programmer est devenu un geste expressif, tout comme peut l'être le fait de danser, de crier ou de faire un solo de guitare. C'est aussi parfois devenu un geste politique ou un acte militant. Depuis le début des années 2000, les live coders ont plus ou moins tous décidé de montrer ce qu'ils font à leur public (collectif TOPLAP, etc.) car ils estiment que c'est important. Ils font leurs concerts dans le noir et projettent leurs écrans pour que le public puisse lire le code et voir le curseur d'édition bouger :
|
||||
|
||||
<br>
|
||||
|
||||
<blockquote class="pl-8 text-2xl">
|
||||
<em>Give us access to the performer's mind, to the whole human instrument. Obscurantism is dangerous. Show us your screens.</em>
|
||||
</blockquote>
|
||||
|
||||
<br>
|
||||
|
||||
## Pourquoi live coder ?
|
||||
|
||||
**Rémi :** “Je cherchais au départ des manières de composer des rythmes complexes. J'ai sombré. J'ai découvert une nouvelle façon de faire et de contrôler la musique et c'était sans doute la manière de faire que j'avais toujours cherchée sans la trouver. Je suis plus proche des sphères de la musique DIY, et le _live coding_ c'est un peu le DIY du numérique. En plus de bidouller l'électronique de mes synthés et j'ai commencé à pouvoir tout fabriquer, tout programmer. J'ai pu d'une certaine manière "augmenter" ou contrôler différemment tout mon matériel et j'y garde toujours ce plaisir du crash et de l'erreur. J'aime le fait que mon programme soit bancal, et qu'il puisse s'arrêter ou se comporter différemment du but premier. Je vais tout faire pour que tout se passe bien mais je ne peux jamais en être certain. J'ai jamais réussi à faire de la musique avec des logiciels faits pour cela, ça a toujours été sans saveur, incompréhensible, super compliqué à démarrer.
|
||||
|
||||
<br>
|
||||
|
||||
Maintenant je crois pas que se soit foncièrement plus simple à démarrer mais au moins je ne peux m'en prendre qu'à moi-même. Je viens du milieu de la technique du son, le _live coding_ m'a aussi appris la programmation, il m'a ouvert la porte de la programmation appliquée à l'audio, et c'est maintenant ce dans quoi j'essaie de travailler.”
|
||||
|
||||
<br>
|
||||
|
||||
**Raphaël :** “J'ai appris à programmer en m'intéressant au _live coding_. J'étais déjà assez pote avec les ordinateurs car mes amis et moi nous amusions à _modder_ des jeux ou à créer des choses intéressantes à l'ordinateur. Je cherchais initialement une manière d'écrire de la musique qui ne soit ni partition graphique, ni partition classique. Je tape super vite sur un clavier et j'aime beaucoup manipuler du texte. Il semblait assez clair que cette pratique était faite pour moi. J'ai appris à faire de la musique avec du code avant de savoir réellement programmer. J'ai commencé ensuite à modifier les outils pour les adapter à ma pratique puis à concevoir les miens. C'est aussi fascinant que nul. On apprend beaucoup, on crée son propre instrument, mais on arrive souvent à un résultat que l'on n'avait pas anticipé ! Je m'intéressais déjà beaucoup à toutes les musiques basées sur des systèmes de règles ou sur des processus génératifs. J'aime beaucoup John Cage, non pas pour sa musique, mais pour [les idées qu'il a pu transmettre](https://editions-contrechamps.org/livres/silence/) à tous les musiciens qui l'ont écouté. Aujourd'hui, je _live code_ car j'étudie ces musiques là dans un [cadre universitaire](https://raphaelforment.fr) mais j'y trouve également du plaisir. Cela ne se ressemble jamais, cela donne perpétuellement l'envie de recommencer. C'est le propre d'un instrument de musique, et je suis content d'avoir fait de mon ordinateur un instrument de musique.”
|
||||
|
||||
## Le live-coding en France
|
||||
|
||||
Le 8 avril 2023, nous avons organisé [une gigantesque algorave au Grrrnd Zero](https://www.grrrndzero.org/index.php/2422-sam-08-04-algorave) à Lyon. 19 projets différents venant de toute la France et parfois même de l'étranger (Italie, Pays-Bas, Etats-Unis) ont joué de la musique ou fait des visuels de 18h à 8h du matin. C'est sans doute la plus grosse algorave de la très longue histoire de France. Même si les gens se reconnaissent comme _live coders_, il n'est pas dit qu'ils se comprennent. On sait qu'on fait la même chose, mais pas nécessairement la même musique. On ne programme pas tous de la même manière, pas avec les mêmes outils ou le même langage, pas pour le même but, etc mais c'est déjà pas mal de savoir qu'on n'est pas tous seuls à avoir une lubie. Organiser des événements de _live coding_ permet de faire vivre cette pratique et de se rendre compte sa diversité. C'est une sorte de grande foire. En France, cela est d'autant plus sensible que la plupart des live coders ont un lien avec la [demoscene](https://cookie.paris) ou avec des cultures informatiques _underground_ qui n'ont jamais vraiment disparues.
|
||||
|
||||
<br>
|
||||
|
||||
Aujourd’hui on s'est un peu lancés comme mission de rassembler toute la communauté française ou du moins de se faire savoir qu'on existe entre nous. On essaie d'organiser des _workshops_, car le _live coding_ est une pratique toujours plus simple à démarrer avec quelqu'un plutôt qu'en écumant des forums.
|
||||
Nous sommes aussi allés représenter cette communauté francophone du live-coding à l'[International Conférence on Live-Coding](https://iclc.toplap.org) à Utrecht en avril 2023. Ça nous a permis de comparer cette scène à l'échelle mondiale et de pouvoir rencontrer en personne tous ces développeurs-artistes d'un petit milieu où tout le monde se connaît un peu.
|
||||
|
||||
<br>
|
||||
|
||||
Si on cherche bien, il y a des _live coders_ partout. Il suffit de les débusquer, souvent dans les écoles d'art, dans les écoles d'ingé ou vraiment un peu partout là où on ne pense jamais à regarder. Bizarrement, on trouve assez peu de _live coding_ dans les conservatoires ou dans les écoles de musique. Tous les _live coders_ ne savent pas nécessairement qu'ils live codent. Parfois, ce n'est juste pas important pour eux, ou cela leur paraît naturel. Les _live coders_ naviguent entre milieux DIY, [réseaux hackers / makers](https://web.archive.org/web/20201202043301id_/https://journals.openedition.org/volume/7211), milieu des arts numériques, etc. Considérer que le _live coding_ est une forme d'art en soi est un réflexe assez anglais, lié à la manière dont la pratique a été popularisée dans les années 2000. En France, le _live coding_ est souvent considéré comme un outil. Ailleurs c'est considéré comme une fin en soi, ce qui n'est pas plus mal !
|
||||
@@ -1,14 +1,15 @@
|
||||
<script>
|
||||
export let data;
|
||||
export let data;
|
||||
</script>
|
||||
|
||||
<article>
|
||||
<h1>{data.title}</h1>
|
||||
<div class="pt-4 flex justify-between mb-12">
|
||||
<p class="inline font-bold">Publié le : {data.date}</p>
|
||||
<p class="inline font-bold">Auteur : {data.author}</p>
|
||||
</div>
|
||||
<div class="px-12 content-center">
|
||||
<svelte:component this={data.content} />
|
||||
</div>
|
||||
</article>
|
||||
<h1>{data.title}</h1>
|
||||
<div class="pt-4 flex justify-between mb-12">
|
||||
<p class="inline font-bold">Publié le : {data.date}</p>
|
||||
<p class="inline font-bold">Auteur : {data.author}</p>
|
||||
</div>
|
||||
<div class="lg:px-24 md:px-12 content-center">
|
||||
<svelte:component this={data.content} />
|
||||
</div>
|
||||
</article>
|
||||
|
||||
|
||||
317
src/routes/guides/cold_dark.css
Normal file
317
src/routes/guides/cold_dark.css
Normal file
@@ -0,0 +1,317 @@
|
||||
/**
|
||||
* Coldark Theme for Prism.js
|
||||
* Theme variation: Dark
|
||||
* Tested with HTML, CSS, JS, JSON, PHP, YAML, Bash script
|
||||
* @author Armand Philippot <contact@armandphilippot.com>
|
||||
* @homepage https://github.com/ArmandPhilippot/coldark-prism
|
||||
* @license MIT
|
||||
*/
|
||||
code[class*="language-"],
|
||||
pre[class*="language-"] {
|
||||
color: #e3eaf2;
|
||||
background: none;
|
||||
font-family: Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace;
|
||||
text-align: left;
|
||||
white-space: pre;
|
||||
word-spacing: normal;
|
||||
word-break: normal;
|
||||
word-wrap: normal;
|
||||
line-height: 1.5;
|
||||
-moz-tab-size: 4;
|
||||
-o-tab-size: 4;
|
||||
tab-size: 4;
|
||||
-webkit-hyphens: none;
|
||||
-moz-hyphens: none;
|
||||
-ms-hyphens: none;
|
||||
hyphens: none;
|
||||
}
|
||||
|
||||
pre[class*="language-"]::-moz-selection,
|
||||
pre[class*="language-"] ::-moz-selection,
|
||||
code[class*="language-"]::-moz-selection,
|
||||
code[class*="language-"] ::-moz-selection {
|
||||
background: #3c526d;
|
||||
}
|
||||
|
||||
pre[class*="language-"]::selection,
|
||||
pre[class*="language-"] ::selection,
|
||||
code[class*="language-"]::selection,
|
||||
code[class*="language-"] ::selection {
|
||||
background: #3c526d;
|
||||
}
|
||||
|
||||
/* Code blocks */
|
||||
pre[class*="language-"] {
|
||||
padding: 1em;
|
||||
margin: 0.5em 0;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
:not(pre) > code[class*="language-"],
|
||||
pre[class*="language-"] {
|
||||
background: #111b27;
|
||||
}
|
||||
|
||||
/* Inline code */
|
||||
:not(pre) > code[class*="language-"] {
|
||||
padding: 0.1em 0.3em;
|
||||
border-radius: 0.3em;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.token.comment,
|
||||
.token.prolog,
|
||||
.token.doctype,
|
||||
.token.cdata {
|
||||
color: #8da1b9;
|
||||
}
|
||||
|
||||
.token.punctuation {
|
||||
color: #e3eaf2;
|
||||
}
|
||||
|
||||
.token.delimiter.important,
|
||||
.token.selector .parent,
|
||||
.token.tag,
|
||||
.token.tag .token.punctuation {
|
||||
color: #66cccc;
|
||||
}
|
||||
|
||||
.token.attr-name,
|
||||
.token.boolean,
|
||||
.token.boolean.important,
|
||||
.token.number,
|
||||
.token.constant,
|
||||
.token.selector .token.attribute {
|
||||
color: #e6d37a;
|
||||
}
|
||||
|
||||
.token.class-name,
|
||||
.token.key,
|
||||
.token.parameter,
|
||||
.token.property,
|
||||
.token.property-access,
|
||||
.token.variable {
|
||||
color: #6cb8e6;
|
||||
}
|
||||
|
||||
.token.attr-value,
|
||||
.token.inserted,
|
||||
.token.color,
|
||||
.token.selector .token.value,
|
||||
.token.string,
|
||||
.token.string .token.url-link {
|
||||
color: #91d076;
|
||||
}
|
||||
|
||||
.token.builtin,
|
||||
.token.keyword-array,
|
||||
.token.package,
|
||||
.token.regex {
|
||||
color: #f4adf4;
|
||||
}
|
||||
|
||||
.token.function,
|
||||
.token.selector .token.class,
|
||||
.token.selector .token.id {
|
||||
color: #c699e3;
|
||||
}
|
||||
|
||||
.token.atrule .token.rule,
|
||||
.token.combinator,
|
||||
.token.keyword,
|
||||
.token.operator,
|
||||
.token.pseudo-class,
|
||||
.token.pseudo-element,
|
||||
.token.selector,
|
||||
.token.unit {
|
||||
color: #e9ae7e;
|
||||
}
|
||||
|
||||
.token.deleted,
|
||||
.token.important {
|
||||
color: #cd6660;
|
||||
}
|
||||
|
||||
.token.keyword-this,
|
||||
.token.this {
|
||||
color: #6cb8e6;
|
||||
}
|
||||
|
||||
.token.important,
|
||||
.token.keyword-this,
|
||||
.token.this,
|
||||
.token.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.token.delimiter.important {
|
||||
font-weight: inherit;
|
||||
}
|
||||
|
||||
.token.italic {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.token.entity {
|
||||
cursor: help;
|
||||
}
|
||||
|
||||
.language-markdown .token.title,
|
||||
.language-markdown .token.title .token.punctuation {
|
||||
color: #6cb8e6;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.language-markdown .token.blockquote.punctuation {
|
||||
color: #f4adf4;
|
||||
}
|
||||
|
||||
.language-markdown .token.code {
|
||||
color: #66cccc;
|
||||
}
|
||||
|
||||
.language-markdown .token.hr.punctuation {
|
||||
color: #6cb8e6;
|
||||
}
|
||||
|
||||
.language-markdown .token.url .token.content {
|
||||
color: #91d076;
|
||||
}
|
||||
|
||||
.language-markdown .token.url-link {
|
||||
color: #e6d37a;
|
||||
}
|
||||
|
||||
.language-markdown .token.list.punctuation {
|
||||
color: #f4adf4;
|
||||
}
|
||||
|
||||
.language-markdown .token.table-header {
|
||||
color: #e3eaf2;
|
||||
}
|
||||
|
||||
.language-json .token.operator {
|
||||
color: #e3eaf2;
|
||||
}
|
||||
|
||||
.language-scss .token.variable {
|
||||
color: #66cccc;
|
||||
}
|
||||
|
||||
/* overrides color-values for the Show Invisibles plugin
|
||||
* https://prismjs.com/plugins/show-invisibles/
|
||||
*/
|
||||
.token.token.tab:not(:empty):before,
|
||||
.token.token.cr:before,
|
||||
.token.token.lf:before,
|
||||
.token.token.space:before {
|
||||
color: #8da1b9;
|
||||
}
|
||||
|
||||
/* overrides color-values for the Toolbar plugin
|
||||
* https://prismjs.com/plugins/toolbar/
|
||||
*/
|
||||
div.code-toolbar > .toolbar.toolbar > .toolbar-item > a,
|
||||
div.code-toolbar > .toolbar.toolbar > .toolbar-item > button {
|
||||
color: #111b27;
|
||||
background: #6cb8e6;
|
||||
}
|
||||
|
||||
div.code-toolbar > .toolbar.toolbar > .toolbar-item > a:hover,
|
||||
div.code-toolbar > .toolbar.toolbar > .toolbar-item > a:focus,
|
||||
div.code-toolbar > .toolbar.toolbar > .toolbar-item > button:hover,
|
||||
div.code-toolbar > .toolbar.toolbar > .toolbar-item > button:focus {
|
||||
color: #111b27;
|
||||
background: #6cb8e6da;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
div.code-toolbar > .toolbar.toolbar > .toolbar-item > span,
|
||||
div.code-toolbar > .toolbar.toolbar > .toolbar-item > span:hover,
|
||||
div.code-toolbar > .toolbar.toolbar > .toolbar-item > span:focus {
|
||||
color: #111b27;
|
||||
background: #8da1b9;
|
||||
}
|
||||
|
||||
/* overrides color-values for the Line Highlight plugin
|
||||
* http://prismjs.com/plugins/line-highlight/
|
||||
*/
|
||||
.line-highlight.line-highlight {
|
||||
background: #3c526d5f;
|
||||
background: linear-gradient(to right, #3c526d5f 70%, #3c526d55);
|
||||
}
|
||||
|
||||
.line-highlight.line-highlight:before,
|
||||
.line-highlight.line-highlight[data-end]:after {
|
||||
background-color: #8da1b9;
|
||||
color: #111b27;
|
||||
box-shadow: 0 1px #3c526d;
|
||||
}
|
||||
|
||||
pre[id].linkable-line-numbers.linkable-line-numbers span.line-numbers-rows > span:hover:before {
|
||||
background-color: #8da1b918;
|
||||
}
|
||||
|
||||
/* overrides color-values for the Line Numbers plugin
|
||||
* http://prismjs.com/plugins/line-numbers/
|
||||
*/
|
||||
.line-numbers.line-numbers .line-numbers-rows {
|
||||
border-right: 1px solid #0b121b;
|
||||
background: #0b121b7a;
|
||||
}
|
||||
|
||||
.line-numbers .line-numbers-rows > span:before {
|
||||
color: #8da1b9da;
|
||||
}
|
||||
|
||||
/* overrides color-values for the Match Braces plugin
|
||||
* https://prismjs.com/plugins/match-braces/
|
||||
*/
|
||||
.rainbow-braces .token.token.punctuation.brace-level-1,
|
||||
.rainbow-braces .token.token.punctuation.brace-level-5,
|
||||
.rainbow-braces .token.token.punctuation.brace-level-9 {
|
||||
color: #e6d37a;
|
||||
}
|
||||
|
||||
.rainbow-braces .token.token.punctuation.brace-level-2,
|
||||
.rainbow-braces .token.token.punctuation.brace-level-6,
|
||||
.rainbow-braces .token.token.punctuation.brace-level-10 {
|
||||
color: #f4adf4;
|
||||
}
|
||||
|
||||
.rainbow-braces .token.token.punctuation.brace-level-3,
|
||||
.rainbow-braces .token.token.punctuation.brace-level-7,
|
||||
.rainbow-braces .token.token.punctuation.brace-level-11 {
|
||||
color: #6cb8e6;
|
||||
}
|
||||
|
||||
.rainbow-braces .token.token.punctuation.brace-level-4,
|
||||
.rainbow-braces .token.token.punctuation.brace-level-8,
|
||||
.rainbow-braces .token.token.punctuation.brace-level-12 {
|
||||
color: #c699e3;
|
||||
}
|
||||
|
||||
/* overrides color-values for the Diff Highlight plugin
|
||||
* https://prismjs.com/plugins/diff-highlight/
|
||||
*/
|
||||
pre.diff-highlight > code .token.token.deleted:not(.prefix),
|
||||
pre > code.diff-highlight .token.token.deleted:not(.prefix) {
|
||||
background-color: #cd66601f;
|
||||
}
|
||||
|
||||
pre.diff-highlight > code .token.token.inserted:not(.prefix),
|
||||
pre > code.diff-highlight .token.token.inserted:not(.prefix) {
|
||||
background-color: #91d0761f;
|
||||
}
|
||||
|
||||
/* overrides color-values for the Command Line plugin
|
||||
* https://prismjs.com/plugins/command-line/
|
||||
*/
|
||||
.command-line .command-line-prompt {
|
||||
border-right: 1px solid #0b121b;
|
||||
}
|
||||
|
||||
.command-line .command-line-prompt > span:before {
|
||||
color: #8da1b9da;
|
||||
}
|
||||
334
src/routes/guides/livecoding_supercollider.md
Normal file
334
src/routes/guides/livecoding_supercollider.md
Normal file
@@ -0,0 +1,334 @@
|
||||
---
|
||||
title: 'Introduction au live coding sur SuperCollider (I)'
|
||||
author: 'Raphaël Maurice Forment'
|
||||
date: '2023-12-24'
|
||||
---
|
||||
|
||||
<script>
|
||||
import Prism from 'prismjs';
|
||||
import Info from '$lib/components/Info.svelte';
|
||||
let language = 'cpp';
|
||||
</script>
|
||||
|
||||
|
||||
## Introduction
|
||||
|
||||
Après avoir travaillé longtemps sur [Sardine](https://sardine.raphaelforment.fr) et [Topos](https://topos.live), je me suis posé la question de savoir si j'étais encore capable de _live coder_ sur **SuperCollider**. J'ai donc décidé de ramasser tout ce que je sais pour constituer un environnement de _live coding_ minimal et efficace. Ce document est le résultat de cette expérience. Il existe aussi un petit [Quark](https://github.com/Bubobubobubobubo/BuboQuark) qui va un peu plus loin que ce guide, mais que je ne documente pas encore. J'avais une certaine jalousie latente vis à vis des artistes qui utilisent **SuperCollider** sans recourir à aucune extension ou surcouche logicielle qui facilite la tâche. Le langage et l'environnement de **SuperCollider** est _monstrueux_ (de complexité, de détails, etc). Il offre toutefois un avantage intéressant : **SuperCollider** est très versatile. Au sein d'un seul langage / interface, il est possible de passer d'une section du code lié aux patterns musicaux à une autre partie du code directement liée à la synthèse et à l'écriture de traitements sonores. On peut aussi s'en servir pour écrire des utilitaires divers et des interfaces graphiques si besoin. **SuperCollider** est aussi un environnement relativement minimal et économe pour la production et le travail du son, développé depuis plus de vingt ans. Cela garantit de pouvoir le faire tourner sur toutes les machines sans aucun problème.
|
||||
|
||||
<br>
|
||||
|
||||
**SuperCollider** a joué un rôle crucial dans le développement du _live coding_ au cours de ces 20 dernières années (dès la parution de **SuperCollider 2**). Il est toujours utilisé par l'immense majorité des artistes et _performers_ sous une forme directe ou indirecte (au travers de [Tidal](https://tidalcycles.org), [FoxDot](https://foxdot681713046.wordpress.com/) ou [Sonic Pi](https://sonic-pi.net)). Bien que ces derniers soient aujourd'hui populaires, il est également intéressant de voir que l'on peut réaliser peu ou prou la même chose tout en éliminant toute une catégorie de problèmes liés à l'installation, au déploiement ou à la personnalisation de ces interfaces.
|
||||
|
||||
<br>
|
||||
|
||||
<Info info="Ce guide est une approche personnelle de <b>SuperCollider</b>. Je ne
|
||||
suis pas particulièrement expert sur le sujet et j'accueille volontiers toutes
|
||||
les suggestions pour améliorer cette série d'articles." markdown=false />
|
||||
|
||||
<br>
|
||||
|
||||

|
||||
|
||||
<br>
|
||||
|
||||
## Mise en place
|
||||
|
||||
La mise en place est relativement simple. Nous aurons uniquement besoin de l'environnement de base et de la librairie _JITLib_, livrée par défaut avec **SuperCollider**. Nous augmenterons progressivement **SuperCollider** avec des _plugins_ ([Quarks](https://doc.sccode.org/Guides/UsingQuarks.html)) mais cela ne requiert pas d'installation directe et peut même se révéler facultatif.
|
||||
|
||||
<br>
|
||||
|
||||
1) **Téléchargez** et installez [SuperCollider](https://supercollider.github.io) depuis le site officiel.
|
||||
|
||||
2) **Optionnel :** téléchargez [sc3-plugins](https://github.com/supercollider/sc3-plugins), une collection officielle d'objets supplémentaires.
|
||||
|
||||
<br>
|
||||
|
||||
Il est important de bien comprendre comment est structuré **SuperCollider**. Il s'agit d'un environnement composé de plusieurs briques logicielles interconnectées (ou non) :
|
||||
|
||||
- **SCLang** : un langage de programmation inspiré de la famille **C** ou
|
||||
**SmallTalk**
|
||||
- **SCSynth** / **SCServer** : un serveur chargé de l'exécution audio
|
||||
- **SCIDE** : l'éditeur par défaut, qui lie ces deux premiers composants
|
||||
|
||||
**SCIDE** est utile, mais si vous préférez utiliser un autre éditeur, il est
|
||||
possible de lier [VSCode](https://code.visualstudio.com/), [Emacs](https://github.com/supercollider/scel) ou [Neovim](https://github.com/davidgranstrom/scnvim). **SCLang** et **SCSynth** sont les deux composants les plus importants, l'un servant au contrôle de l'autre. L'architecture de **SuperCollider** est toujours axée sur la différence entre un _client_ (le langage) et le _serveur_ (qui exécute l'audio).
|
||||
|
||||
<br>
|
||||
|
||||
## Commandes de base
|
||||
|
||||
Lorsque vous ouvrez **SCIDE**, vous vous trouvez face à un document texte vierge. C'est dans cette zone que vous devez programmer et écrire votre code. **SuperCollider** est un langage interprété. Cela signifie que vous allez graduellement soumettre du code à évaluation et recevoir le résultat des commandes éxecutées. Cela peut parfois poser problème aux débutants qui ne sont pas habitués à cette manière de concevoir la programmation :
|
||||
|
||||
- l'évaluation d'un fichier ne s'effectue pas toujours de manière linéaire. On
|
||||
peut évaluer du code bloc par bloc ou modifier un bloc à la volée.
|
||||
**SuperCollider** identifie un bloc à l'aide des parenthèses `()`.
|
||||
- il est possible d'évaluer un fichier de manière linéaire si besoin. Il existe
|
||||
des commandes spécifiques pour ce faire (_par ex._ `"blabla/mon_fichier.scd".loadRelative`).
|
||||
- la librairie standard (classes, extensions) est lue / interprétée de manière
|
||||
linéaire au démarrage de l'interpréteur. Vous ne pourrez pas démarrer
|
||||
l'interpréteur si une erreur est identifiée dans cette partie du code : `Library has not been compiled successfully`.
|
||||
|
||||
<br>
|
||||
|
||||
Selon votre éditeur, les commandes pour évaluer du code ligne par ligne ou bloc par bloc peuvent varier (`Shift + Enter`, `Control + Enter`, etc). Vous pourrez trouvez les commandes dans le menu `Language` de **SCIDE**. Pour vérifier que tout fonctionne, évaluez la ligne suivante (_note :_ les commentaires sont précédés des caractères `//` et ne sont pas évalués) :
|
||||
|
||||
```js
|
||||
s.boot // Démarrage du serveur
|
||||
```
|
||||
|
||||
Attendez quelques secondes pour vérifier que tout se passe correctement puis
|
||||
tuez le serveur :
|
||||
|
||||
```js
|
||||
Server.killAll // Tuer le serveur
|
||||
```
|
||||
|
||||
**SuperCollider** permet de prendre l'habitude de ne pas considérer le code
|
||||
comme un texte linéaire mais comme une interface, ce qui est une caractéristique
|
||||
commune des outils de _live coding_. C'est aussi une constante des
|
||||
environnements pour la programmation musicale (_Max/MSP_, _Pure Data_) qui
|
||||
éliminent / gomment la distinction entre travail sur le programme et exécution
|
||||
du programme.
|
||||
|
||||
<br>
|
||||
|
||||
Ce guide ne vous apprendra pas les rudiments du langage. Il existe de très
|
||||
nombreux guides qui font cela très bien. Notez la parution récente d'un nouvel
|
||||
ouvrage : [SuperCollider for the Creative Musician](https://global.oup.com/academic/product/supercollider-for-the-creative-musician-9780197616994) par Eli Fieldsteel, également auteur d'une [série de vidéos](https://www.youtube.com/@elifieldsteel) que je recommande.
|
||||
|
||||
<br>
|
||||
|
||||
## Prérequis
|
||||
|
||||
<br>
|
||||
|
||||
Dès maintenant, je pars du principe que vous êtes à l'aise avec l'environnement **SuperCollider** et que vous avez au moins quelques rudiments de son utilisation. Il n'est pas nécessaire d'en connaître beaucoup mais au moins de savoir évaluer du code, naviguer dans les fichiers d'aide et de maîtriser quelques raccourcis clavier. Le reste viendra naturellement en pratiquant. Voici quelques suggestions pour découvrir **SuperCollider** et son utilisation :
|
||||
|
||||
- se familiariser avec chaque élément de l'interface (`s.scope`,
|
||||
`s.freqscope`, `s.gui`)
|
||||
- se familiariser avec la documentation intégrée, lire les guides disponibles
|
||||
- apprendre comment contrôler le serveur (`s`, `Server.default`) et l'interpréteur
|
||||
- démarrer et arrêter le serveur
|
||||
- recompiler la librairie / redémarrer l'interpréteur
|
||||
- apprendre la syntaxe de base d'une `SynthDef` (définition de synthèse)
|
||||
- apprendre à jouer avec la librairie des patterns (`Pbind`, `Pseq`, etc)
|
||||
|
||||
## Paramétrage du serveur
|
||||
|
||||
<br>
|
||||
|
||||
Nous allons maintenant commencer à travailler sur un fichier de lancement
|
||||
réutilisable pour **SuperCollider**. Créez un fichier nommé `startup.scd` ou
|
||||
tout autre nom qui vous permettra de l'identifier facilement.
|
||||
|
||||
<br>
|
||||
|
||||
### Choisir une interface audio
|
||||
|
||||
<br>
|
||||
|
||||
Pour connaître le nom des périphériques audio disponibles :
|
||||
|
||||
```supercollider
|
||||
ServerOptions.devices; // Tout ce qui est disponible
|
||||
ServerOptions.inDevices; // Les entrées uniquement
|
||||
ServerOptions.outDevices; // Les sorties uniquement
|
||||
```
|
||||
|
||||
Il est possible de spécifier une entrée et une sortie différente :
|
||||
|
||||
```supercollider
|
||||
Server.default.options.inDevice_("Built-in Microph");
|
||||
Server.default.options.outDevice_("Built-in Output");
|
||||
```
|
||||
|
||||
On peut aussi utiliser le même _device_ pour l'entrée et la sortie :
|
||||
|
||||
```supercollider
|
||||
s.options.device = "BlackHole 16ch"; // Choix de l'interface
|
||||
Server.default.options.device_("BlackHole 16ch"); // Alternative
|
||||
```
|
||||
|
||||
<br>
|
||||
|
||||
Pour appliquer les modifications, il sera nécessaire de redémarrer le serveur.
|
||||
Veillez à ce que votre entrée et votre sortie audio soient à la même fréquence
|
||||
d'échantillonnage (_sampling rate_). Si ce n'est pas le cas, le serveur refusera
|
||||
de démarrer, ce qui est une erreur très courante. Paramétrez votre fréquence
|
||||
sur `44100hz` ou `48000hz`.
|
||||
|
||||
<br>
|
||||
|
||||
**Note :** si vous avez pour habitude d'utiliser des écouteurs ou haut-parleurs
|
||||
_Bluetooth_, les OS modernes ont tendance à changer automatiquement la
|
||||
fréquence d'échantillonnage à la connexion/déconnexion. Il en va de même des
|
||||
micros et carte sons externes.
|
||||
|
||||
|
||||
<br>
|
||||
|
||||
### Router le son de SuperCollider vers un autre logiciel
|
||||
|
||||
<br>
|
||||
|
||||
Il est tout à fait possible d'utiliser **SuperCollider** comme source principale et de router ensuite le son vers un autre logiciel pour le traitement. Cela vous permettra d'enregistrer plus facilement en multipiste, de disposer d'effets ou de synthétiseurs supplémentaires, etc. Vous pourrez aussi contrôler une partie de votre dispositif en **MIDI** ou **OSC** directement depuis **SuperCollider**. Pour pouvoir router librement les signaux sortants de **SuperCollider**, il est préférable d'utiliser une interface virtuelle comme [BlackHole](https://existential.audio/blackhole/) (_cross-platform_), [Loopback](https://rogueamoeba.com/loopback/) (MacOS, payant), [Jack](https://jackaudio.org/) (_cross-platform_) ou [VB-Audio VoiceMeeter](https://vb-audio.com/Voicemeeter/) (Windows, payant). Ces logiciels permettent de créer des _bus_ audio virtuels qui peuvent être utilisés comme entrée ou sortie par **SuperCollider** aussi bien que par n'importe quel autre logiciel. L'utilisation de bus audios virtuels offre une grande flexibilité et je recommande de prendre l'habitude de les utiliser.
|
||||
|
||||
<br>
|
||||
|
||||
1) Choisir comme entrée/sortie une interface virtuelle (BlackHole, Loopback,
|
||||
etc).
|
||||
|
||||
2) Choisir comme entrée dans le logiciel de traitement le bus virtuel que vous
|
||||
venez de créer.
|
||||
|
||||
3) Traiter / enregistrer le son canal par canal dans votre logiciel.
|
||||
|
||||
|
||||
<br>
|
||||
|
||||

|
||||
|
||||
<br>
|
||||
|
||||
### Protéger ses oreilles
|
||||
|
||||
<br>
|
||||
|
||||
**SuperCollider** vous permet de manipuler le son sans aucune restriction. C'est très utile mais c'est aussi assez dangereux non seulement
|
||||
pour vous mais aussi pour votre public si vous vous produisez sur scène :
|
||||
_larsens_, _clipping_, explosion du volume, etc. Heureusement, ce problème est
|
||||
connu et il existe des moyens efficaces de se protéger. Nous allons utiliser le
|
||||
système de _plugins_ interne pour installer un **Quark** très utile. Avec la
|
||||
commande suivante, installez [BatLib](https://github.com/supercollider-quarks/BatLib):
|
||||
|
||||
```supercollider
|
||||
Quarks.install("https://github.com/supercollider-quarks/BatLib")
|
||||
```
|
||||
|
||||
Recompilez ensuite la librairie et vous pourrez utiliser le
|
||||
`StageLimiter`. Il vous sauvera sans doute la vie de nombreuses fois. Vous
|
||||
verrez comment on le démarre dans le récapitulatif plus bas. TLDR, la commande
|
||||
est :
|
||||
|
||||
```supercollider
|
||||
StageLimiter.activate;
|
||||
```
|
||||
|
||||
Si vous routez le son de **SuperCollider** vers une autre application, n'hésitez
|
||||
pas à installer des protections similaires dans cette application (_limiter_,
|
||||
etc).
|
||||
|
||||
<br>
|
||||
|
||||
### Choisir un dossier de stockage
|
||||
|
||||
<br>
|
||||
|
||||
Plutôt que de tout stocker dans le dossier par défaut, je préfère utiliser un
|
||||
dossier qui contient tout ce dont j'ai besoin pour travailler : configuration,
|
||||
définitions de synthèse, échantillons sonores. Cela permet de n'avoir qu'une
|
||||
seule route à retenir si le système est relativement unifié. J'ai choisi de tout
|
||||
stocker dans `.config/livecoding/`, ce qui est une route assez prévisible pour
|
||||
tout ceux qui sont habitués à utiliser le terminal sur **MacOS** / **Linux**.
|
||||
Voici à quoi ressemble mon dossier :
|
||||
|
||||
```bash
|
||||
.
|
||||
├── Configuration.scd
|
||||
├── README.md
|
||||
├── Synthdefs.scd
|
||||
└── samples
|
||||
```
|
||||
<Info info="Ce graphe est généré avec la commande <code>tree -L 1</code>" markdown=false />
|
||||
|
||||
<br>
|
||||
|
||||
Toute la configuration sera chargée à partir de la route
|
||||
`/Users/bubo/.config/livecoding`. Il vous faudra changer ce chemin pour que cela
|
||||
cole avec le dossier que vous aurez choisi. Pareillement, vous n'êtes pas
|
||||
obligés de suivre cette étape qui repose uniquement sur une préférence
|
||||
personnelle.
|
||||
|
||||
<br>
|
||||
|
||||
### Chargement automatique des échantillons
|
||||
|
||||
<br>
|
||||
|
||||
Plutôt que de charger les échantillons sonores au cas par cas, en précisant chaque chemin individuellement, je préfère automatiquement charger une grande bibliothèque d'échantillons. Par défaut, il n'existe aucun mécanisme permettant de gérer cela. Beaucoup de musiciens ont toutefois trouvé des solutions élégantes et assez minimales. Je me suis fié à la technique utilisé par [Scott Carver](https://github.com/scztt). Il utilise une série d'extensions conçues spécialement par ses soins.
|
||||
|
||||
<br>
|
||||
|
||||
Pour installer les **Quarks**, on utilise une nouvelle fois la commande `Quarks.install` :
|
||||
|
||||
```supercollider
|
||||
Quarks.install("https://github.com/scztt/Require.quark");
|
||||
Quarks.install("https://github.com/scztt/Singleton.quark");
|
||||
```
|
||||
|
||||
<br>
|
||||
|
||||
Une fois que cela est fait, il nous reste à installer la pièce finale, [SAMP]( https://gist.github.com/scztt/73a2ae402d9765294ae8f72979d1720e), qui est mentionnée dans un [topic](https://scsynth.org/t/making-own-sounds-libraries/4593/7) de discussion du forum **SuperCollider**. Il vous faudra créer ce fichier dans le dossier **Extensions**. Vous pouvez y accéder dans votre dossier de configuration **SuperCollider** (dépend de l'**OS**). Pour obtenir le chemin vers ce dossier, évaluez le code suivant dans **SuperCollider** :
|
||||
|
||||
```supercollider
|
||||
Platform.userExtensionDir
|
||||
```
|
||||
|
||||
Créez ensuite **SAMP.sc** dans le dossier **Extensions** et collez le code du
|
||||
lien précédemment ouvert. C'est tout ce dont vous avez besoin. Fermez tout et
|
||||
recompilez la librairie une nouvelle fois. Nous détaillerons ultérieurement l'utilisation de **SAMP** pour gérer vos échantillons. Sachez que vous y avez maintenant accès !
|
||||
|
||||
<br>
|
||||
|
||||
**Note :** **SAMP** permet de réaliser un _lazy loading_ des échantillons. Il s'agit d'une technique qui permet de ne pas surcharger d'entrée de jeu la RAM de votre ordinateur en mettant en cache trop d'échantillons. L'utilisation des ressources sera progressive, les échantillons étant chargés uniquement lorsque l'utilisateur les requiert.
|
||||
|
||||
<br>
|
||||
|
||||
### Récapitulatif
|
||||
|
||||
<br>
|
||||
|
||||
Voici le code complet que j'utilise pour le démarrage et la configuration d'un serveur audio minimal pour le _live coding_ :
|
||||
|
||||
```supercollider
|
||||
(
|
||||
s.options.numBuffers = 1024 * 128; // Nombre de buffers disponibles pour stocker des samples
|
||||
s.options.memSize = 8192 * 64; // Mémoire disponible pour le serveur
|
||||
s.options.numWireBufs = 2048; // Augmenter ce nombre si "exceeded number of interconnect buffers"
|
||||
s.options.maxNodes = 1024 * 32; // Changer cette valeur si le son saute avec le message "too many nodes"
|
||||
s.options.device = "BlackHole 16ch"; // Choix de l'interface audio à utiliser
|
||||
s.options.numOutputBusChannels = 2; // Indiquer le nombre de sorties de son interface audio
|
||||
s.options.numInputBusChannels = 2; // Indiquer le nombre d'entrées de son interface audio
|
||||
p=ProxySpace.push(s.boot); // Démarrage du serveur dans un ProxySpace (JITLIB)
|
||||
p.makeTempoClock; // Gestion du tempo
|
||||
p.clock.tempo = 120/60;
|
||||
SAMP.root = "/Users/bubo/.config/livecoding/samples/"; // Chemin vers les samples
|
||||
SAMP.lazyLoading = true; // Chargement paresseux (permet de ne pas remplir la mémoire pour rien)
|
||||
s.waitForBoot({
|
||||
"/Users/bubo/.config/livecoding/Synthdefs.scd".load; // Chargement des synthétiseurs
|
||||
StageLimiter.activate; // StageLimiter pour les oreilles
|
||||
"== 💻 LIVE CODING PRÊT 💻 == ".postln;
|
||||
});
|
||||
)
|
||||
```
|
||||
|
||||
Sauvegardez cet extrait de code dans un fichier **.scd** situé dans votre dossier de stockage. Vous pourrez ensuite l'évaluer à chaque fois que vous voudrez démarrer à l'aide de la commande suivante qu'il vous faudra évaluer dans l'interpréteur :
|
||||
|
||||
```supercollider
|
||||
"/Users/bubo/.config/livecoding/Configuration.scd".load;
|
||||
```
|
||||
|
||||
Si vous souhaitez démarrer **SuperCollider** avec cette configuration par défaut, vous pouvez également tirer parti du fichier de démarrage, qui s'exécute automatiquement à l'ouverture de **SCIDe**. Ce dernier se situe dans votre dossier de configuration **SuperCollider**. Vous pouvez le trouver en évaluant le code suivant :
|
||||
|
||||
```supercollider
|
||||
Platform.userAppSupportDir
|
||||
```
|
||||
|
||||
Il devrait exister un fichier `startup.scd` que vous pouvez remplir avec la
|
||||
configuration ci-dessus, en adaptant les chemins.
|
||||
|
||||
## Conclusion
|
||||
|
||||
Cette configuration sera amenée à évoluer et pourra même faire l'objet d'une
|
||||
refonte complète lorsque vous serez amenés à pré-charger d'autres composants :
|
||||
synthétiseurs, effets pré-déclarés, etc. Nous y reviendrons.
|
||||
329
src/routes/guides/livecoding_supercollider_2.md
Normal file
329
src/routes/guides/livecoding_supercollider_2.md
Normal file
@@ -0,0 +1,329 @@
|
||||
---
|
||||
title: "Introduction au live coding sur SuperCollider (II)"
|
||||
author: "Raphaël Maurice Forment"
|
||||
date: "2023-24-12"
|
||||
---
|
||||
|
||||
<script>
|
||||
import Info from "$lib/components/Info.svelte";
|
||||
</script>
|
||||
|
||||
## Introduction
|
||||
|
||||
### Le labyrinthe **SuperCollider**
|
||||
|
||||
<div style="margin-bottom:100px">
|
||||
<br>
|
||||
|
||||
<div>
|
||||
<a href="https://www.instagram.com/p/CtHWU0fuOKd/"><img style="min-width: 200px;width:30%;height:auto;float:inline-end;padding-right:20px;margin-left:20px" src="/images/supercollider_meme.png"></a>
|
||||
</div>
|
||||
|
||||
Si vous avez lu et suivi le premier article, tout est en place et vous devriez
|
||||
maintenant être prêt à jouer. L'une des qualités mais aussi l'un des défauts de **SuperCollider** est de ne
|
||||
pas vous astreindre à suivre une route particulière concernant la manière dont il vous faut approcher la création sonore lorsque vous débutez. Le logiciel est extrêmement générique et chaque
|
||||
utilisateur développe progressivement ses propres abstractions et une logique qui lui est propre. Il existe plusieurs dizaines de mécanismes
|
||||
distincts et la documentation tentaculaire du logiciel recommande souvent des
|
||||
approches contradictoires ou des solutions qui ne fonctionneront pas
|
||||
nécessairement avec votre méthode de travail. Il est donc nécessaire d'être toujours
|
||||
conscient des choix que vous avez opéré et ne pas hésiter à revenir en
|
||||
arrière si ces derniers ne vous conviennent pas. **SuperCollider** est un logiciel
|
||||
déjà ancien, et la librairie standard est si vaste qu'il est difficile de la comprendre entièrement et encore moins de la maîtriser. Il
|
||||
est toutefois possible de développer une certaine expertise pour utiliser **SuperCollider** d'une certaine manière et de construire progressivement ses connaissances en fonction des projets.
|
||||
|
||||
<br>
|
||||
|
||||
</div>
|
||||
|
||||
### **JITLib** et le _live coding_
|
||||
|
||||
<br>
|
||||
|
||||
L'approche que nous suivons dans ce guide repose sur la librairie [JITLib](https://doc.sccode.org/Overviews/JITLib.html). Cette librairie développée par [Julian Rohrhuber](https://www.rsh-duesseldorf.de/institute/institut-fuer-musik-und-medien/lehrende-mitarbeitende/rohrhuber-julian) est devenue si populaire qu'elle est désormais intégrée par défaut à **SuperCollider** lors de l'installation. Les avantages offerts par cette dernière ne sont pas évidents à saisir lorsqu'on débute sur **SuperCollider**. Un grand nombre d'utilisateurs l'ignorent complètement dans leur travail. La raison qui nous pousse à l'utiliser est que cette dernière est prévue, _par défaut_, pour permettre le *live coding*. Même dans ce domaine déjà très spécifique, **JITLib** reste encore relativement générique. Le mécanisme que la librairie implémente est très simple : **JITLib** permet de remplacer _à chaud_, _en temps réel_, n'importe quelle donnée (audio, information) par une information de nature similaire. Voici la traduction du premier paragraphe de la documentation :
|
||||
|
||||
|
||||
|
||||
<br>
|
||||
|
||||
<blockquote class="bg-base-300 px-4 py-8 border-l-2">
|
||||
|
||||
La programmation _just in time_ (ou la programmation conversationnelle, le _live coding_, la _programmation à la volée_, la programmation interactive) est un paradigme qui inclut l'activité de programmation dans le déroulement du programme. Dans ce paradigme, le programme n'est pas considéré comme un outil qui est conçu avant d'être utilisé plus tard de manière productive. Plutôt, il s'agit de concevoir la conception dynamique des programmes comme une description et comme une conversation. Écrire du code devient une partie intégrante de l'expérience musicale ou de la pratique expérimentale.
|
||||
|
||||
</blockquote>
|
||||
|
||||
<br>
|
||||
|
||||
**JITLib** intègre ce principe à **SuperCollider** de manière assez approfondie. On se retrouve rarement bloqué du fait d'une incompatibilité entre la librairie standard et **JITLib**. Par ailleurs, **JITLib** est si finement intégré qu'il est parfois délicat de savoir si telle ou telle fonctionnalité relève de cette librairie ou vient de l'installation standard de **SuperCollider**.
|
||||
|
||||
<br>
|
||||
|
||||
### Conseils de lecture
|
||||
|
||||
<br>
|
||||
|
||||
Cette partie du guide est _de loin la plus pénible_. Elle introduit tout les concepts importants que nous manipulerons pour faire de la musique avec **SuperCollider**. Il s'agit en quelque sorte du solfège élémentaire pour un _live coder_ utilisant **SuperCollider**. Je suis conscient que les premiers paragraphes sont particulièrement difficiles pour un utilisateur débutant. N'hésitez pas à continuer votre lecture si un détail vous échappe, vous finirez sans doute par comprendre ultérieurement par la pratique. Ne vous laissez pas arrêter par du vocabulaire ou des concepts peu familiers.
|
||||
|
||||
## `ProxySpace` et `Ndefs`
|
||||
|
||||
### Le principe de base de la librairie
|
||||
|
||||
<br>
|
||||
|
||||
Tout commence avec un peu de vocabulaire. **JITLib** introduit la notion de **ProxySpace**, un environnement de références vers des _proxys_ : "_an environment of references on a server_". Une référence est un nom associé à un objet. C'est aussi simple que `~a = 2` ou `~a` est un _proxy_ et `2` un objet. Ce système fonctionne à l'aide de _proxys_, il nous faut donc comprendre ce qu'est un _proxy_. C'est une notion relativement simple, il s'agit d'un objet qui contient _quelque chose_.
|
||||
|
||||
<br>
|
||||
<div class="pl-8 pt-4 pb-4 bg-base-300">
|
||||
|
||||
**Proxy:** un _proxy_ est un contenant pour _quelque chose_ qui tourne sur le serveur, généralement un contrôle ou un algorithme audio. C'est un objet vide ou non-vide. Un _proxy_ peut contenir le _node_ d'un oscillateur (_cf._ la suite) mais il pourrait aussi contenir un filtre audio, un synthétiseur que nous venons de créer ou même un pattern algorithmique. Le _proxy_ englobe ce qu'il contient et réalise à notre place tout un tas d'opérations qu'il est d'ordinaire nécessaire de gérer manuellement. Par exemple, on peut remplacer le contenu d'un _proxy_ par un autre _node_ sans interruption du signal, supprimer le contenant d'un _proxy_ sans pour autant supprimer la boîte elle-même.
|
||||
|
||||
</div>
|
||||
|
||||
<br>
|
||||
|
||||
Un **ProxySpace** est un ensemble de clés et de valeurs, un grand sac dans lequel on manipule des _proxy_. Les clés sont des références vers des `NodeProxy`. Tout ceci est sans aucune importance tant que nous ne le manipulons pas pour générer du son.
|
||||
|
||||
<br>
|
||||
|
||||
|
||||
### Remplacer l'environnement par défaut par un `ProxySpace`
|
||||
|
||||
<br>
|
||||
|
||||
Dans le guide précédent se trouvait une ligne assez inhabituelle, celle qui nous servait pour démarrer le serveur :
|
||||
```supercollider
|
||||
p = ProxySpace.push(s.boot);
|
||||
```
|
||||
|
||||
Sans entrer dans le détail, cette ligne réalise deux actions distinctes :
|
||||
|
||||
<div class="pl-8">
|
||||
|
||||
<br>
|
||||
|
||||
1) elle démarre le serveur audio de **SuperCollider** (`s.boot`)
|
||||
|
||||
2) elle _pousse_ l'environnement par défaut dans un **ProxySpace**
|
||||
|
||||
</div>
|
||||
|
||||
<br>
|
||||
|
||||
Avec la méthode `push`, toutes les variables globales de l'environnement actuel deviennent mécaniquement des `NodeProxy` dans le **ProxySpace**. Pour s'en convaincre, il suffit de taper le nom d'une variable et d'observer la valeur de retour :
|
||||
|
||||
<br>
|
||||
|
||||
```supercollider
|
||||
~bob; // -> NodeProxy.nil(localhost, nil)
|
||||
```
|
||||
|
||||
Ce n'est pas très parlant si vous n'êtes oas habitués à **SuperCollider** ou à la programmation. Essayons maintenant de voir ce que cela signifie lorsque nous souhaitons manipuler du son, sans spécifiquement aborder tout les détails. Évaluez le code suivant ligne par ligne :
|
||||
|
||||
```cpp
|
||||
~osc = {SinOsc.ar(200) * 0.5}; // J'évalue, rien ne se passe. Associe une fonction audio à un NodeProxy
|
||||
~osc.play; // On connecte l'audio à la sortie et on joue la fonction
|
||||
~osc = {SinOsc.ar(400) * 0.5}; // On remplace la fonction précédente par une autre (sans interruption !)
|
||||
~osc.stop(fadeTime: 4); // On stoppe avec un joli fade-out
|
||||
~osc.clear; // On libère la mémoire
|
||||
```
|
||||
|
||||
<br>
|
||||
|
||||
Nous avons associé une fonction audio (`{SinOsc.ar(200) * 0.5}`) à une référence (`~osc`). C'est tout le principe de **JITLib**. Cette association peut être remplacée à tout moment sans interruption grâce au _proxy_. Le `NodeProxy` nommé `~osc` accepte un grand nombre de manipulations différentes et son rôle est totalement redéfini par rapport au comportement habituel d'une variable en dehors de l'utilisation de **JITLib**.
|
||||
|
||||
<br>
|
||||
|
||||
Ce n'est plus une variable, c'est un `Proxy` dans notre `ProxySpace`. La ligne `~osc.stop(fadeTime: 4)` démontre aussi que les `NodeProxy` intègrent de nombreuses méthodes destinées à gérer l'audio: _fade in_, _fade out_, contrôle du niveau des sources : etc.
|
||||
|
||||
<br>
|
||||
|
||||
Nous allons utiliser ce principe fondamental introduit par **JITLib** tout au long de ce guide pour contrôler tout ce que nous souhaitons / pouvons contrôler : **algorithmes audio**, **patterns algorithmiques**, **effets sonores**, etc. Il est **essentiel** de retenir ce principe du _proxy_ car il nous permet de savoir réellement ce que nous sommes en train de manipuler à tout moment au cours du jeu : essentiellement des `NodeProxy`.
|
||||
|
||||
|
||||
<br>
|
||||
|
||||
Sans en savoir beaucoup plus, il est déjà possible de faire un petit peu de musique en s'amusant à remplacer une source par un autre :
|
||||
|
||||
```cpp
|
||||
~osc = {SinOsc.ar([200, 100]) * 0.5}; // On associe une source à un NodeProxy, un double oscillateur
|
||||
~osc.play(fadeTime: 4); // On lance le NodeProxy avec un fade-in
|
||||
~osc.fadeTime = 4; // On change le fadeTime général
|
||||
|
||||
~osc = {LPF.ar(SinOsc.ar([400, 100]), SinOsc.ar(1/4).range(200,2000)) * 0.5}; // On remplace la source
|
||||
~osc = {LPF.ar(SinOsc.ar([800, 350]), SinOsc.ar(1/4).range(200,2000)) * 0.5}; // On remplace la source
|
||||
~osc = {LPF.ar(SinOsc.ar([200, 150]), SinOsc.ar(1/4).range(200,2000)) * 0.5}; // On remplace la source
|
||||
|
||||
~osc.stop(fadeTime: 4); // Fade-out
|
||||
~osc.clear; // On libère la mémoire
|
||||
```
|
||||
|
||||
<br>
|
||||
|
||||
Même si tout reste assez primitif pour le moment, on peut déjà faire beaucoup de choses en suivant ce principe. Il est possible d'utiliser n'importe quel algorithme audio et de le mettre à jour graduellement tout au long d'une performance. Ce type de _live coding_ centré autour de la musique à jour d'un générateur sonore se prête plutôt bien à de la musique électro-acoustique, _ambient_, _noise_, etc.
|
||||
|
||||
<br>
|
||||
|
||||
### Les `Ndefs` : une autre manière de faire la même chose
|
||||
|
||||
<br>
|
||||
|
||||
La technique que nous utilisons avec `ProxySpace.push(s.boot)` _dissimule_ l'utilisation que nous faisons des `NodeProxy`. Cette fonctionnalité a été intégrée car elle permet de gagner du temps de frappe mais elle a pour désavantage de rendre plus difficilement perceptible ce que nous sommes réellement en train de faire. À première vue, il semble que `~a = 2` soit juste une assignation de variable comme dans un langage de programmation classique. Pourtant, il s'agit d'une opération qui crée/modifie un `NodeProxy`.
|
||||
|
||||
<br>
|
||||
|
||||
Nous occultons le fait que les variables globales de **SuperCollider** sont maintenant des `NodeProxy`. Il est possible de se passer entièrement de `Proxyspace.push` et de cet avantage/désagrément en utilisant les `Ndefs`. Il s'agit d'une préférence personnelle, presque d'ordre stylistique.
|
||||
|
||||
<br>
|
||||
|
||||
<Info info="Pour être plus précis, <code>ProxySpace.push(...)</code> transforme le <em>scope</em> global en un <code>ProxySpace</code>. Seule les variables de <code>a</code> à <code>z</code> sont épargnées." markdown=false />
|
||||
|
||||
<br>
|
||||
|
||||
Le terme de **NDef** est un raccourci pour _Node Proxy Definition_. On retrouve du vocabulaire familier. C'est une autre manière de désigner exactement le même type d'objet que ce que nous manipulons depuis le début ! Seule la syntaxe diffère. Profitons-en quand même pour évoquer rapidement ce qu'est un _node_ :
|
||||
|
||||
<br>
|
||||
|
||||
<div class="pl-8 pt-4 pb-4 bg-base-300">
|
||||
|
||||
|
||||
**Node:** un _node_ est un objet défini en interne par le serveur audio de **SuperCollider**. Un synthétiseur est un _node_, beaucoup d'objets présents sur le serveur sont des _nodes_. Il s'agit d'un objet générique utilisé pour une opération audio : contrôle ou synthétiseur. C'est un objet abstrait, qu'on ne manipule jamais directement. Les fonctions audio que nous venons d'utiliser dans l'exemple précédent sont des _nodes_ que l'on associe à un _proxy_. Un _node_ tire ce nom du fait que ce sont des _noeuds_ dans un graphe audio, des objets qui ont une position dans un graphe de traitement du signal.
|
||||
|
||||
</div>
|
||||
|
||||
<br>
|
||||
|
||||
Les `Ndefs` ont pour avantage de ne pas se propager dans l'environnement local. Elles rendent tout un petit peu plus clair. Réécrivons l'exemple précédent en utilisant uniquement des `Ndefs` :
|
||||
|
||||
```cpp
|
||||
Ndef(\osc, {SinOsc.ar([200, 100]) * 0.5}); // On associe une source à un NodeProxy, un double oscillateur
|
||||
Ndef(\osc).play(fadeTime: 4); // On lance le NodeProxy avec un fade-in
|
||||
Ndef(\osc).fadeTime = 4; // On change le fadeTime général
|
||||
|
||||
Ndef(\osc, {LPF.ar(SinOsc.ar([400, 100]), SinOsc.ar(1/4).range(200,2000)) * 0.5}); // On remplace la source
|
||||
Ndef(\osc, {LPF.ar(SinOsc.ar([800, 350]), SinOsc.ar(1/4).range(200,2000)) * 0.5}); // On remplace la source
|
||||
Ndef(\osc, {LPF.ar(SinOsc.ar([200, 150]), SinOsc.ar(1/4).range(200,2000)) * 0.5}); // On remplace la source
|
||||
|
||||
Ndef(\osc).stop(fadeTime: 4); // Fade-out
|
||||
Ndef(\osc).clear; // On libère la mémoire
|
||||
```
|
||||
|
||||
C'est à vous de choisir quelle est la syntaxe que vous préférez.
|
||||
|
||||
## Gestion des `NodeProxy`
|
||||
|
||||
### `fadeTime`
|
||||
|
||||
Nous avons déjà utilisé la capacité des `NodeProxy` à opérer des _fade-ins_ et des _fade-outs_. C'est une fonctionnalité très pratique, surtout lorsque vous manipulez des sources audio dynamiques et que vous souhaitez faire des transitions souples de l'une à l'autre. Il existe trois types de _fade_ :
|
||||
|
||||
- _fade-in_ à l'entrée : c'est un argument de la méthode `.play` : `~osc.play(fadeTime: 4)` ou `Ndef(\osc).play(fadeTime: 4)`
|
||||
- _fade-in_ en sortie : c'est un argument de la méthode `.stop` ou `.clear` : `~osc.stop(fadeTime: 4)` ou `Ndef(\osc).stop(fadeTime: 4)`
|
||||
- _fade_ général : c'est un attribut du `NodeProxy` que l'on contrôle avec la syntaxe `~osc.fadeTime = 4`;
|
||||
|
||||
```cpp
|
||||
~osc = {SinOsc.ar(200) * 0.5}; // On crée une source audio
|
||||
|
||||
~osc.play(fadeTime: 1); // On fait entrer doucement
|
||||
|
||||
~osc.fadeTime = 12; // Transition très longue
|
||||
|
||||
~osc = {SinOsc.ar(2000) * 0.5}; // Transition lente vers la fréquence voulue
|
||||
|
||||
~osc.clear(fadeTime: 4); // On s'arrête
|
||||
```
|
||||
|
||||
|
||||
<br>
|
||||
|
||||
### `.stop` / `.clear`
|
||||
|
||||
Les méthodes `.stop` et `.clear` ne réalisent pas la même opération :
|
||||
|
||||
- `.stop` : déconnecte le `NodeProxy` du reste de la chaîne audio. Il continue à tourner (et à consommer des ressources) mais en silence ! Vous pourrez le reconnecter plus tard.
|
||||
- `.clear` : détruit le `NodeProxy`. Vous pouvez réaliser la même opération en tapant : `~osc = nil`. Notez toutefois que `.clear` permet de spécifier un _fade-out_ avant la destruction.
|
||||
|
||||
Si vous souhaitez vous débarrasser de tout les `NodeProxy` actifs, il existe cette commande :
|
||||
|
||||
```supercollider
|
||||
currentEnvironment.free;
|
||||
```
|
||||
|
||||
Elle applique la fonction `free` à tout ce qui compose l'environnement global.
|
||||
Puisque ce dernier est un `ProxySpace`, on libère tout les `NodeProxy`.
|
||||
|
||||
## Modifier un/des paramètres
|
||||
|
||||
Vous n'êtes pas obligés de réévaluer l'algorithme dans son intégralité pour modifier une valeur sur un `NodeProxy`. Parfois, il est préférable de mettre à jour un paramètre sans que le _fade-in_ et le _fade-out_ ne s'appliquent. Ce problème sera particulièrement sensible lorsque vous utiliserez des effets tels qu'un délai ou une réverbération.
|
||||
|
||||
<br>
|
||||
|
||||
Si vous changez uniquement de valeur en réévaluant l'algorithme en entier, cela causera des problèmes avec l'amplitude générale du signal. Cela peut aussi causer un effet de brouillon lié à la superposition de plusieurs algorithmes en cours de _fade-in_ / _fade-out_. Deux méthodes existent pour mettre à jour un paramètre : `.set` (instantané) et `.xset` (progressif).
|
||||
|
||||
### `.set`
|
||||
|
||||
La méthode `.set` met immédiatement à jour un paramètre **immédiatement**, dès que possible :
|
||||
|
||||
```cpp
|
||||
~osc = { arg freq=200; SinOsc.ar(freq) * 0.5};
|
||||
~osc.play(fadeTime: 2);
|
||||
~osc.set(\freq, 800);
|
||||
~osc.set(\freq, 400);
|
||||
~osc.clear(2);
|
||||
```
|
||||
|
||||
### `.xset`
|
||||
|
||||
La méthode `.xset` met immédiatement à jour un paramètre **progressivement**, suivant le `fadeTime` :
|
||||
|
||||
```cpp
|
||||
~osc = { arg freq=200; SinOsc.ar(freq) * 0.5};
|
||||
~osc.play(fadeTime: 2);
|
||||
~osc.fadeTime = 8; // On change le fadeTime pour .xset
|
||||
~osc.xset(\freq, 800);
|
||||
~osc.xset(\freq, 400);
|
||||
~osc.clear(2);
|
||||
```
|
||||
|
||||
### Contrôler plusieurs paramètres
|
||||
|
||||
<br>
|
||||
|
||||
Il est possible de contrôler plusieurs paramètres en une seule commande si
|
||||
besoin est :
|
||||
|
||||
|
||||
```supercollider
|
||||
~osc.xset(\freq, 800, \amp, 0.2);
|
||||
```
|
||||
|
||||
Tout dépend de ce dont vous avez besoin. Réévaluer la fonction entière peut
|
||||
aussi être une stratégie intéressante dans certains cas.
|
||||
|
||||
## Communication entre `NodeProxies`
|
||||
|
||||
|
||||
On peut associer plusieurs `NodeProxies` pour former des algorithmes audio plus complexes et modulaires. Chaque `NodeProxy` peut être imaginé comme un module remplissant une fonction particulière dans un synthétiseur modulaire plus imposant. Pensez au _patching_ dans un environnement comme _Max/MSP_ ou _Pure Data_ ou au _patching_ analogique d'un synthétiseur physique.
|
||||
|
||||
<br>
|
||||
|
||||
Il est possible de définir un `NodeProxy` oscillateur puis un contrôle (de type _LFO_) pour moduler la fréquence de cet oscillateur. Voici la méthode la plus simple que vous puissiez employer :
|
||||
|
||||
```cpp
|
||||
~source = {arg freq=400; SinOsc.ar(freq) * 0.5}; // Une source que l'on souhaite moduler
|
||||
~source.play;
|
||||
~source.set(\freq, 300); // On peut utiliser set pour une valeur statique
|
||||
~freq = { SinOsc.ar(1/2) * 400 }; // Voici un LFO (Low Frequency Oscillator)
|
||||
~source.map(\\freq, ~freq); // Utilisation de la fonction map
|
||||
```
|
||||
|
||||
`.map` possède une fonction alternative, nommée `.xmap`. Elle fonctionne tout
|
||||
comme `.set` et `.xset`.
|
||||
|
||||
## Conclusion
|
||||
|
||||
Dans cette section du guide, nous avons appris :
|
||||
|
||||
- Ce qu'est un `NodeProxy` et un `ProxySpace`, l'outil de base offert par **JITLib**
|
||||
- La différence entre `ProxySpace.push` et l'utilisation explicite des `NDefs`
|
||||
- Comment démarrer, stopper et arrêter un `NodeProxy`
|
||||
- Comment contrôler le _fade-in_ et le _fade-out_ et la transition entre algorithmes
|
||||
|
||||
Je ne fais ici qu'effleurer les différentes commandes que possèdent les `NodeProxy`. Si vous souhaitez en apprendre plus, allez voir la documentation. Nous utiliserons un nombre limité de méthodes au fur et à mesure, lorsque nous en aurons besoin.
|
||||
Reference in New Issue
Block a user