From cb12c4d8cc0b0c1e3633a0f46ac064eaf270f73e Mon Sep 17 00:00:00 2001 From: Miika Alonen Date: Mon, 28 Aug 2023 17:19:27 +0300 Subject: [PATCH] Documenting ziffers --- index.html | 1 + src/Documentation.ts | 122 ++++++++++++++++++++++++++++++++++++++ src/classes/MidiEvent.ts | 17 +++--- src/classes/SoundEvent.ts | 16 ++--- src/classes/ZPlayer.ts | 4 +- src/main.ts | 3 +- 6 files changed, 142 insertions(+), 21 deletions(-) diff --git a/index.html b/index.html index 53d366b..edf4918 100644 --- a/index.html +++ b/index.html @@ -120,6 +120,7 @@

Samples

Synths

Patterns

+

Ziffers

MIDI

Functions

Shortcuts

diff --git a/src/Documentation.ts b/src/Documentation.ts index 1a2af7c..eca95a4 100644 --- a/src/Documentation.ts +++ b/src/Documentation.ts @@ -1057,6 +1057,127 @@ mod(1)::snd('sine').sustain(0.1).freq([100,100,100,100,200].unique().beat()).out `; +const ziffers: string = ` +# Ziffers + +Ziffers is a musical number based notation developed especially for live coding. It is a very powerful and flexibly notation for describing musical patterns in a short string. + +## Notation + +Basic notation consists of numbers and letters using spaces as separators. + +**Pitches:** Single digits 0-9 or multiple digits escaped {10 11 21} +**Durations:** a-z or decimals: 0.25 = q (quarter), 0.5 = h (half), 1 = w (whole), etc. +**Octave:** ^ _ (up and down) +**Accidentals:** # b +**Rest:** r + +NOTE! Some of the features are still unsupported. For full syntax see article on Ziffers. + +## Keys and scales + +Ziffers supports all the keys and scales. Keys can be defined by using scientific pitch notation, for example 'F3'. Western style (1490 scales) can be used with the scale named named after greek modes and extended by William Zeitler (see full list): + +* Lydian +* Mixolydian +* Aeolian +* Locrian +* Ionian +* Dorian +* Phrygian +* Soryllic +* Modimic +* Ionalian +* ... + +or by most traditional western names: + +* Major +* Minor +* Minor pentatonic +* Major pentatonic +* Harmonic minor +* Harmonic major +* Melodic minor +* Melodic major +* Whole +* Blues minor +* Blues major +* ... + +Microtonal scales can be defined using 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. + +## Chaining and options + +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 + +- Basic notation + +${makeExample( + "Simple method chaining", + ` +z1('0 1 2 3').key('G3').scale('minor').sound('sine').out() +`, + true +)} + +${makeExample( + "More complex chaining", + ` +z1('0 1 2 3 4').key('G3').scale('minor').sound('sine').often(n => n.pitch+=3).rarely(s => s.delay(0.5)).out() +`, + true +)} + +${makeExample( + "Simple options", + ` +z1('0 3 2 4',{key: 'D3', scale: 'minor pentatonic'}).sound('sine').out() +`, + true +)} + +${makeExample( + "Duration chars", + ` +z1('s 0 e 1 q 2 h 3 w 4').sound('sine').scale("locrian").out() +`, + true +)} + +${makeExample( + "Decimal durations", + ` +z1('0.25 5 1 2 6 0.125 3 8 0.5 4 1.0 0').sound('sine').scale("ionian").out() +`, + true +)} + +${makeExample( + "Rest and octaves", + ` +z1('q 0 ^ e0 r _ 0 _ r 4 ^4 4').sound('sine').scale("ionian").out() +`, + true +)} + +`; + + const synths: string = ` # Synthesizers @@ -1418,6 +1539,7 @@ Topos is made to be controlled entirely with a keyboard. It is recommanded to st samples: samples, synths: synths, patterns: patterns, + ziffers: ziffers, midi: midi, functions: functions, reference: reference, diff --git a/src/classes/MidiEvent.ts b/src/classes/MidiEvent.ts index 6fdfa15..eed14af 100644 --- a/src/classes/MidiEvent.ts +++ b/src/classes/MidiEvent.ts @@ -42,10 +42,10 @@ export class NoteEvent extends AudibleEvent { const funcResult = func(this); if(funcResult instanceof Object) { return funcResult; - } else { func(this.values); + this.update(); return this; } } @@ -63,12 +63,15 @@ export class NoteEvent extends AudibleEvent { } update = (): void => { - if(this.values.key && this.values.pitch && this.values.parsedScale && this.values.octave) { - const [note,bend] = noteFromPc(this.values.key, this.values.pitch, this.values.parsedScale, this.values.octave); - this.values.note = note; - this.values.freq = midiToFreq(note); - if(bend) this.values.bend = bend; - } + const [note, bend] = noteFromPc( + this.values.key || "C4", + this.values.pitch || 0, + this.values.parsedScale || "MAJOR", + this.values.octave || 0 + ); + this.values.note = note; + this.values.freq = midiToFreq(note); + if(bend) this.values.bend = bend; } out = (): void => { diff --git a/src/classes/SoundEvent.ts b/src/classes/SoundEvent.ts index 5ca34e5..4daff76 100644 --- a/src/classes/SoundEvent.ts +++ b/src/classes/SoundEvent.ts @@ -225,6 +225,7 @@ export class SoundEvent extends AudibleEvent { if (funcResult instanceof Object) return funcResult; else { func(this.values); + this.update(); return this; } }; @@ -237,20 +238,13 @@ export class SoundEvent extends AudibleEvent { sus = this.sustain; update = (): void => { - if ( - this.values.key && - this.values.pitch && - this.values.parsedScale && - this.values.octave - ) { const [note, _] = noteFromPc( - this.values.key, - this.values.pitch, - this.values.parsedScale, - this.values.octave + this.values.key || "C4", + this.values.pitch || 0, + this.values.parsedScale || "MAJOR", + this.values.octave || 0 ); this.values.freq = midiToFreq(note); - } }; out = (): object => { diff --git a/src/classes/ZPlayer.ts b/src/classes/ZPlayer.ts index 9643f4f..c7d0506 100644 --- a/src/classes/ZPlayer.ts +++ b/src/classes/ZPlayer.ts @@ -124,7 +124,7 @@ export class Player extends Event { if(this.areWeThereYet()) { const event = this.next() as Pitch|Chord|ZRest; if(event instanceof Pitch) { - const obj = event.getExisting("freq","pitch","key","scale","octave"); + const obj = event.getExisting("freq","pitch","key","scale","octave","parsedScale"); return new SoundEvent(obj, this.app).sound(name); } else if(event instanceof ZRest) { return RestEvent.createRestProxy(event.duration, this.app); @@ -138,7 +138,7 @@ export class Player extends Event { if(this.areWeThereYet()) { const event = this.next() as Pitch|Chord|ZRest; if(event instanceof Pitch) { - const obj = event.getExisting("note","pitch","bend","key","scale","octave"); + const obj = event.getExisting("note","pitch","bend","key","scale","octave","parsedScale"); const note = new NoteEvent(obj, this.app); return value ? note.note(value) : note; } else if(event instanceof ZRest) { diff --git a/src/main.ts b/src/main.ts index d180bff..18f059c 100644 --- a/src/main.ts +++ b/src/main.ts @@ -565,6 +565,7 @@ export class Editor { "samples", "synths", "patterns", + "ziffers", "midi", "functions", "reference", @@ -989,5 +990,5 @@ window.addEventListener("beforeunload", () => { // app._mouseY = event.clientY; // } -onmousemove = function(e){console.log("mouse location:", e.clientX, e.clientY)} +// onmousemove = function(e){console.log("mouse location:", e.clientX, e.clientY)}