From df025751fc2baeb69075debd73675f78ebf91c7c Mon Sep 17 00:00:00 2001 From: Miika Alonen Date: Sat, 30 Dec 2023 13:46:19 +0200 Subject: [PATCH] More tonnetz traversing methods and documentation --- package.json | 2 +- src/classes/ZPlayer.ts | 26 +++++++++- .../patterns/ziffers/ziffers_algorithmic.ts | 6 ++- .../patterns/ziffers/ziffers_tonnetz.ts | 52 +++++++++++++++---- yarn.lock | 8 +-- 5 files changed, 77 insertions(+), 17 deletions(-) diff --git a/package.json b/package.json index c80c19f..2a052fe 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ "tone": "^14.8.49", "unique-names-generator": "^4.7.1", "vite-plugin-markdown": "^2.1.0", - "zifferjs": "^0.0.59", + "zifferjs": "^0.0.60", "zyklus": "^0.1.4", "zzfx": "^1.2.0" } diff --git a/src/classes/ZPlayer.ts b/src/classes/ZPlayer.ts index 9ff4d0e..442355f 100644 --- a/src/classes/ZPlayer.ts +++ b/src/classes/ZPlayer.ts @@ -362,6 +362,25 @@ export class Player extends AbstractEvent { if (this.atTheBeginning()) this.ziffers.powerTowers(tonnetz, repeats); return this; } + powerTower = this.powerTowers; + + octaTower(tonnetz: TonnetzSpaces = [3, 4, 5], repeats: number = 3) { + if (this.atTheBeginning()) this.ziffers.octaTower(tonnetz, repeats); + return this; + } + octaTowers = this.octaTower; + + borentzRegions(tonnetz: TonnetzSpaces = [3, 4, 5]) { + if (this.atTheBeginning()) this.ziffers.borentzRegions(tonnetz); + return this; + } + borentz = this.borentzRegions; + + weitzmannRegions(tonnetz: TonnetzSpaces = [3, 4, 5]) { + if (this.atTheBeginning()) this.ziffers.weitzmannRegions(tonnetz); + return this; + } + weitzmann = this.weitzmannRegions; shuffle() { if (this.atTheBeginning()) this.ziffers.shuffle(); @@ -388,13 +407,18 @@ export class Player extends AbstractEvent { return this; } + at(value: number, ...rest: number[]) { + if (this.atTheBeginning()) this.ziffers.at(value, ...rest); + return this; + } + keep() { this.ziffers.setRedo(0); return this; } repeat(amount: number) { - this.ziffers.setRedo(amount); + this.ziffers.setRedo(amount < 0 ? 0 : amount); return this; } diff --git a/src/documentation/patterns/ziffers/ziffers_algorithmic.ts b/src/documentation/patterns/ziffers/ziffers_algorithmic.ts index a1559ba..c427cc0 100644 --- a/src/documentation/patterns/ziffers/ziffers_algorithmic.ts +++ b/src/documentation/patterns/ziffers/ziffers_algorithmic.ts @@ -8,7 +8,7 @@ export const ziffers_algorithmic = (application: Editor): string => { Ziffers provides shorthands for **many** numeric and algorithimic operations such as evaluating random numbers and creating sequences using list operations: - * **List operations:** Cartesian operation (_e.g._ (3 2 1)+(2 5)) using the + operator. All the arithmetic operators are supported. + * **List operations:** Element-wise operation (_e.g._ (3 2 1)+(2 5)) using the + operator. All the arithmetic operators are supported. ${makeExample( "Element-wise operations for melodic generation", @@ -80,8 +80,10 @@ z1("s A=(0 (1,4)) B~(2 (3,8)) A B A B A") ## Generative functions + * at(index: number, ...args?: number[]) Get event(s) at given index * repeat(amount: number) Repeat the generated pattern without re-evaluating random patterns - * shuffle() Shuffle the generated pattern + * keep() Keep the generated pattern without re-evaluating random patterns. Same as repeat(0). + * shuffle() Shuffle the pattern * deal(amount: number): Shuffle the generated pattern and deal given number of elements * retrograde() Reverse the generated pattern * invert() Invert the generated pattern diff --git a/src/documentation/patterns/ziffers/ziffers_tonnetz.ts b/src/documentation/patterns/ziffers/ziffers_tonnetz.ts index 3c9cffd..e760bfe 100644 --- a/src/documentation/patterns/ziffers/ziffers_tonnetz.ts +++ b/src/documentation/patterns/ziffers/ziffers_tonnetz.ts @@ -210,19 +210,17 @@ In addition to the transformations, Ziffers implements cyclic methods that can b * hexaCycle(tonnetz: number[], repeats: number = 3): Cycles through chords in the hexa cycle * octaCycle(tonnetz: number[], repeats: number = 4): Cycles through chords in the octa cycle * enneaCycle(tonnetz: number[], repeats: number = 3): Cycles through chords in the ennea cycle -* powerTowers(tonnetz: number[], repeats: number = 3): Cycles trough chords using the power towers -* cubeDance(tonnetz: number[], repeats: number = 3): Cycles trough chords in a cube dance -HexaCycles are sequences of major and minor triads generated by the p and l transformations . Let's take the following example starting with a C chord: C -> Cm -> Ab -> Abm -> E -> Em. You can start on the chord of your choice. +HexaCycles are sequences of major and minor triads generated by the p and l transformations . Let's take the following example starting with a C chord: C -> Cm -> Ab -> Abm -> E -> Em. You can start on the chord of your choice. -OctaCycles are sequences of major and minor triads generated using p and r transformations. Starting at C, we have the following sequence: C -> Cm -> Eb -> Ebm -> F# -> F#m -> A -> Am. +OctaCycles are sequences of major and minor triads generated using p and r transformations. Starting at C, we have the following sequence: C -> Cm -> Eb -> Ebm -> F# -> F#m -> A -> Am. -Unlike HexaCycles and OctaCycles, EnneaCycles are four-note chord sequences. Considering the functions implemented for tetrachords in Ziffers, we can interpret these sequences as generated by p12, p23, and l13 transformations repeatedly: C7 -> Cm7 -> Cm7b5 -> Ab7 -> Abm7 -> Abm7b5 -> E7 -> Em7 -> Em7b5. +Unlike HexaCycles and OctaCycles, EnneaCycles are four-note chord sequences. Considering the functions implemented for tetrachords in Ziffers, we can interpret these sequences as generated by p12, p23, and l13 transformations repeatedly: C7 -> Cm7 -> Cm7b5 -> Ab7 -> Abm7 -> Abm7b5 -> E7 -> Em7 -> Em7b5. ### Examples: ${makeExample( - "Arpeggio with ennea cycle", +"Arpeggio with ennea cycle", ` z1("0 2 -1 3") .enneaCycle() @@ -236,7 +234,7 @@ z1("0 2 -1 3") )} ${makeExample( - "Variating arpeggios", +"Variating arpeggios", ` z1("s 0 3 2 1") .octaCycle() @@ -278,9 +276,45 @@ By default hexaCycles and enneaCycles have 3 repetitions, while octaCyc * Remark E: These cycles in Tonnetz [3, 4, 5] are implemented based on the work of [Douthett & Steinbach (1998, pp. 245-247)](https://www.jstor.org/stable/843877) -## :construction: Regions and OctaTowers +## Traversing methods - TBD: Implement and write about Weitzmann Regions, Boretz Regions, OctaTowers +In addition to the cyclic traversing methods, Ziffers implements methods based on different theories that traverse the chords in the Tonnetz in different ways. These methods are: + +* powerTowers(tonnetz: number[], repeats: number = 3): Cycles trough chords using the power towers +* cubeDance(tonnetz: number[], repeats: number = 3): Cycles trough chords in a cube dance +* octaTowers(tonnetz: number[], repeats: number = 3): Cycles trough chords using the octa towers +* weitzmannRegions(tonnetz: number[]): Cycles trough chords in a Weitzmann region +* boretzRegions(tonnetz: number[]): Cycles trough chords in a Boretz region + +We encourage you to explore these methods and their different parameters. The tonnetz traversing methods can be used in combination with the Ziffers generative methods to sequence, arpeggiate and to randomize the chords in different ways. + +${makeExample( + "Selecting subset of chords from the cube dance", + ` + z1("1/2 0") + .cubeDance([3,4,5],4) + .at(0,8,2,rI(9,14)) + .sound("triangle") + .ad(0.05,0.15) + .delay(2) + .out() +`, + true +)} + +${makeExample( +"Selecting chords from the weitzmann region", +` +z1("1/8 0") + .weitzmannRegions() + .at(1,rI(0,7),4,6) + .arpeggio(0,2,1,rI(0,2)) + .sound("sine") + .ad(0.15,0.15) + .out() +`, +true +)} `; }; diff --git a/yarn.lock b/yarn.lock index e327bd7..5da6e20 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4033,10 +4033,10 @@ yaml@^2.1.1: resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.1.tgz#02fe0975d23cd441242aa7204e09fc28ac2ac33b" integrity sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ== -zifferjs@^0.0.59: - version "0.0.59" - resolved "https://registry.yarnpkg.com/zifferjs/-/zifferjs-0.0.59.tgz#e18ad4f967f98092f6782abbe0a38c5a148c2bac" - integrity sha512-bssE9Vtgmcoz2d6390pnX6YWQxsewtXi+3HWdNAmzoM+0bupOGOvpGat79fQ5FqXhV5jjrZl2JzDzLCfcwnM5w== +zifferjs@^0.0.60: + version "0.0.60" + resolved "https://registry.yarnpkg.com/zifferjs/-/zifferjs-0.0.60.tgz#c4e7f3b291d9357a3d730a868b311d1a5cfc3b34" + integrity sha512-Z47rZ16fHmPSJSCo9dLJVbKvzvov42e3INTPgB1ClSjSw35Vq3Drl4i+UHDeLrJPjkLYlcJ80J5RxjSpqr5gIQ== zyklus@^0.1.4: version "0.1.4"