diff --git a/webserial/src/editor/defaultCode.ts b/webserial/src/editor/defaultCode.ts index ed40918..03cbd9f 100644 --- a/webserial/src/editor/defaultCode.ts +++ b/webserial/src/editor/defaultCode.ts @@ -4,12 +4,19 @@ // Fixtures library. TODO move this into a separate file class Fixture { - address: number - ctx: Context + startAddress: number - constructor(address: number, ctx: Context) { - this.address = address; - this.ctx = ctx; + constructor(startAddress: number) { + this.startAddress = startAddress; + } + + /** + * Write to a DMX channel + * @param address Address offset (1 = start address) + * @param value between 0 and 255 + */ + setChannel(address: number, value: number) { + ctx.set(this.startAddress + address - 1, value); } } @@ -27,42 +34,43 @@ interface GenericRGBW { class Par extends Fixture implements GenericRGBW { setBrightness(value: number, strobe?: boolean) { if (strobe || false) { - this.ctx.set(this.address, 255); - this.ctx.set(this.address + 7, value * 255); + this.setChannel(1, 255); + this.setChannel(8, value * 255); } else { - this.ctx.set(this.address, value * 255); - this.ctx.set(this.address + 7, 0); + this.setChannel(1, value * 255); + this.setChannel(8, 0); } } setRGBW(rgb: [number, number, number], w?: number) { let [r, g, b] = rgb; - this.ctx.set(this.address + 1, r); - this.ctx.set(this.address + 2, g); - this.ctx.set(this.address + 3, b); - this.ctx.set(this.address + 4, w || 0); + this.setChannel(2, r); + this.setChannel(3, g); + this.setChannel(4, b); + this.setChannel(5, w || 0); } setAUV(a: number, uv: number) { - this.ctx.set(this.address + 5, a); - this.ctx.set(this.address + 6, uv); + this.setChannel(6, a); + this.setChannel(7, uv); } } class MovingHead extends Fixture implements GenericRGBW { setBrightness(value: number, strobe?: boolean) { - let out = (strobe || false) + let val = (strobe || false) ? 135 + (239 - 135) * value : 8 + (134 - 8) * value; - this.ctx.set(this.address + 5, out); + + this.setChannel(6, val); } setRGBW(rgb: [number, number, number], w?: number) { let [r, g, b] = rgb; - this.ctx.set(this.address + 6, r); - this.ctx.set(this.address + 7, g); - this.ctx.set(this.address + 8, b); - this.ctx.set(this.address + 9, w || 0); + this.setChannel(7, r); + this.setChannel(8, g); + this.setChannel(9, b); + this.setChannel(10, w || 0); } /** @@ -82,20 +90,59 @@ class MovingHead extends Fixture implements GenericRGBW { let panFine = 0 let tiltFine = 0 - this.ctx.set(this.address + 0, panRough); - this.ctx.set(this.address + 1, panFine); - this.ctx.set(this.address + 2, tiltRough); - this.ctx.set(this.address + 3, tiltFine); - this.ctx.set(this.address + 4, speed || 0); + this.setChannel(1, panRough); + this.setChannel(2, panFine); + this.setChannel(3, tiltRough); + this.setChannel(4, tiltFine); + this.setChannel(5, speed || 0); } } +class Flower extends Fixture implements GenericRGBW { + + setBrightness(value: number, strobe?: boolean): void { + // dimmer seems unsupported :( + this.setChannel(7, (strobe || false) ? 255 * value : 0); + } + + setRGBW(rgb: [number, number, number], w?: number): void { + const [r, g, b] = rgb; + this.setChannel(1, r); + this.setChannel(2, g); + this.setChannel(3, b); + this.setChannel(4, w || 0); + } + + setAP(a: number, p: number) { + this.setChannel(5, a); + this.setChannel(6, p); + } + + /** + * Set the rotation speed + * @param speed Between -1 (clockwise) and 1 (counterclockwise) + */ + setRotation(direction: number) { + const val = (direction < 0) + ? /* clockwise */ lib.remap(direction, [0, -1], [0, 128], true) + : /* counterclockwise */ lib.remap(direction, [0, 1], [129, 255], true); + + this.setChannel(8, val); + } + + setMacro(pattern: number, speed: number) { + this.setChannel(9, pattern); + this.setChannel(10, speed); + } + +} + // ****************** // * CODE GOES HERE * // ****************** let color = lib.hsl2rgb(360 * t, 100, 50); -let par = new Par(1, ctx); +let par = new Par(1); par.setBrightness(1); par.setRGBW(color); \ No newline at end of file diff --git a/webserial/src/editor/defaultEnv.d.ts b/webserial/src/editor/defaultEnv.d.ts index 9d7cbfd..252c7d4 100644 --- a/webserial/src/editor/defaultEnv.d.ts +++ b/webserial/src/editor/defaultEnv.d.ts @@ -23,7 +23,18 @@ type Lib = { * @param s between 0 and 100 * @param l between 0 and 100 */ - hsl2rgb(h: number, s: number, l: number): [number, number, number] + hsl2rgb(h: number, s: number, l: number): [number, number, number], + + clamp(value: number, boundaries: [number, number]), + + /** + * Map a value from one range to the other + * @param value to be remapped. Does not need to be in the source range. + * @param from [lower, upper] boundaries of source range. + * @param to [lower, upper] boundaries of target range. + * @param clamp clamp the output to the target range boundaries + */ + remap(value: number, from: [number, number], to: [number, number], clamp?: boolean), } /** The standard library */ diff --git a/webserial/src/eval/lib.ts b/webserial/src/eval/lib.ts index 6f1f18b..19c72f6 100644 --- a/webserial/src/eval/lib.ts +++ b/webserial/src/eval/lib.ts @@ -1,16 +1,42 @@ /// -export const lib: Lib = { - hsl2rgb(h, s, l): [number, number, number] { - // https://stackoverflow.com/a/44134328 - l /= 100; - const a = s * Math.min(l, 1 - l) / 100; - const f = n => { - const k = (n + h / 30) % 12; - const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1); - return Math.round(255 * color) - }; - return [f(0), f(8), f(4)]; +function hsl2rgb(h, s, l): [number, number, number] { + // https://stackoverflow.com/a/44134328 + l /= 100; + const a = s * Math.min(l, 1 - l) / 100; + const f = n => { + const k = (n + h / 30) % 12; + const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1); + return Math.round(255 * color) + }; + return [f(0), f(8), f(4)]; - }, +} + +function clamp(value: number, boundaries: [number, number]) { + let [l, r] = boundaries; + return Math.max(l, Math.min(value, r)); +} + +const _clamp = clamp; + +function remap(value: number, from: [number, number], to: [number, number], clamp?: boolean) { + const [a, b] = from; + const normalized = (value - a) / (b - a); + + const [c, d] = to; + let remapped = c + (d - c) * normalized; + + if (clamp) { + remapped = _clamp(remapped, to) + }; + + return remapped; +} + + +export const lib: Lib = { + hsl2rgb: hsl2rgb, + clamp: clamp, + remap: remap, } \ No newline at end of file