From 05382bab6ee26b28dd51c2d8bda0b2773ae12483 Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Sun, 19 Nov 2023 23:43:18 +0100 Subject: [PATCH 1/6] tiny correction --- src/classes/SoundEvent.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/classes/SoundEvent.ts b/src/classes/SoundEvent.ts index 7da55dd..985692b 100644 --- a/src/classes/SoundEvent.ts +++ b/src/classes/SoundEvent.ts @@ -436,12 +436,12 @@ export class SoundEvent extends AudibleEvent { } }; + out = (orbit?: number | number[]): void => { if (orbit) this.values["orbit"] = orbit; const events = objectWithArraysToArrayOfObjects(this.values, [ "parsedScale", ]); - for (const event of events) { // Filter non superdough parameters // TODO: Should filter relevant fields for superdough @@ -449,7 +449,8 @@ export class SoundEvent extends AudibleEvent { const filteredEvent = event; // No need for note if there is freq if (filteredEvent.freq) { delete filteredEvent.note; } - superdough(filteredEvent, this.nudge - this.app.clock.deviation, filteredEvent.dur); + const correction = Math.max(this.nudge - this.app.clock.deviation, 0); + superdough(filteredEvent, correction, filteredEvent.dur); } }; } From 9b7f980027669a6fcc79312ab39da71877896ef3 Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Mon, 20 Nov 2023 01:42:44 +0100 Subject: [PATCH 2/6] working on clock --- src/Clock.ts | 141 ++++++++++++++++++++++++-------------- src/classes/SoundEvent.ts | 4 +- 2 files changed, 93 insertions(+), 52 deletions(-) diff --git a/src/Clock.ts b/src/Clock.ts index 7638c7b..436779d 100644 --- a/src/Clock.ts +++ b/src/Clock.ts @@ -1,7 +1,7 @@ // @ts-ignore -import { TransportNode } from "./TransportNode"; -import TransportProcessor from "./TransportProcessor?worker&url"; import { Editor } from "./main"; +import { tryEvaluate } from "./Evaluator"; +const zeroPad = (num: number, places: number) => String(num).padStart(places, "0"); export interface TimePosition { /** @@ -23,7 +23,6 @@ export class Clock { * * @param app - The main application instance * @param ctx - The current AudioContext used by app - * @param transportNode - The TransportNode helper * @param bpm - The current beats per minute value * @param time_signature - The time signature * @param time_position - The current time position @@ -37,42 +36,75 @@ export class Clock { ctx: AudioContext; logicalTime: number; - transportNode: TransportNode | null; private _bpm: number; time_signature: number[]; time_position: TimePosition; private _ppqn: number; tick: number; running: boolean; - lastPauseTime: number; - lastPlayPressTime: number; - totalPauseTime: number; + private timerWorker: Worker | null = null; + private timeAtStart: number; + + timeviewer: HTMLElement + constructor(public app: Editor, ctx: AudioContext) { + this.timeviewer = document.getElementById("timeviewer")!; this.time_position = { bar: 0, beat: 0, pulse: 0 }; this.time_signature = [4, 4]; this.logicalTime = 0; this.tick = 0; this._bpm = 120; this._ppqn = 48; - this.transportNode = null; this.ctx = ctx; this.running = true; - this.lastPauseTime = 0; - this.lastPlayPressTime = 0; - this.totalPauseTime = 0; - ctx.audioWorklet - .addModule(TransportProcessor) - .then((e) => { - this.transportNode = new TransportNode(ctx, {}, this.app); - this.transportNode.connect(ctx.destination); - return e; - }) - .catch((e) => { - console.log("Error loading TransportProcessor.js:", e); - }); + this.initializeWorker(); + } + + private initializeWorker(): void { + const workerScript = 'onmessage = (e) => { setInterval(() => { postMessage(true) }, e.data)}'; + const blob = new Blob([workerScript], { type: 'text/javascript' }); + this.timerWorker = new Worker(URL.createObjectURL(blob)); + this.timerWorker.onmessage = () => { + // Handle tick update + this.run(); + }; + } + + private setWorkerInterval(): void { + // Calculate the duration of one beat in milliseconds + const beatDurationMs = 60000 / this._bpm; + + // Calculate the duration of one pulse + const pulseDurationMs = beatDurationMs / this._ppqn; + + // Set this as the interval for the worker + this.timerWorker?.postMessage(pulseDurationMs); } + private run = () => { + if (this.running) { + if (this.app.settings.send_clock) { + this.app.api.MidiConnection.sendMidiClock(); + } + const futureTimeStamp = this.convertTicksToTimeposition( + this.tick + ); + this.time_position = futureTimeStamp; + if (futureTimeStamp.pulse % this.app.clock.ppqn == 0) { + this.timeviewer.innerHTML = `${zeroPad(futureTimeStamp.bar, 2)}:${futureTimeStamp.beat + 1 + } / ${this.bpm}`; + } + if (this.app.exampleIsPlaying) { + tryEvaluate(this.app, this.app.example_buffer); + } else { + tryEvaluate(this.app, this.app.global_buffer); + } + this.app.clock.incrementTick(this.bpm); + } + } + + convertTicksToTimeposition(ticks: number): TimePosition { const beatsPerBar = this.app.clock.time_signature[0]; const ppqnPosition = ticks % this.app.clock.ppqn; @@ -147,16 +179,24 @@ export class Clock { return this._bpm; } - set nudge(nudge: number) { - this.transportNode?.setNudge(nudge); - } - set bpm(bpm: number) { if (bpm > 0 && this._bpm !== bpm) { - this.transportNode?.setBPM(bpm); this._bpm = bpm; - this.logicalTime = this.realTime; + + // Restart the worker with the new BPM if the clock is running + if (this.running) { + this.restartWorker(); + } + } + } + + private restartWorker(): void { + // Terminate the existing worker and start a new one with updated interval + if (this.timerWorker) { + this.timerWorker.terminate(); } + this.initializeWorker(); + this.setWorkerInterval(); } get ppqn(): number { @@ -164,17 +204,17 @@ export class Clock { } get realTime(): number { - return this.app.audioContext.currentTime - this.totalPauseTime; + return this.app.audioContext.currentTime; } + get deviation(): number { - return Math.abs(this.logicalTime - this.realTime); + return this.logicalTime - this.realTime; } set ppqn(ppqn: number) { if (ppqn > 0 && this._ppqn !== ppqn) { this._ppqn = ppqn; - this.transportNode?.setPPQN(ppqn); this.logicalTime = this.realTime; } } @@ -207,32 +247,32 @@ export class Clock { } public start(): void { - /** - * Starts the TransportNode (starts the clock). - * - * @remark also sends a MIDI message if a port is declared - */ - this.app.audioContext.resume(); + if (this.running) { + return; + } + this.running = true; + this.app.audioContext.resume(); this.app.api.MidiConnection.sendStartMessage(); - this.lastPlayPressTime = this.app.audioContext.currentTime; - this.totalPauseTime += this.lastPlayPressTime - this.lastPauseTime; - this.transportNode?.start(); + + if (!this.timerWorker) { + this.initializeWorker(); + } + this.setWorkerInterval(); + this.timeAtStart = this.ctx.currentTime; + this.logicalTime = this.timeAtStart } public pause(): void { - /** - * Pauses the TransportNode (pauses the clock). - * - * @remark also sends a MIDI message if a port is declared - */ this.running = false; - this.transportNode?.pause(); this.app.api.MidiConnection.sendStopMessage(); - this.lastPauseTime = this.app.audioContext.currentTime; - this.logicalTime = this.realTime; + if (this.timerWorker) { + this.timerWorker.terminate(); + this.timerWorker = null; + } } + public stop(): void { /** * Stops the TransportNode (stops the clock). @@ -241,10 +281,11 @@ export class Clock { */ this.running = false; this.tick = 0; - this.lastPauseTime = this.app.audioContext.currentTime; - this.logicalTime = this.realTime; this.time_position = { bar: 0, beat: 0, pulse: 0 }; this.app.api.MidiConnection.sendStopMessage(); - this.transportNode?.stop(); + if (this.timerWorker) { + this.timerWorker.terminate(); + this.timerWorker = null; + } } } diff --git a/src/classes/SoundEvent.ts b/src/classes/SoundEvent.ts index 985692b..abe94e5 100644 --- a/src/classes/SoundEvent.ts +++ b/src/classes/SoundEvent.ts @@ -449,8 +449,8 @@ export class SoundEvent extends AudibleEvent { const filteredEvent = event; // No need for note if there is freq if (filteredEvent.freq) { delete filteredEvent.note; } - const correction = Math.max(this.nudge - this.app.clock.deviation, 0); - superdough(filteredEvent, correction, filteredEvent.dur); + // const correction = Math.max(this.nudge - this.app.clock.deviation, 0); + superdough(filteredEvent, this.nudge, filteredEvent.dur); } }; } From ed8bc2171384ad3564efb0c89affb5a8e5104deb Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Mon, 20 Nov 2023 02:29:47 +0100 Subject: [PATCH 3/6] work in progress --- src/Clock.ts | 52 +++++++++++++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/src/Clock.ts b/src/Clock.ts index 436779d..026746f 100644 --- a/src/Clock.ts +++ b/src/Clock.ts @@ -44,6 +44,7 @@ export class Clock { running: boolean; private timerWorker: Worker | null = null; private timeAtStart: number; + nudge: number timeviewer: HTMLElement @@ -56,6 +57,7 @@ export class Clock { this.tick = 0; this._bpm = 120; this._ppqn = 48; + this.nudge = 0; this.ctx = ctx; this.running = true; this.initializeWorker(); @@ -66,7 +68,6 @@ export class Clock { const blob = new Blob([workerScript], { type: 'text/javascript' }); this.timerWorker = new Worker(URL.createObjectURL(blob)); this.timerWorker.onmessage = () => { - // Handle tick update this.run(); }; } @@ -84,27 +85,36 @@ export class Clock { private run = () => { if (this.running) { - if (this.app.settings.send_clock) { - this.app.api.MidiConnection.sendMidiClock(); + const adjustedCurrentTime = this.ctx.currentTime + (this.nudge / 1000); + const beatNumber = adjustedCurrentTime / (60 / this._bpm); + const currentPulsePosition = Math.ceil(beatNumber * this._ppqn); + + if (currentPulsePosition > this.time_position.pulse) { + const futureTimeStamp = this.convertTicksToTimeposition( + this.tick + ); + this.app.clock.incrementTick(this.bpm); + + this.time_position.pulse = currentPulsePosition; + + if (this.app.settings.send_clock) { + if (futureTimeStamp.pulse % 2 == 0) // TODO: Why? + this.app.api.MidiConnection.sendMidiClock(); + } + this.time_position = futureTimeStamp; + if (futureTimeStamp.pulse % this.app.clock.ppqn == 0) { + this.timeviewer.innerHTML = `${zeroPad(futureTimeStamp.bar, 2)}:${futureTimeStamp.beat + 1 + } / ${this.bpm}`; + } + if (this.app.exampleIsPlaying) { + tryEvaluate(this.app, this.app.example_buffer); + } else { + tryEvaluate(this.app, this.app.global_buffer); + } } - const futureTimeStamp = this.convertTicksToTimeposition( - this.tick - ); - this.time_position = futureTimeStamp; - if (futureTimeStamp.pulse % this.app.clock.ppqn == 0) { - this.timeviewer.innerHTML = `${zeroPad(futureTimeStamp.bar, 2)}:${futureTimeStamp.beat + 1 - } / ${this.bpm}`; - } - if (this.app.exampleIsPlaying) { - tryEvaluate(this.app, this.app.example_buffer); - } else { - tryEvaluate(this.app, this.app.global_buffer); - } - this.app.clock.incrementTick(this.bpm); } } - convertTicksToTimeposition(ticks: number): TimePosition { const beatsPerBar = this.app.clock.time_signature[0]; const ppqnPosition = ticks % this.app.clock.ppqn; @@ -165,7 +175,7 @@ export class Clock { /** * Returns the duration of a pulse in seconds. */ - return 60 / this.bpm / this.ppqn; + return 60 / this._bpm / this.ppqn; } public pulse_duration_at_bpm(bpm: number = this.bpm): number { @@ -191,7 +201,6 @@ export class Clock { } private restartWorker(): void { - // Terminate the existing worker and start a new one with updated interval if (this.timerWorker) { this.timerWorker.terminate(); } @@ -207,7 +216,6 @@ export class Clock { return this.app.audioContext.currentTime; } - get deviation(): number { return this.logicalTime - this.realTime; } @@ -215,7 +223,6 @@ export class Clock { set ppqn(ppqn: number) { if (ppqn > 0 && this._ppqn !== ppqn) { this._ppqn = ppqn; - this.logicalTime = this.realTime; } } @@ -272,7 +279,6 @@ export class Clock { } } - public stop(): void { /** * Stops the TransportNode (stops the clock). From 424adeebc037efd3626532146c21f677b27993ad Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Mon, 20 Nov 2023 11:03:46 +0100 Subject: [PATCH 4/6] Cleaning Clock file --- src/Clock.ts | 143 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 121 insertions(+), 22 deletions(-) diff --git a/src/Clock.ts b/src/Clock.ts index 026746f..a6127ec 100644 --- a/src/Clock.ts +++ b/src/Clock.ts @@ -1,7 +1,8 @@ // @ts-ignore import { Editor } from "./main"; import { tryEvaluate } from "./Evaluator"; -const zeroPad = (num: number, places: number) => String(num).padStart(places, "0"); +const zeroPad = (num: number, places: number) => + String(num).padStart(places, "0"); export interface TimePosition { /** @@ -44,10 +45,9 @@ export class Clock { running: boolean; private timerWorker: Worker | null = null; private timeAtStart: number; - nudge: number - - timeviewer: HTMLElement + nudge: number; + timeviewer: HTMLElement; constructor(public app: Editor, ctx: AudioContext) { this.timeviewer = document.getElementById("timeviewer")!; @@ -60,12 +60,23 @@ export class Clock { this.nudge = 0; this.ctx = ctx; this.running = true; + this.timeAtStart = ctx.currentTime; this.initializeWorker(); } private initializeWorker(): void { - const workerScript = 'onmessage = (e) => { setInterval(() => { postMessage(true) }, e.data)}'; - const blob = new Blob([workerScript], { type: 'text/javascript' }); + /** + * Initializes the worker responsible for sending clock pulses. The worker + * is responsible for sending clock pulses at a regular interval. The + * interval is set by the `setWorkerInterval` function. The worker is + * restarted when the BPM is changed. The worker is terminated when the + * clock is stopped. + * + * @returns void + */ + const workerScript = + "onmessage = (e) => { setInterval(() => { postMessage(true) }, e.data)}"; + const blob = new Blob([workerScript], { type: "text/javascript" }); this.timerWorker = new Worker(URL.createObjectURL(blob)); this.timerWorker.onmessage = () => { this.run(); @@ -73,38 +84,52 @@ export class Clock { } private setWorkerInterval(): void { - // Calculate the duration of one beat in milliseconds + /** + * Sets the interval for the worker responsible for sending clock pulses. + * The interval is set by calculating the duration of one pulse. The + * duration of one pulse is calculated by dividing the duration of one beat + * by the number of pulses per quarter note. + * + * @remark The BPM is off constantly by 3~5 BPM. + * @returns void + */ const beatDurationMs = 60000 / this._bpm; - - // Calculate the duration of one pulse const pulseDurationMs = beatDurationMs / this._ppqn; - - // Set this as the interval for the worker this.timerWorker?.postMessage(pulseDurationMs); } private run = () => { + /** + * This function is called by the worker responsible for sending clock + * pulses. It is called at a regular interval. The interval is set by the + * `setWorkerInterval` function. This function is responsible for updating + * the time position and sending MIDI clock messages. It is also responsible + * for evaluating the global buffer. The global buffer is evaluated at the + * beginning of each pulse. + * + * @returns void + */ if (this.running) { - const adjustedCurrentTime = this.ctx.currentTime + (this.nudge / 1000); + const adjustedCurrentTime = this.ctx.currentTime + this.nudge / 1000; const beatNumber = adjustedCurrentTime / (60 / this._bpm); const currentPulsePosition = Math.ceil(beatNumber * this._ppqn); if (currentPulsePosition > this.time_position.pulse) { - const futureTimeStamp = this.convertTicksToTimeposition( - this.tick - ); + const futureTimeStamp = this.convertTicksToTimeposition(this.tick); this.app.clock.incrementTick(this.bpm); this.time_position.pulse = currentPulsePosition; if (this.app.settings.send_clock) { - if (futureTimeStamp.pulse % 2 == 0) // TODO: Why? + if (futureTimeStamp.pulse % 2 == 0) + // TODO: Why? this.app.api.MidiConnection.sendMidiClock(); } this.time_position = futureTimeStamp; if (futureTimeStamp.pulse % this.app.clock.ppqn == 0) { - this.timeviewer.innerHTML = `${zeroPad(futureTimeStamp.bar, 2)}:${futureTimeStamp.beat + 1 - } / ${this.bpm}`; + this.timeviewer.innerHTML = `${zeroPad(futureTimeStamp.bar, 2)}:${ + futureTimeStamp.beat + 1 + } / ${this.bpm}`; } if (this.app.exampleIsPlaying) { tryEvaluate(this.app, this.app.example_buffer); @@ -113,9 +138,14 @@ export class Clock { } } } - } + }; convertTicksToTimeposition(ticks: number): TimePosition { + /** + * This function converts a number of ticks to a time position. + * @param ticks - number of ticks + * @returns time position + */ const beatsPerBar = this.app.clock.time_signature[0]; const ppqnPosition = ticks % this.app.clock.ppqn; const beatNumber = Math.floor(ticks / this.app.clock.ppqn); @@ -149,6 +179,8 @@ export class Clock { get beats_per_bar(): number { /** * Returns the number of beats per bar. + * + * @returns number of beats per bar */ return this.time_signature[0]; } @@ -174,6 +206,8 @@ export class Clock { get pulse_duration(): number { /** * Returns the duration of a pulse in seconds. + * + * @returns duration of a pulse in seconds */ return 60 / this._bpm / this.ppqn; } @@ -181,15 +215,29 @@ export class Clock { public pulse_duration_at_bpm(bpm: number = this.bpm): number { /** * Returns the duration of a pulse in seconds at a specific bpm. + * + * @param bpm - beats per minute + * @returns duration of a pulse in seconds */ return 60 / bpm / this.ppqn; } get bpm(): number { + /** + * Returns the current BPM. + * + * @returns current BPM + */ return this._bpm; } set bpm(bpm: number) { + /** + * Sets the BPM. + * + * @param bpm - beats per minute + * @returns void + */ if (bpm > 0 && this._bpm !== bpm) { this._bpm = bpm; @@ -201,6 +249,11 @@ export class Clock { } private restartWorker(): void { + /** + * Restarts the worker responsible for sending clock pulses. + * + * @returns void + */ if (this.timerWorker) { this.timerWorker.terminate(); } @@ -209,24 +262,52 @@ export class Clock { } get ppqn(): number { + /** + * Returns the current PPQN. + * + * @returns current PPQN + */ return this._ppqn; } get realTime(): number { + /** + * Returns the current time of the audio context. + * + * @returns current time of the audio context + * @remark This is the time of the audio context, not the time of the clock. + */ return this.app.audioContext.currentTime; } get deviation(): number { + /** + * Returns the deviation between the logical time and the real time. + * + * @returns deviation between the logical time and the real time + */ return this.logicalTime - this.realTime; } set ppqn(ppqn: number) { + /** + * Sets the PPQN. + * + * @param ppqn - pulses per quarter note + * @returns void + */ if (ppqn > 0 && this._ppqn !== ppqn) { this._ppqn = ppqn; } } public incrementTick(bpm: number) { + /** + * Increments the tick by one. + * + * @param bpm - beats per minute + * @returns void + */ this.tick++; this.logicalTime += this.pulse_duration_at_bpm(bpm); } @@ -248,12 +329,21 @@ export class Clock { public convertPulseToSecond(n: number): number { /** - * Converts a pulse to a second. + * Converts a number of pulses to a number of seconds. + * + * @param n - number of pulses + * @returns number of seconds */ return n * this.pulse_duration; } public start(): void { + /** + * This function starts the worker. + * + * @remark also sends a MIDI message if a port is declared + * @returns void + */ if (this.running) { return; } @@ -267,10 +357,16 @@ export class Clock { } this.setWorkerInterval(); this.timeAtStart = this.ctx.currentTime; - this.logicalTime = this.timeAtStart + this.logicalTime = this.timeAtStart; } public pause(): void { + /** + * Pauses the Transport worker. + * + * @remark also sends a MIDI message if a port is declared + * @returns void + */ this.running = false; this.app.api.MidiConnection.sendStopMessage(); if (this.timerWorker) { @@ -281,9 +377,12 @@ export class Clock { public stop(): void { /** - * Stops the TransportNode (stops the clock). + * Stops the Transport worker and resets the tick to 0. The time position + * is also reset to 0. The clock is stopped by terminating the worker + * responsible for sending clock pulses. * * @remark also sends a MIDI message if a port is declared + * @returns void */ this.running = false; this.tick = 0; From 8b744e3d906ce94025def9e15e540ad077750e44 Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Mon, 20 Nov 2023 11:04:15 +0100 Subject: [PATCH 5/6] Delete TransportNode and TransportProcessor --- src/TransportNode.js | 67 --------------------------------------- src/TransportProcessor.js | 47 --------------------------- 2 files changed, 114 deletions(-) delete mode 100644 src/TransportNode.js delete mode 100644 src/TransportProcessor.js diff --git a/src/TransportNode.js b/src/TransportNode.js deleted file mode 100644 index 987df5c..0000000 --- a/src/TransportNode.js +++ /dev/null @@ -1,67 +0,0 @@ -import { tryEvaluate } from "./Evaluator"; -const zeroPad = (num, places) => String(num).padStart(places, "0"); - -export class TransportNode extends AudioWorkletNode { - constructor(context, options, application) { - super(context, "transport", options); - this.app = application; - this.port.addEventListener("message", this.handleMessage); - this.port.start(); - this.timeviewer = document.getElementById("timeviewer"); - } - - /** @type {(this: MessagePort, ev: MessageEvent) => any} */ - handleMessage = (message) => { - if (message.data) { - if (message.data.type === "bang") { - if (this.app.clock.running) { - if (this.app.settings.send_clock) { - this.app.api.MidiConnection.sendMidiClock(); - } - const futureTimeStamp = this.app.clock.convertTicksToTimeposition( - this.app.clock.tick - ); - this.app.clock.time_position = futureTimeStamp; - if (futureTimeStamp.pulse % this.app.clock.ppqn == 0) { - this.timeviewer.innerHTML = `${zeroPad(futureTimeStamp.bar, 2)}:${futureTimeStamp.beat + 1 - } / ${this.app.clock.bpm}`; - } - if (this.app.exampleIsPlaying) { - tryEvaluate(this.app, this.app.example_buffer); - } else { - tryEvaluate(this.app, this.app.global_buffer); - } - this.app.clock.incrementTick(message.data.bpm); - } - } - } - }; - - start() { - this.port.postMessage({ type: "start" }); - } - - pause() { - this.port.postMessage({ type: "pause" }); - } - - resume() { - this.port.postMessage({ type: "resume" }); - } - - setBPM(bpm) { - this.port.postMessage({ type: "bpm", value: bpm }); - } - - setPPQN(ppqn) { - this.port.postMessage({ type: "ppqn", value: ppqn }); - } - - setNudge(nudge) { - this.port.postMessage({ type: "nudge", value: nudge }); - } - - stop() { - this.port.postMessage({ type: "stop" }); - } -} diff --git a/src/TransportProcessor.js b/src/TransportProcessor.js deleted file mode 100644 index 20e96ce..0000000 --- a/src/TransportProcessor.js +++ /dev/null @@ -1,47 +0,0 @@ -class TransportProcessor extends AudioWorkletProcessor { - constructor(options) { - super(options); - this.port.addEventListener("message", this.handleMessage); - this.port.start(); - this.nudge = 0; - this.started = false; - this.bpm = 120; - this.ppqn = 48; - this.currentPulsePosition = 0; - } - - handleMessage = (message) => { - if (message.data && message.data.type === "ping") { - this.port.postMessage(message.data); - } else if (message.data.type === "start") { - this.started = true; - } else if (message.data.type === "pause") { - this.started = false; - } else if (message.data.type === "stop") { - this.started = false; - } else if (message.data.type === "bpm") { - this.bpm = message.data.value; - this.currentPulsePosition = currentTime; - } else if (message.data.type === "ppqn") { - this.ppqn = message.data.value; - this.currentPulsePosition = currentTime; - } else if (message.data.type === "nudge") { - this.nudge = message.data.value; - } - }; - - process(inputs, outputs, parameters) { - if (this.started) { - const adjustedCurrentTime = currentTime + this.nudge / 100; - const beatNumber = adjustedCurrentTime / (60 / this.bpm); - const currentPulsePosition = Math.ceil(beatNumber * this.ppqn); - if (currentPulsePosition > this.currentPulsePosition) { - this.currentPulsePosition = currentPulsePosition; - this.port.postMessage({ type: "bang", bpm: this.bpm }); - } - } - return true; - } -} - -registerProcessor("transport", TransportProcessor); From f3ddb39ab66f96d5aa851835a383931bd031111f Mon Sep 17 00:00:00 2001 From: Raphael Forment Date: Mon, 20 Nov 2023 11:12:16 +0100 Subject: [PATCH 6/6] Reintroduce nudge --- src/Clock.ts | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/src/Clock.ts b/src/Clock.ts index a6127ec..ded882a 100644 --- a/src/Clock.ts +++ b/src/Clock.ts @@ -33,6 +33,7 @@ export class Clock { * @param lastPauseTime - The last time the clock was paused * @param lastPlayPressTime - The last time the clock was started * @param totalPauseTime - The total time the clock has been paused / stopped + * @param _nudge - The current nudge value */ ctx: AudioContext; @@ -45,7 +46,7 @@ export class Clock { running: boolean; private timerWorker: Worker | null = null; private timeAtStart: number; - nudge: number; + _nudge: number; timeviewer: HTMLElement; @@ -57,7 +58,7 @@ export class Clock { this.tick = 0; this._bpm = 120; this._ppqn = 48; - this.nudge = 0; + this._nudge = 0; this.ctx = ctx; this.running = true; this.timeAtStart = ctx.currentTime; @@ -110,7 +111,7 @@ export class Clock { * @returns void */ if (this.running) { - const adjustedCurrentTime = this.ctx.currentTime + this.nudge / 1000; + const adjustedCurrentTime = this.ctx.currentTime + this._nudge / 1000; const beatNumber = adjustedCurrentTime / (60 / this._bpm); const currentPulsePosition = Math.ceil(beatNumber * this._ppqn); @@ -231,6 +232,25 @@ export class Clock { return this._bpm; } + set nudge(nudge: number) { + /** + * Sets the nudge. + * + * @param nudge - nudge in seconds + * @returns void + */ + this._nudge = nudge; + } + + get nudge(): number { + /** + * Returns the current nudge. + * + * @returns current nudge + */ + return this._nudge; + } + set bpm(bpm: number) { /** * Sets the BPM.