4 octobre 2019

Ravines colorées

Adaptation d’un court métrage en pièce audiovisuelle.

J’ai présentement la vague idée de revisiter certains concepts développés pour mon court métrage Ravines et de les réutiliser dans une pièce audiovisuelle en programmation à la volée que je pourrai jouer en concert. J’aime l’idée qu’une œuvre animée puisse exister ainsi dans une forme malléable, changeante et utilisable dans un contexte performatif, en plus d’exister sous la forme d’un court métrage (c’est-à-dire dans un état statique et définitif).

L’ordinateur que j’utilise pour mes concerts en programmation à la volée est assez lent, et conséquemment je dois simplifier et optimiser beaucoup les algorithmes originaux du court métrage afin qu’ils puissent être animés en temps réel. Travailler avec de telles limitations est en soi un défi assez intéressant. Les animations créées pour Ravines demandaient trop de ressources à l’ordinateur pour pouvoir être rendues en temps réel. Le rendu complet a pris environ 12 heures à faire (pour un film de 4 minutes et demi).

Comme on le voit dans les images ci-haut et ci-bas, j’ai également comme objectif d’intégrer la couleur dans ce projet. J’aime l’apparence crue du noir et blanc de Ravines, mais généralement je préfère travailler en couleur et je souhaite créer des morceaux de concert colorés et chaleureux. Le fond coloré de ces images est une adaptation de l’effet de fumée trouvé ici sur ShaderToy.

8 avril 2019

Synthèse à tables d’ondes

Esquisses musicales et notes éparses.

Je suis présentement en train d’apprendre les rudiments de la synthèse à tables d’ondes (“wavetable synthesis”) avec SuperCollider, et je vais rassembler ci-dessous mes notes de travail et mes premières esquisses musicales. J’ai commencé mon apprentissage grâce à cette excellente vidéo de Eli Fieldsteel, qui lui-même prend une part de son matériel dans la documentation de la classe Shaper.

Tout commence par la création d’une table d’ondes :

~sig = Signal.newClear(513);
(
~sig.waveFill({
    arg x, y, i;
    // i.linlin(0, 512, -1, 1);
    // sin(x);
    sin(x.cubed * 20);
}, 0, 1);
~sig.plot;
~w = ~sig.asWavetableNoWrap;
~b = Buffer.loadCollection(s, ~w);
)

On crée tout d’abord un Signal, on le remplit avec la méthode waveFill, puis on le transforme en Wavetable, puis en Buffer. L’expression sin(x.cubed * 20) qui remplit le Signal a été écrite arbitrairement après plusieurs essais, et j’aime beaucoup le son qu’elle produit.

29 mars 2019

Le printemps sur Phobos

Programmation à la volée avec WebGL et SuperCollider.

En continuant à apprendre la programmation à la volée avec SuperCollider ainsi que l’écriture de shaders WebGL, j’ai composé une nouvelle pièce audiovisuelle. J’ai interprété cette pièce à La Vitrola le 29 mars 2019, lors de la troisième édition de Signes vitaux, une série de concerts organisée par Rodrigo Velasco (Yecto) et Toplap Montréal.

Malheureusement, mon ordinateur n’est pas assez rapide pour faire un rendu de cette pièce, alors il m’est impossible de la partager en ligne pour le moment.

6 mars 2019

Balancements en boucle

Le bruit OpenSimplex quadridimensionnel à l’usage de la botanique algorithmique.

Le code écrit pour réaliser l’animation ci-dessus et celle ci-dessous se trouve sur la branche noise-loops du projet Evolutionary Botany sur GitHub. L’implémentation du bruit OpenSimplex que j’utilise s’appelle SimplexNoiseJS et a été écrite par Mark Spronck.

15 février 2019

Lignes tangentes

Le calcul intégral sur la pointe des pieds.

En apprenant les bases de l’apprentissage automatique, je me suis frappé (bien entendu) à des notions de calcul intégral et différentiel. Je suis très peu familier avec ces notions et j’aimerais beaucoup pouvoir les apprendre en profondeur, à ma façon, c’est-à-dire en créant un ensemble de petites expériences qui pourraient me permettre d’explorer le sujet d’une manière intuitive.

