From 6aa3545cea45626cc5d6dd840cf3a8183f3d015f Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Mon, 28 Aug 2023 20:31:54 +0200 Subject: [PATCH 1/5] cool ziffers examples --- src/Documentation.ts | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/Documentation.ts b/src/Documentation.ts index c6a32fe..fee1c27 100644 --- a/src/Documentation.ts +++ b/src/Documentation.ts @@ -1215,9 +1215,28 @@ ${makeExample( Ziffers provides shorthands for **many** numeric and algorithimic operations such as evaluating random numbers and creating sequences using list operations: -* **List operations:** (3 2 1)+(2 5) Cartesian operation using + operator (All javascript operators supported). +* **List operations:** Cartesian operation (_e.g._ (3 2 1)+(2 5)) using the + operator. All the arithmetic operators are supported. + +${makeExample( + "Cartesian operation for melodic generation", +` +z1("q 0 s (3 2 1)+(2 5) q 0 s (4 5 6)-(2 3)").sound('sine') + .scale('minor').fmi(2).fmh(2).room(0.5).size(0.5).sustain(0.1) + .delay(0.5).delay(0.125).delayfb(0.25).out(); +`, true)} + * **Random numbers:** (4,6) Random number between 4 and 6 +${makeExample( + "Random numbers, true computer music at last!", +` +z1("s (0,8) 0 0 (0,5) 0 0").sound('sine') + .scale('minor').fmi(2).fmh(2).room(0.5) + .size(0.5).sustain(0.1) .delay(0.5) + .delay(0.125).delayfb(0.25).out(); +mod(.5) :: snd(['kick', 'hat'].div(.5)).out() +`, true)} + ## Keys and scales Ziffers supports all the keys and scales. Keys can be defined by using [scientific pitch notation](https://en.wikipedia.org/wiki/Scientific_pitch_notation), for example F3. Western style (1490 scales) can be with scale names named after greek modes and extended by [William Zeitler](https://ianring.com/musictheory/scales/traditions/zeitler). You will never really run out of scales to play with using Ziffers. Here is a short list of some possible scales that you can play with: @@ -1234,6 +1253,8 @@ Ziffers supports all the keys and scales. Keys can be defined by using [scientif | Soryllic | 11122122| | Modimic | 412122 | | Ionalian   | 1312122 | +| ... | And it goes on for **1490** scales | + From db660e93081e63540bb12d8d5268c37879480929 Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Mon, 28 Aug 2023 20:39:03 +0200 Subject: [PATCH 2/5] some more things --- src/Documentation.ts | 53 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 44 insertions(+), 9 deletions(-) diff --git a/src/Documentation.ts b/src/Documentation.ts index fee1c27..1f43352 100644 --- a/src/Documentation.ts +++ b/src/Documentation.ts @@ -1255,6 +1255,17 @@ Ziffers supports all the keys and scales. Keys can be defined by using [scientif | Ionalian   | 1312122 | | ... | And it goes on for **1490** scales | +${makeExample( + "What the hell is the Modimic scale?", +` +z1("s (0,8) 0 0 (0,5) 0 0").sound('sine') + .scale('modimic').fmi(2).fmh(2).room(0.5) + .size(0.5).sustain(0.1) .delay(0.5) + .delay(0.125).delayfb(0.25).out(); +mod(.5) :: snd(['kick', 'hat'].div(.5)).out() +`, true)} + + @@ -1274,23 +1285,37 @@ You can also use more traditional Scala format or by extended notation defined by Sevish Scale workshop, for example: - **Young:** 106. 198. 306.2 400.1 502. 604. 697.9 806.1 898.1 1004.1 1102. 1200. - **Wendy carlos:** 17/16 9/8 6/5 5/4 4/3 11/8 3/2 13/8 5/3 7/4 15/8 2/1 -## Methods -Ziffers numbered methods **(z0-z16)** can be used to parse and play patterns. Each method is individually cached and can be used to play patterns simultaniously. +${makeExample( + "Wendy Carlos, here we go!", +` +z1("s ^ (0,8) 0 0 _ (0,5) 0 0").sound('sine') + .scale('17/16 9/8 6/5 5/4 4/3 11/8 3/2 13/8 5/3 7/4 15/8 2/1').fmi(2).fmh(2).room(0.5) + .size(0.5).sustain(0.15).delay(0.1) + .delay(0.25).delayfb(0.5).out(); +mod(1, 1.75) :: snd(['kick', 'hat'].div(1)).out() +`, true)} -## Chaining and options +## Synchronization + +Ziffers numbered methods **(z0-z16)** can be used to parse and play patterns. Each method is individually cached and can be used to play multiple patterns simultaneously. They can be synchronized together by using a **cue** system. By default, each Ziffers expression will have a different duration. This system is thus necessary to make everything fit together in a loop-based environment like Topos. -Ziffers patterns can be chained to sound() and midi() to produce different outputs. Chaining is often alternative for passing in options, which can be more efficient. Methods available for chaining are: -* key() - for changing key -* scale() - for chaning scale -* octave() - for changing octave -* sound() - for outputting pattern as sounds (See Sound) -* midi() - for outputting pattern as midi (See Midi) ## Examples @@ -1756,6 +1781,16 @@ Topos is made to be controlled entirely with a keyboard. It is recommanded to st const chaining: string = ` # Chaining + +## Ziffers +Ziffers patterns can be chained to sound() and midi() to produce different outputs. Chaining is often alternative for passing in options, which can be more efficient. Methods available for chaining are: +* key() - for changing key +* scale() - for chaning scale +* octave() - for changing octave +* sound() - for outputting pattern as sounds (See Sound) +* midi() - for outputting pattern as midi (See Midi) + + `; return { From 4fdd69c2816b26ce3cc78ee62045a0ebea1e5b2d Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Mon, 28 Aug 2023 20:45:21 +0200 Subject: [PATCH 3/5] do not erase the welcome universe entirely, only global file --- src/main.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main.ts b/src/main.ts index 9ffed1c..f71fe60 100644 --- a/src/main.ts +++ b/src/main.ts @@ -192,9 +192,11 @@ export class Editor { // Loading the universe from local storage // ================================================================================ - this.universes = { ...template_universes, ...this.settings.universes }; + this.universes = { ...this.settings.universes, ...template_universes }; this.selected_universe = "Welcome"; this.universe_viewer.innerHTML = `Topos: ${this.selected_universe}`; + + // Picking a random example to populate the landing page let random_example = examples[Math.floor(Math.random() * examples.length)]; this.universes[this.selected_universe].global.committed = random_example; this.universes[this.selected_universe].global.candidate = random_example; From 5725ff3d92dd4e46895ee17e385c945b1e707a3c Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Mon, 28 Aug 2023 21:10:05 +0200 Subject: [PATCH 4/5] beginning midi refactor --- src/Documentation.ts | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/Documentation.ts b/src/Documentation.ts index 1f43352..0db17c9 100644 --- a/src/Documentation.ts +++ b/src/Documentation.ts @@ -572,9 +572,23 @@ if((bar() % 4) > 1) { const midi: string = ` # MIDI - + You can use Topos to play MIDI thanks to the [WebMIDI API](https://developer.mozilla.org/en-US/docs/Web/API/Web_MIDI_API). You can currently send notes, control change, program change and so on. You can also send a MIDI Clock to your MIDI devices or favorite DAW. Note that Topos is also capable of playing MIDI using **Ziffers** which provides a better syntax for melodic expression. - + +**Important note:** for the examples on this page to work properly, you will need to configure your web browser to output **MIDI** on the right port. You will also need to make sure to have a synthesizer ready to receive MIDI data (hardware or software). You can use softwares like [VCVRack](https://vcvrack.com/), [Dexed](https://asb2m10.github.io/dexed/), [Surge](https://surge-synthesizer.github.io/) or [SunVox](https://www.warmplace.ru/soft/sunvox/) to get enough instruments for a lifetime. + +## MIDI Configuration + +Your web browser is capable of sending and receiving MIDI information through the [Web MIDI API](https://developer.mozilla.org/en-US/docs/Web/API/Web_MIDI_API). The support for MIDI on browsers is a bit shaky. Please, take some time to configure and test. To our best knowledge, **Chrome** is currently leading on this feature, followed closely by **Firefox**. The other major web browsers are also starting to support this API. **There are two important functions for configuration:** + +- midi_outputs(): prints the list of available MIDI devices to the web console. You will have to open the web console using ${key_shortcut("Ctrl+Shift+I")} or sometimes ${key_shortcut("F12")}. You can also open it from the menu of your web browser. + +${makeExample( + "Listing MIDI outputs", +` +log(midi_outputs()) +`, true)} + ## Notes - midi(note: number|object): send a MIDI Note. Object can take parameters {note: number, channel: number, port: number|string, velocity: number}. From a772f9665941e1aa97cff2a7690957c19e01c433 Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Mon, 28 Aug 2023 21:18:15 +0200 Subject: [PATCH 5/5] first version of the print on screen thingie --- src/API.ts | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/API.ts b/src/API.ts index e63cf0a..b0383a1 100644 --- a/src/API.ts +++ b/src/API.ts @@ -49,6 +49,8 @@ export class UserAPI { public localSeeds = new Map(); public patternCache = new LRUCache({ max: 1000, ttl: 1000 * 60 * 5 }); private errorTimeoutID: number = 0; + private printTimeoutID: number = 0; + MidiConnection: MidiConnection = new MidiConnection(); load: samples; @@ -94,7 +96,9 @@ export class UserAPI { _reportError = (error: any): void => { console.log(error); clearTimeout(this.errorTimeoutID); + clearTimeout(this.printTimeoutID); this.app.error_line.innerHTML = error as string; + this.app.error_line.style.color = "color-red-800"; this.app.error_line.classList.remove("hidden"); this.errorTimeoutID = setTimeout( () => this.app.error_line.classList.add("hidden"), @@ -102,6 +106,19 @@ export class UserAPI { ); }; + _logMessage = (message: any): void => { + console.log(message); + clearTimeout(this.errorTimeoutID); + clearTimeout(this.printTimeoutID); + this.app.error_line.innerHTML = message as string; + this.app.error_line.style.color = "color-white"; + this.app.error_line.classList.remove("hidden"); + this.printTimeoutID = setTimeout( + () => this.app.error_line.classList.add("hidden"), + 4000 + ); + }; + // ============================================================= // Time functions // ============================================================= @@ -223,7 +240,7 @@ export class UserAPI { * * @returns A list of available MIDI outputs */ - console.log(this.MidiConnection.listMidiOutputs()); + this._logMessage(this.MidiConnection.listMidiOutputs()); return this.MidiConnection.midiOutputs; }; @@ -1260,7 +1277,10 @@ export class UserAPI { snd = this.sound; samples = samples; - log = console.log; + log = (message: any) => { + console.log(message); + this._logMessage(message); + } scale = scale;