From 57f0c9dfe6443df3c5721b61107609983014d5f8 Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Sun, 14 Apr 2024 23:34:53 +0200 Subject: [PATCH] Continue adaptation work --- src/API/API.ts | 81 ++-- src/API/Cache.ts | 87 ++-- src/API/Canvas.ts | 604 +++++++++++++------------- src/API/Console.ts | 36 +- src/API/Counter.ts | 71 +-- src/API/Drunk.ts | 64 +-- src/API/Filters.ts | 309 ++++++------- src/API/LFO.ts | 81 ++-- src/API/MIDI.ts | 147 +++---- src/API/Mouse.ts | 50 ++- src/API/OSC.ts | 47 +- src/API/Probabilities.ts | 52 +-- src/API/Randomness.ts | 47 +- src/API/Script.ts | 89 ++-- src/API/Sound.ts | 63 +-- src/API/Theme.ts | 4 +- src/API/Transport.ts | 155 +++---- src/API/Warp.ts | 30 +- src/API/Ziffers.ts | 115 +++-- src/Docs/learning/time/linear_time.ts | 2 +- 20 files changed, 1079 insertions(+), 1055 deletions(-) diff --git a/src/API/API.ts b/src/API/API.ts index a35867d..bacc0a1 100644 --- a/src/API/API.ts +++ b/src/API/API.ts @@ -83,10 +83,9 @@ export class UserAPI { */ public codeExamples: { [key: string]: string } = {}; + public counters: { [key: string]: any } = {}; //@ts-ignore - private counters: { [key: string]: any } = {}; - //@ts-ignore - private _drunk: DrunkWalk = new DrunkWalk(-100, 100, false); + public _drunk: DrunkWalk = new DrunkWalk(-100, 100, false); public randomGen = Math.random; public currentSeed: string | undefined = undefined; public localSeeds = new Map(); @@ -274,11 +273,11 @@ export class UserAPI { this.MidiConnection = new MidiConnection(this, app.settings); this.global = {}; this.g = this.global; - this.time = Transport.time(this.app); - this.play = Transport.play(this.app); - this.pause = Transport.pause(this.app); - this.stop = Transport.stop(this.app); - this.silence = Transport.silence(this.app); + this.time = Transport.time(this); + this.play = Transport.play(this); + this.pause = Transport.pause(this); + this.stop = Transport.stop(this); + this.silence = Transport.silence(this); this.tempo = Transport.tempo(this.app); this.bpb = Transport.bpb(this.app); this.ppqn = Transport.ppqn(this.app); @@ -324,9 +323,9 @@ export class UserAPI { this.animals = Canvas.animals(); this.expressions = Canvas.expressions(); this.generateCacheKey = Cache.generateCacheKey(); - this.resetAllFromCache = Cache.resetAllFromCache(this.app); - this.clearPatternCache = Cache.clearPatternCache(this.app); - this.removePatternFromCache = Cache.removePatternFromCache(this.app); + this.resetAllFromCache = Cache.resetAllFromCache(this); + this.clearPatternCache = Cache.clearPatternCache(this); + this.removePatternFromCache = Cache.removePatternFromCache(this); this.script = Script.script(this.app); this.s = this.script; this.delete_script = Script.delete_script(this.app); @@ -336,10 +335,10 @@ export class UserAPI { this.copy_universe = Script.copy_universe(this.app); this.delete_universe = Script.delete_universe(this.app); this.big_bang = Script.big_bang(this.app); - this.drunk = Drunk.drunk(this.app); - this.drunk_max = Drunk.drunk_max(this.app); - this.drunk_min = Drunk.drunk_min(this.app); - this.drunk_wrap = Drunk.drunk_wrap(this.app); + this.drunk = Drunk.drunk(this); + this.drunk_max = Drunk.drunk_max(this); + this.drunk_min = Drunk.drunk_min(this); + this.drunk_wrap = Drunk.drunk_wrap(this); this.warp = Warp.warp(this.app); this.beat_warp = Warp.beat_warp(this.app); this.min = Mathematics.min(); @@ -359,7 +358,7 @@ export class UserAPI { this.flip = Filters.flip(this.app); this.flipbar = Filters.flipbar(this.app); this.onbar = Filters.onbar(this.app); - this.onbeat = Filters.onbeat(this.app); + this.onbeat = Filters.onbeat(this); this.oncount = Filters.oncount(this.app); this.oneuclid = Filters.oneuclid(this.app); this.euclid = Filters.euclid(); @@ -378,23 +377,23 @@ export class UserAPI { this.usaw = LFO.usaw(this.app); this.triangle = LFO.triangle(this.app); this.utriangle = LFO.utriangle(this.app); - this.square = LFO.square(); - this.usquare = LFO.usquare(); - this.noise = LFO.noise(this.app); - this.unoise = LFO.unoise(this.app); - this.prob = Probability.prob(this.app); - this.toss = Probability.toss(this.app); - this.odds = Probability.odds(this.app); + this.square = LFO.square(this.app); + this.usquare = LFO.usquare(this.app); + this.noise = LFO.noise(this); + this.unoise = LFO.unoise(this); + this.prob = Probability.prob(this); + this.toss = Probability.toss(this); + this.odds = Probability.odds(this); this.never = Probability.never(); - this.almostNever = Probability.almostNever(this.app); - this.rarely = Probability.rarely(this.app); - this.scarcely = Probability.scarcely(this.app); - this.sometimes = Probability.sometimes(this.app); - this.often = Probability.often(this.app); - this.frequently = Probability.frequently(this.app); - this.almostAlways = Probability.almostAlways(this.app); + this.almostNever = Probability.almostNever(this); + this.rarely = Probability.rarely(this); + this.scarcely = Probability.scarcely(this); + this.sometimes = Probability.sometimes(this); + this.often = Probability.often(this); + this.frequently = Probability.frequently(this); + this.almostAlways = Probability.almostAlways(this); this.always = Probability.always(); - this.dice = Probability.dice(this.app); + this.dice = Probability.dice(this); this.osc = OSC.osc(this.app); this.getOSC = OSC.getOSC(this.app); this.gif = Canvas.gif(this.app); @@ -404,16 +403,16 @@ export class UserAPI { this.seed = Randomness.seed(this.app); this.localSeededRandom = Randomness.localSeededRandom(this.app); this.clearLocalSeed = Randomness.clearLocalSeed(this.app); - this.once = Counter.once(this.app); - this.counter = Counter.counter(this.app); + this.once = Counter.once(this); + this.counter = Counter.counter(this); this.$ = this.counter; this.count = this.counter; this.i = Counter.i(this.app); this.sound = Sound.sound(this.app); - this.snd = this.sound; + this.snd = this.sound; this.speak = Sound.speak(); - this.log = Console.log(this.app); - this.logOnce = Console.logOnce(this.app); + this.log = Console.log(this); + this.logOnce = Console.logOnce(this); this.cbar = Transport.cbar(this.app); this.ctick = Transport.ctick(this.app); this.cpulse = Transport.cpulse(this.app); @@ -425,7 +424,7 @@ export class UserAPI { this.denominator = Transport.denominator(this.app); // Alias for meter this.pulsesForBar = Transport.pulsesForBar(this.app); - } + } public g: any; @@ -474,7 +473,7 @@ export class UserAPI { ? code : (this.app.selectedExample as string); } - this.clearPatternCache(); + this.patternCache.clear(); this.stop(); this.play(); }; @@ -609,7 +608,7 @@ export class UserAPI { nearScales = nearScales; public cue = (functionName: string | Function): void => { - functionName = typeof functionName === "function" ? functionName.name : functionName; - this.cueTimes[functionName] = this.app.clock.pulses_since_origin; + functionName = typeof functionName === "function" ? functionName.name : functionName; + this.cueTimes[functionName] = this.app.clock.pulses_since_origin; }; -} \ No newline at end of file +} diff --git a/src/API/Cache.ts b/src/API/Cache.ts index 89996d3..6817560 100644 --- a/src/API/Cache.ts +++ b/src/API/Cache.ts @@ -1,60 +1,61 @@ import { isGenerator, isGeneratorFunction, maybeToNumber } from "../Utils/Generic"; import { type Player } from "../Classes/ZPlayer"; +import { type UserAPI } from "./API"; export const generateCacheKey = () => (...args: any[]): string => { - return args.map((arg) => JSON.stringify(arg)).join(","); + return args.map((arg) => JSON.stringify(arg)).join(","); }; -export const resetAllFromCache = (app: any) => (): void => { - app.patternCache.forEach((player: Player) => player.reset()); +export const resetAllFromCache = (api: UserAPI) => (): void => { + api.patternCache.forEach((player: Player) => player.reset()); }; -export const clearPatternCache = (app: any) => (): void => { - app.patternCache.clear(); +export const clearPatternCache = (api: UserAPI) => (): void => { + api.patternCache.clear(); }; -export const removePatternFromCache = (app: any) => (id: string): void => { - app.patternCache.delete(id); +export const removePatternFromCache = (api: UserAPI) => (id: string): void => { + api.patternCache.delete(id); }; -export const cache = (app: any) => (key: string, value: any) => { - if (value !== undefined) { - if (isGenerator(value)) { - if (app.patternCache.has(key)) { - const cachedValue = (app.patternCache.get(key) as Generator).next().value; - if (cachedValue !== 0 && !cachedValue) { - const generator = value as unknown as Generator; - app.patternCache.set(key, generator); - return maybeToNumber(generator.next().value); - } - return maybeToNumber(cachedValue); - } else { - const generator = value as unknown as Generator; - app.patternCache.set(key, generator); - return maybeToNumber(generator.next().value); - } - } else if (isGeneratorFunction(value)) { - if (app.patternCache.has(key)) { - const cachedValue = (app.patternCache.get(key) as Generator).next().value; - if (cachedValue || cachedValue === 0 || cachedValue === 0n) { - return maybeToNumber(cachedValue); - } else { - const generator = value(); - app.patternCache.set(key, generator); - return maybeToNumber(generator.next().value); - } - } else { - const generator = value(); - app.patternCache.set(key, generator); - return maybeToNumber(generator.next().value); - } - } else { - app.patternCache.set(key, value); - return maybeToNumber(value); +export const cache = (api: UserAPI) => (key: string, value: any) => { + if (value !== undefined) { + if (isGenerator(value)) { + if (api.patternCache.has(key)) { + const cachedValue = (api.patternCache.get(key) as Generator).next().value; + if (cachedValue !== 0 && !cachedValue) { + const generator = value as unknown as Generator; + api.patternCache.set(key, generator); + return maybeToNumber(generator.next().value); } + return maybeToNumber(cachedValue); + } else { + const generator = value as unknown as Generator; + api.patternCache.set(key, generator); + return maybeToNumber(generator.next().value); + } + } else if (isGeneratorFunction(value)) { + if (api.patternCache.has(key)) { + const cachedValue = (api.patternCache.get(key) as Generator).next().value; + if (cachedValue || cachedValue === 0 || cachedValue === 0n) { + return maybeToNumber(cachedValue); + } else { + const generator = value(); + api.patternCache.set(key, generator); + return maybeToNumber(generator.next().value); + } + } else { + const generator = value(); + api.patternCache.set(key, generator); + return maybeToNumber(generator.next().value); + } } else { - return maybeToNumber(app.patternCache.get(key)); + api.patternCache.set(key, value); + return maybeToNumber(value); } -}; \ No newline at end of file + } else { + return maybeToNumber(api.patternCache.get(key)); + } +}; diff --git a/src/API/Canvas.ts b/src/API/Canvas.ts index 5d7ba5a..1a7d220 100644 --- a/src/API/Canvas.ts +++ b/src/API/Canvas.ts @@ -3,412 +3,412 @@ import { ShapeObject, createConicGradient, createLinearGradient, createRadialGra import { Editor } from "../main"; export const w = (app: Editor) => (): number => { - const canvas: HTMLCanvasElement = app.interface.drawings as HTMLCanvasElement; - return canvas.clientWidth; + const canvas: HTMLCanvasElement = app.interface.drawings as HTMLCanvasElement; + return canvas.clientWidth; }; export const pulseLocation = (app: Editor) => (): number => { - return ((app.api.epulse() / app.api.pulsesForBar()) * w(app)()) % w(app)(); + return ((app.api.epulse() / app.api.pulsesForBar()) * w(app)()) % w(app)(); }; export const clear = (app: Editor) => (): boolean => { - const canvas: HTMLCanvasElement = app.interface.drawings as HTMLCanvasElement; - const ctx = canvas.getContext("2d")!; - ctx.clearRect(0, 0, canvas.width, canvas.height); - return true; + const canvas: HTMLCanvasElement = app.interface.drawings as HTMLCanvasElement; + const ctx = canvas.getContext("2d")!; + ctx.clearRect(0, 0, canvas.width, canvas.height); + return true; }; export const h = (app: Editor) => (): number => { - const canvas: HTMLCanvasElement = app.interface.drawings as HTMLCanvasElement; - return canvas.clientHeight; + const canvas: HTMLCanvasElement = app.interface.drawings as HTMLCanvasElement; + return canvas.clientHeight; }; export const hc = (app: Editor) => (): number => { - return h(app)() / 2; + return h(app)() / 2; }; export const wc = (app: Editor) => (): number => { - return w(app)() / 2; + return w(app)() / 2; }; export const background = (app: Editor) => (color: string | number, ...gb: number[]): boolean => { - drawBackground(app.interface.drawings as HTMLCanvasElement, color, ...gb); - return true; + drawBackground(app.interface.drawings as HTMLCanvasElement, color, ...gb); + return true; }; export const bg = background; export const linearGradient = (app: Editor) => (x1: number, y1: number, x2: number, y2: number, ...stops: (number | string)[]): CanvasGradient => { - return createLinearGradient(app.interface.drawings as HTMLCanvasElement, x1, y1, x2, y2, ...stops); + return createLinearGradient(app.interface.drawings as HTMLCanvasElement, x1, y1, x2, y2, ...stops); }; export const radialGradient = (app: Editor) => (x1: number, y1: number, r1: number, x2: number, y2: number, r2: number, ...stops: (number | string)[]) => { - return createRadialGradient(app.interface.drawings as HTMLCanvasElement, x1, y1, r1, x2, y2, r2, ...stops); + return createRadialGradient(app.interface.drawings as HTMLCanvasElement, x1, y1, r1, x2, y2, r2, ...stops); }; export const conicGradient = (app: Editor) => (x: number, y: number, angle: number, ...stops: (number | string)[]) => { - return createConicGradient(app.interface.drawings as HTMLCanvasElement, x, y, angle, ...stops); + return createConicGradient(app.interface.drawings as HTMLCanvasElement, x, y, angle, ...stops); }; export const draw = (app: Editor) => (func: Function): boolean => { - if (typeof func === "string") { - drawText(app.interface.drawings as HTMLCanvasElement, func, 24, 0, "Arial", wc(app)(), hc(app)(), "white", "none"); - } else { - const canvas: HTMLCanvasElement = app.interface.drawings as HTMLCanvasElement; - const ctx = canvas.getContext("2d")!; - func(ctx); - } - return true; + if (typeof func === "string") { + drawText(app.interface.drawings as HTMLCanvasElement, func, 24, 0, "Arial", wc(app)(), hc(app)(), "white", "none"); + } else { + const canvas: HTMLCanvasElement = app.interface.drawings as HTMLCanvasElement; + const ctx = canvas.getContext("2d")!; + func(ctx); + } + return true; }; // Additional drawing and utility functions in canvas.ts export const balloid = (app: Editor) => ( - curves: number | ShapeObject = 6, - radius: number = hc(app)() / 2, - curve: number = 1.5, - fillStyle: string = "white", - secondary: string = "black", - x: number = wc(app)(), - y: number = hc(app)(), + curves: number | ShapeObject = 6, + radius: number = hc(app)() / 2, + curve: number = 1.5, + fillStyle: string = "white", + secondary: string = "black", + x: number = wc(app)(), + y: number = hc(app)(), ): boolean => { - if (typeof curves === "object") { - fillStyle = curves.fillStyle || "white"; - x = curves.x || wc(app)(); - y = curves.y || hc(app)(); - curve = curves.curve || 1.5; - radius = curves.radius || hc(app)() / 2; - curves = curves.curves || 6; - } - drawBalloid(app.interface.drawings as HTMLCanvasElement, curves, radius, curve, fillStyle, secondary, x, y); - return true; + if (typeof curves === "object") { + fillStyle = curves.fillStyle || "white"; + x = curves.x || wc(app)(); + y = curves.y || hc(app)(); + curve = curves.curve || 1.5; + radius = curves.radius || hc(app)() / 2; + curves = curves.curves || 6; + } + drawBalloid(app.interface.drawings as HTMLCanvasElement, curves, radius, curve, fillStyle, secondary, x, y); + return true; }; export const equilateral = (app: Editor) => ( - radius: number | ShapeObject = hc(app)() / 3, - fillStyle: string = "white", - rotation: number = 0, - x: number = wc(app)(), - y: number = hc(app)(), + radius: number | ShapeObject = hc(app)() / 3, + fillStyle: string = "white", + rotation: number = 0, + x: number = wc(app)(), + y: number = hc(app)(), ): boolean => { - if (typeof radius === "object") { - fillStyle = radius.fillStyle || "white"; - x = radius.x || wc(app)(); - y = radius.y || hc(app)(); - rotation = radius.rotation || 0; - radius = radius.radius || hc(app)() / 3; - } - drawEquilateral(app.interface.drawings as HTMLCanvasElement, radius, fillStyle, rotation, x, y); - return true; + if (typeof radius === "object") { + fillStyle = radius.fillStyle || "white"; + x = radius.x || wc(app)(); + y = radius.y || hc(app)(); + rotation = radius.rotation || 0; + radius = radius.radius || hc(app)() / 3; + } + drawEquilateral(app.interface.drawings as HTMLCanvasElement, radius, fillStyle, rotation, x, y); + return true; }; export const triangular = (app: Editor) => ( - width: number | ShapeObject = hc(app)() / 3, - height: number = hc(app)() / 3, - fillStyle: string = "white", - rotation: number = 0, - x: number = wc(app)(), - y: number = hc(app)(), + width: number | ShapeObject = hc(app)() / 3, + height: number = hc(app)() / 3, + fillStyle: string = "white", + rotation: number = 0, + x: number = wc(app)(), + y: number = hc(app)(), ): boolean => { - if (typeof width === "object") { - fillStyle = width.fillStyle || "white"; - x = width.x || wc(app)(); - y = width.y || hc(app)(); - rotation = width.rotation || 0; - height = width.height || hc(app)() / 3; - width = width.width || hc(app)() / 3; - } - drawTriangular(app.interface.drawings as HTMLCanvasElement, width, height, fillStyle, rotation, x, y); - return true; + if (typeof width === "object") { + fillStyle = width.fillStyle || "white"; + x = width.x || wc(app)(); + y = width.y || hc(app)(); + rotation = width.rotation || 0; + height = width.height || hc(app)() / 3; + width = width.width || hc(app)() / 3; + } + drawTriangular(app.interface.drawings as HTMLCanvasElement, width, height, fillStyle, rotation, x, y); + return true; }; export const pointy = triangular; export const ball = (app: Editor) => ( - radius: number | ShapeObject = hc(app)() / 3, - fillStyle: string = "white", - x: number = wc(app)(), - y: number = hc(app)(), + radius: number | ShapeObject = hc(app)() / 3, + fillStyle: string = "white", + x: number = wc(app)(), + y: number = hc(app)(), ): boolean => { - if (typeof radius === "object") { - fillStyle = radius.fillStyle || "white"; - x = radius.x || wc(app)(); - y = radius.y || hc(app)(); - radius = radius.radius || hc(app)() / 3; - } - drawBall(app.interface.drawings as HTMLCanvasElement, radius, fillStyle, x, y); - return true; + if (typeof radius === "object") { + fillStyle = radius.fillStyle || "white"; + x = radius.x || wc(app)(); + y = radius.y || hc(app)(); + radius = radius.radius || hc(app)() / 3; + } + drawBall(app.interface.drawings as HTMLCanvasElement, radius, fillStyle, x, y); + return true; }; export const circle = ball; export const donut = (app: Editor) => ( - slices: number | ShapeObject = 3, - eaten: number = 0, - radius: number = hc(app)() / 3, - hole: number = hc(app)() / 12, - fillStyle: string = "white", - secondary: string = "black", - stroke: string = "black", - rotation: number = 0, - x: number = wc(app)(), - y: number = hc(app)(), + slices: number | ShapeObject = 3, + eaten: number = 0, + radius: number = hc(app)() / 3, + hole: number = hc(app)() / 12, + fillStyle: string = "white", + secondary: string = "black", + stroke: string = "black", + rotation: number = 0, + x: number = wc(app)(), + y: number = hc(app)(), ): boolean => { - if (typeof slices === "object") { - fillStyle = slices.fillStyle || "white"; - x = slices.x || wc(app)(); - y = slices.y || hc(app)(); - rotation = slices.rotation || 0; - radius = slices.radius || hc(app)() / 3; - eaten = slices.eaten || 0; - hole = slices.hole || hc(app)() / 12; - secondary = slices.secondary || "black"; - stroke = slices.stroke || "black"; - slices = slices.slices || 3; - } - drawDonut(app.interface.drawings as HTMLCanvasElement, slices, eaten, radius, hole, fillStyle, secondary, stroke, rotation, x, y); - return true; + if (typeof slices === "object") { + fillStyle = slices.fillStyle || "white"; + x = slices.x || wc(app)(); + y = slices.y || hc(app)(); + rotation = slices.rotation || 0; + radius = slices.radius || hc(app)() / 3; + eaten = slices.eaten || 0; + hole = slices.hole || hc(app)() / 12; + secondary = slices.secondary || "black"; + stroke = slices.stroke || "black"; + slices = slices.slices || 3; + } + drawDonut(app.interface.drawings as HTMLCanvasElement, slices, eaten, radius, hole, fillStyle, secondary, stroke, rotation, x, y); + return true; }; export const pie = (app: Editor) => ( - slices: number | ShapeObject = 3, - eaten: number = 0, - radius: number = hc(app)() / 3, - fillStyle: string = "white", - secondary: string = "black", - stroke: string = "black", - rotation: number = 0, - x: number = wc(app)(), - y: number = hc(app)(), + slices: number | ShapeObject = 3, + eaten: number = 0, + radius: number = hc(app)() / 3, + fillStyle: string = "white", + secondary: string = "black", + stroke: string = "black", + rotation: number = 0, + x: number = wc(app)(), + y: number = hc(app)(), ): boolean => { - if (typeof slices === "object") { - fillStyle = slices.fillStyle || "white"; - x = slices.x || wc(app)(); - y = slices.y || hc(app)(); - rotation = slices.rotation || 0; - radius = slices.radius || hc(app)() / 3; - secondary = slices.secondary || "black"; - stroke = slices.stroke || "black"; - eaten = slices.eaten || 0; - slices = slices.slices || 3; - } - drawPie(app.interface.drawings as HTMLCanvasElement, slices, eaten, radius, fillStyle, secondary, stroke, rotation, x, y); - return true; + if (typeof slices === "object") { + fillStyle = slices.fillStyle || "white"; + x = slices.x || wc(app)(); + y = slices.y || hc(app)(); + rotation = slices.rotation || 0; + radius = slices.radius || hc(app)() / 3; + secondary = slices.secondary || "black"; + stroke = slices.stroke || "black"; + eaten = slices.eaten || 0; + slices = slices.slices || 3; + } + drawPie(app.interface.drawings as HTMLCanvasElement, slices, eaten, radius, fillStyle, secondary, stroke, rotation, x, y); + return true; }; export const star = (app: Editor) => ( - points: number | ShapeObject = 5, - radius: number = hc(app)() / 3, - fillStyle: string = "white", - rotation: number = 0, - outerRadius: number = radius / 100, - x: number = wc(app)(), - y: number = hc(app)(), + points: number | ShapeObject = 5, + radius: number = hc(app)() / 3, + fillStyle: string = "white", + rotation: number = 0, + outerRadius: number = radius / 100, + x: number = wc(app)(), + y: number = hc(app)(), ): boolean => { - if (typeof points === "object") { - radius = points.radius || hc(app)() / 3; - fillStyle = points.fillStyle || "white"; - x = points.x || wc(app)(); - y = points.y || hc(app)(); - rotation = points.rotation || 0; - outerRadius = points.outerRadius || radius / 100; - points = points.points || 5; - } - drawStar(app.interface.drawings as HTMLCanvasElement, points, radius, fillStyle, rotation, outerRadius, x, y); - return true; + if (typeof points === "object") { + radius = points.radius || hc(app)() / 3; + fillStyle = points.fillStyle || "white"; + x = points.x || wc(app)(); + y = points.y || hc(app)(); + rotation = points.rotation || 0; + outerRadius = points.outerRadius || radius / 100; + points = points.points || 5; + } + drawStar(app.interface.drawings as HTMLCanvasElement, points, radius, fillStyle, rotation, outerRadius, x, y); + return true; }; export const stroke = (app: Editor) => ( - width: number | ShapeObject = 1, - strokeStyle: string = "white", - rotation: number = 0, - x1: number = wc(app)() - wc(app)() / 10, - y1: number = hc(app)(), - x2: number = wc(app)() + wc(app)() / 5, - y2: number = hc(app)(), + width: number | ShapeObject = 1, + strokeStyle: string = "white", + rotation: number = 0, + x1: number = wc(app)() - wc(app)() / 10, + y1: number = hc(app)(), + x2: number = wc(app)() + wc(app)() / 5, + y2: number = hc(app)(), ): boolean => { - if (typeof width === "object") { - strokeStyle = width.strokeStyle || "white"; - x1 = width.x1 || wc(app)() - wc(app)() / 10; - y1 = width.y1 || hc(app)(); - x2 = width.x2 || wc(app)() + wc(app)() / 5; - y2 = width.y2 || hc(app)(); - rotation = width.rotation || 0; - width = width.width || 1; - } - drawStroke(app.interface.drawings as HTMLCanvasElement, width, strokeStyle, rotation, x1, y1, x2, y2); - return true; + if (typeof width === "object") { + strokeStyle = width.strokeStyle || "white"; + x1 = width.x1 || wc(app)() - wc(app)() / 10; + y1 = width.y1 || hc(app)(); + x2 = width.x2 || wc(app)() + wc(app)() / 5; + y2 = width.y2 || hc(app)(); + rotation = width.rotation || 0; + width = width.width || 1; + } + drawStroke(app.interface.drawings as HTMLCanvasElement, width, strokeStyle, rotation, x1, y1, x2, y2); + return true; }; export const box = (app: Editor) => ( - width: number | ShapeObject = wc(app)() / 4, - height: number = wc(app)() / 4, - fillStyle: string = "white", - rotation: number = 0, - x: number = wc(app)() - wc(app)() / 8, - y: number = hc(app)() - hc(app)() / 8, + width: number | ShapeObject = wc(app)() / 4, + height: number = wc(app)() / 4, + fillStyle: string = "white", + rotation: number = 0, + x: number = wc(app)() - wc(app)() / 8, + y: number = hc(app)() - hc(app)() / 8, ): boolean => { - if (typeof width === "object") { - fillStyle = width.fillStyle || "white"; - x = width.x || wc(app)() - wc(app)() / 4; - y = width.y || hc(app)() - hc(app)() / 2; - rotation = width.rotation || 0; - height = width.height || wc(app)() / 4; - width = width.width || wc(app)() / 4; - } - drawBox(app.interface.drawings as HTMLCanvasElement, width, height, fillStyle, rotation, x, y); - return true; + if (typeof width === "object") { + fillStyle = width.fillStyle || "white"; + x = width.x || wc(app)() - wc(app)() / 4; + y = width.y || hc(app)() - hc(app)() / 2; + rotation = width.rotation || 0; + height = width.height || wc(app)() / 4; + width = width.width || wc(app)() / 4; + } + drawBox(app.interface.drawings as HTMLCanvasElement, width, height, fillStyle, rotation, x, y); + return true; }; export const smiley = (app: Editor) => ( - happiness: number | ShapeObject = 0, - radius: number = hc(app)() / 3, - eyeSize: number = 3.0, - fillStyle: string = "yellow", - rotation: number = 0, - x: number = wc(app)(), - y: number = hc(app)(), + happiness: number | ShapeObject = 0, + radius: number = hc(app)() / 3, + eyeSize: number = 3.0, + fillStyle: string = "yellow", + rotation: number = 0, + x: number = wc(app)(), + y: number = hc(app)(), ): boolean => { - if (typeof happiness === "object") { - fillStyle = happiness.fillStyle || "yellow"; - x = happiness.x || wc(app)(); - y = happiness.y || hc(app)(); - rotation = happiness.rotation || 0; - eyeSize = happiness.eyeSize || 3.0; - radius = happiness.radius || hc(app)() / 3; - happiness = happiness.happiness || 0; - } - drawSmiley(app.interface.drawings as HTMLCanvasElement, happiness, radius, eyeSize, fillStyle, rotation, x, y); - return true; + if (typeof happiness === "object") { + fillStyle = happiness.fillStyle || "yellow"; + x = happiness.x || wc(app)(); + y = happiness.y || hc(app)(); + rotation = happiness.rotation || 0; + eyeSize = happiness.eyeSize || 3.0; + radius = happiness.radius || hc(app)() / 3; + happiness = happiness.happiness || 0; + } + drawSmiley(app.interface.drawings as HTMLCanvasElement, happiness, radius, eyeSize, fillStyle, rotation, x, y); + return true; }; export const text = (app: Editor) => ( - text: string | ShapeObject, - fontSize: number = 24, - rotation: number = 0, - font: string = "Arial", - x: number = wc(app)(), - y: number = hc(app)(), - fillStyle: string = "white", - filter: string = "none", + text: string | ShapeObject, + fontSize: number = 24, + rotation: number = 0, + font: string = "Arial", + x: number = wc(app)(), + y: number = hc(app)(), + fillStyle: string = "white", + filter: string = "none", ): boolean => { - if (typeof text === "object") { - fillStyle = text.fillStyle || "white"; - x = text.x || wc(app)(); - y = text.y || hc(app)(); - rotation = text.rotation || 0; - font = text.font || "Arial"; - fontSize = text.fontSize || 24; - filter = text.filter || "none"; - text = text.text || ""; - } - drawText(app.interface.drawings as HTMLCanvasElement, text, fontSize, rotation, font, x, y, fillStyle, filter); - return true; + if (typeof text === "object") { + fillStyle = text.fillStyle || "white"; + x = text.x || wc(app)(); + y = text.y || hc(app)(); + rotation = text.rotation || 0; + font = text.font || "Arial"; + fontSize = text.fontSize || 24; + filter = text.filter || "none"; + text = text.text || ""; + } + drawText(app.interface.drawings as HTMLCanvasElement, text, fontSize, rotation, font, x, y, fillStyle, filter); + return true; }; export const image = (app: Editor) => ( - url: string | ShapeObject, - width: number = wc(app)() / 2, - height: number = hc(app)() / 2, - rotation: number = 0, - x: number = wc(app)(), - y: number = hc(app)(), - filter: string = "none", + url: string | ShapeObject, + width: number = wc(app)() / 2, + height: number = hc(app)() / 2, + rotation: number = 0, + x: number = wc(app)(), + y: number = hc(app)(), + filter: string = "none", ): boolean => { - if (typeof url === "object") { - if (!url.url) return true; - x = url.x || wc(app)(); - y = url.y || hc(app)(); - rotation = url.rotation || 0; - width = url.width || 100; - height = url.height || 100; - filter = url.filter || "none"; - url = url.url || ""; - } - drawImage(app.interface.drawings as HTMLCanvasElement, url, width, height, rotation, x, y, filter); - return true; + if (typeof url === "object") { + if (!url.url) return true; + x = url.x || wc(app)(); + y = url.y || hc(app)(); + rotation = url.rotation || 0; + width = url.width || 100; + height = url.height || 100; + filter = url.filter || "none"; + url = url.url || ""; + } + drawImage(app.interface.drawings as HTMLCanvasElement, url, width, height, rotation, x, y, filter); + return true; }; export const randomChar = () => (length: number = 1, min: number = 0, max: number = 65536): string => { - return Array.from( - { length }, () => String.fromCodePoint(Math.floor(Math.random() * (max - min) + min)) - ).join(''); + return Array.from( + { length }, () => String.fromCodePoint(Math.floor(Math.random() * (max - min) + min)) + ).join(''); }; export const randomFromRange = () => (min: number, max: number): string => { - const codePoint = Math.floor(Math.random() * (max - min) + min); - return String.fromCodePoint(codePoint); + const codePoint = Math.floor(Math.random() * (max - min) + min); + return String.fromCodePoint(codePoint); }; export const emoji = () => (n: number = 1): string => { - return randomChar()(n, 0x1f600, 0x1f64f); + return randomChar()(n, 0x1f600, 0x1f64f); }; export const food = () => (n: number = 1): string => { - return randomChar()(n, 0x1f32d, 0x1f37f); + return randomChar()(n, 0x1f32d, 0x1f37f); }; export const animals = () => (n: number = 1): string => { - return randomChar()(n, 0x1f400, 0x1f4d3); + return randomChar()(n, 0x1f400, 0x1f4d3); }; export const expressions = () => (n: number = 1): string => { - return randomChar()(n, 0x1f910, 0x1f92f); + return randomChar()(n, 0x1f910, 0x1f92f); }; -export const gif = (app: any) => (options: any): void => { - const { - url, - posX = 0, - posY = 0, - opacity = 1, - size = "auto", - center = false, - rotation = 0, - filter = 'none', - duration = 10 - } = options; +export const gif = (app: Editor) => (options: any): void => { + const { + url, + posX = 0, + posY = 0, + opacity = 1, + size = "auto", + center = false, + rotation = 0, + filter = 'none', + duration = 10 + } = options; - let real_duration = duration * app.clock.pulse_duration * app.clock.ppqn; - let fadeOutDuration = real_duration * 0.1; - let visibilityDuration = real_duration - fadeOutDuration; - const gifElement = document.createElement("img"); - gifElement.src = url; - gifElement.style.position = "fixed"; - gifElement.style.left = center ? "50%" : `${posX}px`; - gifElement.style.top = center ? "50%" : `${posY}px`; - gifElement.style.opacity = `${opacity}`; - gifElement.style.zIndex = "1000"; // Ensure it's on top, fixed zIndex - if (size !== "auto") { - gifElement.style.width = size; - gifElement.style.height = size; + let real_duration = duration * app.clock.pulse_duration * app.clock.ppqn; + let fadeOutDuration = real_duration * 0.1; + let visibilityDuration = real_duration - fadeOutDuration; + const gifElement = document.createElement("img"); + gifElement.src = url; + gifElement.style.position = "fixed"; + gifElement.style.left = center ? "50%" : `${posX}px`; + gifElement.style.top = center ? "50%" : `${posY}px`; + gifElement.style.opacity = `${opacity}`; + gifElement.style.zIndex = "1000"; // Ensure it's on top, fixed zIndex + if (size !== "auto") { + gifElement.style.width = size; + gifElement.style.height = size; + } + const transformRules = [`rotate(${rotation}deg)`]; + if (center) { + transformRules.unshift("translate(-50%, -50%)"); + } + gifElement.style.transform = transformRules.join(" "); + gifElement.style.filter = filter; + gifElement.style.transition = `opacity ${fadeOutDuration}s ease`; + document.body.appendChild(gifElement); + + // Start the fade-out at the end of the visibility duration + setTimeout(() => { + gifElement.style.opacity = "0"; + }, visibilityDuration * 1000); + + // Remove the GIF from the DOM after the fade-out duration + setTimeout(() => { + if (document.body.contains(gifElement)) { + document.body.removeChild(gifElement); } - const transformRules = [`rotate(${rotation}deg)`]; - if (center) { - transformRules.unshift("translate(-50%, -50%)"); - } - gifElement.style.transform = transformRules.join(" "); - gifElement.style.filter = filter; - gifElement.style.transition = `opacity ${fadeOutDuration}s ease`; - document.body.appendChild(gifElement); - - // Start the fade-out at the end of the visibility duration - setTimeout(() => { - gifElement.style.opacity = "0"; - }, visibilityDuration * 1000); - - // Remove the GIF from the DOM after the fade-out duration - setTimeout(() => { - if (document.body.contains(gifElement)) { - document.body.removeChild(gifElement); - } - }, real_duration * 1000); + }, real_duration * 1000); }; -export const scope = (app: any) => (config: OscilloscopeConfig): void => { - /** - * Configures the oscilloscope. - * @param config - The configuration object for the oscilloscope. - */ - app.osc = { - ...app.osc, - ...config, - }; -}; \ No newline at end of file +export const scope = (app: Editor) => (config: OscilloscopeConfig): void => { + /** + * Configures the oscilloscope. + * @param config - The configuration object for the oscilloscope. + */ + app.osc = { + ...app.osc, + ...config, + }; +}; diff --git a/src/API/Console.ts b/src/API/Console.ts index 54358dd..288b44d 100644 --- a/src/API/Console.ts +++ b/src/API/Console.ts @@ -1,20 +1,22 @@ -export const log = (app: any) => (message: any) => { - /** - * Logs a message to the console and app-specific logger. - * @param message - The message to log. - */ - console.log(message); - app._logMessage(message, false); +import { type UserAPI } from "./API"; + +export const log = (api: UserAPI) => (message: any) => { + /** + * Logs a message to the console and app-specific logger. + * @param message - The message to log. + */ + console.log(message); + api._logMessage(message, false); }; -export const logOnce = (app: any) => (message: any) => { - /** - * Logs a message to the console and app-specific logger, but only once. - * @param message - The message to log. - */ - if (app.onceEvaluator) { - console.log(message); - app._logMessage(message, false); - app.onceEvaluator = false; - } +export const logOnce = (api: UserAPI) => (message: any) => { + /** + * Logs a message to the console and app-specific logger, but only once. + * @param message - The message to log. + */ + if (api.onceEvaluator) { + console.log(message); + api._logMessage(message, false); + api.onceEvaluator = false; + } }; diff --git a/src/API/Counter.ts b/src/API/Counter.ts index 221d8e5..bf87c87 100644 --- a/src/API/Counter.ts +++ b/src/API/Counter.ts @@ -1,40 +1,43 @@ -export const once = (app: any) => (): boolean => { - const firstTime = app.api.onceEvaluator; - app.api.onceEvaluator = false; - return firstTime; +import { type UserAPI } from "./API"; +import { type Editor } from "../main"; + +export const once = (api: UserAPI) => (): boolean => { + const firstTime = api.onceEvaluator; + api.onceEvaluator = false; + return firstTime; }; -export const counter = (app: any) => (name: string | number, limit?: number, step?: number): number => { - if (!(name in app.counters)) { - app.counters[name] = { - value: 0, - step: step ?? 1, - limit, - }; - } else { - if (app.counters[name].limit !== limit) { - app.counters[name].value = 0; - app.counters[name].limit = limit; - } - - if (app.counters[name].step !== step) { - app.counters[name].step = step ?? app.counters[name].step; - } - - app.counters[name].value += app.counters[name].step; - - if (app.counters[name].limit !== undefined && app.counters[name].value > app.counters[name].limit) { - app.counters[name].value = 0; - } +export const counter = (api: UserAPI) => (name: string | number, limit?: number, step?: number): number => { + if (!(name in api.counters)) { + api.counters[name] = { + value: 0, + step: step ?? 1, + limit, + }; + } else { + if (api.counters[name].limit !== limit) { + api.counters[name].value = 0; + api.counters[name].limit = limit; } - return app.counters[name].value; + if (api.counters[name].step !== step) { + api.counters[name].step = step ?? api.counters[name].step; + } + + api.counters[name].value += api.counters[name].step; + + if (api.counters[name].limit !== undefined && api.counters[name].value > api.counters[name].limit) { + api.counters[name].value = 0; + } + } + + return api.counters[name].value; }; -export const i = (app: any) => (n?: number) => { - if (n !== undefined) { - app.universes[app.selected_universe].global.evaluations = n; - return app.universes[app.selected_universe]; - } - return app.universes[app.selected_universe].global.evaluations as number; -}; \ No newline at end of file +export const i = (app: Editor) => (n?: number) => { + if (n !== undefined) { + app.universes[app.selected_universe].global.evaluations = n; + return app.universes[app.selected_universe]; + } + return app.universes[app.selected_universe].global.evaluations as number; +}; diff --git a/src/API/Drunk.ts b/src/API/Drunk.ts index 680b14c..4bbc2c2 100644 --- a/src/API/Drunk.ts +++ b/src/API/Drunk.ts @@ -1,37 +1,39 @@ -export const drunk = (app: any) => (n?: number): number => { - /** - * This function sets or returns the current drunk mechanism's value. - * @param n - [optional] The value to set the drunk mechanism to - * @returns The current value of the drunk mechanism - */ - if (n !== undefined) { - app._drunk.position = n; - return app._drunk.getPosition(); - } - app._drunk.step(); - return app._drunk.getPosition(); +import { type UserAPI } from './API'; + +export const drunk = (api: UserAPI) => (n?: number): number => { + /** + * This function sets or returns the current drunk mechanism's value. + * @param n - [optional] The value to set the drunk mechanism to + * @returns The current value of the drunk mechanism + */ + if (n !== undefined) { + api._drunk.position = n; + return api._drunk.getPosition(); + } + api._drunk.step(); + return api._drunk.getPosition(); }; -export const drunk_max = (app: any) => (max: number): void => { - /** - * Sets the maximum value of the drunk mechanism. - * @param max - The maximum value of the drunk mechanism - */ - app._drunk.max = max; +export const drunk_max = (api: UserAPI) => (max: number): void => { + /** + * Sets the maximum value of the drunk mechanism. + * @param max - The maximum value of the drunk mechanism + */ + api._drunk.max = max; }; -export const drunk_min = (app: any) => (min: number): void => { - /** - * Sets the minimum value of the drunk mechanism. - * @param min - The minimum value of the drunk mechanism - */ - app._drunk.min = min; +export const drunk_min = (api: UserAPI) => (min: number): void => { + /** + * Sets the minimum value of the drunk mechanism. + * @param min - The minimum value of the drunk mechanism + */ + api._drunk.min = min; }; -export const drunk_wrap = (app: any) => (wrap: boolean): void => { - /** - * Sets whether the drunk mechanism should wrap around - * @param wrap - Whether the drunk mechanism should wrap around - */ - app._drunk.toggleWrap(wrap); -}; \ No newline at end of file +export const drunk_wrap = (api: UserAPI) => (wrap: boolean): void => { + /** + * Sets whether the drunk mechanism should wrap around + * @param wrap - Whether the drunk mechanism should wrap around + */ + api._drunk.toggleWrap(wrap); +}; diff --git a/src/API/Filters.ts b/src/API/Filters.ts index 22296ed..6065c5c 100644 --- a/src/API/Filters.ts +++ b/src/API/Filters.ts @@ -1,203 +1,206 @@ +import { type Editor } from "../main"; +import { UserAPI } from "./API"; + const _euclidean_cycle = ( - pulses: number, - length: number, - rotate: number = 0, - ): boolean[] => { - if (pulses == length) return Array.from({ length }, () => true); - function startsDescent(list: number[], i: number): boolean { - const length = list.length; - const nextIndex = (i + 1) % length; - return list[i] > list[nextIndex] ? true : false; - } - if (pulses >= length) return [true]; - const resList = Array.from( - { length }, - (_, i) => (((pulses * (i - 1)) % length) + length) % length, - ); - let cycle = resList.map((_, i) => startsDescent(resList, i)); - if (rotate != 0) { - cycle = cycle.slice(rotate).concat(cycle.slice(0, rotate)); - } - return cycle; + pulses: number, + length: number, + rotate: number = 0, +): boolean[] => { + if (pulses == length) return Array.from({ length }, () => true); + function startsDescent(list: number[], i: number): boolean { + const length = list.length; + const nextIndex = (i + 1) % length; + return list[i] > list[nextIndex] ? true : false; } + if (pulses >= length) return [true]; + const resList = Array.from( + { length }, + (_, i) => (((pulses * (i - 1)) % length) + length) % length, + ); + let cycle = resList.map((_, i) => startsDescent(resList, i)); + if (rotate != 0) { + cycle = cycle.slice(rotate).concat(cycle.slice(0, rotate)); + } + return cycle; +} export const fullseq = () => (sequence: string, duration: number): boolean | Array => { - if (sequence.split("").every((c) => c === "x" || c === "o")) { - return [...sequence].map((c) => c === "x").beat(duration); - } else { - return false; - } + if (sequence.split("").every((c) => c === "x" || c === "o")) { + return [...sequence].map((c) => c === "x").beat(duration); + } else { + return false; + } }; export const seq = (app: any) => (expr: string, duration: number = 0.5): boolean => { - let len = expr.length * duration; - let output: number[] = []; + let len = expr.length * duration; + let output: number[] = []; - for (let i = 1; i <= len + 1; i += duration) { - output.push(Math.floor(i * 10) / 10); - } - output.pop(); + for (let i = 1; i <= len + 1; i += duration) { + output.push(Math.floor(i * 10) / 10); + } + output.pop(); - output = output.filter((_, idx) => { - const exprIdx = idx % expr.length; - return expr[exprIdx] === "x"; - }); + output = output.filter((_, idx) => { + const exprIdx = idx % expr.length; + return expr[exprIdx] === "x"; + }); - return oncount(app)(output, len); + return oncount(app)(output, len); }; -export const beat = (app: any) => (n: number | number[] = 1, nudge: number = 0): boolean => { - const nArray = Array.isArray(n) ? n : [n]; - const results: boolean[] = nArray.map( - (value) => - (app.clock.pulses_since_origin - Math.floor(nudge * app.clock.ppqn)) % - Math.floor(value * app.clock.ppqn) === 0, - ); - return results.some((value) => value === true); +export const beat = (app: Editor) => (n: number | number[] = 1, nudge: number = 0): boolean => { + const nArray = Array.isArray(n) ? n : [n]; + const results: boolean[] = nArray.map( + (value) => + (app.clock.pulses_since_origin - Math.floor(nudge * app.clock.ppqn)) % + Math.floor(value * app.clock.ppqn) === 0, + ); + return results.some((value) => value === true); }; -export const bar = (app: any) => (n: number | number[] = 1, nudge: number = 0): boolean => { - const nArray = Array.isArray(n) ? n : [n]; - const barLength = app.clock.time_signature[1] * app.clock.ppqn; - const nudgeInPulses = Math.floor(nudge * barLength); - const results: boolean[] = nArray.map( - (value) => - (app.clock.pulses_since_origin - nudgeInPulses) % - Math.floor(value * barLength) === 0, - ); - return results.some((value) => value === true); +export const bar = (app: Editor) => (n: number | number[] = 1, nudge: number = 0): boolean => { + const nArray = Array.isArray(n) ? n : [n]; + const barLength = app.clock.time_signature[1] * app.clock.ppqn; + const nudgeInPulses = Math.floor(nudge * barLength); + const results: boolean[] = nArray.map( + (value) => + (app.clock.pulses_since_origin - nudgeInPulses) % + Math.floor(value * barLength) === 0, + ); + return results.some((value) => value === true); }; -export const pulse = (app: any) => (n: number | number[] = 1, nudge: number = 0): boolean => { - const nArray = Array.isArray(n) ? n : [n]; - const results: boolean[] = nArray.map( - (value) => (app.clock.pulses_since_origin - nudge) % value === 0, - ); - return results.some((value) => value === true); +export const pulse = (app: Editor) => (n: number | number[] = 1, nudge: number = 0): boolean => { + const nArray = Array.isArray(n) ? n : [n]; + const results: boolean[] = nArray.map( + (value) => (app.clock.pulses_since_origin - nudge) % value === 0, + ); + return results.some((value) => value === true); }; -export const tick = (app: any) => (tick: number | number[], offset: number = 0): boolean => { - const nArray = Array.isArray(tick) ? tick : [tick]; - const results: boolean[] = nArray.map( - (value) => app.clock.time_position.pulse === value + offset, - ); - return results.some((value) => value === true); +export const tick = (app: Editor) => (tick: number | number[], offset: number = 0): boolean => { + const nArray = Array.isArray(tick) ? tick : [tick]; + const results: boolean[] = nArray.map( + (value) => app.clock.time_position.pulse === value + offset, + ); + return results.some((value) => value === true); }; -export const dur = (app: any) => (n: number | number[]): boolean => { - let nums: number[] = Array.isArray(n) ? n : [n]; - return beat(app)(nums.dur(...nums)); +export const dur = (app: Editor) => (n: number | number[]): boolean => { + let nums: number[] = Array.isArray(n) ? n : [n]; + return beat(app)(nums.dur(...nums)); }; -export const flip = (app: any) => (chunk: number, ratio: number = 50): boolean => { - let realChunk = chunk * 2; - const time_pos = app.clock.pulses_since_origin; - const full_chunk = Math.floor(realChunk * app.clock.ppqn); - const threshold = Math.floor((ratio / 100) * full_chunk); - const pos_within_chunk = time_pos % full_chunk; - return pos_within_chunk < threshold; +export const flip = (app: Editor) => (chunk: number, ratio: number = 50): boolean => { + let realChunk = chunk * 2; + const time_pos = app.clock.pulses_since_origin; + const full_chunk = Math.floor(realChunk * app.clock.ppqn); + const threshold = Math.floor((ratio / 100) * full_chunk); + const pos_within_chunk = time_pos % full_chunk; + return pos_within_chunk < threshold; }; -export const flipbar = (app: any) => (chunk: number = 1): boolean => { - let realFlip = chunk; - const time_pos = app.clock.time_position.bar; - const current_chunk = Math.floor(time_pos / realFlip); - return current_chunk % 2 === 0; +export const flipbar = (app: Editor) => (chunk: number = 1): boolean => { + let realFlip = chunk; + const time_pos = app.clock.time_position.bar; + const current_chunk = Math.floor(time_pos / realFlip); + return current_chunk % 2 === 0; }; -export const onbar = (app: any) => ( - bars: number[] | number, - n: number = app.clock.time_signature[0], +export const onbar = (app: Editor) => ( + bars: number[] | number, + n: number = app.clock.time_signature[0], ): boolean => { - let current_bar = (app.clock.time_position.bar % n) + 1; - return typeof bars === "number" - ? bars === current_bar - : bars.some((b) => b === current_bar); + let current_bar = (app.clock.time_position.bar % n) + 1; + return typeof bars === "number" + ? bars === current_bar + : bars.some((b) => b === current_bar); }; -export const onbeat = (app: any) => (...beat: number[]): boolean => { - let final_pulses: boolean[] = []; - beat.forEach((b) => { - let beatNumber = b % app.nominator() || app.nominator(); - let integral_part = Math.floor(beatNumber); - integral_part = integral_part === 0 ? app.nominator() : integral_part; - let decimal_part = Math.floor((beatNumber - integral_part) * app.clock.ppqn + 1); - if (decimal_part <= 0) - decimal_part += app.clock.ppqn * app.nominator(); - final_pulses.push( - integral_part === app.cbeat() && app.cpulse() === decimal_part, - ); - }); - return final_pulses.some((p) => p === true); +export const onbeat = (api: UserAPI) => (...beat: number[]): boolean => { + let final_pulses: boolean[] = []; + beat.forEach((b) => { + let beatNumber = b % api.nominator() || api.nominator(); + let integral_part = Math.floor(beatNumber); + integral_part = integral_part === 0 ? api.nominator() : integral_part; + let decimal_part = Math.floor((beatNumber - integral_part) * api.app.clock.ppqn + 1); + if (decimal_part <= 0) + decimal_part += api.app.clock.ppqn * api.nominator(); + final_pulses.push( + integral_part === api.cbeat() && api.cpulse() === decimal_part, + ); + }); + return final_pulses.some((p) => p === true); }; -export const oncount = (app: any) => (beats: number[] | number, count: number): boolean => { - if (typeof beats === "number") beats = [beats]; - const origin = app.clock.pulses_since_origin; - let final_pulses: boolean[] = []; - beats.forEach((b) => { - b = b < 1 ? 0 : b - 1; - const beatInTicks = Math.ceil(b * app.clock.ppqn); - const meterPosition = origin % (app.clock.ppqn * count); - final_pulses.push(meterPosition === beatInTicks); - }); - return final_pulses.some((p) => p === true); +export const oncount = (app: Editor) => (beats: number[] | number, count: number): boolean => { + if (typeof beats === "number") beats = [beats]; + const origin = app.clock.pulses_since_origin; + let final_pulses: boolean[] = []; + beats.forEach((b) => { + b = b < 1 ? 0 : b - 1; + const beatInTicks = Math.ceil(b * app.clock.ppqn); + const meterPosition = origin % (app.clock.ppqn * count); + final_pulses.push(meterPosition === beatInTicks); + }); + return final_pulses.some((p) => p === true); }; -export const oneuclid = (app: any) => (pulses: number, length: number, rotate: number = 0): boolean => { - const cycle = _euclidean_cycle(pulses, length, rotate); - const beats = cycle.reduce((acc: number[], x: boolean, i: number) => { - if (x) acc.push(i + 1); - return acc; - }, []); - return oncount(app)(beats, length); +export const oneuclid = (app: Editor) => (pulses: number, length: number, rotate: number = 0): boolean => { + const cycle = _euclidean_cycle(pulses, length, rotate); + const beats = cycle.reduce((acc: number[], x: boolean, i: number) => { + if (x) acc.push(i + 1); + return acc; + }, []); + return oncount(app)(beats, length); }; export const euclid = () => (iterator: number, pulses: number, length: number, rotate: number = 0): boolean => { - /** - * Returns a Euclidean cycle of size length, with n pulses, rotated or not. - */ - return _euclidean_cycle(pulses, length, rotate)[iterator % length]; + /** + * Returns a Euclidean cycle of size length, with n pulses, rotated or not. + */ + return _euclidean_cycle(pulses, length, rotate)[iterator % length]; }; export const ec = euclid; -export const rhythm = (app: any) => (div: number, pulses: number, length: number, rotate: number = 0): boolean => { - /** - * Returns a rhythm based on Euclidean cycle. - */ - return ( - beat(app)(div) && _euclidean_cycle(pulses, length, rotate).beat(div) - ); +export const rhythm = (app: Editor) => (div: number, pulses: number, length: number, rotate: number = 0): boolean => { + /** + * Returns a rhythm based on Euclidean cycle. + */ + return ( + beat(app)(div) && _euclidean_cycle(pulses, length, rotate).beat(div) + ); }; export const ry = rhythm; -export const nrhythm = (app: any) => (div: number, pulses: number, length: number, rotate: number = 0): boolean => { - /** - * Returns a negated rhythm based on Euclidean cycle. - */ - let rhythm = _euclidean_cycle(pulses, length, rotate).map((n: any) => !n); - return ( - beat(app)(div) && rhythm.beat(div) - ); +export const nrhythm = (app: Editor) => (div: number, pulses: number, length: number, rotate: number = 0): boolean => { + /** + * Returns a negated rhythm based on Euclidean cycle. + */ + let rhythm = _euclidean_cycle(pulses, length, rotate).map((n: any) => !n); + return ( + beat(app)(div) && rhythm.beat(div) + ); }; export const nry = nrhythm; export const bin = () => (iterator: number, n: number): boolean => { - /** - * Returns a binary cycle of size n. - */ - let convert: string = n.toString(2); - let tobin: boolean[] = convert.split("").map((x: string) => x === "1"); - return tobin[iterator % tobin.length]; + /** + * Returns a binary cycle of size n. + */ + let convert: string = n.toString(2); + let tobin: boolean[] = convert.split("").map((x: string) => x === "1"); + return tobin[iterator % tobin.length]; }; -export const binrhythm = (app: any) => (div: number, n: number): boolean => { - /** - * Returns a binary rhythm based on division and binary cycle. - */ - let convert: string = n.toString(2); - let tobin: boolean[] = convert.split("").map((x: string) => x === "1"); - return beat(app)(div) && tobin.beat(div); +export const binrhythm = (app: Editor) => (div: number, n: number): boolean => { + /** + * Returns a binary rhythm based on division and binary cycle. + */ + let convert: string = n.toString(2); + let tobin: boolean[] = convert.split("").map((x: string) => x === "1"); + return beat(app)(div) && tobin.beat(div); }; -export const bry = binrhythm; \ No newline at end of file +export const bry = binrhythm; diff --git a/src/API/LFO.ts b/src/API/LFO.ts index c0509ce..2b4103c 100644 --- a/src/API/LFO.ts +++ b/src/API/LFO.ts @@ -1,65 +1,68 @@ +import { Editor } from "../main"; +import { UserAPI } from "./API"; + export const line = () => (start: number, end: number, step: number = 1): number[] => { - const countPlaces = (num: number) => { - var text = num.toString(); - var index = text.indexOf("."); - return index == -1 ? 0 : (text.length - index - 1); - }; + const countPlaces = (num: number) => { + var text = num.toString(); + var index = text.indexOf("."); + return index == -1 ? 0 : (text.length - index - 1); + }; - const result: number[] = []; + const result: number[] = []; - if ((end > start && step > 0) || (end < start && step < 0)) { - for (let value = start; value <= end; value += step) { - result.push(value); - } - } else if ((end > start && step < 0) || (end < start && step > 0)) { - for (let value = start; value >= end; value -= step) { - result.push(parseFloat(value.toFixed(countPlaces(step)))); - } - } else { - console.error("Invalid range or step provided."); + if ((end > start && step > 0) || (end < start && step < 0)) { + for (let value = start; value <= end; value += step) { + result.push(value); } + } else if ((end > start && step < 0) || (end < start && step > 0)) { + for (let value = start; value >= end; value -= step) { + result.push(parseFloat(value.toFixed(countPlaces(step)))); + } + } else { + console.error("Invalid range or step provided."); + } - return result; + return result; }; -export const sine = (app: any) => (freq: number = 1, phase: number = 0): number => { - return Math.sin(2 * Math.PI * freq * (app.clock.ctx.currentTime - phase)); +export const sine = (app: Editor) => (freq: number = 1, phase: number = 0): number => { + return Math.sin(2 * Math.PI * freq * (app.clock.ctx.currentTime - phase)); }; -export const usine = (app: any) => (freq: number = 1, phase: number = 0): number => { - return ((sine(app)(freq, phase) + 1) / 2); +export const usine = (app: Editor) => (freq: number = 1, phase: number = 0): number => { + return ((sine(app)(freq, phase) + 1) / 2); }; -export const saw = (app: any) => (freq: number = 1, phase: number = 0): number => { - return (((app.clock.ctx.currentTime * freq + phase) % 1) * 2 - 1); +export const saw = (app: Editor) => (freq: number = 1, phase: number = 0): number => { + return (((app.clock.ctx.currentTime * freq + phase) % 1) * 2 - 1); }; -export const usaw = (app: any) => (freq: number = 1, phase: number = 0): number => { - return ((saw(app)(freq, phase) + 1) / 2); +export const usaw = (app: Editor) => (freq: number = 1, phase: number = 0): number => { + return ((saw(app)(freq, phase) + 1) / 2); }; -export const triangle = (app: any) => (freq: number = 1, phase: number = 0): number => { - return (Math.abs(saw(app)(freq, phase)) * 2 - 1); +export const triangle = (app: Editor) => (freq: number = 1, phase: number = 0): number => { + return (Math.abs(saw(app)(freq, phase)) * 2 - 1); }; -export const utriangle = (app: any) => (freq: number = 1, phase: number = 0): number => { - return ((triangle(app)(freq, phase) + 1) / 2); +export const utriangle = (app: Editor) => (freq: number = 1, phase: number = 0): number => { + return ((triangle(app)(freq, phase) + 1) / 2); }; -export const square = () => (freq: number = 1, duty: number = 0.5): number => { - const period = 1 / freq; - const t = (Date.now() / 1000) % period; - return (t / period < duty ? 1 : -1); +export const square = (app: Editor) => (freq: number = 1, duty: number = 0.5): number => { + const period = 1 / freq; + const t = (app.clock.ctx.currentTime % period); + return (t / period < duty ? 1 : -1); }; -export const usquare = () => (freq: number = 1, duty: number = 0.5): number => { - return ((square()(freq, duty) + 1) / 2); +export const usquare = (app: Editor) => (freq: number = 1, duty: number = 0.5): number => { + return ((square(app)(freq, duty) + 1) / 2); }; -export const noise = (app: any) => (): number => { - return (app.randomGen() * 2 - 1); // Assuming randomGen() is defined in the app context +export const noise = (api: UserAPI) => (): number => { + return (api.randomGen() * 2 - 1); // Assuming randomGen() is defined in the app context }; -export const unoise = (app: any) => (): number => { - return ((noise(app)() + 1) / 2); +export const unoise = (api: UserAPI) => (): number => { + return ((noise(api)() + 1) / 2); }; diff --git a/src/API/MIDI.ts b/src/API/MIDI.ts index 09f7401..63ce54e 100644 --- a/src/API/MIDI.ts +++ b/src/API/MIDI.ts @@ -4,6 +4,8 @@ import { MidiNoteEvent, } from "../IO/MidiConnection"; import { MidiEvent, MidiParams } from "../Classes/MidiEvent"; +import { UserAPI } from './API'; +import { Editor } from '../main'; interface ControlChange { channel: number; @@ -11,20 +13,19 @@ interface ControlChange { value: number; } - -export const midi_outputs = (app: any) => (): void => { - app._logMessage(app.MidiConnection.listMidiOutputs(), false); +export const midi_outputs = (api: UserAPI) => (): void => { + api._logMessage(api.MidiConnection.listMidiOutputs(), false); }; -export const midi_output = (app: any) => (outputName: string): void => { +export const midi_output = (api: UserAPI) => (outputName: string): void => { if (!outputName) { - console.log(app.MidiConnection.getCurrentMidiPort()); + console.log(api.MidiConnection.getCurrentMidiPort()); } else { - app.MidiConnection.switchMidiOutput(outputName); + api.MidiConnection.switchMidiOutput(outputName); } }; -export const midi = (app: any) => ( +export const midi = (app: Editor) => ( value: number | number[] = 60, velocity?: number | number[], channel?: number | number[], @@ -34,164 +35,164 @@ export const midi = (app: any) => ( return new MidiEvent(event, app); }; -export const sysex = (app: any) => (data: Array): void => { - app.MidiConnection.sendSysExMessage(data); +export const sysex = (api: UserAPI) => (data: Array): void => { + api.MidiConnection.sendSysExMessage(data); }; -export const pitch_bend = (app: any) => (value: number, channel: number): void => { - app.MidiConnection.sendPitchBend(value, channel); +export const pitch_bend = (api: UserAPI) => (value: number, channel: number): void => { + api.MidiConnection.sendPitchBend(value, channel); }; -export const program_change = (app: any) => (program: number, channel: number): void => { - app.MidiConnection.sendProgramChange(program, channel); +export const program_change = (api: UserAPI) => (program: number, channel: number): void => { + api.MidiConnection.sendProgramChange(program, channel); }; -export const midi_clock = (app: any) => (): void => { - app.MidiConnection.sendMidiClock(); +export const midi_clock = (api: UserAPI) => (): void => { + api.MidiConnection.sendMidiClock(); }; -export const control_change = (app: any) => ({ +export const control_change = (api: UserAPI) => ({ control = 20, value = 0, channel = 0, }: ControlChange): void => { - app.MidiConnection.sendMidiControlChange(control, value, channel); + api.MidiConnection.sendMidiControlChange(control, value, channel); }; export const cc = control_change; -export const midi_panic = (app: any) => (): void => { - app.MidiConnection.panic(); +export const midi_panic = (api: UserAPI) => (): void => { + api.MidiConnection.panic(); }; -export const active_note_events = (app: any) => ( +export const active_note_events = (api: UserAPI) => ( channel?: number, ): MidiNoteEvent[] | undefined => { let events; if (channel) { - events = app.MidiConnection.activeNotesFromChannel(channel); + events = api.MidiConnection.activeNotesFromChannel(channel); } else { - events = app.MidiConnection.activeNotes; + events = api.MidiConnection.activeNotes; } if (events.length > 0) return events; else return undefined; }; -export const transmission = (app: any) => (): boolean => { - return app.MidiConnection.activeNotes.length > 0; +export const transmission = (api: UserAPI) => (): boolean => { + return api.MidiConnection.activeNotes.length > 0; }; -export const active_notes = (app: any) => (channel?: number): number[] | undefined => { - const events = active_note_events(app)(channel); +export const active_notes = (api: UserAPI) => (channel?: number): number[] | undefined => { + const events = active_note_events(api)(channel); if (events && events.length > 0) return events.map((e) => e.note); else return undefined; }; -export const kill_active_notes = (app: any) => (): void => { - app.MidiConnection.activeNotes = []; +export const kill_active_notes = (api: UserAPI) => (): void => { + api.MidiConnection.activeNotes = []; }; -export const sticky_notes = (app: any) => (channel?: number): number[] | undefined => { +export const sticky_notes = (api: UserAPI) => (channel?: number): number[] | undefined => { let notes; - if (channel) notes = app.MidiConnection.stickyNotesFromChannel(channel); - else notes = app.MidiConnection.stickyNotes; + if (channel) notes = api.MidiConnection.stickyNotesFromChannel(channel); + else notes = api.MidiConnection.stickyNotes; if (notes.length > 0) return notes.map((e: any) => e.note); else return undefined; }; -export const kill_sticky_notes = (app: any) => (): void => { - app.MidiConnection.stickyNotes = []; +export const kill_sticky_notes = (api: UserAPI) => (): void => { + api.MidiConnection.stickyNotes = []; }; -export const buffer = (app: any) => (channel?: number): boolean => { +export const buffer = (api: UserAPI) => (channel?: number): boolean => { if (channel) return ( - app.MidiConnection.findNoteFromBufferInChannel(channel) !== undefined + api.MidiConnection.findNoteFromBufferInChannel(channel) !== undefined ); - else return app.MidiConnection.noteInputBuffer.length > 0; + else return api.MidiConnection.noteInputBuffer.length > 0; }; -export const buffer_event = (app: any) => (channel?: number): MidiNoteEvent | undefined => { +export const buffer_event = (api: UserAPI) => (channel?: number): MidiNoteEvent | undefined => { if (channel) - return app.MidiConnection.findNoteFromBufferInChannel(channel); - else return app.MidiConnection.noteInputBuffer.shift(); + return api.MidiConnection.findNoteFromBufferInChannel(channel); + else return api.MidiConnection.noteInputBuffer.shift(); }; -export const buffer_note = (app: any) => (channel?: number): number | undefined => { - const note = buffer_event(app)(channel); +export const buffer_note = (api: UserAPI) => (channel?: number): number | undefined => { + const note = buffer_event(api)(channel); return note ? note.note : undefined; }; -export const last_note_event = (app: any) => (channel?: number): MidiNoteEvent | undefined => { - if (channel) return app.MidiConnection.lastNoteInChannel[channel]; - else return app.MidiConnection.lastNote; +export const last_note_event = (api: UserAPI) => (channel?: number): MidiNoteEvent | undefined => { + if (channel) return api.MidiConnection.lastNoteInChannel[channel]; + else return api.MidiConnection.lastNote; }; -export const last_note = (app: any) => (channel?: number): number => { - const note = last_note_event(app)(channel); +export const last_note = (api: UserAPI) => (channel?: number): number => { + const note = last_note_event(api)(channel); return note ? note.note : 60; }; -export const ccIn = (app: any) => (control: number, channel?: number): number => { +export const ccIn = (api: UserAPI) => (control: number, channel?: number): number => { if (channel) { - if (app.MidiConnection.lastCCInChannel[channel]) { - return app.MidiConnection.lastCCInChannel[channel][control]; + if (api.MidiConnection.lastCCInChannel[channel]) { + return api.MidiConnection.lastCCInChannel[channel][control]; } else return 0; - } else return app.MidiConnection.lastCC[control] || 0; + } else return api.MidiConnection.lastCC[control] || 0; }; -export const has_cc = (app: any) => (channel?: number): boolean => { +export const has_cc = (api: UserAPI) => (channel?: number): boolean => { if (channel) return ( - app.MidiConnection.findCCFromBufferInChannel(channel) !== undefined + api.MidiConnection.findCCFromBufferInChannel(channel) !== undefined ); - else return app.MidiConnection.ccInputBuffer.length > 0; + else return api.MidiConnection.ccInputBuffer.length > 0; }; -export const buffer_cc = (app: any) => (channel?: number): MidiCCEvent | undefined => { - if (channel) return app.MidiConnection.findCCFromBufferInChannel(channel); - else return app.MidiConnection.ccInputBuffer.shift(); +export const buffer_cc = (api: UserAPI) => (channel?: number): MidiCCEvent | undefined => { + if (channel) return api.MidiConnection.findCCFromBufferInChannel(channel); + else return api.MidiConnection.ccInputBuffer.shift(); }; -export const show_scale = (app: any) => ( +export const show_scale = (api: UserAPI) => ( root: number | string, scale: number | string, channel: number = 0, - port: number | string = app.MidiConnection.currentOutputIndex || 0, + port: number | string = api.MidiConnection.currentOutputIndex || 0, soundOff: boolean = false, ): void => { - if (!app.scale_aid || scale !== app.scale_aid) { - hide_scale(app)(channel, port); + if (!api.scale_aid || scale !== api.scale_aid) { + hide_scale(api)(channel, port); const scaleNotes = getAllScaleNotes(scale, root); scaleNotes.forEach((note) => { - app.MidiConnection.sendMidiOn(note, channel, 1, port); - if (soundOff) app.MidiConnection.sendAllSoundOff(channel, port); + api.MidiConnection.sendMidiOn(note, channel, 1, port); + if (soundOff) api.MidiConnection.sendAllSoundOff(channel, port); }); - app.scale_aid = scale; + api.scale_aid = scale; } }; -export const hide_scale = (app: any) => ( +export const hide_scale = (api: UserAPI) => ( channel: number = 0, - port: number | string = app.MidiConnection.currentOutputIndex || 0, + port: number | string = api.MidiConnection.currentOutputIndex || 0, ): void => { const allNotes = Array.from(Array(128).keys()); allNotes.forEach((note) => { - app.MidiConnection.sendMidiOff(note, channel, port); + api.MidiConnection.sendMidiOff(note, channel, port); }); - app.scale_aid = undefined; + api.scale_aid = undefined; }; -export const midi_notes_off = (app: any) => ( +export const midi_notes_off = (api: UserAPI) => ( channel: number = 0, - port: number | string = app.MidiConnection.currentOutputIndex || 0, + port: number | string = api.MidiConnection.currentOutputIndex || 0, ): void => { - app.MidiConnection.sendAllNotesOff(channel, port); + api.MidiConnection.sendAllNotesOff(channel, port); }; -export const midi_sound_off = (app: any) => ( +export const midi_sound_off = (api: UserAPI) => ( channel: number = 0, - port: number | string = app.MidiConnection.currentOutputIndex || 0, + port: number | string = api.MidiConnection.currentOutputIndex || 0, ): void => { - app.MidiConnection.sendAllSoundOff(channel, port); + api.MidiConnection.sendAllSoundOff(channel, port); }; diff --git a/src/API/Mouse.ts b/src/API/Mouse.ts index c7506fd..0acbfa4 100644 --- a/src/API/Mouse.ts +++ b/src/API/Mouse.ts @@ -1,33 +1,35 @@ +import { Editor } from "../main"; + // mouse.ts -export const onmousemove = (app: any) => (e: MouseEvent): void => { - app._mouseX = e.pageX; - app._mouseY = e.pageY; +export const onmousemove = (app: Editor) => (e: MouseEvent): void => { + app._mouseX = e.pageX; + app._mouseY = e.pageY; }; -export const mouseX = (app: any) => (): number => { - /** - * @returns The current x position of the mouse - */ - return app._mouseX; +export const mouseX = (app: Editor) => (): number => { + /** + * @returns The current x position of the mouse + */ + return app._mouseX; }; -export const mouseY = (app: any) => (): number => { - /** - * @returns The current y position of the mouse - */ - return app._mouseY; +export const mouseY = (app: Editor) => (): number => { + /** + * @returns The current y position of the mouse + */ + return app._mouseY; }; -export const noteX = (app: any) => (): number => { - /** - * @returns The current x position scaled to 0-127 using screen width - */ - return Math.floor((app._mouseX / document.body.clientWidth) * 127); +export const noteX = (app: Editor) => (): number => { + /** + * @returns The current x position scaled to 0-127 using screen width + */ + return Math.floor((app._mouseX / document.body.clientWidth) * 127); }; -export const noteY = (app: any) => (): number => { - /** - * @returns The current y position scaled to 0-127 using screen height - */ - return Math.floor((app._mouseY / document.body.clientHeight) * 127); -}; \ No newline at end of file +export const noteY = (app: Editor) => (): number => { + /** + * @returns The current y position scaled to 0-127 using screen height + */ + return Math.floor((app._mouseY / document.body.clientHeight) * 127); +}; diff --git a/src/API/OSC.ts b/src/API/OSC.ts index 7a66b05..7388b91 100644 --- a/src/API/OSC.ts +++ b/src/API/OSC.ts @@ -1,27 +1,28 @@ import { sendToServer, type OSCMessage } from "../IO/OSC"; +import { Editor } from "../main"; +import { oscMessages } from "../IO/OSC"; -export const osc = (app: any) => (address: string, port: number, ...args: any[]): void => { - /** - * Sends an OSC message to the server. - */ - sendToServer({ - address: address, - port: port, - args: args, - timetag: Math.round(Date.now() + (app.clock.nudge - app.clock.deviation)), - } as OSCMessage); +export const osc = (app: Editor) => (address: string, port: number, ...args: any[]): void => { + /** + * Sends an OSC message to the server. + */ + sendToServer({ + address: address, + port: port, + args: args, + timetag: Math.round(Date.now() + (app.clock.nudge - app.clock.deviation)), + } as OSCMessage); }; -export const getOSC = (app: any) => (address?: string): any[] => { - /** - * Retrieves incoming OSC messages. Filters by address if provided. - */ - let oscMessages = app.oscMessages; // Assuming `oscMessages` is stored in `app` - if (address) { - let messages = oscMessages.filter((msg: { address: string; }) => msg.address === address); - messages = messages.map((msg: { data: any; }) => msg.data); - return messages; - } else { - return oscMessages; - } -}; \ No newline at end of file +export const getOSC = () => (address?: string): any[] => { + /** + * Retrieves incoming OSC messages. Filters by address if provided. + */ + if (address) { + let messages = oscMessages.filter((msg: { address: string; }) => msg.address === address); + messages = messages.map((msg: { data: any; }) => msg.data); + return messages; + } else { + return oscMessages; + } +}; diff --git a/src/API/Probabilities.ts b/src/API/Probabilities.ts index 5cd3fdc..7d72b5d 100644 --- a/src/API/Probabilities.ts +++ b/src/API/Probabilities.ts @@ -1,53 +1,53 @@ -// Probability.ts +import { type UserAPI } from "./API"; -export const prob = (app: any) => (p: number): boolean => { - return app.randomGen() * 100 < p; +export const prob = (api: UserAPI) => (p: number): boolean => { + return api.randomGen() * 100 < p; }; -export const toss = (app: any) => (): boolean => { - return app.randomGen() > 0.5; +export const toss = (api: UserAPI) => (): boolean => { + return api.randomGen() > 0.5; }; -export const odds = (app: any) => (n: number, beats: number = 1): boolean => { - return app.randomGen() < (n * app.ppqn()) / (app.ppqn() * beats); +export const odds = (api: UserAPI) => (n: number, beats: number = 1): boolean => { + return api.randomGen() < (n * api.ppqn()) / (api.ppqn() * beats); }; export const never = () => (): boolean => { - return false; + return false; }; -export const almostNever = (app: any) => (beats: number = 1): boolean => { - return app.randomGen() < (0.025 * app.ppqn()) / (app.ppqn() * beats); +export const almostNever = (api: UserAPI) => (beats: number = 1): boolean => { + return api.randomGen() < (0.025 * api.ppqn()) / (api.ppqn() * beats); }; -export const rarely = (app: any) => (beats: number = 1): boolean => { - return app.randomGen() < (0.1 * app.ppqn()) / (app.ppqn() * beats); +export const rarely = (api: UserAPI) => (beats: number = 1): boolean => { + return api.randomGen() < (0.1 * api.ppqn()) / (api.ppqn() * beats); }; -export const scarcely = (app: any) => (beats: number = 1): boolean => { - return app.randomGen() < (0.25 * app.ppqn()) / (app.ppqn() * beats); +export const scarcely = (api: UserAPI) => (beats: number = 1): boolean => { + return api.randomGen() < (0.25 * api.ppqn()) / (api.ppqn() * beats); }; -export const sometimes = (app: any) => (beats: number = 1): boolean => { - return app.randomGen() < (0.5 * app.ppqn()) / (app.ppqn() * beats); +export const sometimes = (api: UserAPI) => (beats: number = 1): boolean => { + return api.randomGen() < (0.5 * api.ppqn()) / (api.ppqn() * beats); }; -export const often = (app: any) => (beats: number = 1): boolean => { - return app.randomGen() < (0.75 * app.ppqn()) / (app.ppqn() * beats); +export const often = (api: UserAPI) => (beats: number = 1): boolean => { + return api.randomGen() < (0.75 * api.ppqn()) / (api.ppqn() * beats); }; -export const frequently = (app: any) => (beats: number = 1): boolean => { - return app.randomGen() < (0.9 * app.ppqn()) / (app.ppqn() * beats); +export const frequently = (api: UserAPI) => (beats: number = 1): boolean => { + return api.randomGen() < (0.9 * api.ppqn()) / (api.ppqn() * beats); }; -export const almostAlways = (app: any) => (beats: number = 1): boolean => { - return app.randomGen() < (0.985 * app.ppqn()) / (app.ppqn() * beats); +export const almostAlways = (api: UserAPI) => (beats: number = 1): boolean => { + return api.randomGen() < (0.985 * api.ppqn()) / (api.ppqn() * beats); }; export const always = () => (): boolean => { - return true; + return true; }; -export const dice = (app: any) => (sides: number): number => { - return Math.floor(app.randomGen() * sides) + 1; -}; \ No newline at end of file +export const dice = (api: UserAPI) => (sides: number): number => { + return Math.floor(api.randomGen() * sides) + 1; +}; diff --git a/src/API/Randomness.ts b/src/API/Randomness.ts index d8fb82c..9f02aac 100644 --- a/src/API/Randomness.ts +++ b/src/API/Randomness.ts @@ -1,33 +1,34 @@ import { seededRandom } from "zifferjs"; +import { UserAPI } from "./API"; -export const randI = (app: any) => (min: number, max: number): number => { - return Math.floor(app.randomGen() * (max - min + 1)) + min; +export const randI = (api: UserAPI) => (min: number, max: number): number => { + return Math.floor(api.randomGen() * (max - min + 1)) + min; }; -export const rand = (app: any) => (min: number, max: number): number => { - return app.randomGen() * (max - min) + min; +export const rand = (api: UserAPI) => (min: number, max: number): number => { + return api.randomGen() * (max - min) + min; }; -export const seed = (app: any) => (seed: string | number): void => { - if (typeof seed === "number") seed = seed.toString(); - if (app.currentSeed !== seed) { - app.currentSeed = seed; - app.randomGen = seededRandom(seed); - } +export const seed = (api: UserAPI) => (seed: string | number): void => { + if (typeof seed === "number") seed = seed.toString(); + if (api.currentSeed !== seed) { + api.currentSeed = seed; + api.randomGen = seededRandom(seed); + } }; -export const localSeededRandom = (app: any) => (seed: string | number): Function => { - if (typeof seed === "number") seed = seed.toString(); - if (app.localSeeds.has(seed)) return app.localSeeds.get(seed) as Function; - const newSeededRandom = seededRandom(seed); - app.localSeeds.set(seed, newSeededRandom); - return newSeededRandom; +export const localSeededRandom = (api: UserAPI) => (seed: string | number): Function => { + if (typeof seed === "number") seed = seed.toString(); + if (api.localSeeds.has(seed)) return api.localSeeds.get(seed) as Function; + const newSeededRandom = seededRandom(seed); + api.localSeeds.set(seed, newSeededRandom); + return newSeededRandom; }; -export const clearLocalSeed = (app: any) => (seed: string | number | undefined = undefined): void => { - if (seed) { - app.localSeeds.delete(seed.toString()); - } else { - app.localSeeds.clear(); - } -}; \ No newline at end of file +export const clearLocalSeed = (api: UserAPI) => (seed: string | number | undefined = undefined): void => { + if (seed) { + api.localSeeds.delete(seed.toString()); + } else { + api.localSeeds.clear(); + } +}; diff --git a/src/API/Script.ts b/src/API/Script.ts index a25f19d..61ad10c 100644 --- a/src/API/Script.ts +++ b/src/API/Script.ts @@ -1,63 +1,64 @@ import { tryEvaluate } from "../Evaluator"; import { blinkScript } from "../DOM/Visuals/Blinkers"; import { template_universes } from "../Editor/FileManagement"; +import { Editor } from "../main"; -export const script = (app: any) => (...args: number[]): void => { - args.forEach((arg) => { - if (arg >= 1 && arg <= 9) { - blinkScript(app, "local", arg); - tryEvaluate( - app, - app.universes[app.selected_universe].locals[arg], - ); - } - }); +export const script = (app: Editor) => (...args: number[]): void => { + args.forEach((arg) => { + if (arg >= 1 && arg <= 9) { + blinkScript(app, "local", arg); + tryEvaluate( + app, + app.universes[app.selected_universe].locals[arg], + ); + } + }); }; export const s = script; -export const delete_script = (app: any) => (script: number): void => { - app.universes[app.selected_universe].locals[script] = { - candidate: "", - committed: "", - evaluations: 0, - }; +export const delete_script = (app: Editor) => (script: number): void => { + app.universes[app.selected_universe].locals[script] = { + candidate: "", + committed: "", + evaluations: 0, + }; }; -export const copy_script = (app: any) => (from: number, to: number): void => { - app.universes[app.selected_universe].locals[to] = { - ...app.universes[app.selected_universe].locals[from], - }; +export const copy_script = (app: Editor) => (from: number, to: number): void => { + app.universes[app.selected_universe].locals[to] = { + ...app.universes[app.selected_universe].locals[from], + }; }; -export const copy_universe = (app: any) => (from: string, to: string): void => { - app.universes[to] = { - ...app.universes[from], - }; +export const copy_universe = (app: Editor) => (from: string, to: string): void => { + app.universes[to] = { + ...app.universes[from], + }; }; -export const delete_universe = (app: any) => (universe: string): void => { - if (app.selected_universe === universe) { - app.selected_universe = "Default"; - } - delete app.universes[universe]; +export const delete_universe = (app: Editor) => (universe: string): void => { + if (app.selected_universe === universe) { + app.selected_universe = "Default"; + } + delete app.universes[universe]; + app.settings.saveApplicationToLocalStorage( + app.universes, + app.settings, + ); + app.updateKnownUniversesView(); +}; + +export const big_bang = (app: Editor) => (): void => { + if (confirm("Are you sure you want to delete all universes?")) { + app.universes = { + ...template_universes, // Assuming template_universes is defined elsewhere + }; app.settings.saveApplicationToLocalStorage( app.universes, app.settings, ); - app.updateKnownUniversesView(); + } + app.selected_universe = "Default"; + app.updateKnownUniversesView(); }; - -export const big_bang = (app: any) => (): void => { - if (confirm("Are you sure you want to delete all universes?")) { - app.universes = { - ...template_universes, // Assuming template_universes is defined elsewhere - }; - app.settings.saveApplicationToLocalStorage( - app.universes, - app.settings, - ); - } - app.selected_universe = "Default"; - app.updateKnownUniversesView(); -}; \ No newline at end of file diff --git a/src/API/Sound.ts b/src/API/Sound.ts index 0fc3e31..81cedcd 100644 --- a/src/API/Sound.ts +++ b/src/API/Sound.ts @@ -1,43 +1,44 @@ import { SoundEvent } from "../Classes/SoundEvent"; import { SkipEvent } from "../Classes/SkipEvent"; +import { Editor } from "../main"; -export const sound = (app: any) => (sound: string | string[] | null | undefined) => { - /** - * Creates a sound event if a sound is specified, otherwise returns a skip event. - * @param sound - The sound identifier or array of identifiers to play. - * @returns SoundEvent if sound is defined, otherwise SkipEvent. - */ - if (sound) return new SoundEvent(sound, app); - else return new SkipEvent(); +export const sound = (app: Editor) => (sound: string | string[] | null | undefined) => { + /** + * Creates a sound event if a sound is specified, otherwise returns a skip event. + * @param sound - The sound identifier or array of identifiers to play. + * @returns SoundEvent if sound is defined, otherwise SkipEvent. + */ + if (sound) return new SoundEvent(sound, app); + else return new SkipEvent(); }; export const snd = sound; export const speak = () => (text: string, lang: string = "en-US", voiceIndex: number = 0, rate: number = 1, pitch: number = 1): void => { - /** - * Speaks the given text using the browser's speech synthesis API. - * @param text - The text to speak. - * @param lang - The language code (e.g., "en-US"). - * @param voiceIndex - The index of the voice to use from the speechSynthesis voice list. - * @param rate - The rate at which to speak the text. - * @param pitch - The pitch at which to speak the text. - */ - const msg = new SpeechSynthesisUtterance(text); - msg.lang = lang; - msg.rate = rate; - msg.pitch = pitch; + /** + * Speaks the given text using the browser's speech synthesis API. + * @param text - The text to speak. + * @param lang - The language code (e.g., "en-US"). + * @param voiceIndex - The index of the voice to use from the speechSynthesis voice list. + * @param rate - The rate at which to speak the text. + * @param pitch - The pitch at which to speak the text. + */ + const msg = new SpeechSynthesisUtterance(text); + msg.lang = lang; + msg.rate = rate; + msg.pitch = pitch; - // Set the voice using a provided index - const voices = window.speechSynthesis.getVoices(); - msg.voice = voices[voiceIndex] || null; + // Set the voice using a provided index + const voices = window.speechSynthesis.getVoices(); + msg.voice = voices[voiceIndex] || null; - window.speechSynthesis.speak(msg); + window.speechSynthesis.speak(msg); - msg.onend = () => { - console.log("Finished speaking:", text); - }; + msg.onend = () => { + console.log("Finished speaking:", text); + }; - msg.onerror = (event) => { - console.error("Speech synthesis error:", event); - }; -}; \ No newline at end of file + msg.onerror = (event) => { + console.error("Speech synthesis error:", event); + }; +}; diff --git a/src/API/Theme.ts b/src/API/Theme.ts index 3a54c56..31efd37 100644 --- a/src/API/Theme.ts +++ b/src/API/Theme.ts @@ -26,5 +26,5 @@ export const nextTheme = (app: Editor) => (): void => { }; export const getThemes = () => (): string[] => { - return Object.keys(colorschemes); -}; \ No newline at end of file + return Object.keys(colorschemes); +}; diff --git a/src/API/Transport.ts b/src/API/Transport.ts index 021cdea..ff1c059 100644 --- a/src/API/Transport.ts +++ b/src/API/Transport.ts @@ -1,114 +1,117 @@ -export const time = (app: any) => (): number => { - return app.audioContext.currentTime; +import { type UserAPI } from "./API"; +import { type Editor } from "../main"; + +export const time = (api: UserAPI) => (): number => { + return api.app.audioContext.currentTime; }; -export const play = (app: any) => (): void => { - app.setButtonHighlighting("play", true); - app.MidiConnection.sendStartMessage(); - app.clock.start(); +export const play = (api: UserAPI) => (): void => { + api.app.setButtonHighlighting("play", true); + api.MidiConnection.sendStartMessage(); + api.app.clock.start(); }; -export const pause = (app: any) => (): void => { - app.setButtonHighlighting("pause", true); - app.clock.pause(); +export const pause = (api: UserAPI) => (): void => { + api.app.setButtonHighlighting("pause", true); + api.app.clock.pause(); }; -export const stop = (app: any) => (): void => { - app.setButtonHighlighting("stop", true); - app.clock.stop(); +export const stop = (api: UserAPI) => (): void => { + api.app.setButtonHighlighting("stop", true); + api.app.clock.stop(); }; -export const silence = (app: any) => (): void => { - return stop(app)(); +export const silence = (api: UserAPI) => (): void => { + return stop(api)(); }; -export const tempo = (app: any) => (n?: number): number => { - /** - * Sets or returns the current bpm. - */ - if (n === undefined) return app.clock.bpm; +export const tempo = (app: Editor) => (n?: number): number => { + /** + * Sets or returns the current bpm. + */ + if (n === undefined) return app.clock.bpm; - if (n >= 1 && n <= 500) { - app.clock.bpm = n; - } else { - console.error("BPM out of acceptable range (1-500)."); - } - return n; + if (n >= 1 && n <= 500) { + app.clock.bpm = n; + } else { + console.error("BPM out of acceptable range (1-500)."); + } + return n; }; -export const bpb = (app: any) => (n?: number): number => { - /** - * Sets or returns the number of beats per bar. - */ - if (n === undefined) return app.clock.time_signature[0]; +export const bpb = (app: Editor) => (n?: number): number => { + /** + * Sets or returns the number of beats per bar. + */ + if (n === undefined) return app.clock.time_signature[0]; - if (n >= 1) { - app.clock.time_signature[0] = n; - } else { - console.error("Beats per bar must be at least 1."); - } - return n; + if (n >= 1) { + app.clock.time_signature[0] = n; + } else { + console.error("Beats per bar must be at least 1."); + } + return n; }; -export const ppqn = (app: any) => (n?: number): number => { - /** - * Sets or returns the number of pulses per quarter note. - */ - if (n === undefined) return app.clock.ppqn; +export const ppqn = (app: Editor) => (n?: number): number => { + /** + * Sets or returns the number of pulses per quarter note. + */ + if (n === undefined) return app.clock.ppqn; - if (n >= 1) { - app.clock.ppqn = n; - } else { - console.error("Pulses per quarter note must be at least 1."); - } - return n; + if (n >= 1) { + app.clock.ppqn = n; + } else { + console.error("Pulses per quarter note must be at least 1."); + } + return n; }; -export const time_signature = (app: any) => (numerator: number, denominator: number): void => { - /** - * Sets the time signature. - */ - if (numerator < 1 || denominator < 1) { - console.error("Time signature values must be at least 1."); - } else { - app.clock.time_signature = [numerator, denominator]; - } +export const time_signature = (app: Editor) => (numerator: number, denominator: number): void => { + /** + * Sets the time signature. + */ + if (numerator < 1 || denominator < 1) { + console.error("Time signature values must be at least 1."); + } else { + app.clock.time_signature = [numerator, denominator]; + } }; -export const cbar = (app: any) => (): number => { - return app.clock.time_position.bar + 1; +export const cbar = (app: Editor) => (): number => { + return app.clock.time_position.bar + 1; }; -export const ctick = (app: any) => (): number => { - return app.clock.tick + 1; +export const ctick = (app: Editor) => (): number => { + return app.clock.tick + 1; }; -export const cpulse = (app: any) => (): number => { - return app.clock.time_position.pulse + 1; +export const cpulse = (app: Editor) => (): number => { + return app.clock.time_position.pulse + 1; }; -export const cbeat = (app: any) => (): number => { - return app.clock.time_position.beat + 1; +export const cbeat = (app: Editor) => (): number => { + return app.clock.time_position.beat + 1; }; -export const ebeat = (app: any) => (): number => { - return app.clock.beats_since_origin + 1; +export const ebeat = (app: Editor) => (): number => { + return app.clock.beats_since_origin + 1; }; -export const epulse = (app: any) => (): number => { - return app.clock.pulses_since_origin + 1; +export const epulse = (app: Editor) => (): number => { + return app.clock.pulses_since_origin + 1; }; -export const nominator = (app: any) => (): number => { - return app.clock.time_signature[0]; +export const nominator = (app: Editor) => (): number => { + return app.clock.time_signature[0]; }; -export const meter = (app: any) => (): number => { - return app.clock.time_signature[1]; +export const meter = (app: Editor) => (): number => { + return app.clock.time_signature[1]; }; -export const denominator = meter; // Alias for meter +export const denominator = meter; -export const pulsesForBar = (app: any) => (): number => { - return (app.clock.bpm * app.clock.ppqn * nominator(app)()) / 60; -}; \ No newline at end of file +export const pulsesForBar = (app: Editor) => (): number => { + return (app.clock.bpm * app.clock.ppqn * nominator(app)()) / 60; +}; diff --git a/src/API/Warp.ts b/src/API/Warp.ts index 7de5e8d..b7fb35a 100644 --- a/src/API/Warp.ts +++ b/src/API/Warp.ts @@ -1,16 +1,18 @@ -export const warp = (app: any) => (n: number): void => { - /** - * Time-warp the clock by using the tick you wish to jump to. - */ - app.clock.tick = n; - app.clock.time_position = app.clock.convertTicksToTimeposition(n); +import { Editor } from "../main"; + +export const warp = (app: Editor) => (n: number): void => { + /** + * Time-warp the clock by using the tick you wish to jump to. + */ + app.clock.tick = n; + app.clock.time_position = app.clock.convertTicksToTimeposition(n); }; -export const beat_warp = (app: any) => (beat: number): void => { - /** - * Time-warp the clock by using the tick you wish to jump to. - */ - const ticks = beat * app.clock.ppqn; - app.clock.tick = ticks; - app.clock.time_position = app.clock.convertTicksToTimeposition(ticks); -}; \ No newline at end of file +export const beat_warp = (app: Editor) => (beat: number): void => { + /** + * Time-warp the clock by using the tick you wish to jump to. + */ + const ticks = beat * app.clock.ppqn; + app.clock.tick = ticks; + app.clock.time_position = app.clock.convertTicksToTimeposition(ticks); +}; diff --git a/src/API/Ziffers.ts b/src/API/Ziffers.ts index eae95c2..52f28b6 100644 --- a/src/API/Ziffers.ts +++ b/src/API/Ziffers.ts @@ -1,73 +1,72 @@ import { InputOptions, Player } from "../Classes/ZPlayer"; +import { UserAPI } from "./API"; import { generateCacheKey, removePatternFromCache } from "./Cache" +export const z = (api: UserAPI) => (input: string | Generator, options: InputOptions = {}, id: number | string = ""): Player => { + const zid = "z" + id.toString(); + const key = id === "" ? generateCacheKey()(input, options) : zid; -// ziffersFunctions.ts -export const z = (app: any) => (input: string | Generator, options: InputOptions = {}, id: number | string = ""): Player => { - const zid = "z" + id.toString(); - const key = id === "" ? generateCacheKey()(input, options) : zid; + const validSyntax = typeof input === "string" && !api.invalidPatterns[input] - const validSyntax = typeof input === "string" && !app.invalidPatterns[input] + let player; + let replace = false; - let player; - let replace = false; + if (api.patternCache.has(key)) { + player = api.patternCache.get(key) as Player; - if (app.patternCache.has(key)) { - player = app.patternCache.get(key) as Player; - - if (typeof input === "string" && - player.input !== input && - (player.atTheBeginning() || app.forceEvaluator)) { - replace = true; - } + if (typeof input === "string" && + player.input !== input && + (player.atTheBeginning() || api.forceEvaluator)) { + replace = true; } + } - if ((typeof input !== "string" || validSyntax) && (!player || replace)) { - if (typeof input === "string" && player && app.forceEvaluator) { - if (!player.updatePattern(input, options)) { - app.logOnce(`Invalid syntax: ${input}`); - }; - app.forceEvaluator = false; - } else { - const newPlayer = player ? new Player(input, options, app, zid, player.nextEndTime()) : new Player(input, options, app, zid); - if (newPlayer.isValid()) { - player = newPlayer; - app.patternCache.set(key, player); - } else if (typeof input === "string") { - app.invalidPatterns[input] = true; - } - } - } - - if (player) { - if (player.atTheBeginning()) { - if (typeof input === "string" && !validSyntax) app.log(`Invalid syntax: ${input}`); - } - - if (player.ziffers.generator && player.ziffers.generatorDone) { - removePatternFromCache(app)(key); - } - - if (typeof id === "number") player.zid = zid; - - player.updateLastCallTime(); - - if (id !== "" && zid !== "z0") { - // Sync named patterns to z0 by default - player.sync("z0", false); - } - - return player; + if ((typeof input !== "string" || validSyntax) && (!player || replace)) { + if (typeof input === "string" && player && api.forceEvaluator) { + if (!player.updatePattern(input, options)) { + api.logOnce(`Invalid syntax: ${input}`); + }; + api.forceEvaluator = false; } else { - throw new Error(`Invalid syntax: ${input}`); + const newPlayer = player ? new Player(input, options, api.app, zid, player.nextEndTime()) : new Player(input, options, api.app, zid); + if (newPlayer.isValid()) { + player = newPlayer; + api.patternCache.set(key, player); + } else if (typeof input === "string") { + api.invalidPatterns[input] = true; + } } + } + + if (player) { + if (player.atTheBeginning()) { + if (typeof input === "string" && !validSyntax) api.log(`Invalid syntax: ${input}`); + } + + if (player.ziffers.generator && player.ziffers.generatorDone) { + removePatternFromCache(api)(key); + } + + if (typeof id === "number") player.zid = zid; + + player.updateLastCallTime(); + + if (id !== "" && zid !== "z0") { + // Sync named patterns to z0 by default + player.sync("z0", false); + } + + return player; + } else { + throw new Error(`Invalid syntax: ${input}`); + } }; // Generating numbered functions dynamically -export const generateZFunctions = (app: any) => { - const zFunctions: { [key: string]: (input: string, opts: InputOptions) => Player } = {}; - for (let i = 0; i <= 16; i++) { - zFunctions[`z${i}`] = (input: string, opts: InputOptions = {}) => z(app)(input, opts, i); - } - return zFunctions; +export const generateZFunctions = (api: UserAPI) => { + const zFunctions: { [key: string]: (input: string, opts: InputOptions) => Player } = {}; + for (let i = 0; i <= 16; i++) { + zFunctions[`z${i}`] = (input: string, opts: InputOptions = {}) => z(api)(input, opts, i); + } + return zFunctions; }; diff --git a/src/Docs/learning/time/linear_time.ts b/src/Docs/learning/time/linear_time.ts index 51efaf4..ae9beb1 100644 --- a/src/Docs/learning/time/linear_time.ts +++ b/src/Docs/learning/time/linear_time.ts @@ -126,7 +126,7 @@ beat([.25,.125].beat(2))::snd('arpy') .cutoff(usine(.5) * 5000).resonance(20).gain(0.3) .end(0.8).room(0.9).size(0.9).n(3).out(); beat(.5) :: snd('arpy').note( - [30, 33, 35].repeatAll(4).beat(1) - [12,0].beat(0.5)).out() + [30, 33, 35].repeat(4).beat(1) - [12,0].beat(0.5)).out() // Comment me to stop warping! beat(1) :: beat_warp([2,4,5,10,11].pick()) `,