3 Commits

17 changed files with 7370 additions and 7530 deletions

View File

@ -1,16 +1,16 @@
{ {
"name": "topos-server", "name": "topos-server",
"version": "0.0.1", "version": "1.0.0",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "topos-server", "name": "topos-server",
"version": "0.0.1", "version": "1.0.0",
"license": "GPL-3.0-or-later", "license": "GPL-3.0-or-later",
"dependencies": { "dependencies": {
"osc": "^2.4.4", "osc": "^2.4.4",
"ws": "^8.17.1" "ws": "^8.14.2"
} }
}, },
"node_modules/@serialport/binding-mock": { "node_modules/@serialport/binding-mock": {
@ -309,9 +309,9 @@
"integrity": "sha512-P+6vtWyuDw+MB01X7UeF8TaHBvbCovf4HPEMF/SV7BdDc1SMTiBy13SRD71lQh4ExFTG1d/WNzDGDCyOKSMblw==" "integrity": "sha512-P+6vtWyuDw+MB01X7UeF8TaHBvbCovf4HPEMF/SV7BdDc1SMTiBy13SRD71lQh4ExFTG1d/WNzDGDCyOKSMblw=="
}, },
"node_modules/ws": { "node_modules/ws": {
"version": "8.17.1", "version": "8.14.2",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz",
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", "integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==",
"engines": { "engines": {
"node": ">=10.0.0" "node": ">=10.0.0"
}, },

View File

@ -10,6 +10,6 @@
"license": "GPL-3.0-or-later", "license": "GPL-3.0-or-later",
"dependencies": { "dependencies": {
"osc": "^2.4.4", "osc": "^2.4.4",
"ws": "^8.17.1" "ws": "^8.14.2"
} }
} }

View File

@ -174,7 +174,6 @@
<summary class="font-semibold lg:text-xl text-orange-300">Basics</summary> <summary class="font-semibold lg:text-xl text-orange-300">Basics</summary>
<div class="flex flex-col"> <div class="flex flex-col">
<p rel="noopener noreferrer" id="docs_introduction" class="doc_header">Welcome </p> <p rel="noopener noreferrer" id="docs_introduction" class="doc_header">Welcome </p>
<p rel="noopener noreferrer" id="docs_atelier" class="doc_header">Atelier (FR)</p>
<p rel="noopener noreferrer" id="docs_interface" class="doc_header">Interface</p> <p rel="noopener noreferrer" id="docs_interface" class="doc_header">Interface</p>
<p rel="noopener noreferrer" id="docs_interaction" class="doc_header">Interaction</p> <p rel="noopener noreferrer" id="docs_interaction" class="doc_header">Interaction</p>
<p rel="noopener noreferrer" id="docs_shortcuts" class="doc_header">Keyboard</p> <p rel="noopener noreferrer" id="docs_shortcuts" class="doc_header">Keyboard</p>
@ -202,6 +201,7 @@
<div class="flex flex-col"> <div class="flex flex-col">
<p rel="noopener noreferrer" id="docs_audio_basics" class="doc_subheader">Playing a sound</p> <p rel="noopener noreferrer" id="docs_audio_basics" class="doc_subheader">Playing a sound</p>
<p rel="noopener noreferrer" id="docs_amplitude" class="doc_subheader">Amplitude</p> <p rel="noopener noreferrer" id="docs_amplitude" class="doc_subheader">Amplitude</p>
<p rel="noopener noreferrer" id="docs_pitch" class="doc_subheader">Pitch</p>
<p rel="noopener noreferrer" id="docs_sampler" class="doc_subheader">Sampler</p> <p rel="noopener noreferrer" id="docs_sampler" class="doc_subheader">Sampler</p>
<p rel="noopener noreferrer" id="docs_synths" class="doc_subheader">Synths</p> <p rel="noopener noreferrer" id="docs_synths" class="doc_subheader">Synths</p>
<p rel="noopener noreferrer" id="docs_filters" class="doc_subheader">Filters</p> <p rel="noopener noreferrer" id="docs_filters" class="doc_subheader">Filters</p>
@ -368,12 +368,10 @@
<input id="show-completions" type="checkbox" value="" class="w-4 h-4 text-blue-600 rounded focus:ring-blue-600 focus:ring-2"> <input id="show-completions" type="checkbox" value="" class="w-4 h-4 text-blue-600 rounded focus:ring-blue-600 focus:ring-2">
<label for="default-checkbox" class="ml-2 text-sm font-medium text-foreground">Show Completions</label> <label for="default-checkbox" class="ml-2 text-sm font-medium text-foreground">Show Completions</label>
</div> </div>
<!--
<div class="flex items-center mb-4 ml-5"> <div class="flex items-center mb-4 ml-5">
<input id="load-demo-songs" type="checkbox" value="" class="w-4 h-4 text-blue-600 rounded focus:ring-blue-600"> <input id="load-demo-songs" type="checkbox" value="" class="w-4 h-4 text-blue-600 rounded focus:ring-blue-600">
<label for="default-checkbox" class="ml-2 text-sm font-medium text-foreground">Load Demo Song</label> <label for="default-checkbox" class="ml-2 text-sm font-medium text-foreground">Load Demo Song</label>
</div> </div>
-->
</div> </div>
</div> </div>

