From a838624ac8231b76d63f188c01aad5bfa7762c69 Mon Sep 17 00:00:00 2001 From: JulienH2000 Date: Thu, 21 Sep 2023 19:09:06 +0200 Subject: [PATCH 01/15] Working scale fonction :) --- src/API.ts | 1 + src/ArrayExtensions.ts | 28 +++++++++++++++++++++++++++- src/Scales.ts | 11 ++++++++--- src/main.ts | 2 ++ 4 files changed, 38 insertions(+), 4 deletions(-) diff --git a/src/API.ts b/src/API.ts index 871b99e..ee919a0 100644 --- a/src/API.ts +++ b/src/API.ts @@ -7,6 +7,7 @@ import { Editor } from "./main"; import { SoundEvent } from "./classes/SoundEvent"; import { MidiEvent } from "./classes/MidiEvent"; import { LRUCache } from "lru-cache"; +import { SCALES } from "./Scales" import { InputOptions, Player } from "./classes/ZPlayer"; import { samples, diff --git a/src/ArrayExtensions.ts b/src/ArrayExtensions.ts index b87e53a..894a19f 100644 --- a/src/ArrayExtensions.ts +++ b/src/ArrayExtensions.ts @@ -1,4 +1,5 @@ import { type UserAPI } from "./API"; +import { SCALES } from "./Scales"; export {}; declare global { @@ -238,7 +239,8 @@ export const makeArrayExtensions = (api: UserAPI) => { for (let j = 0; j < amount; j++) { result.push(this[i]); } - } + } + this.length = 0; this.push(...result); return this; @@ -341,3 +343,27 @@ export const makeArrayExtensions = (api: UserAPI) => { }; Array.prototype.rand = Array.prototype.random; }; + +Array.prototype.scale = function (this: T[], scaleName: string = "major") { + + const scale = SCALES[scaleName]; + + if (!scale) { + throw new Error(`Unknown scale ${scaleName}`); + } + + let result = []; + + for (let i = 0; i < scale.length; i++) { + + if (!this[i]) { + result.push(this[0] + scale[i]); + } else { + result.push(this[i] + scale[i]); + } + } + + this.shift() + this.push(...result); + return this; +}; diff --git a/src/Scales.ts b/src/Scales.ts index de046f8..1850fc3 100644 --- a/src/Scales.ts +++ b/src/Scales.ts @@ -1,4 +1,4 @@ -const SCALES: Record = { +export const SCALES: Record = { major: [0, 2, 4, 5, 7, 9, 11], naturalMinor: [0, 2, 3, 5, 7, 8, 10], harmonicMinor: [0, 2, 3, 5, 7, 8, 11], @@ -53,18 +53,21 @@ const SCALES: Record = { orientalA: [0, 1, 4, 5, 6, 9, 10], }; + +// Legacy function, see Array.prototype.scale @ ArrayExtensions.ts +/* export function scale( n: number, scaleName: string = "major", octave: number = 4 ): number { - /** + /* * Returns the MIDI note number for the given scale degree in the given scale. * @param {number} n - The scale degree, where 0 is the tonic. * @param {string} scaleName - The name of the scale. * @param {number} octave - The octave number. * @returns {number} The MIDI note number. - */ + * / const scale = SCALES[scaleName]; if (!scale) { @@ -76,3 +79,5 @@ export function scale( let additionalOctaves = Math.floor(n / scale.length); return 60 + (octave + additionalOctaves) * 12 + scale[index]; } + +*/ diff --git a/src/main.ts b/src/main.ts index 6ae6b33..fc2e8e4 100644 --- a/src/main.ts +++ b/src/main.ts @@ -66,6 +66,8 @@ const bindings = Object.keys(classMap).map((key) => ({ replace: (match, p1) => `<${key} class="${classMap[key]}" ${p1}>`, })); + + export class Editor { universes: Universes = template_universes; selected_universe: string; From a86d0c923a7de431b9d7271c52e25465e6129b99 Mon Sep 17 00:00:00 2001 From: JulienH2000 Date: Thu, 21 Sep 2023 19:41:28 +0200 Subject: [PATCH 02/15] corrected useless shift/push/return / delete ambiguous import in API.ts + scale = scale; --- src/API.ts | 3 --- src/ArrayExtensions.ts | 7 ++++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/API.ts b/src/API.ts index ee919a0..012e7ec 100644 --- a/src/API.ts +++ b/src/API.ts @@ -2,12 +2,10 @@ import { seededRandom } from "zifferjs"; import { MidiConnection } from "./IO/MidiConnection"; import { tryEvaluate, evaluateOnce } from "./Evaluator"; import { DrunkWalk } from "./Utils/Drunk"; -import { scale } from "./Scales"; import { Editor } from "./main"; import { SoundEvent } from "./classes/SoundEvent"; import { MidiEvent } from "./classes/MidiEvent"; import { LRUCache } from "lru-cache"; -import { SCALES } from "./Scales" import { InputOptions, Player } from "./classes/ZPlayer"; import { samples, @@ -1514,7 +1512,6 @@ export class UserAPI { this._logMessage(message); }; - scale = scale; rate = (rate: number): void => { rate = rate; diff --git a/src/ArrayExtensions.ts b/src/ArrayExtensions.ts index 894a19f..acfe23f 100644 --- a/src/ArrayExtensions.ts +++ b/src/ArrayExtensions.ts @@ -348,6 +348,7 @@ Array.prototype.scale = function (this: T[], scaleName: string = "major") { const scale = SCALES[scaleName]; + //input protect from unknow scale if (!scale) { throw new Error(`Unknown scale ${scaleName}`); } @@ -363,7 +364,7 @@ Array.prototype.scale = function (this: T[], scaleName: string = "major") { } } - this.shift() - this.push(...result); - return this; + //this.shift() + //this = [...result]; + return result; }; From d133169eb9f312e5dc1604b6f902154f5f97c2e6 Mon Sep 17 00:00:00 2001 From: JulienH2000 Date: Thu, 21 Sep 2023 20:34:16 +0200 Subject: [PATCH 03/15] scale now accept any array length --- package.json | 1 - src/ArrayExtensions.ts | 12 +++++------- yarn.lock | 5 ----- 3 files changed, 5 insertions(+), 13 deletions(-) diff --git a/package.json b/package.json index 6cea638..5664b89 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,6 @@ "devDependencies": { "@tauri-apps/cli": "^1.4.0", "@types/audioworklet": "^0.0.49", - "typescript": "^5.0.2", "vite": "^4.4.5" }, "dependencies": { diff --git a/src/ArrayExtensions.ts b/src/ArrayExtensions.ts index acfe23f..848c1e4 100644 --- a/src/ArrayExtensions.ts +++ b/src/ArrayExtensions.ts @@ -355,16 +355,14 @@ Array.prototype.scale = function (this: T[], scaleName: string = "major") { let result = []; - for (let i = 0; i < scale.length; i++) { + for (let j = 0; j < scale.length; j++) { - if (!this[i]) { - result.push(this[0] + scale[i]); - } else { - result.push(this[i] + scale[i]); + for (let i = 0; i < this.length; i++) { + + result.push(this[i] + scale[j]); } + } - //this.shift() - //this = [...result]; return result; }; diff --git a/yarn.lock b/yarn.lock index b25765a..46dd46d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1375,11 +1375,6 @@ tslib@^2.3.1, tslib@^2.6.1: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.1.tgz#fd8c9a0ff42590b25703c0acb3de3d3f4ede0410" integrity sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig== -typescript@^5.0.2: - version "5.1.6" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.1.6.tgz#02f8ac202b6dad2c0dd5e0913745b47a37998274" - integrity sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA== - uc.micro@^1.0.1, uc.micro@^1.0.5: version "1.0.6" resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac" From 5486c295c5690a6acabc8278cb7ff68da01d3034 Mon Sep 17 00:00:00 2001 From: JulienH2000 Date: Thu, 21 Sep 2023 20:43:23 +0200 Subject: [PATCH 04/15] oops --- .gitignore | 6 +++++- package.json | 1 + yarn.lock | 5 +++++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index a9ab0f1..20acbf8 100644 --- a/.gitignore +++ b/.gitignore @@ -42,4 +42,8 @@ yarn.lock .DS_Store -.vs \ No newline at end of file +.vs + +package.json + +yarn.lock \ No newline at end of file diff --git a/package.json b/package.json index 5664b89..9c592a8 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "devDependencies": { "@tauri-apps/cli": "^1.4.0", "@types/audioworklet": "^0.0.49", + "typescript": "^5.2.2", "vite": "^4.4.5" }, "dependencies": { diff --git a/yarn.lock b/yarn.lock index 46dd46d..a840f11 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1375,6 +1375,11 @@ tslib@^2.3.1, tslib@^2.6.1: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.1.tgz#fd8c9a0ff42590b25703c0acb3de3d3f4ede0410" integrity sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig== +typescript@^5.2.2: + version "5.2.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.2.2.tgz#5ebb5e5a5b75f085f22bc3f8460fba308310fa78" + integrity sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w== + uc.micro@^1.0.1, uc.micro@^1.0.5: version "1.0.6" resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac" From 20189941c48ef7a068b1ae22dd25b1c41daea190 Mon Sep 17 00:00:00 2001 From: JulienH2000 Date: Thu, 21 Sep 2023 20:44:50 +0200 Subject: [PATCH 05/15] oops oops --- .gitignore | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 20acbf8..a9ab0f1 100644 --- a/.gitignore +++ b/.gitignore @@ -42,8 +42,4 @@ yarn.lock .DS_Store -.vs - -package.json - -yarn.lock \ No newline at end of file +.vs \ No newline at end of file From 6076ea226f65e4709e1c411e7873a14bbc55d04b Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Thu, 21 Sep 2023 21:06:35 +0200 Subject: [PATCH 06/15] Fixing logic --- src/ArrayExtensions.ts | 74 +++++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 40 deletions(-) diff --git a/src/ArrayExtensions.ts b/src/ArrayExtensions.ts index 848c1e4..a6663a7 100644 --- a/src/ArrayExtensions.ts +++ b/src/ArrayExtensions.ts @@ -1,6 +1,6 @@ import { type UserAPI } from "./API"; import { SCALES } from "./Scales"; -export {}; +export { }; declare global { interface Array { @@ -21,6 +21,7 @@ declare global { pick(): T; loop(index: number): T; shuffle(): this; + scale(name: string, base_note?: number): this; rotate(steps: number): this; unique(): this; in(value: T): boolean; @@ -35,14 +36,14 @@ export const makeArrayExtensions = (api: UserAPI) => { return this.includes(value); }; - 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.sqrt = function (): number[] { + Array.prototype.sqrt = function(): number[] { /** * @returns New array with square roots of values. Throws if any element is negative. */ @@ -51,7 +52,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. @@ -59,7 +60,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. @@ -67,7 +68,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. @@ -75,7 +76,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. @@ -84,7 +85,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. * @@ -93,7 +94,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 @@ -110,7 +111,7 @@ export const makeArrayExtensions = (api: UserAPI) => { ); }; - Array.prototype.bar = function () { + Array.prototype.bar = function() { /** * Returns an element from an array based on the current bar. * @@ -119,7 +120,7 @@ export const makeArrayExtensions = (api: UserAPI) => { return this[api.app.clock.time_position.bar % this.length]; }; - Array.prototype.pulse = function () { + Array.prototype.pulse = function() { /** * Returns an element from an array based on the current pulse. * @@ -128,7 +129,7 @@ export const makeArrayExtensions = (api: UserAPI) => { return this[api.app.clock.time_position.pulse % this.length]; }; - 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( @@ -137,7 +138,7 @@ export const makeArrayExtensions = (api: UserAPI) => { return this[slice_count % this.length]; }; - Array.prototype.shuffle = function () { + Array.prototype.shuffle = function() { /** * Shuffles the array in place. * @@ -156,7 +157,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. * @@ -176,7 +177,7 @@ export const makeArrayExtensions = (api: UserAPI) => { return this; }; - Array.prototype.unique = function () { + Array.prototype.unique = function() { /** * Removes duplicate elements from the array in place. * @@ -209,7 +210,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) { @@ -239,7 +240,7 @@ export const makeArrayExtensions = (api: UserAPI) => { for (let j = 0; j < amount; j++) { result.push(this[i]); } - } + } this.length = 0; this.push(...result); @@ -322,7 +323,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. @@ -333,7 +334,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. * @@ -344,25 +345,18 @@ export const makeArrayExtensions = (api: UserAPI) => { Array.prototype.rand = Array.prototype.random; }; -Array.prototype.scale = function (this: T[], scaleName: string = "major") { - - const scale = SCALES[scaleName]; - - //input protect from unknow scale - if (!scale) { - throw new Error(`Unknown scale ${scaleName}`); - } - - let result = []; - - for (let j = 0; j < scale.length; j++) { - - for (let i = 0; i < this.length; i++) { - - result.push(this[i] + scale[j]); - } - - } - - return result; +Array.prototype.scale = function(scale: string = "major", base_note: number = 0) { + /** + * Returns a note from an array containing a specific scale. + * + * @param scale - the scale name (string) + * @param base_note - the base note to start at (MIDI note number) + * + */ + if (SCALES.hasOwnProperty(scale)) { + const selected_scale = SCALES[scale] + return this.map((value) => selected_scale[value % selected_scale.length] + base_note); + } else { + return this.map((value) => value + base_note); + } }; From 512523d74f076a1832c0849df3f9686c36e51b43 Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Thu, 21 Sep 2023 21:12:50 +0200 Subject: [PATCH 07/15] adding octaviation up or down --- src/ArrayExtensions.ts | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/src/ArrayExtensions.ts b/src/ArrayExtensions.ts index a6663a7..202a5e3 100644 --- a/src/ArrayExtensions.ts +++ b/src/ArrayExtensions.ts @@ -347,15 +347,35 @@ export const makeArrayExtensions = (api: UserAPI) => { Array.prototype.scale = function(scale: string = "major", base_note: number = 0) { /** - * Returns a note from an array containing a specific scale. - * - * @param scale - the scale name (string) + * @param scale - the scale name * @param base_note - the base note to start at (MIDI note number) - * */ if (SCALES.hasOwnProperty(scale)) { - const selected_scale = SCALES[scale] - return this.map((value) => selected_scale[value % selected_scale.length] + base_note); + const selected_scale = SCALES[scale]; + return this.map((value) => { + const octaveShift = Math.floor(value / selected_scale.length) * 12 * Math.sign(value); + return selected_scale[Math.abs(value) % selected_scale.length] + base_note + octaveShift; + }); + } else { + return this.map((value) => value + base_note); + } +}; + + +Array.prototype.scale = function(scale: string = "major", base_note: number = 0) { + /** + * @param scale - the scale name + * @param base_note - the base note to start at (MIDI note number) + */ + + // This is a helper function to handle up or down octaviation. + const mod = (n: number, m: number) => ((n % m) + m) % m; + if (SCALES.hasOwnProperty(scale)) { + const selected_scale = SCALES[scale]; + return this.map((value) => { + const octaveShift = Math.floor(value / selected_scale.length) * 12; + return selected_scale[mod(value, selected_scale.length)] + base_note + octaveShift; + }); } else { return this.map((value) => value + base_note); } From 578dc694880021eacb0297f219a2a4a386583a11 Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Thu, 21 Sep 2023 21:35:03 +0200 Subject: [PATCH 08/15] restore func --- src/ArrayExtensions.ts | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/ArrayExtensions.ts b/src/ArrayExtensions.ts index 202a5e3..b7d73c1 100644 --- a/src/ArrayExtensions.ts +++ b/src/ArrayExtensions.ts @@ -1,5 +1,6 @@ import { type UserAPI } from "./API"; import { SCALES } from "./Scales"; +import { safeScale } from "zifferjs"; export { }; declare global { @@ -22,6 +23,7 @@ declare global { loop(index: number): T; shuffle(): this; scale(name: string, base_note?: number): this; + arp(scaleName: string): this; rotate(steps: number): this; unique(): this; in(value: T): boolean; @@ -366,10 +368,13 @@ Array.prototype.scale = function(scale: string = "major", base_note: number = 0) /** * @param scale - the scale name * @param base_note - the base note to start at (MIDI note number) + * + * @returns notes from the desired scalek */ // This is a helper function to handle up or down octaviation. const mod = (n: number, m: number) => ((n % m) + m) % m; + if (SCALES.hasOwnProperty(scale)) { const selected_scale = SCALES[scale]; return this.map((value) => { @@ -380,3 +385,25 @@ Array.prototype.scale = function(scale: string = "major", base_note: number = 0) return this.map((value) => value + base_note); } }; + +Array.prototype.arp = function(scaleName: string = "major") { + /* + * Ajouter documentation + * + */ + const scale = SCALES[scaleName]; + + //input protect from unknow scale + + if (!scale) { + throw new Error(`Unknown scale ${scaleName}`); + } + + let result = []; + for (let j = 0; j < scale.length; j++) { + for (let i = 0; i < this.length; i++) { + result.push(this[i] + scale[j]); + } + } + return result; +}; From 3c5ffca02a64402b1bfa453249b53c5da252507c Mon Sep 17 00:00:00 2001 From: JulienH2000 Date: Thu, 21 Sep 2023 22:00:47 +0200 Subject: [PATCH 09/15] doc + Masking --- src/ArrayExtensions.ts | 22 ++++++++++- src/documentation/patterns.ts | 70 ++++++++++++++++++++++++++++++++++- 2 files changed, 89 insertions(+), 3 deletions(-) diff --git a/src/ArrayExtensions.ts b/src/ArrayExtensions.ts index 848c1e4..532f963 100644 --- a/src/ArrayExtensions.ts +++ b/src/ArrayExtensions.ts @@ -344,18 +344,36 @@ export const makeArrayExtensions = (api: UserAPI) => { Array.prototype.rand = Array.prototype.random; }; -Array.prototype.scale = function (this: T[], scaleName: string = "major") { +Array.prototype.scale = function (this: T[], scaleName: string = "major", maskLength: number = 0) { + + /** + * @param scale - the scale name + * @param mask - masking the scale array + */ const scale = SCALES[scaleName]; + let mask = maskLength; //input protect from unknow scale if (!scale) { throw new Error(`Unknown scale ${scaleName}`); } + //input protect from to long mask + if (mask > scale.length) { + mask = scale.length; + throw new Error(`Mask exceeds selected scale length`) + } + + // default mask = scale length + if (mask == 0) { + mask = scale.length; + } + + let result = []; - for (let j = 0; j < scale.length; j++) { + for (let j = 0; j < mask; j++) { for (let i = 0; i < this.length; i++) { diff --git a/src/documentation/patterns.ts b/src/documentation/patterns.ts index ffeeb48..2e07c9f 100644 --- a/src/documentation/patterns.ts +++ b/src/documentation/patterns.ts @@ -183,7 +183,75 @@ ${makeExample( beat(1)::snd('sine').sustain(0.1).freq([100,100,100,100,200].unique().beat()).out() `, true -)} + )} + +- scale(scale: string, mask: number): extrapolate a custom-masked scale from each list elements. _[0].scale("major", 3)_ returns _[0,2,4]_ + +${makeExample( + "Extrapolate a 3-elements Persian scale from 2 notes", + ` +beat(1) :: snd('gtr') + .note([0,5].scale("persian", 3).beat() + 50) + .out() +`, + true + )} + +- Currently supported scales : +| Scale name | Values | +|------------|------------------------| +| major | 0, 2, 4, 5, 7, 9, 11 +| naturalMinor | 0, 2, 3, 5, 7, 8, 10 +| harmonicMinor | 0, 2, 3, 5, 7, 8, 11 +| melodicMinor | 0, 2, 3, 5, 7, 9, 11 +| dorian | 0, 2, 3, 5, 7, 9, 10 +| phrygian | 0, 1, 3, 5, 7, 8, 10 +| lydian | 0, 2, 4, 6, 7, 9, 11 +| mixolydian | 0, 2, 4, 5, 7, 9, 10 +| aeolian | 0, 2, 3, 5, 7, 8, 10 +| locrian | 0, 1, 3, 5, 6, 8, 10 +| wholeTone | 0, 2, 4, 6, 8, 10 +| majorPentatonic | 0, 2, 4, 7, 9 +| minorPentatonic | 0, 3, 5, 7, 10 +| chromatic | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 +| blues | 0, 3, 5, 6, 7, 10 +| diminished | 0, 2, 3, 5, 6, 8, 9, 11 +| neapolitanMinor | 0, 1, 3, 5, 7, 8, 11 +| neapolitanMajor | 0, 1, 3, 5, 7, 9, 11 +| enigmatic | 0, 1, 4, 6, 8, 10, 11], +| doubleHarmonic | 0, 1, 4, 5, 7, 8, 11 +| octatonic | 0, 2, 3, 5, 6, 8, 9, 11 +| bebopDominant | 0, 2, 4, 5, 7, 9, 10, 11 +| bebopMajor | 0, 2, 4, 5, 7, 8, 9, 11 +| bebopMinor | 0, 2, 3, 5, 7, 8, 9, 11 +| bebopDorian | 0, 2, 3, 4, 5, 7, 9, 10 +| harmonicMajor | 0, 2, 4, 5, 7, 8, 11 +| hungarianMinor | 0, 2, 3, 6, 7, 8, 11 +| hungarianMajor | 0, 3, 4, 6, 7, 9, 10 +| oriental | 0, 1, 4, 5, 6, 9, 10 +| romanianMinor | 0, 2, 3, 6, 7, 9, 10 +| spanishGypsy | 0, 1, 4, 5, 7, 8, 10 +| jewish | 0, 1, 4, 5, 7, 8, 10 +| hindi | 0, 2, 4, 5, 7, 8, 10 +| japanese | 0, 1, 5, 7, 8 +| hirajoshi | 0, 2, 3, 7, 8 +| kumoi | 0, 2, 3, 7, 9 +| inSen | 0, 1, 5, 7, 10 +| iwato | 0, 1, 5, 6, 10 +| yo | 0, 2, 5, 7, 9 +| minorBlues | 0, 3, 5, 6, 7, 10 +| algerian | 0, 2, 3, 5, 6, 7, 8, 11 +| augmented | 0, 3, 4, 7, 8, 11 +| balinese | 0, 1, 3, 7, 8 +| byzantine | 0, 1, 4, 5, 7, 8, 11 +| chinese | 0, 4, 6, 7, 11 +| egyptian |0, 2, 5, 7, 10 +| eightToneSpanish | 0, 1, 3, 4, 5, 6, 8, 10 +| hawaiian | 0, 2, 3, 5, 7, 9, 10 +| hindustan | 0, 2, 4, 5, 7, 8, 10 +| persian | 0, 1, 4, 5, 6, 8, 11 +| eastIndianPurvi | 0, 1, 4, 6, 7, 8, 11 +| orientalA | 0, 1, 4, 5, 6, 9, 10 - add(): add a given amount to every list element. - sub(): add a given amount to every list element. From ce8b93fd7b9534b86acf07e32d72a44e35fdd7d0 Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Thu, 21 Sep 2023 22:12:02 +0200 Subject: [PATCH 10/15] On hold while safeScale is not accessible --- src/ArrayExtensions.ts | 24 +++--------- src/Scales.ts | 83 ------------------------------------------ 2 files changed, 6 insertions(+), 101 deletions(-) delete mode 100644 src/Scales.ts diff --git a/src/ArrayExtensions.ts b/src/ArrayExtensions.ts index b7d73c1..7a5fc3f 100644 --- a/src/ArrayExtensions.ts +++ b/src/ArrayExtensions.ts @@ -1,5 +1,4 @@ import { type UserAPI } from "./API"; -import { SCALES } from "./Scales"; import { safeScale } from "zifferjs"; export { }; @@ -374,16 +373,11 @@ Array.prototype.scale = function(scale: string = "major", base_note: number = 0) // This is a helper function to handle up or down octaviation. const mod = (n: number, m: number) => ((n % m) + m) % m; - - if (SCALES.hasOwnProperty(scale)) { - const selected_scale = SCALES[scale]; - return this.map((value) => { - const octaveShift = Math.floor(value / selected_scale.length) * 12; - return selected_scale[mod(value, selected_scale.length)] + base_note + octaveShift; - }); - } else { - return this.map((value) => value + base_note); - } + let selected_scale = safeScale(scale); + return this.map((value) => { + const octaveShift = Math.floor(value / selected_scale.length) * 12; + return selected_scale[mod(value, selected_scale.length)] + base_note + octaveShift; + }); }; Array.prototype.arp = function(scaleName: string = "major") { @@ -391,13 +385,7 @@ Array.prototype.arp = function(scaleName: string = "major") { * Ajouter documentation * */ - const scale = SCALES[scaleName]; - - //input protect from unknow scale - - if (!scale) { - throw new Error(`Unknown scale ${scaleName}`); - } + const scale = safeScale[scaleName]; let result = []; for (let j = 0; j < scale.length; j++) { diff --git a/src/Scales.ts b/src/Scales.ts deleted file mode 100644 index 1850fc3..0000000 --- a/src/Scales.ts +++ /dev/null @@ -1,83 +0,0 @@ -export const SCALES: Record = { - major: [0, 2, 4, 5, 7, 9, 11], - naturalMinor: [0, 2, 3, 5, 7, 8, 10], - harmonicMinor: [0, 2, 3, 5, 7, 8, 11], - melodicMinor: [0, 2, 3, 5, 7, 9, 11], - dorian: [0, 2, 3, 5, 7, 9, 10], - phrygian: [0, 1, 3, 5, 7, 8, 10], - lydian: [0, 2, 4, 6, 7, 9, 11], - mixolydian: [0, 2, 4, 5, 7, 9, 10], - aeolian: [0, 2, 3, 5, 7, 8, 10], - locrian: [0, 1, 3, 5, 6, 8, 10], - wholeTone: [0, 2, 4, 6, 8, 10], - majorPentatonic: [0, 2, 4, 7, 9], - minorPentatonic: [0, 3, 5, 7, 10], - chromatic: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], - blues: [0, 3, 5, 6, 7, 10], - diminished: [0, 2, 3, 5, 6, 8, 9, 11], - neapolitanMinor: [0, 1, 3, 5, 7, 8, 11], - neapolitanMajor: [0, 1, 3, 5, 7, 9, 11], - enigmatic: [0, 1, 4, 6, 8, 10, 11], - doubleHarmonic: [0, 1, 4, 5, 7, 8, 11], - octatonic: [0, 2, 3, 5, 6, 8, 9, 11], - bebopDominant: [0, 2, 4, 5, 7, 9, 10, 11], - bebopMajor: [0, 2, 4, 5, 7, 8, 9, 11], - bebopMinor: [0, 2, 3, 5, 7, 8, 9, 11], - bebopDorian: [0, 2, 3, 4, 5, 7, 9, 10], - harmonicMajor: [0, 2, 4, 5, 7, 8, 11], - hungarianMinor: [0, 2, 3, 6, 7, 8, 11], - hungarianMajor: [0, 3, 4, 6, 7, 9, 10], - oriental: [0, 1, 4, 5, 6, 9, 10], - romanianMinor: [0, 2, 3, 6, 7, 9, 10], - spanishGypsy: [0, 1, 4, 5, 7, 8, 10], - jewish: [0, 1, 4, 5, 7, 8, 10], - hindu: [0, 2, 4, 5, 7, 8, 10], - japanese: [0, 1, 5, 7, 8], - hirajoshi: [0, 2, 3, 7, 8], - kumoi: [0, 2, 3, 7, 9], - inSen: [0, 1, 5, 7, 10], - iwato: [0, 1, 5, 6, 10], - yo: [0, 2, 5, 7, 9], - minorBlues: [0, 3, 5, 6, 7, 10], - algerian: [0, 2, 3, 5, 6, 7, 8, 11], - augmented: [0, 3, 4, 7, 8, 11], - balinese: [0, 1, 3, 7, 8], - byzantine: [0, 1, 4, 5, 7, 8, 11], - chinese: [0, 4, 6, 7, 11], - egyptian: [0, 2, 5, 7, 10], - eightToneSpanish: [0, 1, 3, 4, 5, 6, 8, 10], - hawaiian: [0, 2, 3, 5, 7, 9, 10], - hindustan: [0, 2, 4, 5, 7, 8, 10], - persian: [0, 1, 4, 5, 6, 8, 11], - eastIndianPurvi: [0, 1, 4, 6, 7, 8, 11], - orientalA: [0, 1, 4, 5, 6, 9, 10], -}; - - -// Legacy function, see Array.prototype.scale @ ArrayExtensions.ts -/* -export function scale( - n: number, - scaleName: string = "major", - octave: number = 4 -): number { - /* - * Returns the MIDI note number for the given scale degree in the given scale. - * @param {number} n - The scale degree, where 0 is the tonic. - * @param {string} scaleName - The name of the scale. - * @param {number} octave - The octave number. - * @returns {number} The MIDI note number. - * / - const scale = SCALES[scaleName]; - - if (!scale) { - throw new Error(`Unknown scale ${scaleName}`); - } - - let index = n % scale.length; - if (index < 0) index += scale.length; // adjust for negative indexes - let additionalOctaves = Math.floor(n / scale.length); - return 60 + (octave + additionalOctaves) * 12 + scale[index]; -} - -*/ From ba271e1f3a55ebf9500d193f7b1cf6b19d7da8b2 Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Thu, 21 Sep 2023 22:28:28 +0200 Subject: [PATCH 11/15] Small corrections --- src/ArrayExtensions.ts | 45 ++++++++++++++++++------------------------ 1 file changed, 19 insertions(+), 26 deletions(-) diff --git a/src/ArrayExtensions.ts b/src/ArrayExtensions.ts index 3e1e8b2..eab3f90 100644 --- a/src/ArrayExtensions.ts +++ b/src/ArrayExtensions.ts @@ -22,7 +22,7 @@ declare global { loop(index: number): T; shuffle(): this; scale(name: string, base_note?: number): this; - arp(scaleName: string): this; + scaleArp(scaleName: string): this; rotate(steps: number): this; unique(): this; in(value: T): boolean; @@ -374,47 +374,40 @@ Array.prototype.scale = function ( * @param scale - the scale name * @param base_note - the base note to start at (MIDI note number) * - * @returns notes from the desired scalek + * @returns notes from the desired scale */ // This is a helper function to handle up or down octaviation. const mod = (n: number, m: number) => ((n % m) + m) % m; - - if (SCALES.hasOwnProperty(scale)) { - const selected_scale = SCALES[scale]; - return this.map((value) => { - const octaveShift = Math.floor(value / selected_scale.length) * 12; - return ( - selected_scale[mod(value, selected_scale.length)] + - base_note + - octaveShift - ); - }); - } else { - return this.map((value) => value + base_note); - } + const selected_scale = safeScale[scale]; + return this.map((value) => { + const octaveShift = Math.floor(value / selected_scale.length) * 12; + return ( + selected_scale[mod(value, selected_scale.length)] + + base_note + + octaveShift + ); + }); }; -Array.prototype.arp = function (scaleName: string = "major", mask: number = 0) { +Array.prototype.scaleArp = function ( + scaleName: string = "major", + boundary: number = 0 +) { /* * @param scaleName - the scale name * @param mask - the length of the mask * + * @returns arpeggiated notes from the scale */ const scale = safeScale[scaleName]; - //input protect from unknow scale - - if (!scale) { - throw new Error(`Unknown scale ${scaleName}`); - } - let result = []; - mask = mask > scale.length ? scale.length : mask; - mask = mask == 0 ? scale.length : mask; + boundary = boundary > scale.length ? scale.length : boundary; + boundary = boundary == 0 ? scale.length : boundary; - for (let j = 0; j < mask; j++) { + for (let j = 0; j < boundary; j++) { for (let i = 0; i < this.length; i++) { result.push(this[i] + scale[j]); } From 11ee9aa209639713c81b8cdf4f28e715917b14f3 Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Thu, 21 Sep 2023 22:30:41 +0200 Subject: [PATCH 12/15] Adapt to future ziffers import --- src/ArrayExtensions.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ArrayExtensions.ts b/src/ArrayExtensions.ts index eab3f90..7dde51f 100644 --- a/src/ArrayExtensions.ts +++ b/src/ArrayExtensions.ts @@ -1,5 +1,5 @@ import { type UserAPI } from "./API"; -import { safeScale } from "zifferjs"; +import { safeScale, stepsToScale } from "zifferjs"; export {}; declare global { @@ -379,7 +379,7 @@ Array.prototype.scale = function ( // This is a helper function to handle up or down octaviation. const mod = (n: number, m: number) => ((n % m) + m) % m; - const selected_scale = safeScale[scale]; + const selected_scale = stepsToScale(safeScale[scale]); return this.map((value) => { const octaveShift = Math.floor(value / selected_scale.length) * 12; return ( @@ -400,7 +400,7 @@ Array.prototype.scaleArp = function ( * * @returns arpeggiated notes from the scale */ - const scale = safeScale[scaleName]; + const scale = stepsToScale(safeScale[scaleName]); let result = []; From 89d1e7675871c86f0bc1d355c1097d8a66bf7e1a Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Thu, 21 Sep 2023 22:55:06 +0200 Subject: [PATCH 13/15] wtf is happening --- src/ArrayExtensions.ts | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/src/ArrayExtensions.ts b/src/ArrayExtensions.ts index 7dde51f..bbfa5ab 100644 --- a/src/ArrayExtensions.ts +++ b/src/ArrayExtensions.ts @@ -346,26 +346,6 @@ export const makeArrayExtensions = (api: UserAPI) => { Array.prototype.rand = Array.prototype.random; }; -Array.prototype.scale = function ( - scale: string = "major", - base_note: number = 0 -) { - /** - * @param scale - the scale name - * @param base_note - the base note to start at (MIDI note number) - */ - const selected_scale = SCALES[scale]; - return this.map((value) => { - const octaveShift = - Math.floor(value / selected_scale.length) * 12 * Math.sign(value); - return ( - selected_scale[Math.abs(value) % selected_scale.length] + - base_note + - octaveShift - ); - }); -}; - Array.prototype.scale = function ( scale: string = "major", base_note: number = 0 From 1a093d13f6f036dcb82559930d88fc2c9f24353e Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Thu, 21 Sep 2023 22:56:43 +0200 Subject: [PATCH 14/15] Last fix I hope --- src/ArrayExtensions.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ArrayExtensions.ts b/src/ArrayExtensions.ts index bbfa5ab..36e53ac 100644 --- a/src/ArrayExtensions.ts +++ b/src/ArrayExtensions.ts @@ -359,7 +359,7 @@ Array.prototype.scale = function ( // This is a helper function to handle up or down octaviation. const mod = (n: number, m: number) => ((n % m) + m) % m; - const selected_scale = stepsToScale(safeScale[scale]); + const selected_scale = stepsToScale(safeScale(scale)); return this.map((value) => { const octaveShift = Math.floor(value / selected_scale.length) * 12; return ( @@ -380,7 +380,7 @@ Array.prototype.scaleArp = function ( * * @returns arpeggiated notes from the scale */ - const scale = stepsToScale(safeScale[scaleName]); + const scale = stepsToScale(safeScale(scaleName)); let result = []; From 145b5eaca6451c0765edac4bee94d1bcf4647917 Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Fri, 22 Sep 2023 18:51:29 +0200 Subject: [PATCH 15/15] updating demo songs --- src/examples/excerpts.ts | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/src/examples/excerpts.ts b/src/examples/excerpts.ts index fb29854..62b332a 100644 --- a/src/examples/excerpts.ts +++ b/src/examples/excerpts.ts @@ -6,7 +6,7 @@ beat(.25) :: sound('wt_symetric:8') .cutoff(1500 + usine(1/8) * 5000) .lpadsr(16, 0.2, 0.2, 0.125/2, 0) .room(0.9).size(0.9).resonance(20) - .gain(0.3).out() + .gain(0.7).out() beat(1) :: sound('kick').n(4).out() beat(2) :: sound('snare').out() beat(.5) :: sound('hh').out()`, @@ -18,9 +18,9 @@ beat(2) :: app.hydra.osc(frequencies/100, 0.25, 0.5) .posterize([32,4,8,16].beat(2)).rotate(cpulse()) .kaleid([1,2,3].beat()).out()`, `// The real internet of things - Bubobubobubo -beat(.5) :: sound('STA6').cut(1).vel(0.4) +beat(.5) :: sound('STA6').cut(1).vel(0.8) .orbit(2).room(0.5).size(0.5).n(irand(1,4)) - .speed([0.15, 0.30].beat() * 1.5).loop([1,0] + .speed([0.15, 0.30].beat() * 3).loop([1,0] .beat(.125)).loopEnd([1,0.5].beat(2)).out() binrhythm(.5, 50) :: sound('shaker').out() binrhythm(.5, 52) :: sound('808bd').n(3).out() @@ -93,14 +93,11 @@ if (flip(8, 75)) { }`, `// Race day - Bubobubobubo bpm(125); -beat(.5) :: sound('STB6') - .n(irand(1,10)).speed(0.5).rel(1) - .sus(0.1).out() +beat(.5) :: sound('STB6').n(irand(1,10)).gain(1).out() rhythm(flip(4) ? 1 : .5, 5, 8) :: sound('kick').out() rhythm(flip(2) ? .5 : .25, 7, 8) :: sound('click') .vel(0.1 + utriangle(.25)).n(irand(1,5)).out() -rhythm(.5, 2, 8) :: sound('snare').out() -`, +rhythm(.5, 2, 8) :: sound('snare').out()`, `// Structure et approximation - Bubobubobubo beat(.25) :: sound('zzfx').zzfx( // Randomized chaos :) @@ -126,7 +123,7 @@ beat(rarely(12) ? .5 : .25) :: sound('ST22') .cutoff(irand(200, 5000)) .resonance(rand(0.2,0.8)) .room(0.9).size(1).orbit(2) - .speed(0.25).vel(0.3).end(0.5) + .speed(0.5).vel(0.6).end(0.5) .out() beat(.5) :: snd('dr') .n([0, 0, 0, 0, 2, 8].beat()) @@ -135,21 +132,19 @@ beat(flip(2) ? 1 : 0.75) :: snd('bd').n(2).out() beat(4) :: snd('snare').n(5) .delay(0.5).delayt(bpm() / 60 / 8) .delayfb(0.25).out() -`, - `// Atarism - Bubobubobubo +`, `// Atarism - Bubobubobubo bpm(85); let modifier = [.5, 1, 2].beat(8); let othermod = [1, .5, 4].beat(4); -beat(modifier / 2):: sound('STA9').n([0,2].beat(.5)).speed(0.5).vel(0.5).out() -beat(.5)::sound('STA9').n([0, 20].beat(.5)).speed([1,1.5].repeatAll(4).beat() / 4) - .cutoff(500 + usine(.25) * 3000).vel(0.5).out() +beat(modifier / 2):: sound('STA9').n([0,2].beat(.5)).vel(0.5).out() +beat(.5)::sound('STA9').n([0, 20].beat(.5)).speed([1,1.5].repeatAll(4).beat() /2) + .cutoff(500 + usine(.25) * 3000).vel(1).room(0.9).out() beat(modifier / 2):: sound('STA9') - .n([0,7].beat(.5)).speed(flip(othermod) ? 2 :4).vel(0.45).out() + .n([0,7].beat(.5)).speed(flip(othermod) ? 2 : 4).vel(1).out() rhythm(.25, 3, 8, 1) :: sound('STA9') - .note([30, 33].pick()).n(32).speed(0.5).out() + .note([30, 33].pick()).n(32).out() rhythm(othermod, 5, 8) :: sound('dr').n([0,1,2].beat()).out() -beat(1) :: sound('kick').vel(1).out() -`, +beat(1) :: sound('kick').vel(1).out()`, `// Ancient rhythms - Bubobubobubo beat(1) :: snd('kick').out(); beat(2) :: snd('sd').room(0.9).size(0.9).out();