17 Commits

Author SHA1 Message Date
dea8808721 Bump ws from 8.14.2 to 8.17.1 in /ToposServer
Bumps [ws](https://github.com/websockets/ws) from 8.14.2 to 8.17.1.
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/8.14.2...8.17.1)

---
updated-dependencies:
- dependency-name: ws
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-21 15:57:40 +00:00
aa2eb0651d Merge pull request #129 from MartinDelille/patch-1
Add missing out()
2024-03-29 11:13:44 +01:00
ec68419775 Add missing out() 2024-03-16 20:18:51 +01:00
cf702fd9f1 Rogue import 2024-03-06 11:34:22 +01:00
5e565e3a11 Remove demo songs mechanism 2024-03-06 11:32:54 +01:00
d9906857d3 Fix theme defaulting to Everblush 2024-03-06 11:23:06 +01:00
e592499711 Atelier : document final 2024-03-05 16:26:22 +01:00
c13d1bb072 Add temporary workshop documentation 2024-03-05 15:59:19 +01:00
d2f9376197 Merge branch 'main' of github.com:Bubobubobubobubo/Topos 2024-02-28 12:14:58 +01:00
8940bf3505 Fix: Cast numbers to int with .scale function 2024-02-28 12:14:49 +01:00
9d7fe9e815 Merge pull request #128 from ChrisCollis/main
Added theme -  theotteryears2
2024-02-24 16:16:14 +01:00
59dc42b103 Added themes - theotteryears and theotteryears2 2024-02-24 15:11:04 +00:00
47534a0724 Addition: color theme theotteryears 2024-02-24 12:22:45 +01:00
a36aa53e04 fix again 2024-02-23 10:03:42 +01:00
4db41275b4 Fix : .pdf path 2024-02-23 09:58:45 +01:00
8b10af555c Addition : listing .pdf as alternative source 2024-02-23 09:55:01 +01:00
2ee66cd9fb Addition: adding the negative euclidean rhythm function 2024-02-19 16:12:34 +01:00
13 changed files with 7531 additions and 7281 deletions

View File

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

View File

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

View File

@ -174,6 +174,7 @@
<summary class="font-semibold lg:text-xl text-orange-300">Basics</summary>
<div class="flex flex-col">
<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_interaction" class="doc_header">Interaction</p>
<p rel="noopener noreferrer" id="docs_shortcuts" class="doc_header">Keyboard</p>
@ -367,10 +368,12 @@
<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>
</div>
<!--
<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">
<label for="default-checkbox" class="ml-2 text-sm font-medium text-foreground">Load Demo Song</label>
</div>
-->
</div>
</div>

View File