View File

@ -22,6 +22,7 @@
"@codemirror/theme-one-dark": "^6.1.2", "@codemirror/theme-one-dark": "^6.1.2",
"@replit/codemirror-vim": "^6.0.14", "@replit/codemirror-vim": "^6.0.14",
"@strudel.cycles/webaudio": "^0.8.2", "@strudel.cycles/webaudio": "^0.8.2",
"@strudel/soundfonts": "^0.11.0",
"@types/marked": "^5.0.1", "@types/marked": "^5.0.1",
"@types/showdown": "^2.0.1", "@types/showdown": "^2.0.1",
"acorn": "^8.10.0", "acorn": "^8.10.0",
@ -38,7 +39,7 @@
"postcss": "^8.4.27", "postcss": "^8.4.27",
"showdown": "^2.1.0", "showdown": "^2.1.0",
"showdown-highlight": "^3.1.0", "showdown-highlight": "^3.1.0",
"superdough": "^0.9.12", "superdough": "^0.10.0",
"tailwind-highlightjs": "^2.0.1", "tailwind-highlightjs": "^2.0.1",
"tailwindcss": "^3.3.3", "tailwindcss": "^3.3.3",
"tone": "^14.8.49", "tone": "^14.8.49",

View File

@ -27,6 +27,10 @@ import {
soundMap, soundMap,
// @ts-ignore // @ts-ignore
} from "superdough"; } from "superdough";
import {
registerSoundfonts
// @ts-ignore
} from "@strudel/soundfonts";
import { Speaker } from "./extensions/StringExtensions"; import { Speaker } from "./extensions/StringExtensions";
import { getScaleNotes } from "zifferjs"; import { getScaleNotes } from "zifferjs";
import { OscilloscopeConfig } from "./Visuals/Oscilloscope"; import { OscilloscopeConfig } from "./Visuals/Oscilloscope";
@ -70,6 +74,7 @@ export async function loadSamples() {
samples("github:Bubobubobubobubo/Dough-Waveforms/main", undefined, { samples("github:Bubobubobubobubo/Dough-Waveforms/main", undefined, {
tag: "Waveforms", tag: "Waveforms",
}), }),
registerSoundfonts(),
]); ]);
} }
@ -1602,20 +1607,6 @@ export class UserAPI {
}; };
ry = this.rhythm; ry = this.rhythm;
public nrhythm = (
div: number,
pulses: number,
length: number,
rotate: number = 0,
): boolean => {
let rhythm = this._euclidean_cycle(pulses, length, rotate).map(n => !n)
return (
this.beat(div) && rhythm.beat(div)
);
};
nry = this.nrhythm;
_euclidean_cycle( _euclidean_cycle(
pulses: number, pulses: number,
length: number, length: number,

View File

@ -1,9 +1,9 @@
import { type Editor } from "./main"; import { type Editor } from "./main";
// Basics // Basics
import { introduction } from "./documentation/basics/welcome"; import { introduction } from "./documentation/basics/welcome";
import { atelier } from "./documentation/basics/atelier";
import { loading_samples } from "./documentation/learning/samples/loading_samples"; import { loading_samples } from "./documentation/learning/samples/loading_samples";
import { amplitude } from "./documentation/learning/audio_engine/amplitude"; import { amplitude } from "./documentation/learning/audio_engine/amplitude";
import { pitch } from "./documentation/learning/audio_engine/pitch";
import { effects } from "./documentation/learning/audio_engine/effects"; import { effects } from "./documentation/learning/audio_engine/effects";
import { sampler } from "./documentation/learning/audio_engine/sampler"; import { sampler } from "./documentation/learning/audio_engine/sampler";
import { sample_banks } from "./documentation/learning/samples/sample_banks"; import { sample_banks } from "./documentation/learning/samples/sample_banks";
@ -78,7 +78,6 @@ export const makeExampleFactory = (application: Editor): Function => {
export const documentation_pages = [ export const documentation_pages = [
"introduction", "introduction",
"atelier",
"sampler", "sampler",
"amplitude", "amplitude",
"audio_basics", "audio_basics",
@ -128,7 +127,6 @@ export const documentation_factory = (application: Editor) => {
return { return {
introduction: introduction(application), introduction: introduction(application),
atelier: atelier(application),
interface: software_interface(application), interface: software_interface(application),
interaction: interaction(application), interaction: interaction(application),
code: code(application), code: code(application),
@ -155,6 +153,7 @@ export const documentation_factory = (application: Editor) => {
generators: generators(application), generators: generators(application),
shortcuts: shortcuts(application), shortcuts: shortcuts(application),
amplitude: amplitude(application), amplitude: amplitude(application),
pitch: pitch(application),
effects: effects(application), effects: effects(application),
sampler: sampler(application), sampler: sampler(application),
mouse: mouse(application), mouse: mouse(application),

View File

@ -1,6 +1,6 @@
// import { tutorial_universe } from "./universes/tutorial"; // import { tutorial_universe } from "./universes/tutorial";
import { gzipSync, decompressSync, strFromU8 } from "fflate"; import { gzipSync, decompressSync, strFromU8 } from "fflate";
// import { examples } from "./examples/excerpts"; import { examples } from "./examples/excerpts";
import { type Editor } from "./main"; import { type Editor } from "./main";
import { uniqueNamesGenerator, colors, animals } from "unique-names-generator"; import { uniqueNamesGenerator, colors, animals } from "unique-names-generator";
import { tryEvaluate } from "./Evaluator"; import { tryEvaluate } from "./Evaluator";
@ -63,7 +63,7 @@ export interface Settings {
selected_universe: string; selected_universe: string;
line_numbers: boolean; line_numbers: boolean;
time_position: boolean; time_position: boolean;
// load_demo_songs: boolean; load_demo_songs: boolean;
tips: boolean; tips: boolean;
completions: boolean; completions: boolean;
send_clock: boolean; send_clock: boolean;
@ -150,7 +150,7 @@ export class AppSettings {
public midi_clock_input: string | undefined = undefined; public midi_clock_input: string | undefined = undefined;
public default_midi_input: string | undefined = undefined; public default_midi_input: string | undefined = undefined;
public midi_clock_ppqn: number = 24; public midi_clock_ppqn: number = 24;
// public load_demo_songs: boolean = true; public load_demo_songs: boolean = true;
constructor() { constructor() {
const settingsFromStorage = JSON.parse( const settingsFromStorage = JSON.parse(
@ -174,7 +174,7 @@ export class AppSettings {
this.midi_clock_input = settingsFromStorage.midi_clock_input; this.midi_clock_input = settingsFromStorage.midi_clock_input;
this.midi_clock_ppqn = settingsFromStorage.midi_clock_ppqn || 24; this.midi_clock_ppqn = settingsFromStorage.midi_clock_ppqn || 24;
this.default_midi_input = settingsFromStorage.default_midi_input; this.default_midi_input = settingsFromStorage.default_midi_input;
// this.load_demo_songs = settingsFromStorage.load_demo_songs; this.load_demo_songs = settingsFromStorage.load_demo_songs;
} else { } else {
this.universes = template_universes; this.universes = template_universes;
} }
@ -204,7 +204,7 @@ export class AppSettings {
midi_clock_input: this.midi_clock_input, midi_clock_input: this.midi_clock_input,
midi_clock_ppqn: this.midi_clock_ppqn, midi_clock_ppqn: this.midi_clock_ppqn,
default_midi_input: this.default_midi_input, default_midi_input: this.default_midi_input,
// load_demo_songs: this.load_demo_songs, load_demo_songs: this.load_demo_songs,
}; };
} }
@ -232,7 +232,7 @@ export class AppSettings {
this.midi_clock_input = settings.midi_clock_input; this.midi_clock_input = settings.midi_clock_input;
this.midi_clock_ppqn = settings.midi_clock_ppqn; this.midi_clock_ppqn = settings.midi_clock_ppqn;
this.default_midi_input = settings.default_midi_input; this.default_midi_input = settings.default_midi_input;
// this.load_demo_songs = settings.load_demo_songs; this.load_demo_songs = settings.load_demo_songs;
localStorage.setItem("topos", JSON.stringify(this.data)); localStorage.setItem("topos", JSON.stringify(this.data));
} }
} }
@ -245,13 +245,13 @@ export const initializeSelectedUniverse = (app: Editor): void => {
* @param app - The main application * @param app - The main application
* @returns void * @returns void
*/ */
// if (app.settings.load_demo_songs) { if (app.settings.load_demo_songs) {
// let random_example = examples[Math.floor(Math.random() * examples.length)]; let random_example = examples[Math.floor(Math.random() * examples.length)];
// app.selected_universe = "Demo"; app.selected_universe = "Demo";
// app.universes[app.selected_universe] = structuredClone(template_universe); app.universes[app.selected_universe] = structuredClone(template_universe);
// app.universes[app.selected_universe].global.committed = random_example; app.universes[app.selected_universe].global.committed = random_example;
// app.universes[app.selected_universe].global.candidate = random_example; app.universes[app.selected_universe].global.candidate = random_example;
// } else { } else {
try { try {
app.selected_universe = app.settings.selected_universe; app.selected_universe = app.settings.selected_universe;
if (app.universes[app.selected_universe] === undefined) if (app.universes[app.selected_universe] === undefined)
@ -262,6 +262,7 @@ export const initializeSelectedUniverse = (app: Editor): void => {
app.selected_universe = app.settings.selected_universe; app.selected_universe = app.settings.selected_universe;
app.universes[app.selected_universe] = structuredClone(template_universe); app.universes[app.selected_universe] = structuredClone(template_universe);
} }
}
( (
app.interface.universe_viewer as HTMLInputElement app.interface.universe_viewer as HTMLInputElement
).placeholder! = `${app.selected_universe}`; ).placeholder! = `${app.selected_universe}`;

View File

@ -44,8 +44,8 @@ export const installInterfaceLogic = (app: Editor) => {
app.settings.midi_channels_scripts; app.settings.midi_channels_scripts;
(app.interface.midi_clock_ppqn as HTMLInputElement).value = (app.interface.midi_clock_ppqn as HTMLInputElement).value =
app.settings.midi_clock_ppqn.toString(); app.settings.midi_clock_ppqn.toString();
// (app.interface.load_demo_songs as HTMLInputElement).checked = (app.interface.load_demo_songs as HTMLInputElement).checked =
// app.settings.load_demo_songs; app.settings.load_demo_songs;
const tabs = document.querySelectorAll('[id^="tab-"]'); const tabs = document.querySelectorAll('[id^="tab-"]');
// Iterate over the tabs with an index // Iterate over the tabs with an index
@ -373,8 +373,8 @@ export const installInterfaceLogic = (app: Editor) => {
midiChannelsScripts.checked = app.settings.midi_channels_scripts; midiChannelsScripts.checked = app.settings.midi_channels_scripts;
const midiClockPpqn = app.interface.midi_clock_ppqn as HTMLInputElement; const midiClockPpqn = app.interface.midi_clock_ppqn as HTMLInputElement;
midiClockPpqn.value = app.settings.midi_clock_ppqn.toString(); midiClockPpqn.value = app.settings.midi_clock_ppqn.toString();
// const loadDemoSongs = app.interface.load_demo_songs as HTMLInputElement; const loadDemoSongs = app.interface.load_demo_songs as HTMLInputElement;
// loadDemoSongs.checked = app.settings.load_demo_songs; loadDemoSongs.checked = app.settings.load_demo_songs;
const vimModeCheckbox = app.interface.vim_mode_checkbox as HTMLInputElement; const vimModeCheckbox = app.interface.vim_mode_checkbox as HTMLInputElement;
vimModeCheckbox.checked = app.settings.vimMode; vimModeCheckbox.checked = app.settings.vimMode;
@ -502,12 +502,12 @@ export const installInterfaceLogic = (app: Editor) => {
app.settings.midi_clock_ppqn = value; app.settings.midi_clock_ppqn = value;
}); });
// app.interface.load_demo_songs.addEventListener("change", () => { app.interface.load_demo_songs.addEventListener("change", () => {
// let checked = (app.interface.load_demo_songs as HTMLInputElement).checked let checked = (app.interface.load_demo_songs as HTMLInputElement).checked
// ? true ? true
// : false; : false;
// app.settings.load_demo_songs = checked; app.settings.load_demo_songs = checked;
// }); });
app.interface.universe_creator.addEventListener("submit", (event) => { app.interface.universe_creator.addEventListener("submit", (event) => {
event.preventDefault(); event.preventDefault();

View File

@ -80,7 +80,13 @@ export class SoundEvent extends AudibleEvent {
fmrelease: ["fmrelease", "fmrel"], fmrelease: ["fmrelease", "fmrel"],
fmvelocity: ["fmvelocity", "fmvel"], fmvelocity: ["fmvelocity", "fmvel"],
fmwave: ["fmwave", "fmw"], fmwave: ["fmwave", "fmw"],
phaser: ["phaser", "phas"], pattack: ["pattack", "patt"],
pdecay: ["pdecay", "pdec"],
psustain: ["psustain", "psus"],
prelease: ["prelease", "prel"],
penv: ["penv"],
pcurve: ["pcurve"],
panchor: ["panchor"],
phaserDepth: ["phaserDepth", "phasdepth"], phaserDepth: ["phaserDepth", "phasdepth"],
phaserSweep: ["phaserSweep", "phassweep"], phaserSweep: ["phaserSweep", "phassweep"],
phaserCenter: ["phaserCenter", "phascenter"], phaserCenter: ["phaserCenter", "phascenter"],

View File

@ -1,50 +1,4 @@
{ {
"theotteryears": {
"black": "#000000",
"color1": "#e52222",
"green": "#5ef763",
"yellow": "#fc951e",
"blue": "#c48dff",
"magenta": "#fa2573",
"cyan": "#67d9f0",
"white": "#f2f2f2",
"brightblack": "#555555",
"brightred": "#ff5555",
"brightgreen": "#55ff55",
"brightyellow": "#ffff55",
"brightblue": "#5555ff",
"brightmagenta": "#ff55ff",
"brightcyan": "#55ffff",
"brightwhite": "#ffffff",
"background": "#000000",
"selection_foreground": "#000000",
"cursor": "#bbbbbb",
"foreground": "#bbbbbb",
"selection_background": "#bbbbbb"
},
"theotteryears 2": {
"black": "#000000",
"color1": "#8AA2A9",
"green": "#7FDEFF",
"yellow": "#F3DFBF",
"blue": "#EB8A90",
"magenta": "#E8871E",
"cyan": "#E8871E",
"white": "#E8871E",
"brightblack": "#FF3864",
"brightred": "#FF3864",
"brightgreen": "#FF3864",
"brightyellow": "#FF3864",
"brightblue": "#71baf2",
"brightmagenta": "#FF3864",
"brightcyan": "#FF3864",
"brightwhite": "#ffffff",
"background": "#000000",
"selection_foreground": "#000000",
"cursor": "#bdc3c2",
"foreground": "#bdc3c2",
"selection_background": "#FF3864"
},
"Tomorrow Night Burns": { "Tomorrow Night Burns": {
"black": "#252525", "black": "#252525",
"color1": "#832e31", "color1": "#832e31",

View File

@ -1,193 +0,0 @@
import { type Editor } from "../../main";
import { makeExampleFactory } from "../../Documentation";
export const atelier = (application: Editor): string => {
const makeExample = makeExampleFactory(application);
return `
# Atelier (06 mars 2024)
Bonjour tout le monde ! Nous sommes :
- [Rémi Georges](https://remigeorges.fr) : musicien, réalisateur en informatique musicale.
- [Agathe Herrou](https://www.youtube.com/@th4music) : musicienne, chercheuse.
- [Raphaël Forment](https://raphaelforment.fr) : musicien, doctorant.
Nous pratiquons le [live coding](https://livecoding.fr). Nous utilisons notre ordinateur comme un instrument de musique, nous programmons de la musique devant notre public. Nous pouvons faire plein de choses comme :
- créer des instruments de musique, des synthétiseurs, des boîtes à rythme.
- jouer des échantillons, charger des images, des vidéos, créer des animations.
- contrôler d'autres instruments, jouer avec d'autres musiciens.
Topos est un instrument de musique. On peut l'utiliser depuis n'importe quel ordinateur, sans avoir à installer quoi que ce soit. Nous l'avons fabriqué pour que tout le monde puisse jouer facilement de la musique.
## Découverte
<br>
${makeExample(
"Percussions", `
tempo(120) // Changer le tempo
beat(1)::sound('kick').out()
beat(2)::sound('snare').out()
beat(.5)::sound('hh').out()
`, true,)}
<br>
- Qu'est-ce qu'il se passe si je change un nombre ?
- Qu'est-ce qu'il se passe si je change un nom ?
- Essayez par exemple <ic>"sid"</ic> ou <ic>"trump"</ic>.
- Qu'est-ce qu'il se passe si j'enlève <ic>.out()</ic> ?
- Est-il possible de jouer un rythme très rapide ou très lent ?
### Ajout d'une basse
<br>
${makeExample(
"Une basse", `
// Aucun changement dans le code
beat(1)::sound('kick').out()
beat(2)::sound('snare').out()
beat(.5)::sound('hh').out()
// Une nouvelle partie
beat([0.25,0.5].beat(1))::sound("pluck")
.note([40,45].beat(2)).out()
`, true,)}
<br>
- Qu'est-ce que le son <ic>"pluck"</ic> ?
- Que signifie <ic>.note([40,45].beat(2))</ic> ?
- Que se passe-t-il si je change la valeur dans <ic>.beat(2)</ic> ?
- Que se passe-t-il lorsque j'ajoute de nouveaux nombres dans <ic>[40, 45]</ic> ?
### Ajout d'une mélodie
<br>
${makeExample(
"Le morceau complet", `
// Aucun changement dans le code
beat(1)::sound('kick').out()
beat(2)::sound('snare').out()
beat(.5)::sound('hh').out()
beat([0.25,0.5].beat(1))::sound("pluck")
.note([40,45].beat(2)).out()
// Nouvelle partie mélodique
beat([0.25,0.5].beat())::sound("pluck")
.note([0,7,5,8,2,9,0].scale("Major",60).beat(1))
.vib(8).vibmod(1/4)
.delay(0.5).room(1.5).size(0.5)
.out()
`, true,)}
<br>
Ici, on ajoute une nouvelle mélodie mais il s'agit aussi d'un nouvel instrument. C'est pour cela que le code est plus long. Quand on fait du <em>live coding</em>, on code tout en même temps : notes, rythmes, mélodies, sons. C'est beaucoup de choses ! C'est pour cela que le code est court, on essaie de tout taper très vite en jouant !
- Que signifie selon vous <ic>vib</ic>, <ic>delay</ic>, <ic>room</ic> ou <ic>size</ic> ?
- Que se passe-t-il si je change les valeurs dans <ic>vib</ic>, <ic>delay</ic>, <ic>room</ic> ou <ic>size</ic> ?
<br>
**Exercices :**
- Transformer <ic>vib(8)</ic> en <ic>vib([2,4,8].beat(1))</ic>.
- Transformer <ic>"pluck"</ic> en <ic>["pluck", "clap"].beat(1)</ic>.
Vous pouvez aussi utiliser la fonction <ic>rhythm</ic> pour jouer rapidement des rythmes.
${makeExample(
"Rythmes rythmes rythmes", `
rhythm(0.5, 3, 8)::sound('bd').out()
rhythm(0.5, 3, 8)::sound('clap').out()
rhythm(0.5, 6, 8)::sound('hat').out()
rhythm(0.25, 6, 8)::sound('hat')
.vel(0.3).speed(2).out()
rhythm(0.5, 2, 8)::sound('sd').out()
`, true)};
## Créer un instrument
<br>
Nous allons créer un nouvel instrument à partir d'un son de base. Voici un premier son :
${makeExample("Notre son de base", `beat(2)::sound('sine').note(50).ad(0, .5).out()`, true)}
<br>
Ce son est assez ennuyeux. Nous allons ajouter quelques paramètres :
${makeExample("Beaucoup mieux !", `beat(2)::sound('sine').note(50).fmi(2).fmh(2).ad(0, .5).out()`, true)}
<br>
Nous allons aussi ajouter quelques effets intéressants :
${makeExample("Ajout d'un écho", `beat(2)::sound('sine').note(50)
.fmi(2).fmh(2).ad(1/16, 1.5)
.delay(0.5).delayt(0.75).out()`,
true)}
<br>
Nous pouvons utiliser plusieurs techniques pour rendre le son plus dynamique :
- générer des valeurs aléatoires pour les paramètres
- utiliser des générateurs de valeurs (comme <ic>usine</ic>)
- utiliser la souris ou un autre contrôleur pour changer les valeurs en temps réel
${makeExample("Plus dynamique encore", `
beat(2)::sound('sine').note([50,55,57,62,66, 69, 74].mouseX())
.fmi(usine(1/4)).fmh([1,2,0.5].beat())
.ad(1/16, 1.5).delay(0.5).delayt(0.75)
.out()`, true)}
<br>
Un exemple final, le plus complexe jusqu'à présent :
${makeExample("Un instrument de musique complet", `
beat(2)::sound('triangle')
.note([50,55,57,62,66, 69, 74].mouseX())
.fmi(usine(1/4)).fmh([1,2,0.5].beat())
.ad(1/16, 1.5).delay(0.5).delayt(0.75)
.room(0.5).size(8).lpf(usine(1/3)*4000).out()`, true)}
## Compléments
${makeExample("Quelques échantillons", `
ab ade ades2 ades3 ades4 alex alphabet amencutup armora arp arpy auto
baa baa2 bass bass0 bass1 bass2 bass3 bassdm bassfoo battles bd bend
bev bin birds birds3 bleep blip blue bottle breaks125 breaks152
breaks157 breaks165 breath bubble can casio cb cc chin circus clak
click clubkick co coins control cosmicg cp cr crow d db diphone
diphone2 dist dork2 dorkbot dr dr2 dr55 dr_few drum drumtraks e east
electro1 em2 erk f feel feelfx fest fire flick fm foo future gab
gabba gabbaloud gabbalouder glasstap glitch glitch2 gretsch gtr h
hand hardcore hardkick haw hc hh hh27 hit hmm ho hoover house ht if
ifdrums incoming industrial insect invaders jazz jungbass jungle juno
jvbass kicklinn koy kurt latibro led less lighter linnhats lt made
made2 mash mash2 metal miniyeah monsterb moog mouth mp3 msg mt mute
newnotes noise noise2 notes numbers oc off outdoor pad padlong pebbles
perc peri pluck popkick print proc procshort psr rave rave2 ravemono
realclaps reverbkick rm rs sax sd seawolf sequential sf sheffield
short sid sine sitar sn space speakspell speech speechless speedupdown
stab stomp subroc3d sugar sundance tabla tabla2 tablex tacscan tech
techno tink tok toys trump ul ulgab uxay v voodoo wind wobble world
xmas yeah`, true)}
`
};

View File

@ -63,9 +63,11 @@ beat(.25) :: sound('sid').note(
Topos is deeply inspired by the [Monome Teletype](https://monome.org/). The Teletype is/was an open source hardware module for Eurorack synthesizers. While the Teletype was initially born as an hardware module, Topos aims to be a web-browser based cousin of it! It is a sequencer, a scriptable interface, a companion for algorithmic music-making. Topos wishes to fullfill the same goal as the Teletype, keeping the same spirit alive on the web. It is free, open-source, and made to be shared and used by everyone. Learn more about live coding on [livecoding.fr](https://livecoding.fr). Topos is deeply inspired by the [Monome Teletype](https://monome.org/). The Teletype is/was an open source hardware module for Eurorack synthesizers. While the Teletype was initially born as an hardware module, Topos aims to be a web-browser based cousin of it! It is a sequencer, a scriptable interface, a companion for algorithmic music-making. Topos wishes to fullfill the same goal as the Teletype, keeping the same spirit alive on the web. It is free, open-source, and made to be shared and used by everyone. Learn more about live coding on [livecoding.fr](https://livecoding.fr).
## Alternative documentation source (.pdf) ## Demo Songs
You can also find a .pdf version listing the principal commands and functions [here](https://github.com/Bubobubobubobubo/topos/blob/main/src/documentation/basics/TOPOS_COMMANDS.pdf). This document has been generated by Chris Collis. It recaps the main sections of this documentation and can be a good companion while learning Topos. Reloading the application will get you one random song example to study every time. Press ${key_shortcut(
"F5",
)} and listen to them all! The demo songs are also used a bit everywhere in the documentation to illustrate some of the working principles :).
## Support ## Support

View File

@ -0,0 +1,28 @@
import { type Editor } from "../../../main";
import { makeExampleFactory } from "../../../Documentation";
export const pitch = (application: Editor): string => {
// @ts-ignore
const makeExample = makeExampleFactory(application);
return `# Pitch
## Pitch envelope
Similar to the amplitude envelope, you can use an envelope to shape the pitch
of your sounds (can be samples or synthesizers). This is super useful to create
new timbres out of existing sounds.
| Method | Alias | Description |
|---------|-------|-----------------------------------------------|
| <ic>pattack</ic> | patt | Attack time |
| <ic>pdecay</ic> | pdec | Decay time |
| <ic>psustain</ic> | psus | Sustain value |
| <ic>prelease</ic> | prel | Release time |
| <ic>penv</ic> | | Pitch envelope strength (positive or negative) |
| <ic>panchor</ic> | | Envelope anchor range (0 - 1) |
Resume writing the pitch documentation here.
`;
};

View File

@ -442,7 +442,7 @@ Array.prototype.scale = function(
return this.map((value) => { return this.map((value) => {
const octaveShift = Math.floor(value / selected_scale.length) * 12; const octaveShift = Math.floor(value / selected_scale.length) * 12;
return ( return (
selected_scale[mod(Math.floor(value), selected_scale.length)] + selected_scale[mod(value, selected_scale.length)] +
base_note + base_note +
octaveShift octaveShift
); );

View File

@ -213,7 +213,13 @@ export class Editor {
loadUniverserFromUrl(this); loadUniverserFromUrl(this);
// Set the color scheme for the application // Set the color scheme for the application
let available_themes = Object.keys(colors);
if (this.settings.theme in available_themes) {
this.readTheme(this.settings.theme); this.readTheme(this.settings.theme);
} else {
this.settings.theme = "Everblush";
this.readTheme(this.settings.theme);
}
this.documentationStyle = createDocumentationStyle(this); this.documentationStyle = createDocumentationStyle(this);
this.bindings = Object.keys(this.documentationStyle).map((key) => ({ this.bindings = Object.keys(this.documentationStyle).map((key) => ({

View File

@ -1461,6 +1461,31 @@
"@strudel.cycles/core" "0.8.2" "@strudel.cycles/core" "0.8.2"
nanostores "^0.8.1" nanostores "^0.8.1"
"@strudel/core@0.11.0":
version "0.11.0"
resolved "https://registry.yarnpkg.com/@strudel/core/-/core-0.11.0.tgz#65d18c513f04ab1020325be56044c34f255bc37b"
integrity sha512-7tOqsm13fsTOd9iPR7NybNN+QbkIyOR7JXpjIMRuQybkH15/NGOTAxNAbghKoesMU8/dLkR7/xVg231Ype3HMQ==
dependencies:
fraction.js "^4.3.7"
"@strudel/soundfonts@^0.11.0":
version "0.11.0"
resolved "https://registry.yarnpkg.com/@strudel/soundfonts/-/soundfonts-0.11.0.tgz#1bfcb6885fad5c07e9e81855fecb59cf55cfd865"
integrity sha512-a60Jya1d78lxr6QkEhrbmStrY/H3OneCssuzepfxG7Az1INWuqeTgJ653GcLv9v6+kpdurwAf9SvfHzx9XgbHw==
dependencies:
"@strudel/core" "0.11.0"
"@strudel/webaudio" "0.11.0"
sfumato "^0.1.2"
soundfont2 "^0.4.0"
"@strudel/webaudio@0.11.0":
version "0.11.0"
resolved "https://registry.yarnpkg.com/@strudel/webaudio/-/webaudio-0.11.0.tgz#1c595718c0bd72caec8e34ac2792ddde969e7ecf"
integrity sha512-Yqc/th969RREqmqtppXTDZKxIgKBsqEG1aJX9T8sTxvYcgGjCC3auH96TF9JtwfVE/VhTxwsxjZDiLcuXTJtCA==
dependencies:
"@strudel/core" "0.11.0"
superdough "0.10.0"
"@surma/rollup-plugin-off-main-thread@^2.2.3": "@surma/rollup-plugin-off-main-thread@^2.2.3":
version "2.2.3" version "2.2.3"
resolved "https://registry.yarnpkg.com/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz#ee34985952ca21558ab0d952f00298ad2190c053" resolved "https://registry.yarnpkg.com/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz#ee34985952ca21558ab0d952f00298ad2190c053"
@ -2257,6 +2282,11 @@ fraction.js@^4.2.0:
resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.2.0.tgz#448e5109a313a3527f5a3ab2119ec4cf0e0e2950" resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.2.0.tgz#448e5109a313a3527f5a3ab2119ec4cf0e0e2950"
integrity sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA== integrity sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==
fraction.js@^4.3.7:
version "4.3.7"
resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.3.7.tgz#06ca0085157e42fda7f9e726e79fefc4068840f7"
integrity sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==
front-matter@^4.0.0: front-matter@^4.0.0:
version "4.0.2" version "4.0.2"
resolved "https://registry.yarnpkg.com/front-matter/-/front-matter-4.0.2.tgz#b14e54dc745cfd7293484f3210d15ea4edd7f4d5" resolved "https://registry.yarnpkg.com/front-matter/-/front-matter-4.0.2.tgz#b14e54dc745cfd7293484f3210d15ea4edd7f4d5"
@ -2908,6 +2938,11 @@ nanostores@^0.8.1:
resolved "https://registry.yarnpkg.com/nanostores/-/nanostores-0.8.1.tgz#963577028ac10eeb50bec376535f4762ab5af9be" resolved "https://registry.yarnpkg.com/nanostores/-/nanostores-0.8.1.tgz#963577028ac10eeb50bec376535f4762ab5af9be"
integrity sha512-1ZCfQtII2XeFDrtqXL2cdQ/diGrLxzRB3YMyQjn8m7GSGQrJfGST2iuqMpWnS/ZlifhtjgR/SX0Jy6Uij6lRLA== integrity sha512-1ZCfQtII2XeFDrtqXL2cdQ/diGrLxzRB3YMyQjn8m7GSGQrJfGST2iuqMpWnS/ZlifhtjgR/SX0Jy6Uij6lRLA==
nanostores@^0.9.5:
version "0.9.5"
resolved "https://registry.yarnpkg.com/nanostores/-/nanostores-0.9.5.tgz#4fcfce9786c4bf16e045a899cda2e46e90780a5b"
integrity sha512-Z+p+g8E7yzaWwOe5gEUB2Ox0rCEeXWYIZWmYvw/ajNYX8DlXdMvMDj8DWfM/subqPAcsf8l8Td4iAwO1DeIIRQ==
node-addon-api@^5.0.0: node-addon-api@^5.0.0:
version "5.1.0" version "5.1.0"
resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-5.1.0.tgz#49da1ca055e109a23d537e9de43c09cca21eb762" resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-5.1.0.tgz#49da1ca055e109a23d537e9de43c09cca21eb762"
@ -3304,6 +3339,13 @@ set-function-name@^2.0.0:
functions-have-names "^1.2.3" functions-have-names "^1.2.3"
has-property-descriptors "^1.0.0" has-property-descriptors "^1.0.0"
sfumato@^0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/sfumato/-/sfumato-0.1.2.tgz#d24cd491456dc3b3e4a3237a457b800b681b4387"
integrity sha512-j2s5BLUS5VUNtaK1l+v+yal3XjjV7JXCQIwE5Xs4yiQ3HJ+2Fc/dd3IkkrVHn0AJO2epShSWVoP3GnE0TvPdMg==
dependencies:
soundfont2 "^0.4.0"
showdown-highlight@^3.1.0: showdown-highlight@^3.1.0:
version "3.1.0" version "3.1.0"
resolved "https://registry.yarnpkg.com/showdown-highlight/-/showdown-highlight-3.1.0.tgz#c9ec902c35100e1ac3433761cdb655810120f1e5" resolved "https://registry.yarnpkg.com/showdown-highlight/-/showdown-highlight-3.1.0.tgz#c9ec902c35100e1ac3433761cdb655810120f1e5"
@ -3334,6 +3376,11 @@ slip@1.0.2:
resolved "https://registry.yarnpkg.com/slip/-/slip-1.0.2.tgz#ba45a923034d6cf41b1a27aebe7128282c8d551f" resolved "https://registry.yarnpkg.com/slip/-/slip-1.0.2.tgz#ba45a923034d6cf41b1a27aebe7128282c8d551f"
integrity sha512-XrcHe3NAcyD3wO+O4I13RcS4/3AF+S9RvGNj9JhJeS02HyImwD2E3QWLrmn9hBfL+fB6yapagwxRkeyYzhk98g== integrity sha512-XrcHe3NAcyD3wO+O4I13RcS4/3AF+S9RvGNj9JhJeS02HyImwD2E3QWLrmn9hBfL+fB6yapagwxRkeyYzhk98g==
soundfont2@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/soundfont2/-/soundfont2-0.4.0.tgz#a1efd642f2ae247a5530cd530ae364a095126be5"
integrity sha512-537WiurDBRbDLVhJMxXLE06D6yWxJCidfPClnibZ0f8dKMDpv+0fIfwCQ8pELE0JqKX05SOJosNJgKzQobaAEA==
source-map-js@^1.0.2: source-map-js@^1.0.2:
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
@ -3460,12 +3507,12 @@ sucrase@^3.32.0:
pirates "^4.0.1" pirates "^4.0.1"
ts-interface-checker "^0.1.9" ts-interface-checker "^0.1.9"
superdough@^0.9.12: superdough@0.10.0, superdough@^0.10.0:
version "0.9.12" version "0.10.0"
resolved "https://registry.yarnpkg.com/superdough/-/superdough-0.9.12.tgz#455f8860bc13cffbe1d8f391919e8f1dba1ff0b5" resolved "https://registry.yarnpkg.com/superdough/-/superdough-0.10.0.tgz#06b027b16f54473f0281fcb0adcc1177d07d6e96"
integrity sha512-rsdCoYk5rLYster4tE5mSGjotf/TNP3gPpsuK4hxTZNxL92TkdEcbPFLnJfky5oMQJtpRY1XqAXUx3htLbHEZA== integrity sha512-VMSUyKqTJumAd28I2rN5L8pTbzlp7Vsszri2BHlYipZ4vXO/B88cMjqtLqsCP4KaoARsput0kMXbpZ9JhjWbYQ==
dependencies: dependencies:
nanostores "^0.8.1" nanostores "^0.9.5"
supports-color@^5.3.0: supports-color@^5.3.0:
version "5.5.0" version "5.5.0"