Updated zifferjs and added edo scales
This commit is contained in:
@ -43,7 +43,7 @@
|
||||
"tone": "^14.8.49",
|
||||
"unique-names-generator": "^4.7.1",
|
||||
"vite-plugin-markdown": "^2.1.0",
|
||||
"zifferjs": "^0.0.53",
|
||||
"zifferjs": "^0.0.54",
|
||||
"zyklus": "^0.1.4",
|
||||
"zzfx": "^1.2.0"
|
||||
}
|
||||
|
||||
@ -146,6 +146,7 @@ export class UserAPI {
|
||||
: (this.app.selectedExample as string);
|
||||
}
|
||||
this.stop();
|
||||
this.resetAllFromCache();
|
||||
this.play();
|
||||
};
|
||||
|
||||
@ -168,6 +169,7 @@ export class UserAPI {
|
||||
this.stop();
|
||||
this.play();
|
||||
this.app.exampleIsPlaying = true;
|
||||
this.resetAllFromCache();
|
||||
evaluateOnce(this.app, code as string);
|
||||
};
|
||||
|
||||
|
||||
@ -8,7 +8,7 @@ import {
|
||||
} from "zifferjs";
|
||||
import { SkipEvent } from "./SkipEvent";
|
||||
import { SoundParams } from "./SoundEvent";
|
||||
import { centsToSemitones, ratiosToSemitones } from "zifferjs/src/scale";
|
||||
import { centsToSemitones, edoToSemitones, ratiosToSemitones } from "zifferjs/src/scale";
|
||||
|
||||
export type EventOperation<T> = (instance: T, ...args: any[]) => void;
|
||||
|
||||
@ -295,7 +295,9 @@ export abstract class AudibleEvent extends AbstractEvent {
|
||||
value = Array.isArray(value) ? value.concat(kwargs) : [value, ...kwargs];
|
||||
}
|
||||
this.values["pitch"] = value;
|
||||
if (this.values.key && this.values.parsedScale) this.update();
|
||||
this.values["originalPitch"] = value;
|
||||
this.defaultPitchKeyScale();
|
||||
this.update();
|
||||
return this;
|
||||
};
|
||||
|
||||
@ -310,7 +312,7 @@ export abstract class AudibleEvent extends AbstractEvent {
|
||||
if (kwargs.length > 0) {
|
||||
value = Array.isArray(value) ? value.concat(kwargs) : [value, ...kwargs];
|
||||
}
|
||||
this.values["octave"] = value;
|
||||
this.values["paramOctave"] = value;
|
||||
if (
|
||||
this.values.key &&
|
||||
(this.values.pitch || this.values.pitch === 0) &&
|
||||
@ -338,6 +340,12 @@ export abstract class AudibleEvent extends AbstractEvent {
|
||||
return this;
|
||||
};
|
||||
|
||||
defaultPitchKeyScale() {
|
||||
if (!this.values.key) this.values.key = 60;
|
||||
if (!(this.values.pitch || this.values.pitch === 0)) this.values.pitch = 0;
|
||||
if (!this.values.parsedScale) this.values.parsedScale = safeScale("major");
|
||||
}
|
||||
|
||||
scale = (
|
||||
value: string | number | (number | string)[],
|
||||
...kwargs: (string | number)[]
|
||||
@ -355,30 +363,24 @@ export abstract class AudibleEvent extends AbstractEvent {
|
||||
} else if (Array.isArray(value)) {
|
||||
this.values.parsedScale = value.map((v) => safeScale(v));
|
||||
}
|
||||
if (this.values.key && (this.values.pitch || this.values.pitch === 0)) {
|
||||
this.update();
|
||||
}
|
||||
this.defaultPitchKeyScale();
|
||||
this.update();
|
||||
return this;
|
||||
};
|
||||
|
||||
updateKeyAndPitch() {
|
||||
if (!this.values.key) this.values.key = 60;
|
||||
if (!(this.values.pitch || this.values.pitch === 0)) this.values.pitch = 0;
|
||||
}
|
||||
|
||||
semitones(values: number|number[], ...rest: number[]) {
|
||||
const scaleValues = typeof values === "number" ? [values, ...rest] : values;
|
||||
this.values.parsedScale = safeScale(scaleValues);
|
||||
this.updateKeyAndPitch();
|
||||
this.defaultPitchKeyScale();
|
||||
this.update();
|
||||
return this;
|
||||
}
|
||||
steps = this.semitones;
|
||||
|
||||
|
||||
cents(values: number|number[], ...rest: number[]) {
|
||||
const scaleValues = typeof values === "number" ? [values, ...rest] : values;
|
||||
this.values.parsedScale = safeScale(centsToSemitones(scaleValues));
|
||||
this.updateKeyAndPitch();
|
||||
this.defaultPitchKeyScale();
|
||||
this.update();
|
||||
return this;
|
||||
}
|
||||
@ -386,11 +388,18 @@ export abstract class AudibleEvent extends AbstractEvent {
|
||||
ratios(values: number|number[], ...rest: number[]) {
|
||||
const scaleValues = typeof values === "number" ? [values, ...rest] : values;
|
||||
this.values.parsedScale = safeScale(ratiosToSemitones(scaleValues));
|
||||
this.updateKeyAndPitch();
|
||||
this.defaultPitchKeyScale();
|
||||
this.update();
|
||||
return this;
|
||||
}
|
||||
|
||||
edo(value: number, intervals: string|number[] = new Array(value).fill(1)) {
|
||||
this.values.parsedScale = edoToSemitones(value, intervals);
|
||||
this.defaultPitchKeyScale();
|
||||
this.update();
|
||||
return this;
|
||||
}
|
||||
|
||||
protected updateValue<T>(key: string, value: T | T[] | null): this {
|
||||
if (value == null) return this;
|
||||
this.values[key] = value;
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { AudibleEvent } from "./AbstractEvents";
|
||||
import { type Editor } from "../main";
|
||||
import { MidiConnection } from "../IO/MidiConnection";
|
||||
import { noteFromPc } from "zifferjs";
|
||||
import { resolvePitchClass } from "zifferjs";
|
||||
import {
|
||||
filterObject,
|
||||
arrayOfObjectsToObjectWithArrays,
|
||||
@ -84,31 +84,32 @@ export class MidiEvent extends AudibleEvent {
|
||||
};
|
||||
|
||||
update = (): void => {
|
||||
// Get key, pitch, parsedScale and octave from this.values object
|
||||
const filteredValues = filterObject(this.values, [
|
||||
"key",
|
||||
"pitch",
|
||||
"originalPitch",
|
||||
"parsedScale",
|
||||
"octave",
|
||||
"addedOctave"
|
||||
]);
|
||||
|
||||
const events = objectWithArraysToArrayOfObjects(filteredValues, [
|
||||
"parsedScale",
|
||||
]);
|
||||
|
||||
events.forEach((event) => {
|
||||
const [note, bend] = noteFromPc(
|
||||
(event.key as number) || "C4",
|
||||
(event.pitch as number) || 0,
|
||||
(event.parsedScale as number[]) || event.scale || "MAJOR",
|
||||
(event.octave as number) || 0,
|
||||
events.forEach((soundEvent) => {
|
||||
const resolvedPitchClass = resolvePitchClass(
|
||||
(soundEvent.key || "C4"),
|
||||
(soundEvent.originalPitch || soundEvent.pitch || 0),
|
||||
(soundEvent.parsedScale || soundEvent.scale || "MAJOR"),
|
||||
(soundEvent.addedOctave || 0)
|
||||
);
|
||||
event.note = note;
|
||||
if (bend) event.bend = bend;
|
||||
soundEvent.note = resolvedPitchClass.note;
|
||||
soundEvent.pitch = resolvedPitchClass.pitch;
|
||||
soundEvent.octave = resolvedPitchClass.octave;
|
||||
});
|
||||
|
||||
const newArrays = arrayOfObjectsToObjectWithArrays(events) as MidiParams;
|
||||
|
||||
|
||||
this.values.note = newArrays.note;
|
||||
if (newArrays.bend) this.values.bend = newArrays.bend;
|
||||
};
|
||||
|
||||
@ -6,7 +6,7 @@ import {
|
||||
arrayOfObjectsToObjectWithArrays,
|
||||
objectWithArraysToArrayOfObjects,
|
||||
} from "../Utils/Generic";
|
||||
import { midiToFreq, noteFromPc } from "zifferjs";
|
||||
import { midiToFreq, resolvePitchClass } from "zifferjs";
|
||||
|
||||
import {
|
||||
superdough,
|
||||
@ -22,10 +22,13 @@ export type SoundParams = {
|
||||
note?: number | number[];
|
||||
freq?: number | number[];
|
||||
pitch?: number | number[];
|
||||
originalPitch?: number | number[];
|
||||
key?: string;
|
||||
scale?: string;
|
||||
parsedScale?: number[];
|
||||
octave?: number | number[];
|
||||
addedOctave?: number | number[];
|
||||
pitchOctave?: number | number[];
|
||||
};
|
||||
|
||||
export class SoundEvent extends AudibleEvent {
|
||||
@ -387,27 +390,36 @@ export class SoundEvent extends AudibleEvent {
|
||||
const filteredValues = filterObject(this.values, [
|
||||
"key",
|
||||
"pitch",
|
||||
"originalPitch",
|
||||
"parsedScale",
|
||||
"addedOctave",
|
||||
"octave",
|
||||
"paramOctave"
|
||||
]);
|
||||
const events = objectWithArraysToArrayOfObjects(filteredValues, [
|
||||
"parsedScale",
|
||||
]);
|
||||
events.forEach((event) => {
|
||||
const [note, _] = noteFromPc(
|
||||
(event.key as number) || "C4",
|
||||
(event.pitch as number) || 0,
|
||||
(event.parsedScale as number[]) || event.scale || "MAJOR",
|
||||
(event.octave as number) || 0,
|
||||
events.forEach((soundEvent) => {
|
||||
const resolvedPitchClass = resolvePitchClass(
|
||||
(soundEvent.key || "C4"),
|
||||
(soundEvent.originalPitch || soundEvent.pitch || 0),
|
||||
(soundEvent.parsedScale || soundEvent.scale || "MAJOR"),
|
||||
(soundEvent.paramOctave || 0)+(soundEvent.addedOctave || 0)
|
||||
);
|
||||
event.note = note;
|
||||
event.freq = midiToFreq(note);
|
||||
soundEvent.note = resolvedPitchClass.note;
|
||||
soundEvent.freq = midiToFreq(resolvedPitchClass.note);
|
||||
soundEvent.pitch = resolvedPitchClass.pitch;
|
||||
soundEvent.octave = resolvedPitchClass.octave;
|
||||
});
|
||||
|
||||
const newArrays = arrayOfObjectsToObjectWithArrays(events) as SoundParams;
|
||||
|
||||
this.values.note = newArrays.note;
|
||||
this.values.freq = newArrays.freq;
|
||||
this.values.pitch = newArrays.pitch;
|
||||
this.values.octave = newArrays.octave;
|
||||
this.values.pitchOctave = newArrays.pitchOctave;
|
||||
|
||||
};
|
||||
|
||||
out = (orbit?: number | number[]): void => {
|
||||
|
||||
@ -186,9 +186,12 @@ export class Player extends AbstractEvent {
|
||||
"freq",
|
||||
"note",
|
||||
"pitch",
|
||||
"originalPitch",
|
||||
"key",
|
||||
"scale",
|
||||
"octave",
|
||||
"pitchOctave",
|
||||
"addedOctave",
|
||||
"parsedScale",
|
||||
) as SoundParams;
|
||||
|
||||
@ -205,9 +208,12 @@ export class Player extends AbstractEvent {
|
||||
"freq",
|
||||
"note",
|
||||
"pitch",
|
||||
"originalPitch",
|
||||
"key",
|
||||
"scale",
|
||||
"octave",
|
||||
"pitchOctave",
|
||||
"addedOctave",
|
||||
"parsedScale",
|
||||
);
|
||||
}) as SoundParams[];
|
||||
@ -236,10 +242,13 @@ export class Player extends AbstractEvent {
|
||||
const obj = event.getExisting(
|
||||
"note",
|
||||
"pitch",
|
||||
"originalPitch",
|
||||
"bend",
|
||||
"key",
|
||||
"scale",
|
||||
"octave",
|
||||
"pitchOctave",
|
||||
"addedOctave",
|
||||
"parsedScale",
|
||||
) as MidiParams;
|
||||
if (event instanceof Pitch) {
|
||||
@ -281,6 +290,11 @@ export class Player extends AbstractEvent {
|
||||
return this;
|
||||
}
|
||||
|
||||
edo(value: number, scale: string|number[] = new Array(value).fill(1)) {
|
||||
if (this.atTheBeginning()) this.ziffers.edo(value, scale);
|
||||
return this;
|
||||
}
|
||||
|
||||
key(name: string) {
|
||||
if (this.atTheBeginning()) this.ziffers.key(name);
|
||||
return this;
|
||||
|
||||
@ -170,6 +170,26 @@ ${makeExample(
|
||||
true,
|
||||
)}
|
||||
|
||||
- <ic>edo(number, scale?: string|number[])</ic>: Create scale from equal divisions of the octave. Creates chromatic scale by default.
|
||||
|
||||
${makeExample(
|
||||
"Play pitches from scale created from equal divisions of the octave",
|
||||
`
|
||||
z0("e bd bd <bd bd [bd bd] [bd bd bd bd]>").sound().out()
|
||||
flipbar(1) :: rhythm(.25,14,16) :: sound("ST10:30").stretch(3).gain(0.5)
|
||||
.pitch([0,10,r(20,40),r(100,200),r(-200,200),r(200,300),200,r(3,666)].beat([1.0,0.5,0.25].bar(6)))
|
||||
.octave(r(-6,6))
|
||||
.edo(666,"rocritonic")
|
||||
.out()
|
||||
rhythm(2.0,26,32) :: sound("ST20").n([22,5,24,34,31,5,11,19].pick()).stretch(rI(1,6))
|
||||
.pitch(rI(127,300))
|
||||
.edo(666)
|
||||
.out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
|
||||
|
||||
- <ic>scale(scale: string, base note: number)</ic>: Map each element of the list to the closest note of the slected scale. [0, 2, 3, 5 ].scale("major", 50) returns [50, 52, <ic>54</ic>, 55]. You can use western scale names like (Major, Minor, Minor pentatonic ...) or [zeitler](https://ianring.com/musictheory/scales/traditions/zeitler) scale names. Alternatively you can also use the integers as used by Ian Ring in his [study of scales](https://ianring.com/musictheory/scales/).
|
||||
|
||||
${makeExample(
|
||||
|
||||
@ -4028,10 +4028,10 @@ yaml@^2.1.1:
|
||||
resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.1.tgz#02fe0975d23cd441242aa7204e09fc28ac2ac33b"
|
||||
integrity sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==
|
||||
|
||||
zifferjs@^0.0.53:
|
||||
version "0.0.53"
|
||||
resolved "https://registry.yarnpkg.com/zifferjs/-/zifferjs-0.0.53.tgz#5e6e8a80ef90cd59ed607ab7cf02592efc03b08d"
|
||||
integrity sha512-XGREU1ClhaatEZaek6gTBcwaNfFkUZLENWhXILPjLCODXzFoC6D/qaYCaIegcJdGgqB7At3DqID4yNwFLRPeqQ==
|
||||
zifferjs@^0.0.54:
|
||||
version "0.0.54"
|
||||
resolved "https://registry.yarnpkg.com/zifferjs/-/zifferjs-0.0.54.tgz#2dd4b43820f85d797c13dd35d933476ecacdb146"
|
||||
integrity sha512-vo1I12VvW4yFdVJTVnrfOxeOpWq7tIMZ67BfXxcK0t9GveLi+3GrF1zjowq8WCDssVgw+lQHEjdGVhO5FbK3RA==
|
||||
|
||||
zyklus@^0.1.4:
|
||||
version "0.1.4"
|
||||
|
||||
Reference in New Issue
Block a user