temp work

This commit is contained in:
2023-12-04 12:18:34 +01:00
75 changed files with 3079 additions and 3357 deletions

View File

@ -1,14 +1,17 @@
import { type Editor } from "../main";
import {
freqToMidi,
chord as parseChord,
noteNameToMidi,
resolvePitchBend,
safeScale
safeScale,
} from "zifferjs";
import { SkipEvent } from "./SkipEvent";
export type EventOperation<T> = (instance: T, ...args: any[]) => void;
export interface AbstractEvent {
[key: string]: any
[key: string]: any;
}
export class AbstractEvent {
@ -208,19 +211,26 @@ export class AbstractEvent {
return this.modify(func);
};
noteLength = (value: number | number[], ...kwargs: number[]): AbstractEvent => {
noteLength = (
value: number | number[],
...kwargs: number[]
): AbstractEvent => {
/**
* This function is used to set the note length of the Event.
*/
if(kwargs.length > 0) {
value = (Array.isArray(value) ? value.concat(kwargs) : [value, ...kwargs]);
if (kwargs.length > 0) {
value = Array.isArray(value) ? value.concat(kwargs) : [value, ...kwargs];
}
if(Array.isArray(value)) {
if (Array.isArray(value)) {
this.values["noteLength"] = value;
this.values.dur = value.map((v) => this.app.clock.convertPulseToSecond(v*4*this.app.clock.ppqn));
this.values.dur = value.map((v) =>
this.app.clock.convertPulseToSecond(v * 4 * this.app.clock.ppqn),
);
} else {
this.values["noteLength"] = value;
this.values.dur = this.app.clock.convertPulseToSecond(value*4*this.app.clock.ppqn);
this.values.dur = this.app.clock.convertPulseToSecond(
value * 4 * this.app.clock.ppqn,
);
}
return this;
};
@ -232,83 +242,138 @@ export abstract class AudibleEvent extends AbstractEvent {
}
pitch = (value: number | number[], ...kwargs: number[]): this => {
/*
* This function is used to set the pitch of the Event.
* @param value - The pitch value
* @returns The Event
*/
if(kwargs.length > 0) {
value = (Array.isArray(value) ? value.concat(kwargs) : [value, ...kwargs]);
/*
* This function is used to set the pitch of the Event.
* @param value - The pitch value
* @returns The Event
*/
if (kwargs.length > 0) {
value = Array.isArray(value) ? value.concat(kwargs) : [value, ...kwargs];
}
this.values["pitch"] = value;
if(this.values.key && this.values.parsedScale) this.update();
if (this.values.key && this.values.parsedScale) this.update();
return this;
}
};
pc = this.pitch;
octave = (value: number | number[], ...kwargs: number[]): this => {
/*
* This function is used to set the octave of the Event.
* @param value - The octave value
* @returns The Event
*/
if(kwargs.length > 0) {
value = (Array.isArray(value) ? value.concat(kwargs) : [value, ...kwargs]);
* This function is used to set the octave of the Event.
* @param value - The octave value
* @returns The Event
*/
if (kwargs.length > 0) {
value = Array.isArray(value) ? value.concat(kwargs) : [value, ...kwargs];
}
this.values["octave"] = value;
if(this.values.key && (this.values.pitch || this.values.pitch === 0) && this.values.parsedScale) this.update();
if (
this.values.key &&
(this.values.pitch || this.values.pitch === 0) &&
this.values.parsedScale
)
this.update();
return this;
};
key = (value: string | string[], ...kwargs: string[]): this => {
/*
* This function is used to set the key of the Event.
* @param value - The key value
* @returns The Event
*/
if(kwargs.length > 0) {
value = (Array.isArray(value) ? value.concat(kwargs) : [value, ...kwargs]);
/*
* This function is used to set the key of the Event.
* @param value - The key value
* @returns The Event
*/
if (kwargs.length > 0) {
value = Array.isArray(value) ? value.concat(kwargs) : [value, ...kwargs];
}
this.values["key"] = value;
if((this.values.pitch || this.values.pitch === 0) && this.values.parsedScale) this.update();
if (
(this.values.pitch || this.values.pitch === 0) &&
this.values.parsedScale
)
this.update();
return this;
};
scale = (value: string | number | (number|string)[], ...kwargs: (string|number)[]): this => {
scale = (
value: string | number | (number | string)[],
...kwargs: (string | number)[]
): this => {
/*
* This function is used to set the scale of the Event.
* @param value - The scale value
* @returns The Event
*/
if(kwargs.length > 0) {
value = (Array.isArray(value) ? value.concat(kwargs) : [value, ...kwargs]);
* This function is used to set the scale of the Event.
* @param value - The scale value
* @returns The Event
*/
if (kwargs.length > 0) {
value = Array.isArray(value) ? value.concat(kwargs) : [value, ...kwargs];
}
if (typeof value === "string" || typeof value === "number") {
this.values.parsedScale = safeScale(value) as number[];
} else if(Array.isArray(value)) {
} 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();
if (this.values.key && (this.values.pitch || this.values.pitch === 0)) {
this.update();
}
return this;
};
protected updateValue<T>(key: string, value: T | T[] | null): this {
if (value == null) return this;
this.values[key] = value;
return this;
}
public note = (
value: number | string | null,
...kwargs: number[] | string[]
) => {
if (typeof value === "string") {
const parsedNote = noteNameToMidi(value);
return this.updateValue("note", [parsedNote, ...kwargs].flat(Infinity));
} else if (typeof value == null || value == undefined) {
return new SkipEvent();
} else {
return this.updateValue("note", [value, ...kwargs].flat(Infinity));
}
};
public chord = (value: number | string, ...kwargs: number[]) => {
if (typeof value === "string") {
const chord = parseChord(value);
return this.updateValue("note", chord);
} else {
const chord = [value, ...kwargs].flat(Infinity);
return this.updateValue("note", chord);
}
};
public invert = (howMany: number = 0) => {
if (this.values.note) {
let notes = [...this.values.note];
notes = howMany < 0 ? [...notes].reverse() : notes;
for (let i = 0; i < Math.abs(howMany); i++) {
notes[i % notes.length] += howMany <= 0 ? -12 : 12;
}
return this.updateValue("note", notes);
} else {
return this;
}
};
freq = (value: number | number[], ...kwargs: number[]): this => {
/*
* This function is used to set the frequency of the Event.
* @param value - The frequency value
* @returns The Event
*/
if(kwargs.length > 0) {
value = (Array.isArray(value) ? value.concat(kwargs) : [value, ...kwargs]);
* This function is used to set the frequency of the Event.
* @param value - The frequency value
* @returns The Event
*/
if (kwargs.length > 0) {
value = Array.isArray(value) ? value.concat(kwargs) : [value, ...kwargs];
}
this.values["freq"] = value;
if(Array.isArray(value)) {
if (Array.isArray(value)) {
this.values["note"] = [];
this.values["bend"] = [];
for(const v of value) {
for (const v of value) {
const midiNote = freqToMidi(v);
if (midiNote % 1 !== 0) {
this.values["note"].push(Math.floor(midiNote));
@ -317,7 +382,7 @@ export abstract class AudibleEvent extends AbstractEvent {
this.values["note"].push(midiNote);
}
}
if(this.values.bend.length === 0) delete this.values.bend;
if (this.values.bend.length === 0) delete this.values.bend;
} else {
const midiNote = freqToMidi(value);
if (midiNote % 1 !== 0) {

View File

@ -1,8 +1,12 @@
import { AudibleEvent } from "./AbstractEvents";
import { type Editor } from "../main";
import { MidiConnection } from "../IO/MidiConnection";
import { noteFromPc, chord as parseChord } from "zifferjs";
import { filterObject, arrayOfObjectsToObjectWithArrays, objectWithArraysToArrayOfObjects } from "../Utils/Generic";
import { noteFromPc } from "zifferjs";
import {
filterObject,
arrayOfObjectsToObjectWithArrays,
objectWithArraysToArrayOfObjects,
} from "../Utils/Generic";
export type MidiParams = {
note: number;
@ -11,27 +15,20 @@ export type MidiParams = {
port?: number;
sustain?: number;
velocity?: number;
}
};
export class MidiEvent extends AudibleEvent {
midiConnection: MidiConnection;
constructor(input: MidiParams, public app: Editor) {
constructor(
input: MidiParams,
public app: Editor,
) {
super(app);
this.values = input;
this.midiConnection = app.api.MidiConnection;
}
public chord = (value: string) => {
this.values.note = parseChord(value);
return this;
};
note = (value: number | number[]): this => {
this.values["note"] = value;
return this;
};
sustain = (value: number | number[]): this => {
this.values["sustain"] = value;
return this;
@ -40,7 +37,7 @@ export class MidiEvent extends AudibleEvent {
velocity = (value: number | number[]): this => {
this.values["velocity"] = value;
return this;
}
};
channel = (value: number | number[]): this => {
this.values["channel"] = value;
@ -48,10 +45,12 @@ export class MidiEvent extends AudibleEvent {
};
port = (value: number | string | number[] | string[]): this => {
if(typeof value === "string"){
if (typeof value === "string") {
this.values["port"] = this.midiConnection.getMidiOutputIndex(value);
} else if(Array.isArray(value)){
this.values["port"] = value.map((v) => typeof v === "string" ? this.midiConnection.getMidiOutputIndex(v) : v);
} else if (Array.isArray(value)) {
this.values["port"] = value.map((v) =>
typeof v === "string" ? this.midiConnection.getMidiOutputIndex(v) : v,
);
}
return this;
};
@ -86,25 +85,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", "parsedScale", "octave"]);
const events = objectWithArraysToArrayOfObjects(filteredValues,["parsedScale"]);
const filteredValues = filterObject(this.values, [
"key",
"pitch",
"parsedScale",
"octave",
]);
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
(event.key as number) || "C4",
(event.pitch as number) || 0,
(event.parsedScale as number[]) || event.scale || "MAJOR",
(event.octave as number) || 0,
);
event.note = note;
if(bend) event.bend = bend;
if (bend) event.bend = bend;
});
const newArrays = arrayOfObjectsToObjectWithArrays(events) as MidiParams;
this.values.note = newArrays.note;
if(newArrays.bend) this.values.bend = newArrays.bend;
if (newArrays.bend) this.values.bend = newArrays.bend;
};
out = (): void => {
@ -114,9 +120,7 @@ export class MidiEvent extends AudibleEvent {
const note = params.note ? params.note : 60;
const sustain = params.sustain
? params.sustain *
event.app.clock.pulse_duration *
event.app.api.ppqn()
? params.sustain * event.app.clock.pulse_duration * event.app.api.ppqn()
: event.app.clock.pulse_duration * event.app.api.ppqn();
const bend = params.bend ? params.bend : undefined;
@ -124,22 +128,23 @@ export class MidiEvent extends AudibleEvent {
const port = params.port
? event.midiConnection.getMidiOutputIndex(params.port)
: event.midiConnection.getCurrentMidiPortIndex() || 0;
event.midiConnection.sendMidiNote(
note,
channel,
velocity,
sustain,
port,
bend
bend,
);
}
const events = objectWithArraysToArrayOfObjects(this.values,["parsedScale"]) as MidiParams[];
const events = objectWithArraysToArrayOfObjects(this.values, [
"parsedScale",
]) as MidiParams[];
events.forEach((p: MidiParams) => {
play(this,p);
play(this, p);
});
};
}

View File

@ -11,10 +11,7 @@ export class RestEvent extends AbstractEvent {
return RestEvent.createRestProxy(this.values["noteLength"], this.app);
};
public static createRestProxy = (
length: number,
app: Editor
): RestEvent => {
public static createRestProxy = (length: number, app: Editor): RestEvent => {
const instance = new RestEvent(length, app);
return new Proxy(instance, {
// @ts-ignore

View File

@ -6,17 +6,13 @@ import {
arrayOfObjectsToObjectWithArrays,
objectWithArraysToArrayOfObjects,
} from "../Utils/Generic";
import {
chord as parseChord,
midiToFreq,
noteFromPc,
noteNameToMidi,
} from "zifferjs";
import { midiToFreq, noteFromPc } from "zifferjs";
import {
superdough,
// @ts-ignore
} from "superdough";
// import { Sound } from "zifferjs/src/types";
export type SoundParams = {
dur: number | number[];
@ -36,7 +32,7 @@ export class SoundEvent extends AudibleEvent {
nudge: number;
sound: any;
private methodMap = {
private static methodMap = {
volume: ["volume", "vol"],
zrand: ["zrand", "zr"],
curve: ["curve"],
@ -70,17 +66,23 @@ export class SoundEvent extends AudibleEvent {
phaserDepth: ["phaserDepth", "phasdepth"],
phaserSweep: ["phaserSweep", "phassweep"],
phaserCenter: ["phaserCenter", "phascenter"],
fmadsr: (a: number, d: number, s: number, r: number) => {
this.updateValue("fmattack", a);
this.updateValue("fmdecay", d);
this.updateValue("fmsustain", s);
this.updateValue("fmrelease", r);
return this;
fmadsr: function (
self: SoundEvent,
a: number,
d: number,
s: number,
r: number,
) {
self.updateValue("fmattack", a);
self.updateValue("fmdecay", d);
self.updateValue("fmsustain", s);
self.updateValue("fmrelease", r);
return self;
},
fmad: (a: number, d: number) => {
this.updateValue("fmattack", a);
this.updateValue("fmdecay", d);
return this;
fmad: function (self: SoundEvent, a: number, d: number) {
self.updateValue("fmattack", a);
self.updateValue("fmdecay", d);
return self;
},
ftype: ["ftype"],
fanchor: ["fanchor"],
@ -88,147 +90,185 @@ export class SoundEvent extends AudibleEvent {
decay: ["decay", "dec"],
sustain: ["sustain", "sus"],
release: ["release", "rel"],
adsr: (a: number, d: number, s: number, r: number) => {
this.updateValue("attack", a);
this.updateValue("decay", d);
this.updateValue("sustain", s);
this.updateValue("release", r);
return this;
adsr: function (
self: SoundEvent,
a: number,
d: number,
s: number,
r: number,
) {
self.updateValue("attack", a);
self.updateValue("decay", d);
self.updateValue("sustain", s);
self.updateValue("release", r);
return self;
},
ad: (a: number, d: number) => {
this.updateValue("attack", a);
this.updateValue("decay", d);
this.updateValue("sustain", 0.0);
this.updateValue("release", 0.0);
return this;
ad: function (self: SoundEvent, a: number, d: number) {
self.updateValue("attack", a);
self.updateValue("decay", d);
self.updateValue("sustain", 0.0);
self.updateValue("release", 0.0);
return self;
},
scope: function (self: SoundEvent) {
self.updateValue("analyze", true);
return self;
},
debug: function (self: SoundEvent, callback?: Function) {
self.updateValue("debug", true);
if (callback) {
self.updateValue("debugFunction", callback);
}
return self;
},
lpenv: ["lpenv", "lpe"],
lpattack: ["lpattack", "lpa"],
lpdecay: ["lpdecay", "lpd"],
lpsustain: ["lpsustain", "lps"],
lprelease: ["lprelease", "lpr"],
cutoff: (value: number, resonance?: number) => {
this.updateValue("cutoff", value);
cutoff: function (self: SoundEvent, value: number, resonance?: number) {
self.updateValue("cutoff", value);
if (resonance) {
this.updateValue("resonance", resonance);
self.updateValue("resonance", resonance);
}
return this;
return self;
},
lpf: (value: number, resonance?: number) => {
this.updateValue("cutoff", value);
lpf: function (self: SoundEvent, value: number, resonance?: number) {
self.updateValue("cutoff", value);
if (resonance) {
this.updateValue("resonance", resonance);
self.updateValue("resonance", resonance);
}
return this;
return self;
},
resonance: (value: number) => {
resonance: function (self: SoundEvent, value: number) {
if (value >= 0 && value <= 1) {
this.updateValue("resonance", 50 * value);
self.updateValue("resonance", 50 * value);
}
return this;
return self;
},
lpadsr: (depth: number, a: number, d: number, s: number, r: number) => {
this.updateValue("lpenv", depth);
this.updateValue("lpattack", a);
this.updateValue("lpdecay", d);
this.updateValue("lpsustain", s);
this.updateValue("lprelease", r);
return this;
lpadsr: function (
self: SoundEvent,
depth: number,
a: number,
d: number,
s: number,
r: number,
) {
self.updateValue("lpenv", depth);
self.updateValue("lpattack", a);
self.updateValue("lpdecay", d);
self.updateValue("lpsustain", s);
self.updateValue("lprelease", r);
return self;
},
lpad: (depth: number, a: number, d: number) => {
this.updateValue("lpenv", depth);
this.updateValue("lpattack", a);
this.updateValue("lpdecay", d);
this.updateValue("lpsustain", 0);
this.updateValue("lprelease", 0);
return this;
lpad: function (self: SoundEvent, depth: number, a: number, d: number) {
self.updateValue("lpenv", depth);
self.updateValue("lpattack", a);
self.updateValue("lpdecay", d);
self.updateValue("lpsustain", 0);
self.updateValue("lprelease", 0);
return self;
},
hpenv: ["hpenv", "hpe"],
hpattack: ["hpattack", "hpa"],
hpdecay: ["hpdecay", "hpd"],
hpsustain: ["hpsustain", "hpsus"],
hprelease: ["hprelease", "hpr"],
hcutoff: (value: number, resonance?: number) => {
this.updateValue("hcutoff", value);
hcutoff: function (self: SoundEvent, value: number, resonance?: number) {
self.updateValue("hcutoff", value);
if (resonance) {
this.updateValue("hresonance", resonance);
self.updateValue("hresonance", resonance);
}
return this;
return self;
},
hpf: (value: number, resonance?: number) => {
this.updateValue("hcutoff", value);
hpf: function (self: SoundEvent, value: number, resonance?: number) {
self.updateValue("hcutoff", value);
if (resonance) {
this.updateValue("hresonance", resonance);
self.updateValue("hresonance", resonance);
}
return this;
return self;
},
hpq: (value: number) => {
this.updateValue("hresonance", value);
return this;
hpq: function (self: SoundEvent, value: number) {
self.updateValue("hresonance", value);
return self;
},
hpadsr: (depth: number, a: number, d: number, s: number, r: number) => {
this.updateValue("hpenv", depth);
this.updateValue("hpattack", a);
this.updateValue("hpdecay", d);
this.updateValue("hpsustain", s);
this.updateValue("hprelease", r);
return this;
hpadsr: function (
self: SoundEvent,
depth: number,
a: number,
d: number,
s: number,
r: number,
) {
self.updateValue("hpenv", depth);
self.updateValue("hpattack", a);
self.updateValue("hpdecay", d);
self.updateValue("hpsustain", s);
self.updateValue("hprelease", r);
return self;
},
hpad: (depth: number, a: number, d: number) => {
this.updateValue("hpenv", depth);
this.updateValue("hpattack", a);
this.updateValue("hpdecay", d);
this.updateValue("hpsustain", 0);
this.updateValue("hprelease", 0);
return this;
hpad: function (self: SoundEvent, depth: number, a: number, d: number) {
self.updateValue("hpenv", depth);
self.updateValue("hpattack", a);
self.updateValue("hpdecay", d);
self.updateValue("hpsustain", 0);
self.updateValue("hprelease", 0);
return self;
},
bpenv: ["bpenv", "bpe"],
bpattack: ["bpattack", "bpa"],
bpdecay: ["bpdecay", "bpd"],
bpsustain: ["bpsustain", "bps"],
bprelease: ["bprelease", "bpr"],
bandf: (value: number, resonance?: number) => {
this.updateValue("bandf", value);
bandf: function (self: SoundEvent, value: number, resonance?: number) {
self.updateValue("bandf", value);
if (resonance) {
this.updateValue("bandq", resonance);
self.updateValue("bandq", resonance);
}
return this;
return self;
},
bpf: (value: number, resonance?: number) => {
this.updateValue("bandf", value);
bpf: function (self: SoundEvent, value: number, resonance?: number) {
self.updateValue("bandf", value);
if (resonance) {
this.updateValue("bandq", resonance);
self.updateValue("bandq", resonance);
}
return this;
return self;
},
bandq: ["bandq", "bpq"],
bpadsr: (depth: number, a: number, d: number, s: number, r: number) => {
this.updateValue("bpenv", depth);
this.updateValue("bpattack", a);
this.updateValue("bpdecay", d);
this.updateValue("bpsustain", s);
this.updateValue("bprelease", r);
return this;
bpadsr: function (
self: SoundEvent,
depth: number,
a: number,
d: number,
s: number,
r: number,
) {
self.updateValue("bpenv", depth);
self.updateValue("bpattack", a);
self.updateValue("bpdecay", d);
self.updateValue("bpsustain", s);
self.updateValue("bprelease", r);
return self;
},
bpad: (depth: number, a: number, d: number) => {
this.updateValue("bpenv", depth);
this.updateValue("bpattack", a);
this.updateValue("bpdecay", d);
this.updateValue("bpsustain", 0);
this.updateValue("bprelease", 0);
return this;
bpad: function (self: SoundEvent, depth: number, a: number, d: number) {
self.updateValue("bpenv", depth);
self.updateValue("bpattack", a);
self.updateValue("bpdecay", d);
self.updateValue("bpsustain", 0);
self.updateValue("bprelease", 0);
return self;
},
vib: ["vib"],
vibmod: ["vibmod"],
fm: (value: number | string) => {
fm: function (self: SoundEvent, value: number | string) {
if (typeof value === "number") {
this.values["fmi"] = value;
self.values["fmi"] = value;
} else {
let values = value.split(":");
this.values["fmi"] = parseFloat(values[0]);
if (values.length > 1) this.values["fmh"] = parseFloat(values[1]);
self.values["fmi"] = parseFloat(values[0]);
if (values.length > 1) self.values["fmh"] = parseFloat(values[1]);
}
return this;
return self;
},
loop: ["loop"],
loopBegin: ["loopBegin", "loopb"],
@ -236,13 +276,13 @@ export class SoundEvent extends AudibleEvent {
begin: ["begin"],
end: ["end"],
gain: ["gain"],
dbgain: (value: number) => {
this.updateValue("gain", Math.min(Math.pow(10, value / 20), 10));
return this;
dbgain: function (self: SoundEvent, value: number) {
self.updateValue("gain", Math.min(Math.pow(10, value / 20), 10));
return self;
},
db: (value: number) => {
this.updateValue("gain", Math.min(Math.pow(10, value / 20), 10));
return this;
db: function (self: SoundEvent, value: number) {
self.updateValue("gain", Math.min(Math.pow(10, value / 20), 10));
return self;
},
velocity: ["velocity", "vel"],
pan: ["pan"],
@ -263,59 +303,74 @@ export class SoundEvent extends AudibleEvent {
roomlp: ["roomlp", "rlp"],
roomdim: ["roomdim", "rdim"],
sound: ["s", "sound"],
size: (value: number) => {
this.updateValue("roomsize", value);
return this;
size: function (self: SoundEvent, value: number) {
self.updateValue("roomsize", value);
return self;
},
sz: (value: number) => {
this.updateValue("roomsize", value);
return this;
sz: function (self: SoundEvent, value: number) {
self.updateValue("roomsize", value);
return self;
},
comp: ["compressor", "cmp"],
ratio: (value: number) => {
this.updateValue("compressorRatio", value);
return this;
ratio: function (self: SoundEvent, value: number) {
self.updateValue("compressorRatio", value);
return self;
},
knee: (value: number) => {
this.updateValue("compressorKnee", value);
return this;
knee: function (self: SoundEvent, value: number) {
self.updateValue("compressorKnee", value);
return self;
},
compAttack: (value: number) => {
this.updateValue("compressorAttack", value);
return this;
compAttack: function (self: SoundEvent, value: number) {
self.updateValue("compressorAttack", value);
return self;
},
compRelease: (value: number) => {
this.updateValue("compressorRelease", value);
return this;
compRelease: function (self: SoundEvent, value: number) {
self.updateValue("compressorRelease", value);
return self;
},
stretch: (beat: number) => {
this.updateValue("unit", "c");
this.updateValue("speed", 1 / beat);
this.updateValue("cut", beat);
return this;
stretch: function (self: SoundEvent, beat: number) {
self.updateValue("unit", "c");
self.updateValue("speed", 1 / beat);
self.updateValue("cut", beat);
return self;
},
};
constructor(sound: string | string[] | SoundParams, public app: Editor) {
constructor(
sound: string | string[] | SoundParams,
public app: Editor,
) {
super(app);
this.nudge = app.dough_nudge / 100;
for (const [methodName, keys] of Object.entries(this.methodMap)) {
if (Symbol.iterator in Object(keys)) {
for (const [methodName, keys] of Object.entries(SoundEvent.methodMap)) {
if (typeof keys === "object" && Symbol.iterator in Object(keys)) {
for (const key of keys as string[]) {
// @ts-ignore
// Using arrow function to maintain 'this' context
this[key] = (value: number) => this.updateValue(keys[0], value);
}
} else {
// @ts-ignore
this[methodName] = keys;
this[methodName] = (...args) => keys(this, ...args);
}
}
// for (const [methodName, keys] of Object.entries(SoundEvent.methodMap)) {
// if (typeof keys === "object" && Symbol.iterator in Object(keys)) {
// for (const key of keys as string[]) {
// // @ts-ignore
// this[key] = (value: number) => this.updateValue(this, keys[0], value);
// }
// } else {
// // @ts-ignore
// this[methodName] = keys;
// }
// }
this.values = this.processSound(sound);
}
private processSound = (
sound: string | string[] | SoundParams | SoundParams[]
sound: string | string[] | SoundParams | SoundParams[],
): SoundParams => {
if (Array.isArray(sound) && typeof sound[0] === "string") {
const s: string[] = [];
@ -331,12 +386,10 @@ export class SoundEvent extends AudibleEvent {
s,
n: n.length > 0 ? n : undefined,
dur: this.app.clock.convertPulseToSecond(this.app.clock.ppqn),
analyze: true,
};
} else if (typeof sound === "object") {
const validatedObj: SoundParams = {
dur: this.app.clock.convertPulseToSecond(this.app.clock.ppqn),
analyze: true,
...(sound as Partial<SoundParams>),
};
return validatedObj;
@ -349,23 +402,13 @@ export class SoundEvent extends AudibleEvent {
s,
n,
dur: this.app.clock.convertPulseToSecond(this.app.clock.ppqn),
analyze: true,
};
} else {
return { s: sound, dur: 0.5, analyze: true };
return { s: sound, dur: 0.5 };
}
}
};
private updateValue<T>(
key: string,
value: T | T[] | SoundParams[] | null
): this {
if (value == null) return this;
this.values[key] = value;
return this;
}
// ================================================================================
// AbstactEvent overrides
// ================================================================================
@ -395,7 +438,7 @@ export class SoundEvent extends AudibleEvent {
(event.key as number) || "C4",
(event.pitch as number) || 0,
(event.parsedScale as number[]) || event.scale || "MAJOR",
(event.octave as number) || 0
(event.octave as number) || 0,
);
event.note = note;
event.freq = midiToFreq(note);
@ -407,38 +450,6 @@ export class SoundEvent extends AudibleEvent {
this.values.freq = newArrays.freq;
};
public chord = (value: string) => {
const chord = parseChord(value);
return this.updateValue("note", chord);
};
public invert = (howMany: number = 0) => {
if (this.values.chord) {
let notes = this.values.chord.map(
(obj: { [key: string]: number }) => obj.note
);
notes = howMany < 0 ? [...notes].reverse() : notes;
for (let i = 0; i < Math.abs(howMany); i++) {
notes[i % notes.length] += howMany <= 0 ? -12 : 12;
}
const chord = notes.map((note: number) => {
return { note: note, freq: midiToFreq(note) };
});
return this.updateValue("chord", chord);
} else {
return this;
}
};
public note = (value: number | string | null) => {
if (typeof value === "string") {
return this.updateValue("note", noteNameToMidi(value));
} else if (typeof value == null || value == undefined) {
return this.updateValue("note", 0).updateValue("gain", 0);
} else {
return this.updateValue("note", value);
}
};
out = (orbit?: number | number[]): void => {
if (orbit) this.values["orbit"] = orbit;
const events = objectWithArraysToArrayOfObjects(this.values, [
@ -456,7 +467,7 @@ export class SoundEvent extends AudibleEvent {
}
superdough(
filteredEvent,
this.nudge - this.app.clock.deviation,
this.nudge - this.app.clock.deadline,
filteredEvent.dur
);
}
@ -482,7 +493,7 @@ export class SoundEvent extends AudibleEvent {
address: oscAddress,
port: oscPort,
message: event,
timetag: Math.round(Date.now() + this.nudge - this.app.clock.deviation),
timetag: Math.round(Date.now() + this.nudge - this.app.clock.deadline),
} as OSCMessage);
}
};

View File

@ -11,7 +11,7 @@ import { TonnetzSpaces } from "zifferjs/src/tonnetz";
export type InputOptions = { [key: string]: string | number };
export class Player extends AbstractEvent {
input: string|number;
input: string | number;
ziffers: Ziffers;
initCallTime: number = 0;
startCallTime: number = 0;
@ -26,10 +26,10 @@ export class Player extends AbstractEvent {
skipIndex = 0;
constructor(
input: string|number|Generator<number>,
input: string | number | Generator<number>,
options: InputOptions,
public app: Editor,
zid: string = ""
zid: string = "",
) {
super(app);
this.options = options;
@ -38,9 +38,9 @@ export class Player extends AbstractEvent {
this.ziffers = new Ziffers(input, options);
} else if (typeof input === "number") {
this.input = input;
this.ziffers = Ziffers.fromNumber(input,options);
this.ziffers = Ziffers.fromNumber(input, options);
} else {
this.ziffers = Ziffers.fromGenerator(input,options);
this.ziffers = Ziffers.fromGenerator(input, options);
this.input = this.ziffers.input;
}
this.zid = zid;
@ -159,7 +159,7 @@ export class Player extends AbstractEvent {
if (this.areWeThereYet()) {
const event = this.next() as Pitch | Chord | ZRest;
const noteLengthInSeconds = this.app.clock.convertPulseToSecond(
event.duration * 4 * this.app.clock.ppqn
event.duration * 4 * this.app.clock.ppqn,
);
if (event instanceof Pitch) {
const obj = event.getExisting(
@ -169,7 +169,7 @@ export class Player extends AbstractEvent {
"key",
"scale",
"octave",
"parsedScale"
"parsedScale",
) as SoundParams;
if (event.sound) name = event.sound as string;
if (event.soundIndex) obj.n = event.soundIndex as number;
@ -184,14 +184,14 @@ export class Player extends AbstractEvent {
"key",
"scale",
"octave",
"parsedScale"
"parsedScale",
);
}) as SoundParams[];
const add = { dur: noteLengthInSeconds } as SoundParams;
if (name) add.s = name;
let sound = arrayOfObjectsToObjectWithArrays(
pitches,
add
add,
) as SoundParams;
return new SoundEvent(sound, this.app);
} else if (event instanceof ZRest) {
@ -212,7 +212,7 @@ export class Player extends AbstractEvent {
"key",
"scale",
"octave",
"parsedScale"
"parsedScale",
) as MidiParams;
if (event instanceof Pitch) {
if (event.soundIndex) obj.channel = event.soundIndex as number;
@ -245,6 +245,12 @@ export class Player extends AbstractEvent {
return this;
}
tonnetz(transform: string, tonnetz: TonnetzSpaces = [3, 4, 5]) {
// @ts-ignore
if (this.atTheBeginning()) this.ziffers.tonnetz(transform, tonnetz);
return this;
}
triadTonnetz(transform: string, tonnetz: TonnetzSpaces = [3, 4, 5]) {
if (this.atTheBeginning()) this.ziffers.triadTonnetz(transform, tonnetz);
return this;