@ -1602,6 +1602,20 @@ export class UserAPI {
};
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(
pulses: number,
length: number,

View File

@ -1,6 +1,7 @@
import { type Editor } from "./main";
// Basics
import { introduction } from "./documentation/basics/welcome";
import { atelier } from "./documentation/basics/atelier";
import { loading_samples } from "./documentation/learning/samples/loading_samples";
import { amplitude } from "./documentation/learning/audio_engine/amplitude";
import { effects } from "./documentation/learning/audio_engine/effects";
@ -77,6 +78,7 @@ export const makeExampleFactory = (application: Editor): Function => {
export const documentation_pages = [
"introduction",
"atelier",
"sampler",
"amplitude",
"audio_basics",
@ -126,6 +128,7 @@ export const documentation_factory = (application: Editor) => {
return {
introduction: introduction(application),
atelier: atelier(application),
interface: software_interface(application),
interaction: interaction(application),
code: code(application),
@ -223,7 +226,7 @@ export const updateDocumentationContent = (app: Editor, bindings: any) => {
}), ...bindings],
});
if(Object.keys(app.docs).length === 0) {
if (Object.keys(app.docs).length === 0) {
app.docs = documentation_factory(app);
}
@ -233,7 +236,7 @@ export const updateDocumentationContent = (app: Editor, bindings: any) => {
);
callback(converted_markdown)
}
_update_and_assign((e: string)=> {
_update_and_assign((e: string) => {
let display_content = e === undefined ? loading_message : e;
document.getElementById("documentation-content")!.innerHTML = display_content;
})

View File

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

View File

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

View File

@ -1,4 +1,50 @@
{
"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": {
"black": "#252525",
"color1": "#832e31",

Binary file not shown.

View File

@ -0,0 +1,193 @@
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

@ -15,7 +15,7 @@ ${makeExample(
"Welcome! Eval to get started",
examples[Math.floor(Math.random() * examples.length)],
true,
)}
)}
# What is Topos?
@ -31,7 +31,7 @@ rhythm(.25, [5, 7].beat(2), 8) :: sound(['hc', 'fikea', 'hat'].pick(1))
beat([2,0.5].dur(13.5, 0.5))::snd('fsoftsnare')
.n(0).speed([1, 0.5]).o(4).out()`,
false,
)}
)}
${makeExample(
"Computer music should be immediate and intuitive",
@ -48,7 +48,7 @@ beat(.25)::snd('sine')
.room(0.5).size(8) // Reverb
.out()`,
false,
)}
)}
${makeExample(
"Making the web less dreadful, one beep at at time",
@ -59,15 +59,13 @@ beat(.25) :: sound('sid').note(
[34, 36, 41].beat(.25) + [[0,-24].pick(),12].beat())
.room(0.9).size(0.9).n(4).out()`,
false,
)}
)}
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).
## Demo Songs
## Alternative documentation source (.pdf)
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 :).
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.
## Support

View File

@ -1,6 +1,6 @@
import { type UserAPI } from "../API";
import { safeScale, stepsToScale } from "zifferjs";
export {};
export { };
declare global {
interface Array<T> {
@ -60,14 +60,14 @@ export const makeArrayExtensions = (api: UserAPI) => {
return this[zoneIndex];
};
Array.prototype.square = function (): number[] {
Array.prototype.square = function(): number[] {
/**
* @returns New array with squared values.
*/
return this.map((x: number) => x * x);
};
Array.prototype.sometimes = function (func: Function): number[] {
Array.prototype.sometimes = function(func: Function): number[] {
if (api.randomGen() < 0.5) {
return func(this);
} else {
@ -75,11 +75,11 @@ export const makeArrayExtensions = (api: UserAPI) => {
}
};
Array.prototype.apply = function (func: Function): number[] {
Array.prototype.apply = function(func: Function): number[] {
return func(this);
};
Array.prototype.sqrt = function (): number[] {
Array.prototype.sqrt = function(): number[] {
/**
* @returns New array with square roots of values. Throws if any element is negative.
*/
@ -88,7 +88,7 @@ export const makeArrayExtensions = (api: UserAPI) => {
return this.map((x: number) => Math.sqrt(x));
};
Array.prototype.add = function (amount: number): number[] {
Array.prototype.add = function(amount: number): number[] {
/**
* @param amount - The value to add to each element in the array.
* @returns New array with added values.
@ -96,7 +96,7 @@ export const makeArrayExtensions = (api: UserAPI) => {
return this.map((x: number) => x + amount);
};
Array.prototype.sub = function (amount: number): number[] {
Array.prototype.sub = function(amount: number): number[] {
/**
* @param amount - The value to subtract from each element in the array.
* @returns New array with subtracted values.
@ -104,7 +104,7 @@ export const makeArrayExtensions = (api: UserAPI) => {
return this.map((x: number) => x - amount);
};
Array.prototype.mult = function (amount: number): number[] {
Array.prototype.mult = function(amount: number): number[] {
/**
* @param amount - The value to multiply with each element in the array.
* @returns New array with multiplied values.
@ -112,7 +112,7 @@ export const makeArrayExtensions = (api: UserAPI) => {
return this.map((x: number) => x * amount);
};
Array.prototype.div = function (amount: number): number[] {
Array.prototype.div = function(amount: number): number[] {
/**
* @param amount - The value to divide each element in the array by.
* @returns New array with divided values. Throws if division by zero.
@ -121,7 +121,7 @@ export const makeArrayExtensions = (api: UserAPI) => {
return this.map((x: number) => x / amount);
};
Array.prototype.pick = function () {
Array.prototype.pick = function() {
/**
* Returns a random element from an array.
*
@ -130,7 +130,7 @@ export const makeArrayExtensions = (api: UserAPI) => {
return this[Math.floor(api.randomGen() * this.length)];
};
Array.prototype.gen = function (min: number, max: number, times: number) {
Array.prototype.gen = function(min: number, max: number, times: number) {
/**
* Returns an array of random numbers.
* @param min - The minimum value of the random numbers
@ -147,7 +147,7 @@ export const makeArrayExtensions = (api: UserAPI) => {
);
};
Array.prototype.bar = function (value: number = 1) {
Array.prototype.bar = function(value: number = 1) {
/**
* Returns an element from an array based on the current bar.
*
@ -162,7 +162,7 @@ export const makeArrayExtensions = (api: UserAPI) => {
}
};
Array.prototype.beat = function (divisor: number = 1) {
Array.prototype.beat = function(divisor: number = 1) {
const chunk_size = divisor; // Get the first argument (chunk size)
const timepos = api.app.clock.pulses_since_origin;
const slice_count = Math.floor(
@ -172,7 +172,7 @@ export const makeArrayExtensions = (api: UserAPI) => {
};
Array.prototype.b = Array.prototype.beat;
Array.prototype.dur = function (...durations: number[]) {
Array.prototype.dur = function(...durations: number[]) {
const timepos = api.app.clock.pulses_since_origin;
const ppqn = api.ppqn();
const adjustedDurations: number[] = this.map(
@ -195,7 +195,7 @@ export const makeArrayExtensions = (api: UserAPI) => {
throw new Error("Durations array does not match the pattern length.");
};
Array.prototype.shuffle = function () {
Array.prototype.shuffle = function() {
/**
* Shuffles the array in place.
*
@ -214,7 +214,7 @@ export const makeArrayExtensions = (api: UserAPI) => {
return this;
};
Array.prototype.rotate = function (steps: number) {
Array.prototype.rotate = function(steps: number) {
/**
* Rotates the array in place.
*
@ -234,7 +234,7 @@ export const makeArrayExtensions = (api: UserAPI) => {
return this;
};
Array.prototype.unique = function () {
Array.prototype.unique = function() {
/**
* Removes duplicate elements from the array in place.
*
@ -267,7 +267,7 @@ export const makeArrayExtensions = (api: UserAPI) => {
if (this.length <= 1) {
return this;
}
for (let i = 0; i < this.length; ) {
for (let i = 0; i < this.length;) {
const rand = api.randomGen() * 100;
if (rand < amount) {
if (this.length > 1) {
@ -380,7 +380,7 @@ export const makeArrayExtensions = (api: UserAPI) => {
return left_to_right.concat(right_to_left);
};
Array.prototype.loop = function (index: number) {
Array.prototype.loop = function(index: number) {
/**
* Returns an element from the array based on the index.
* The index will wrap over the array.
@ -391,7 +391,7 @@ export const makeArrayExtensions = (api: UserAPI) => {
return this[index % this.length];
};
Array.prototype.random = function () {
Array.prototype.random = function() {
/**
* Returns a random element from the array.
*
@ -410,10 +410,10 @@ export const makeArrayExtensions = (api: UserAPI) => {
*
* @returns the shifted array
*/
const idx = api.counter(name,limit,step);
if(limit) {
const idx = api.counter(name, limit, step);
if (limit) {
return this[idx % this.length];
} else if(idx < this.length) {
} else if (idx < this.length) {
return this[idx];
} else {
return this[this.length - 1];
@ -425,7 +425,7 @@ export const makeArrayExtensions = (api: UserAPI) => {
Array.prototype.scale = function (
Array.prototype.scale = function(
scale: string = "major",
base_note: number = 0,
) {
@ -442,14 +442,14 @@ Array.prototype.scale = function (
return this.map((value) => {
const octaveShift = Math.floor(value / selected_scale.length) * 12;
return (
selected_scale[mod(value, selected_scale.length)] +
selected_scale[mod(Math.floor(value), selected_scale.length)] +
base_note +
octaveShift
);
});
};
Array.prototype.scaleArp = function (
Array.prototype.scaleArp = function(
scaleName: string = "major",
boundary: number = 0,
) {

View File

@ -213,13 +213,7 @@ export class Editor {
loadUniverserFromUrl(this);
// 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);
} else {
this.settings.theme = "Everblush";
this.readTheme(this.settings.theme);
}
this.documentationStyle = createDocumentationStyle(this);
this.bindings = Object.keys(this.documentationStyle).map((key) => ({