From f8a0a8e6f51b108e258ef2edbf723ce5fd25734d Mon Sep 17 00:00:00 2001 From: Miika Alonen Date: Wed, 30 Aug 2023 00:21:50 +0300 Subject: [PATCH] Removed latency calculation --- src/API.ts | 15 +++----- src/Clock.ts | 16 ++++---- src/TransportNode.js | 79 ++++++++------------------------------- src/TransportProcessor.js | 12 +++--- src/classes/ZPlayer.ts | 63 +++++++++++++++---------------- 5 files changed, 62 insertions(+), 123 deletions(-) diff --git a/src/API.ts b/src/API.ts index 5e2aeaa..6a7ead8 100644 --- a/src/API.ts +++ b/src/API.ts @@ -366,7 +366,7 @@ export class UserAPI { const key = id==="" ? this.generateCacheKey(input, options) : zid; let player; - + if (this.app.api.patternCache.has(key)) { player = this.app.api.patternCache.get(key) as Player; if(player.input!==input) { @@ -379,7 +379,6 @@ export class UserAPI { this.app.api.patternCache.set(key, player); } - if(typeof id === "number") player.zid = zid; player.updateLastCallTime(); @@ -950,16 +949,12 @@ export class UserAPI { */ let final_pulses: boolean[] = []; beat.forEach((b) => { - b = b % this.app.clock.time_signature[0] || this.app.clock.time_signature[0]; - let integral_part = Math.floor(b); - console.log("INTEGRAL: ", integral_part, this.app.clock.time_position.beat) - let decimal_part = (b - integral_part)+1; - console.log("HUH?", this.app.clock.time_position); - console.log("DECIMAL:",decimal_part, this.app.clock.time_position.pulse) + const beat = b % this.app.clock.time_signature[0] || this.app.clock.time_signature[0]; + const integral_part = Math.floor(beat); + const decimal_part = ((beat - integral_part) * this.app.clock.ppqn) + 1; final_pulses.push( integral_part === this.app.clock.time_position.beat && - this.app.clock.time_position.pulse === - decimal_part * this.app.clock.ppqn + this.app.clock.time_position.pulse === decimal_part ); }); return final_pulses.some((p) => p == true); diff --git a/src/Clock.ts b/src/Clock.ts index a0d91ae..1e1d164 100644 --- a/src/Clock.ts +++ b/src/Clock.ts @@ -43,7 +43,7 @@ export class Clock { constructor(public app: Editor, ctx: AudioContext) { this.time_position = { bar: 0, beat: 0, pulse: 0 } this.time_signature = [4, 4]; - this.tick = -1; + this.tick = 0; this._bpm = 120; this._ppqn = 48; this.transportNode = null; @@ -65,9 +65,9 @@ export class Clock { * * @returns number of ticks until next bar */ - const currentBeatInTicks = ((this.app.clock.beats_since_origin * this.ppqn) + this.time_position.pulse); - const nextBarinTicks = (this.beats_per_bar * this.ppqn) * this.time_position.bar; - return nextBarinTicks - currentBeatInTicks; + const ticskMissingFromBeat = this.ppqn - this.time_position.pulse; + const beatsMissingFromBar = this.beats_per_bar - this.time_position.beat; + return (beatsMissingFromBar * this.ppqn) + ticskMissingFromBeat; } get next_beat_in_ticks(): number { @@ -77,8 +77,7 @@ export class Clock { * * @returns number of ticks until next beat */ - const ticksMissingToNextBeat = (this.time_position.pulse) % this.ppqn; - return this.app.clock.pulses_since_origin + ticksMissingToNextBeat; + return this.app.clock.pulses_since_origin + this.time_position.pulse; } get beats_per_bar(): number { @@ -143,9 +142,7 @@ export class Clock { /** * Starts the TransportNode (starts the clock). */ - // @ts-ignore - console.log("STARTING?"); - this.app.audioContext.resume() + this.app.audioContext.resume(); this.transportNode?.start(); } @@ -161,6 +158,7 @@ export class Clock { /** * Stops the TransportNode (stops the clock). */ + this.app.clock.tick = 0; this.transportNode?.stop(); } } \ No newline at end of file diff --git a/src/TransportNode.js b/src/TransportNode.js index 115523b..1fc5672 100644 --- a/src/TransportNode.js +++ b/src/TransportNode.js @@ -8,17 +8,6 @@ export class TransportNode extends AudioWorkletNode { this.app = application this.port.addEventListener("message", this.handleMessage); this.port.start(); - /** @type {HTMLSpanElement} */ - this.$clock = document.getElementById("clockviewer"); - this.currentPulsePosition = 0; - this.executionLatency = 0; - this.lastLatencies = [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ]; - this.indexOfLastLatencies = 0; this.logicalTime = 0; } @@ -26,25 +15,26 @@ export class TransportNode extends AudioWorkletNode { handleMessage = (message) => { if (message.data && message.data.type === "bang") { this.logicalTime = message.data.logicalTime; - this.app.clock.tick++ + let futureTimeStamp = this.convertTicksToTimeposition(this.app.clock.tick); - console.log("BANG", this.logicalTime, futureTimeStamp); - - setTimeout(() => { - console.log("EVALUATING"); - const now = this.app.audioContext.currentTime; - this.app.clock.time_position = futureTimeStamp; - tryEvaluate(this.app, this.app.global_buffer); - const then = this.app.audioContext.currentTime; - this.lastLatencies[this.indexOfLastLatencies] = then - now; - this.indexOfLastLatencies = (this.indexOfLastLatencies + 1) % this.lastLatencies.length; - const averageLatency = this.lastLatencies.reduce((a, b) => a + b) / this.lastLatencies.length; - this.executionLatency = averageLatency / 1000; - }, (this.app.clock.pulse_duration + this.executionLatency) * 1000); + // console.log("BANG", this.logicalTime, futureTimeStamp); + this.app.clock.time_position = futureTimeStamp; + tryEvaluate(this.app, this.app.global_buffer); + } }; + convertTicksToTimeposition(ticks) { + const beatsPerBar = this.app.clock.time_signature[0]; + const ppqnPosition = (ticks % this.app.clock.ppqn)+1; + const beatNumber = Math.floor(ticks / this.app.clock.ppqn); + const barNumber = Math.floor(beatNumber / beatsPerBar)+1; + const beatWithinBar = Math.floor(beatNumber % beatsPerBar)+1; + this.app.clock.tick++ + return {bar: barNumber, beat: beatWithinBar, pulse: ppqnPosition}; + } + start() { this.port.postMessage("start"); } @@ -62,46 +52,7 @@ export class TransportNode extends AudioWorkletNode { } stop() { - this.app.clock.tick = 0; - // this.$clock.innerHTML = `[${1} | ${1} | ${zeroPad(1, '2')}]`; this.port.postMessage("stop"); } - convertTimeToBarsBeats(currentTime) { - const beatDuration = 60 / this.app.clock.bpm; - const beatNumber = (currentTime) / beatDuration; - - const beatsPerBar = this.app.clock.time_signature[0]; - const barNumber = Math.floor(beatNumber / beatsPerBar) + 1; - const beatWithinBar = Math.floor(beatNumber % beatsPerBar) + 1; - - const ppqnPosition = Math.floor((beatNumber % 1) * this.app.clock.ppqn); - this.app.clock.tick++ - return { bar: barNumber, beat: beatWithinBar, ppqn: ppqnPosition }; - } - - convertTimeToNextBarsBeats(currentTime) { - - const beatDuration = 60 / this.app.clock.bpm; - const beatNumber = (currentTime) / beatDuration; - const beatsPerBar = this.app.clock.time_signature[0]; - - this.currentPulsePosition = beatNumber * this.app.clock.ppqn; - const nextPulsePosition = Math.ceil(this.currentPulsePosition); - const timeToNextPulse = this.app.clock.convertPulseToSecond(this.nextPulsePosition - this.currentPulsePosition); - - const futureBeatNumber = this.nextPulsePosition / this.app.clock.ppqn; - const futureBarNumber = futureBeatNumber / beatsPerBar; - - } - - convertTicksToTimeposition(ticks) { - const beatsPerBar = this.app.clock.time_signature[0]; - const ppqnPosition = (ticks % this.app.clock.ppqn)+1; - const beatNumber = Math.floor(ticks / this.app.clock.ppqn); - const barNumber = Math.floor(beatNumber / beatsPerBar)+1; - const beatWithinBar = Math.floor(beatNumber % beatsPerBar)+1; - return {bar: barNumber, beat: beatWithinBar, pulse: ppqnPosition}; - } - } \ No newline at end of file diff --git a/src/TransportProcessor.js b/src/TransportProcessor.js index 69e3cea..de6f6d5 100644 --- a/src/TransportProcessor.js +++ b/src/TransportProcessor.js @@ -48,15 +48,13 @@ class TransportProcessor extends AudioWorkletProcessor { this.startedAgainTime = currentTime; this.wasStopped = false; } + const logicalTime = currentTime-this.totalPausedTime-this.startedAgainTime; - //console.log(currentTime, this.totalPausedTime, this.startedAgainTime); - //console.log("Logical/Current:", logicalTime, currentTime); - const beatNumber = logicalTime / (60 / this.bpm); - const nextPulsePosition = Math.ceil(beatNumber * this.ppqn); - - if(nextPulsePosition > this.currentPulsePosition) { - this.currentPulsePosition = nextPulsePosition; + const currentPulsePosition = Math.ceil(beatNumber * this.ppqn); + + if(currentPulsePosition > this.currentPulsePosition) { + this.currentPulsePosition = currentPulsePosition; this.port.postMessage({ type: "bang", logicalTime }); } } diff --git a/src/classes/ZPlayer.ts b/src/classes/ZPlayer.ts index ee7b7fb..b083372 100644 --- a/src/classes/ZPlayer.ts +++ b/src/classes/ZPlayer.ts @@ -11,17 +11,19 @@ export type InputOptions = { [key: string]: string | number }; export class Player extends Event { input: string; ziffers: Ziffers; - initCallTime: number = 0; - startCallTime: number = 0; - lastCallTime: number = 0; + initCallTime: number = 1; + startCallTime: number = 1; + lastCallTime: number = 1; waitTime = 0; startBeat: number = 0; played: boolean = false; current!: Pitch|Chord|ZRest; retro: boolean = false; index: number = -1; - zid: string|undefined = undefined; + zid: string = ""; options: InputOptions = {}; + skipIndex = 0; + endTime = 0; constructor(input: string, options: InputOptions, public app: Editor) { super(app); @@ -61,15 +63,15 @@ export class Player extends Event { } firstRun = (): boolean => { - return this.origin()<=0 && this.notStarted(); + return this.notStarted(); } atTheBeginning = (): boolean => { - return this.ziffers.index===0; + return this.skipIndex === 0 && this.ziffers.index<=0; } origin = (): number => { - return this.app.clock.pulses_since_origin+1; + return this.app.clock.pulses_since_origin; } pulse = (): number => { @@ -86,10 +88,13 @@ export class Player extends Event { // Check if it's time to play the event areWeThereYet = (): boolean => { + // If clock has stopped if(this.app.clock.pulses_since_origin= this.app.clock.next_beat_in_ticks) && - (this.app.clock.pulses_since_origin+1 >= this.waitTime) + this.app.clock.pulses_since_origin >= this.app.clock.next_beat_in_ticks) && + (this.app.clock.pulses_since_origin >= this.waitTime) ) || ( // If pattern is already playing this.current && - (this.pulseToSecond(this.app.clock.pulses_since_origin+1) >= + (this.pulseToSecond(this.app.clock.pulses_since_origin) >= this.pulseToSecond(this.lastCallTime) + (this.current.duration*4) * this.pulseToSecond(this.app.api.ppqn())) && - (this.app.clock.pulses_since_origin+1 >= this.waitTime) + (this.app.clock.pulses_since_origin >= this.waitTime) ) ); + + // Increment index of how many times call is skipped + this.skipIndex = howAboutNow ? 0 : this.skipIndex+1; // Increment index of how many times sound/midi have been called this.index = howAboutNow ? this.index+1 : this.index; + if(howAboutNow && this.notStarted()) { - this.initCallTime = this.app.clock.pulses_since_origin+1; + this.initCallTime = this.app.clock.pulses_since_origin; } if(this.atTheBeginning()) { @@ -159,10 +168,7 @@ export class Player extends Event { } key(name: string) { - if(this.firstRun() || this.atTheBeginning()) { - console.log("At", this.app.clock.time_position); - this.ziffers.key(name); - } + if(this.atTheBeginning()) this.ziffers.key(name); return this; } @@ -176,23 +182,14 @@ export class Player extends Event { return this; } - wait(value: number) { - if(this.index === -1 && this.ziffers.index === -1) { - - // TODO: THIS LATER! - - /* if(typeof value === "string") { - const cueKey = this.app.api.patternCues.get(value); - if(cueKey) { - const waitedPatter = this.app.api.patternCache.get(cueKey) as Player; - if(waitedPatter) { - this.waitTime = waitedPatter.nextEndTime(); - } - } - } */ - + wait(value: number|Function) { + if(this.atTheBeginning()) { + if(typeof value === "function") { + const refPat = this.app.api.patternCache.get(value.name) as Player; + if(refPat) this.waitTime = refPat.nextEndTime(); + return this; + } this.waitTime = this.origin() + Math.ceil(value*4*this.app.clock.ppqn); - } return this; }