diff --git a/src/API.ts b/src/API.ts index 3269f6d..a4962d8 100644 --- a/src/API.ts +++ b/src/API.ts @@ -27,7 +27,8 @@ import { } from "superdough"; import { Speaker } from "./extensions/StringExtensions"; import { getScaleNotes } from "zifferjs"; -import { OscilloscopeConfig, blinkScript } from "./AudioVisualisation"; +import { OscilloscopeConfig } from "./Visuals/Oscilloscope"; +import { blinkScript } from "./Visuals/Blinkers"; import { SkipEvent } from "./classes/SkipEvent"; import { AbstractEvent, EventOperation } from "./classes/AbstractEvents"; import drums from "./tidal-drum-machines.json"; diff --git a/src/Visuals/Blinkers.ts b/src/Visuals/Blinkers.ts new file mode 100644 index 0000000..d14d765 --- /dev/null +++ b/src/Visuals/Blinkers.ts @@ -0,0 +1,118 @@ +import { type Editor } from "../main"; + +export const drawCircle = ( + /** + * Draw a circle at a specific position on the canvas. + * @param {number} x - The x-coordinate of the circle's center. + * @param {number} y - The y-coordinate of the circle's center. + * @param {number} radius - The radius of the circle. + * @param {string} color - The fill color of the circle. + */ + app: Editor, + x: number, + y: number, + radius: number, + color: string, +): void => { + // @ts-ignore + const canvas: HTMLCanvasElement = app.interface.feedback; + const ctx = canvas.getContext("2d"); + if (!ctx) return; + + ctx.beginPath(); + ctx.arc(x, y, radius, 0, Math.PI * 2); + ctx.fillStyle = color; + ctx.fill(); + ctx.closePath(); +}; + +export const blinkScript = ( + /** + * Blinks a script indicator circle. + * @param script - The type of script. + * @param no - The shift amount multiplier. + */ + app: Editor, + script: "local" | "global" | "init", + no?: number, +) => { + if (no !== undefined && no < 1 && no > 9) return; + const blinkDuration = + (app.clock.bpm / 60 / app.clock.time_signature[1]) * 200; + // @ts-ignore + const ctx = app.interface.feedback.getContext("2d"); // Assuming a canvas context + + /** + * Draws a circle at a given shift. + * @param shift - The pixel distance from the origin. + */ + const _drawBlinker = (shift: number) => { + const horizontalOffset = 50; + drawCircle( + app, + horizontalOffset + shift, + app.interface.feedback.clientHeight - 15, + 8, + "#fdba74", + ); + }; + + const _clearBlinker = (shift: number) => { + /** + * Clears the circle at a given shift. + * @param shift - The pixel distance from the origin. + */ + const x = 50 + shift; + const y = app.interface.feedback.clientHeight - 15; + const radius = 8; + ctx.clearRect(x - radius, y - radius, radius * 2, radius * 2); + }; + + if (script === "local" && no !== undefined) { + const shiftAmount = no * 25; + + // Clear existing timeout if any + if (app.blinkTimeouts[shiftAmount]) { + clearTimeout(app.blinkTimeouts[shiftAmount]); + } + + _drawBlinker(shiftAmount); + + // Save timeout ID for later clearing + // @ts-ignore + app.blinkTimeouts[shiftAmount] = setTimeout(() => { + _clearBlinker(shiftAmount); + // Clear the canvas before drawing new blinkers + (app.interface.feedback as HTMLCanvasElement) + .getContext("2d")! + .clearRect( + 0, + 0, + (app.interface.feedback as HTMLCanvasElement).width, + (app.interface.feedback as HTMLCanvasElement).height, + ); + }, blinkDuration); + } +}; + +export const scriptBlinkers = () => { + /** + * Manages animation updates using requestAnimationFrame. + * @param app - The Editor application context. + */ + + let lastFrameTime = Date.now(); + const frameRate = 10; + const minFrameDelay = 1000 / frameRate; + + const update = () => { + const now = Date.now(); + const timeSinceLastFrame = now - lastFrameTime; + + if (timeSinceLastFrame >= minFrameDelay) { + lastFrameTime = now; + } + requestAnimationFrame(update); + }; + requestAnimationFrame(update); +}; diff --git a/src/AudioVisualisation.ts b/src/Visuals/Oscilloscope.ts similarity index 68% rename from src/AudioVisualisation.ts rename to src/Visuals/Oscilloscope.ts index 07a9c8e..18309c9 100644 --- a/src/AudioVisualisation.ts +++ b/src/Visuals/Oscilloscope.ts @@ -1,123 +1,6 @@ // @ts-ignore import { getAnalyser } from "superdough"; -import { type Editor } from "./main"; - -export const drawCircle = ( - /** - * Draw a circle at a specific position on the canvas. - * @param {number} x - The x-coordinate of the circle's center. - * @param {number} y - The y-coordinate of the circle's center. - * @param {number} radius - The radius of the circle. - * @param {string} color - The fill color of the circle. - */ - app: Editor, - x: number, - y: number, - radius: number, - color: string, -): void => { - // @ts-ignore - const canvas: HTMLCanvasElement = app.interface.feedback; - const ctx = canvas.getContext("2d"); - if (!ctx) return; - - ctx.beginPath(); - ctx.arc(x, y, radius, 0, Math.PI * 2); - ctx.fillStyle = color; - ctx.fill(); - ctx.closePath(); -}; - -export const blinkScript = ( - /** - * Blinks a script indicator circle. - * @param script - The type of script. - * @param no - The shift amount multiplier. - */ - app: Editor, - script: "local" | "global" | "init", - no?: number, -) => { - if (no !== undefined && no < 1 && no > 9) return; - const blinkDuration = - (app.clock.bpm / 60 / app.clock.time_signature[1]) * 200; - // @ts-ignore - const ctx = app.interface.feedback.getContext("2d"); // Assuming a canvas context - - /** - * Draws a circle at a given shift. - * @param shift - The pixel distance from the origin. - */ - const _drawBlinker = (shift: number) => { - const horizontalOffset = 50; - drawCircle( - app, - horizontalOffset + shift, - app.interface.feedback.clientHeight - 15, - 8, - "#fdba74", - ); - }; - - const _clearBlinker = (shift: number) => { - /** - * Clears the circle at a given shift. - * @param shift - The pixel distance from the origin. - */ - const x = 50 + shift; - const y = app.interface.feedback.clientHeight - 15; - const radius = 8; - ctx.clearRect(x - radius, y - radius, radius * 2, radius * 2); - }; - - if (script === "local" && no !== undefined) { - const shiftAmount = no * 25; - - // Clear existing timeout if any - if (app.blinkTimeouts[shiftAmount]) { - clearTimeout(app.blinkTimeouts[shiftAmount]); - } - - _drawBlinker(shiftAmount); - - // Save timeout ID for later clearing - // @ts-ignore - app.blinkTimeouts[shiftAmount] = setTimeout(() => { - _clearBlinker(shiftAmount); - // Clear the canvas before drawing new blinkers - (app.interface.feedback as HTMLCanvasElement) - .getContext("2d")! - .clearRect( - 0, - 0, - (app.interface.feedback as HTMLCanvasElement).width, - (app.interface.feedback as HTMLCanvasElement).height, - ); - }, blinkDuration); - } -}; - -export const scriptBlinkers = () => { - /** - * Manages animation updates using requestAnimationFrame. - * @param app - The Editor application context. - */ - - let lastFrameTime = Date.now(); - const frameRate = 10; - const minFrameDelay = 1000 / frameRate; - - const update = () => { - const now = Date.now(); - const timeSinceLastFrame = now - lastFrameTime; - - if (timeSinceLastFrame >= minFrameDelay) { - lastFrameTime = now; - } - requestAnimationFrame(update); - }; - requestAnimationFrame(update); -}; +import { Editor } from "../main"; export interface OscilloscopeConfig { enabled: boolean; diff --git a/src/main.ts b/src/main.ts index a8d8677..4b5569a 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,9 +1,6 @@ -import { - OscilloscopeConfig, - runOscilloscope, - scriptBlinkers, -} from "./AudioVisualisation"; +import { OscilloscopeConfig, runOscilloscope } from "./Visuals/Oscilloscope"; import { EditorState, Compartment } from "@codemirror/state"; +import { scriptBlinkers } from "./Visuals/Blinkers"; import { javascript } from "@codemirror/lang-javascript"; import { markdown } from "@codemirror/lang-markdown"; import { Extension } from "@codemirror/state";