import { ipcMain } from 'electron'; import { blackout } from '../patterns/blackout'; import { Pattern, PatternOutput, Time } from '../patterns/proto'; import { TestPattern } from '../patterns/test'; import rust, { BeatTrackerHandle, MovingHeadState, OutputHandle, TrackerConfig } from 'rust_native_module'; import { ChaserPattern } from '../patterns/chaser'; export type AppState = { patterns: { [key: string]: PatternOutput }, selectedPattern: string | null, beatProgress: number | null, graphData: { bassFiltered: Array, autoCorrelated: Array, } | null, trackerConfig: TrackerConfig, }; class Backend { beatTracker: BeatTrackerHandle; dmxOutput: OutputHandle; patterns: Map; // patternOutputs: Map; // selectedPattern: string; state: AppState; constructor() { // beat tracking let beatTracker = rust.getBeatTracker(); if (beatTracker.type !== 'success') { throw new Error("could not initialize beat tracking"); } this.beatTracker = beatTracker.value; ipcMain.on('beat-tracking', async (_, arg) => { if (arg === 'tap') { this.beatTracker.tap(); } }); // output let dmxOutput = rust.openOutput("/dev/ttyUSB0"); if (dmxOutput.type !== 'success') { throw new Error("could not open DMX output"); } this.dmxOutput = dmxOutput.value; // patterns this.patterns = new Map(); this.patterns.set("test", new TestPattern()); this.patterns.set("chaser", new ChaserPattern()); this.state = { patterns: {}, selectedPattern: null, beatProgress: null, graphData: null, trackerConfig: { mode: "auto", acThreshold: 1000, zeroCrossingBeatDelay: 0, } } ipcMain.on('pattern-select', async (_, arg) => { this.state.selectedPattern = arg; }); ipcMain.on('update-delay', async (_, delay) => { this.state.trackerConfig.zeroCrossingBeatDelay = Math.floor(delay); this.beatTracker.setConfig(this.state.trackerConfig); }); ipcMain.on('manual-mode', async (_, is_manual) => { this.state.trackerConfig.mode = is_manual ? "manual" : "auto"; this.beatTracker.setConfig(this.state.trackerConfig); }); let time: Time = { absolute: 0, beatRelative: this.state.beatProgress, } for (let [patternId, pattern] of this.patterns.entries()) { let patternOutput = pattern.render(time); this.state.patterns[patternId] = patternOutput; } ipcMain.handle('poll', async (_) => { return this.getState(); }); } getState(): AppState { return this.state; } update() { let beatProgress = this.beatTracker.getProgress(); if (beatProgress.type == 'some') { this.state.beatProgress = beatProgress.value; } else { this.state.beatProgress = null; } this.state.graphData = this.beatTracker.getGraphPoints(); let date = new Date(); let time: Time = { absolute: date.getTime() / 1000, beatRelative: this.state.beatProgress, } // render all patterns and write selected pattern to DMX let output: Array = blackout; for (let [patternId, pattern] of this.patterns.entries()) { let patternOutput = pattern.render(time); this.state.patterns[patternId] = patternOutput; if (patternId === this.state.selectedPattern && patternOutput) { output = patternOutput; } } this.dmxOutput.set(output); } close() { this.dmxOutput.close(); } } export default Backend;