L’animation ci-dessous est une de ces expériences. Elle m’a aidé à me familiariser avec les concepts de limite et de tangente. Une ligne est tangente à un cercle lorsque sa pente est identique à celle du cercle à l’endroit où elle le touche. Cette pente est calculée en prenant deux points différents sur le cercle, et en rapetissant quasi-infiniment la distance entre ces deux points. Écrire le code nécessaire à faire cette animation m’a demandé de faire exactement ceci. J’étais intéressé de voir quelles sortes de formes je pourrais créer en considérant ces notions, et je me suis retrouvé avec cette grille de lignes tangentes également distribuées autour d’un cercle. J’étais ensuite curieux de voir quels mouvements traverseraient cette grille si la forme du cercle était altérée.

27 janvier 2019

Petit réseau neuronal

Notes prises lors de la construction d’un réseau neuronal très simple.

J’ai rassemblé ci-dessous des notes que j’ai prises en suivant les tutoriels vidéo de Daniel Shiffman sur les réseaux neuronaux, qui eux-mêmes s’inspirent largement de Make Your Own Neural Network, un livre écrit par Tariq Rashid. Les concepts et les formules ne sont pas de moi, je ne fais que les écrire afin de m’aider à les comprendre et à les mémoriser.

Algorithme de propagation avant

Le calcul réalisé par une des couches du réseau, qui se fait en considérant ses « poids synaptiques » (en anglais, “weights”), peut se résumer par le produit matriciel ci-dessous, dans lequel h représente une des couches intermédiaires (ou « couches cachées ») du réseau, w représente les poids et x représente les nœuds d’entrées (“inputs”) . Dans cette notation inversée, wij indique le poids de j vers i.

[h1h2]=[w11w12w13w21w22w23]x1x2x3

Ce produit peut aussi se représenter ainsi :

h1=(w11×x1)+(w12×x2)+(w13×x3)h2=(w21×x1)+(w22×x2)+(w23×x3)
26 janvier 2019

Régression linéaire

Quelques pas vers l’apprentissage automatique.

J’ai rassemblé ci-dessous des notes que j’ai prises en suivant les tutoriels vidéo de Daniel Shiffman sur les réseaux neuronaux, qui eux-mêmes s’inspirent largement de Make Your Own Neural Network, un livre écrit par Tariq Rashid. Les concepts et les formules ne sont pas de moi, je ne fais que les écrire afin de m’aider à les comprendre et à les mémoriser.

Pente et ordonnée à l’origine

Une droite est traditionnellement représentée par cette équation, dans laquelle m représente la pente et b l’ordonnée à l’origine :

y=mx+b

Dans le cas de la régression linéaire (ou méthode des moindres carrés ordinaire), nous allons calculer la valeur m avec la formule ci-dessous. Cette formule est tirée de cette vidéo réalisée par Daniel Shiffman dans le cadre de son cours Intelligence et apprentissage. Nous pouvons considérer que le numérateur de cette fraction représente la corrélation entre la croissance de la valeur x et celle de la valeur y (qui détermine la pente de notre droite).

m=ni=0(xi¯x)(yi¯y)ni=0(xi¯x)2
12 janvier 2019

Arbres chantants

Graphes animés.

Mes séquenceurs en forme de graphe pourraient également générer leur propre accompagnement musical lorsqu’ils croissent.

Structure et composition

Comment ces arbres produiront-ils de la musique ? Comment cette musique sera-t-elle définie à l’intérieur de l’arbre ? Par exemple, un arbre pourrait être doté d’une tonique et d’une armature.

La notion de « marcheur » est aussi très importante. Ce devrait être le marcheur qui « consulte » l’arbre et produit la musique. De cette façon, puisque l’on voit le marcheur se promener, le lien visuel entre son mouvement et la musique est plus intéressant que si la musique provenait inexplicablement de l’arbre seul. Enfin, la musique sans marcheur pourrait aussi être intéressante, mais je vais commencer par les marcheurs.

Un marcheur pourrait commencer au tronc de l’arbre en produisant la tonique. Lorsqu’il arrive à un embranchement, il pourra créer un nouveau marcheur. Ces marcheurs pourront ensuite s’engager dans les branches de l’arbre, et générer des sons simultanément.

Les notes pourraient être générées par les embranchements ou par les branches elles-mêmes. La longueur d’une note pourrait être déterminée par la longueur du segment sur lequel le marcheur se trouve — cependant, ces longueurs pourraient changer pendant que le marcheur avance, ce qui créerait des sons atonaux.

