Pushing the experimental SoundEvent refactoring

This commit is contained in:
2023-11-26 13:43:46 +01:00
parent c56d6b1688
commit 70c20b2d4a

View File

@ -16,6 +16,7 @@ import {
superdough, superdough,
// @ts-ignore // @ts-ignore
} from "superdough"; } from "superdough";
import { Sound } from "zifferjs/src/types";
export type SoundParams = { export type SoundParams = {
dur: number | number[]; dur: number | number[];
@ -35,7 +36,16 @@ export class SoundEvent extends AudibleEvent {
nudge: number; nudge: number;
sound: any; sound: any;
private methodMap = { public updateValue<T>(
key: string,
value: T | T[] | SoundParams[] | null
): this {
if (value == null) return this;
this.values[key] = value;
return this;
}
private static methodMap = {
volume: ["volume", "vol"], volume: ["volume", "vol"],
zrand: ["zrand", "zr"], zrand: ["zrand", "zr"],
curve: ["curve"], curve: ["curve"],
@ -67,17 +77,23 @@ export class SoundEvent extends AudibleEvent {
phaserDepth: ["phaserDepth", "phasdepth"], phaserDepth: ["phaserDepth", "phasdepth"],
phaserSweep: ["phaserSweep", "phassweep"], phaserSweep: ["phaserSweep", "phassweep"],
phaserCenter: ["phaserCenter", "phascenter"], phaserCenter: ["phaserCenter", "phascenter"],
fmadsr: (a: number, d: number, s: number, r: number) => { fmadsr: function (
this.updateValue("fmattack", a); self: SoundEvent,
this.updateValue("fmdecay", d); a: number,
this.updateValue("fmsustain", s); d: number,
this.updateValue("fmrelease", r); s: number,
return this; 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) => { fmad: function (self: SoundEvent, a: number, d: number) {
this.updateValue("fmattack", a); self.updateValue("fmattack", a);
this.updateValue("fmdecay", d); self.updateValue("fmdecay", d);
return this; return self;
}, },
ftype: ["ftype"], ftype: ["ftype"],
fanchor: ["fanchor"], fanchor: ["fanchor"],
@ -85,147 +101,174 @@ export class SoundEvent extends AudibleEvent {
decay: ["decay", "dec"], decay: ["decay", "dec"],
sustain: ["sustain", "sus"], sustain: ["sustain", "sus"],
release: ["release", "rel"], release: ["release", "rel"],
adsr: (a: number, d: number, s: number, r: number) => { adsr: function (
this.updateValue("attack", a); self: SoundEvent,
this.updateValue("decay", d); a: number,
this.updateValue("sustain", s); d: number,
this.updateValue("release", r); s: number,
return this; 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) => { ad: function (self: SoundEvent, a: number, d: number) {
this.updateValue("attack", a); self.updateValue("attack", a);
this.updateValue("decay", d); self.updateValue("decay", d);
this.updateValue("sustain", 0.0); self.updateValue("sustain", 0.0);
this.updateValue("release", 0.0); self.updateValue("release", 0.0);
return this; return self;
}, },
lpenv: ["lpenv", "lpe"], lpenv: ["lpenv", "lpe"],
lpattack: ["lpattack", "lpa"], lpattack: ["lpattack", "lpa"],
lpdecay: ["lpdecay", "lpd"], lpdecay: ["lpdecay", "lpd"],
lpsustain: ["lpsustain", "lps"], lpsustain: ["lpsustain", "lps"],
lprelease: ["lprelease", "lpr"], lprelease: ["lprelease", "lpr"],
cutoff: (value: number, resonance?: number) => { cutoff: function (self: SoundEvent, value: number, resonance?: number) {
this.updateValue("cutoff", value); self.updateValue("cutoff", value);
if (resonance) { if (resonance) {
this.updateValue("resonance", resonance); self.updateValue("resonance", resonance);
} }
return this; return self;
}, },
lpf: (value: number, resonance?: number) => { lpf: function (self: SoundEvent, value: number, resonance?: number) {
this.updateValue("cutoff", value); self.updateValue("cutoff", value);
if (resonance) { 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) { 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) => { lpadsr: function (
this.updateValue("lpenv", depth); self: SoundEvent,
this.updateValue("lpattack", a); depth: number,
this.updateValue("lpdecay", d); a: number,
this.updateValue("lpsustain", s); d: number,
this.updateValue("lprelease", r); s: number,
return this; 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) => { lpad: function (self: SoundEvent, depth: number, a: number, d: number) {
this.updateValue("lpenv", depth); self.updateValue("lpenv", depth);
this.updateValue("lpattack", a); self.updateValue("lpattack", a);
this.updateValue("lpdecay", d); self.updateValue("lpdecay", d);
this.updateValue("lpsustain", 0); self.updateValue("lpsustain", 0);
this.updateValue("lprelease", 0); self.updateValue("lprelease", 0);
return this; return self;
}, },
hpenv: ["hpenv", "hpe"], hpenv: ["hpenv", "hpe"],
hpattack: ["hpattack", "hpa"], hpattack: ["hpattack", "hpa"],
hpdecay: ["hpdecay", "hpd"], hpdecay: ["hpdecay", "hpd"],
hpsustain: ["hpsustain", "hpsus"], hpsustain: ["hpsustain", "hpsus"],
hprelease: ["hprelease", "hpr"], hprelease: ["hprelease", "hpr"],
hcutoff: (value: number, resonance?: number) => { hcutoff: function (self: SoundEvent, value: number, resonance?: number) {
this.updateValue("hcutoff", value); self.updateValue("hcutoff", value);
if (resonance) { if (resonance) {
this.updateValue("hresonance", resonance); self.updateValue("hresonance", resonance);
} }
return this; return self;
}, },
hpf: (value: number, resonance?: number) => { hpf: function (self: SoundEvent, value: number, resonance?: number) {
this.updateValue("hcutoff", value); self.updateValue("hcutoff", value);
if (resonance) { if (resonance) {
this.updateValue("hresonance", resonance); self.updateValue("hresonance", resonance);
} }
return this; return self;
}, },
hpq: (value: number) => { hpq: function (self: SoundEvent, value: number) {
this.updateValue("hresonance", value); self.updateValue("hresonance", value);
return this; return self;
}, },
hpadsr: (depth: number, a: number, d: number, s: number, r: number) => { hpadsr: function (
this.updateValue("hpenv", depth); self: SoundEvent,
this.updateValue("hpattack", a); depth: number,
this.updateValue("hpdecay", d); a: number,
this.updateValue("hpsustain", s); d: number,
this.updateValue("hprelease", r); s: number,
return this; 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) => { hpad: function (self: SoundEvent, depth: number, a: number, d: number) {
this.updateValue("hpenv", depth); self.updateValue("hpenv", depth);
this.updateValue("hpattack", a); self.updateValue("hpattack", a);
this.updateValue("hpdecay", d); self.updateValue("hpdecay", d);
this.updateValue("hpsustain", 0); self.updateValue("hpsustain", 0);
this.updateValue("hprelease", 0); self.updateValue("hprelease", 0);
return this; return self;
}, },
bpenv: ["bpenv", "bpe"], bpenv: ["bpenv", "bpe"],
bpattack: ["bpattack", "bpa"], bpattack: ["bpattack", "bpa"],
bpdecay: ["bpdecay", "bpd"], bpdecay: ["bpdecay", "bpd"],
bpsustain: ["bpsustain", "bps"], bpsustain: ["bpsustain", "bps"],
bprelease: ["bprelease", "bpr"], bprelease: ["bprelease", "bpr"],
bandf: (value: number, resonance?: number) => { bandf: function (self: SoundEvent, value: number, resonance?: number) {
this.updateValue("bandf", value); self.updateValue("bandf", value);
if (resonance) { if (resonance) {
this.updateValue("bandq", resonance); self.updateValue("bandq", resonance);
} }
return this; return self;
}, },
bpf: (value: number, resonance?: number) => { bpf: function (self: SoundEvent, value: number, resonance?: number) {
this.updateValue("bandf", value); self.updateValue("bandf", value);
if (resonance) { if (resonance) {
this.updateValue("bandq", resonance); self.updateValue("bandq", resonance);
} }
return this; return self;
}, },
bandq: ["bandq", "bpq"], bandq: ["bandq", "bpq"],
bpadsr: (depth: number, a: number, d: number, s: number, r: number) => { bpadsr: function (
this.updateValue("bpenv", depth); self: SoundEvent,
this.updateValue("bpattack", a); depth: number,
this.updateValue("bpdecay", d); a: number,
this.updateValue("bpsustain", s); d: number,
this.updateValue("bprelease", r); s: number,
return this; 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) => { bpad: function (self: SoundEvent, depth: number, a: number, d: number) {
this.updateValue("bpenv", depth); self.updateValue("bpenv", depth);
this.updateValue("bpattack", a); self.updateValue("bpattack", a);
this.updateValue("bpdecay", d); self.updateValue("bpdecay", d);
this.updateValue("bpsustain", 0); self.updateValue("bpsustain", 0);
this.updateValue("bprelease", 0); self.updateValue("bprelease", 0);
return this; return self;
}, },
vib: ["vib"], vib: ["vib"],
vibmod: ["vibmod"], vibmod: ["vibmod"],
fm: (value: number | string) => { fm: function (self: SoundEvent, value: number | string) {
if (typeof value === "number") { if (typeof value === "number") {
this.values["fmi"] = value; self.values["fmi"] = value;
} else { } else {
let values = value.split(":"); let values = value.split(":");
this.values["fmi"] = parseFloat(values[0]); self.values["fmi"] = parseFloat(values[0]);
if (values.length > 1) this.values["fmh"] = parseFloat(values[1]); if (values.length > 1) self.values["fmh"] = parseFloat(values[1]);
} }
return this; return self;
}, },
loop: ["loop"], loop: ["loop"],
loopBegin: ["loopBegin", "loopb"], loopBegin: ["loopBegin", "loopb"],
@ -233,13 +276,13 @@ export class SoundEvent extends AudibleEvent {
begin: ["begin"], begin: ["begin"],
end: ["end"], end: ["end"],
gain: ["gain"], gain: ["gain"],
dbgain: (value: number) => { dbgain: function (self: SoundEvent, value: number) {
this.updateValue("gain", Math.min(Math.pow(10, value / 20), 10)); self.updateValue("gain", Math.min(Math.pow(10, value / 20), 10));
return this; return self;
}, },
db: (value: number) => { db: function (self: SoundEvent, value: number) {
this.updateValue("gain", Math.min(Math.pow(10, value / 20), 10)); self.updateValue("gain", Math.min(Math.pow(10, value / 20), 10));
return this; return self;
}, },
velocity: ["velocity", "vel"], velocity: ["velocity", "vel"],
pan: ["pan"], pan: ["pan"],
@ -260,62 +303,71 @@ export class SoundEvent extends AudibleEvent {
roomlp: ["roomlp", "rlp"], roomlp: ["roomlp", "rlp"],
roomdim: ["roomdim", "rdim"], roomdim: ["roomdim", "rdim"],
sound: ["s", "sound"], sound: ["s", "sound"],
size: (value: number) => { size: function (self: SoundEvent, value: number) {
this.updateValue("roomsize", value); self.updateValue("roomsize", value);
return this; return self;
}, },
sz: (value: number) => { sz: function (self: SoundEvent, value: number) {
this.updateValue("roomsize", value); self.updateValue("roomsize", value);
return this; return self;
}, },
comp: ["compressor", "cmp"], comp: ["compressor", "cmp"],
ratio: (value: number) => { ratio: function (self: SoundEvent, value: number) {
this.updateValue("compressorRatio", value); self.updateValue("compressorRatio", value);
return this; return self;
}, },
knee: (value: number) => { knee: function (self: SoundEvent, value: number) {
this.updateValue("compressorKnee", value); self.updateValue("compressorKnee", value);
return this; return self;
}, },
compAttack: (value: number) => { compAttack: function (self: SoundEvent, value: number) {
this.updateValue("compressorAttack", value); self.updateValue("compressorAttack", value);
return this; return self;
}, },
compRelease: (value: number) => { compRelease: function (self: SoundEvent, value: number) {
this.updateValue("compressorRelease", value); self.updateValue("compressorRelease", value);
return this; return self;
}, },
stretch: (beat: number) => { stretch: function (self: SoundEvent, beat: number) {
this.updateValue("unit", "c"); self.updateValue("unit", "c");
this.updateValue("speed", 1 / beat); self.updateValue("speed", 1 / beat);
this.updateValue("cut", beat); self.updateValue("cut", beat);
return this; return self;
}, },
}; };
constructor( constructor(sound: string | string[] | SoundParams, public app: Editor) {
sound: string | string[] | SoundParams,
public app: Editor,
) {
super(app); super(app);
this.nudge = app.dough_nudge / 100; this.nudge = app.dough_nudge / 100;
for (const [methodName, keys] of Object.entries(this.methodMap)) { for (const [methodName, keys] of Object.entries(SoundEvent.methodMap)) {
if (Symbol.iterator in Object(keys)) { if (typeof keys === "object" && Symbol.iterator in Object(keys)) {
for (const key of keys as string[]) { 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); this[key] = (value: number) => this.updateValue(keys[0], value);
} }
} else { } else {
// @ts-ignore // this[methodName] = keys.bind(this);
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); this.values = this.processSound(sound);
} }
private processSound = ( private processSound = (
sound: string | string[] | SoundParams | SoundParams[], sound: string | string[] | SoundParams | SoundParams[]
): SoundParams => { ): SoundParams => {
if (Array.isArray(sound) && typeof sound[0] === "string") { if (Array.isArray(sound) && typeof sound[0] === "string") {
const s: string[] = []; const s: string[] = [];
@ -357,15 +409,6 @@ export class SoundEvent extends AudibleEvent {
} }
}; };
private updateValue<T>(
key: string,
value: T | T[] | SoundParams[] | null,
): this {
if (value == null) return this;
this.values[key] = value;
return this;
}
// ================================================================================ // ================================================================================
// AbstactEvent overrides // AbstactEvent overrides
// ================================================================================ // ================================================================================
@ -395,7 +438,7 @@ export class SoundEvent extends AudibleEvent {
(event.key as number) || "C4", (event.key as number) || "C4",
(event.pitch as number) || 0, (event.pitch as number) || 0,
(event.parsedScale as number[]) || event.scale || "MAJOR", (event.parsedScale as number[]) || event.scale || "MAJOR",
(event.octave as number) || 0, (event.octave as number) || 0
); );
event.note = note; event.note = note;
event.freq = midiToFreq(note); event.freq = midiToFreq(note);
@ -415,7 +458,7 @@ export class SoundEvent extends AudibleEvent {
public invert = (howMany: number = 0) => { public invert = (howMany: number = 0) => {
if (this.values.chord) { if (this.values.chord) {
let notes = this.values.chord.map( let notes = this.values.chord.map(
(obj: { [key: string]: number }) => obj.note, (obj: { [key: string]: number }) => obj.note
); );
notes = howMany < 0 ? [...notes].reverse() : notes; notes = howMany < 0 ? [...notes].reverse() : notes;
for (let i = 0; i < Math.abs(howMany); i++) { for (let i = 0; i < Math.abs(howMany); i++) {
@ -457,7 +500,7 @@ export class SoundEvent extends AudibleEvent {
superdough( superdough(
filteredEvent, filteredEvent,
this.nudge - this.app.clock.deviation, this.nudge - this.app.clock.deviation,
filteredEvent.dur, filteredEvent.dur
); );
} }
}; };