Pour l’instant, les notes seront représentées par les embranchements. Ça me semble une façon naturelle de commencer l’expérience. Donc, les objets Segment dont la propriété children est plus grande que 1 représentent un embranchement. Ce serait plus simple qu’un marcheur « s’endorme » lorsqu’il atteint un embranchement. Avant de s’endormir, il crée de nouveaux marcheurs (un pour chaque children du Segment) et leur lègue sa mémoire. Ou alors il ne s’endort pas et s’engage toujours dans la première branche de la liste children. De toute façon, un marcheur et les marcheurs qu’il a généré doivent être absolument égaux, il n’y aura pas de hiérarchie chez ces marcheurs.

// All the walkers would refer to a single instance of Song.
// Then, when a walker modulates the song, it will be modulated
// for all walkers.
let mixo = new Song({
    scale: "E mixolydian",
    currentChord: 1
});
// Define the music inside the Walker itself?
// The melody notes should represent degrees on the scale,
// starting at 1 being the tonic,
// not semitones with zero-based numbering.

//branchingModulo
let walker = new Walker({
    scale: "E mixolydian",
    melodies: [[1, 4, 6, 7],
               [1, 5, 8, 9]],
    currentMelodyIndex: [0, 2],
    speed: 3,
    branchingModulo: 4,
    walkingDepth: 0,
    song: mixo
});

// A walker could then have any number of methods
// that would define and alter its behaviour.

walker.branch = function(s) {
    // What happens when the Walker meets a branching Segment
    // s.children
    this.makeNote();
    this.currentSegment = s.children[0];
};

walker.sing = function() {
    // What happens when the Walker meets a branching Segment
    this.sing();
};

L’avancée d’un marcheur

Le niveau d’avancée d’un marcheur sur son segment doit être une valeur entre 0 et 1. Donc, sa vitesse est aussi un nombre entre 0 et 1. Sa vitesse est ajoutée à son niveau d’avancée à chaque pas (niveau qui plafonne à 1). La position du marcheur est ensuite calculée par interpolation linéaire entre les deux extrémités du segment.

Librairies musicales

Afin de soutenir ces liens entre la structure mathématique (et spatiale) de mes arbres et les accompagnements musicaux qu’ils généreront, je vais utiliser deux librairies JavaScript à vocation musicale: Tonal et Teoria. Ces outils devraient me permettre de manipuler des notions de théorie musicale plus aisément.

Une note à moi-même : afin d’utiliser l’extension Tonal.Key de Tonal.js dans un fureteur (plutôt que sur un serveur Node.js), j’ai dû utiliser Browserify en l’invoquant de cette manière :

node ./node_modules/.bin/browserify main.js -o bundle.js

Contexte

Cette note de blog fait partie de mon projet de recherche Vers un cinéma algorithmique, démarré en avril 2018. Je vous invite à consulter la toute première note du projet pour en apprendre davantage.

17 décembre 2018

Quadrilatères flous

Études géométriques avec WebGL.

Dessiner des formes floues avec WebGL n’est pas simple. Par défaut, toutes les formes créées sont très précises et leurs contours bien définis. Comme je cherche à créer des animations aux ambiances brumeuses et incertaines, je suis en train de créer quelques premiers outils pour me permettre de dessiner du flou avec WebGL.

Dessiner des cercles flous ne s’est pas avéré trop compliqué, puisqu’une simple fonction de distance par rapport au centre du cercle peut être calculée aisément par le gpu. Le dessin de formes plus complexes me demande cependant d’en apprendre beaucoup plus sur WebGL, une technologie que je connais encore peu.

J’ai commencé par les quadrilatères. J’ai créé un système avec lequel je peux définir un rectangle principal, qui sera formé par les triangles a et b que l’on voit dans le diagramme en haut à gauche de mes notes crayonnées.

12 décembre 2018

Volées d’oiseaux artificiels

Une première plongée dans la programmation à la volée.

Ce projet constitue ma toute première expérience de programmation à la volée, c’est-à-dire que le programme a été conçu pour être modifié en temps réel. L’animation de ce programme est réalisée avec p5.js et WebGL, et la musique est produite avec SuperCollider. La musique utilise également des échantillons de piano distribués librement.

Le principe sur lequel cette animation repose est la simulation du comportement d’une volée d’oiseaux, ces oiseaux artificiels que l’on appelle boids en anglais. J’ai d’abord appris l’existence de ces simulations grâce aux vidéos de Daniel Shiffman. Shiffman a traité à plusieurs reprises de ce sujet, mais cette vidéo en particulier m’a inspiré cette animation.

Le projet peut être visionné sur YouTube et une version plus courte (qui contient, à mon avis, la meilleure partie de la vidéo) est présente sur mon fil Twitter.