Removed latency calculation
This commit is contained in:
15
src/API.ts
15
src/API.ts
@ -366,7 +366,7 @@ export class UserAPI {
|
|||||||
const key = id==="" ? this.generateCacheKey(input, options) : zid;
|
const key = id==="" ? this.generateCacheKey(input, options) : zid;
|
||||||
|
|
||||||
let player;
|
let player;
|
||||||
|
|
||||||
if (this.app.api.patternCache.has(key)) {
|
if (this.app.api.patternCache.has(key)) {
|
||||||
player = this.app.api.patternCache.get(key) as Player;
|
player = this.app.api.patternCache.get(key) as Player;
|
||||||
if(player.input!==input) {
|
if(player.input!==input) {
|
||||||
@ -379,7 +379,6 @@ export class UserAPI {
|
|||||||
this.app.api.patternCache.set(key, player);
|
this.app.api.patternCache.set(key, player);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if(typeof id === "number") player.zid = zid;
|
if(typeof id === "number") player.zid = zid;
|
||||||
|
|
||||||
player.updateLastCallTime();
|
player.updateLastCallTime();
|
||||||
@ -950,16 +949,12 @@ export class UserAPI {
|
|||||||
*/
|
*/
|
||||||
let final_pulses: boolean[] = [];
|
let final_pulses: boolean[] = [];
|
||||||
beat.forEach((b) => {
|
beat.forEach((b) => {
|
||||||
b = b % this.app.clock.time_signature[0] || this.app.clock.time_signature[0];
|
const beat = b % this.app.clock.time_signature[0] || this.app.clock.time_signature[0];
|
||||||
let integral_part = Math.floor(b);
|
const integral_part = Math.floor(beat);
|
||||||
console.log("INTEGRAL: ", integral_part, this.app.clock.time_position.beat)
|
const decimal_part = ((beat - integral_part) * this.app.clock.ppqn) + 1;
|
||||||
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)
|
|
||||||
final_pulses.push(
|
final_pulses.push(
|
||||||
integral_part === this.app.clock.time_position.beat &&
|
integral_part === this.app.clock.time_position.beat &&
|
||||||
this.app.clock.time_position.pulse ===
|
this.app.clock.time_position.pulse === decimal_part
|
||||||
decimal_part * this.app.clock.ppqn
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
return final_pulses.some((p) => p == true);
|
return final_pulses.some((p) => p == true);
|
||||||
|
|||||||
16
src/Clock.ts
16
src/Clock.ts
@ -43,7 +43,7 @@ export class Clock {
|
|||||||
constructor(public app: Editor, ctx: AudioContext) {
|
constructor(public app: Editor, ctx: AudioContext) {
|
||||||
this.time_position = { bar: 0, beat: 0, pulse: 0 }
|
this.time_position = { bar: 0, beat: 0, pulse: 0 }
|
||||||
this.time_signature = [4, 4];
|
this.time_signature = [4, 4];
|
||||||
this.tick = -1;
|
this.tick = 0;
|
||||||
this._bpm = 120;
|
this._bpm = 120;
|
||||||
this._ppqn = 48;
|
this._ppqn = 48;
|
||||||
this.transportNode = null;
|
this.transportNode = null;
|
||||||
@ -65,9 +65,9 @@ export class Clock {
|
|||||||
*
|
*
|
||||||
* @returns number of ticks until next bar
|
* @returns number of ticks until next bar
|
||||||
*/
|
*/
|
||||||
const currentBeatInTicks = ((this.app.clock.beats_since_origin * this.ppqn) + this.time_position.pulse);
|
const ticskMissingFromBeat = this.ppqn - this.time_position.pulse;
|
||||||
const nextBarinTicks = (this.beats_per_bar * this.ppqn) * this.time_position.bar;
|
const beatsMissingFromBar = this.beats_per_bar - this.time_position.beat;
|
||||||
return nextBarinTicks - currentBeatInTicks;
|
return (beatsMissingFromBar * this.ppqn) + ticskMissingFromBeat;
|
||||||
}
|
}
|
||||||
|
|
||||||
get next_beat_in_ticks(): number {
|
get next_beat_in_ticks(): number {
|
||||||
@ -77,8 +77,7 @@ export class Clock {
|
|||||||
*
|
*
|
||||||
* @returns number of ticks until next beat
|
* @returns number of ticks until next beat
|
||||||
*/
|
*/
|
||||||
const ticksMissingToNextBeat = (this.time_position.pulse) % this.ppqn;
|
return this.app.clock.pulses_since_origin + this.time_position.pulse;
|
||||||
return this.app.clock.pulses_since_origin + ticksMissingToNextBeat;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get beats_per_bar(): number {
|
get beats_per_bar(): number {
|
||||||
@ -143,9 +142,7 @@ export class Clock {
|
|||||||
/**
|
/**
|
||||||
* Starts the TransportNode (starts the clock).
|
* Starts the TransportNode (starts the clock).
|
||||||
*/
|
*/
|
||||||
// @ts-ignore
|
this.app.audioContext.resume();
|
||||||
console.log("STARTING?");
|
|
||||||
this.app.audioContext.resume()
|
|
||||||
this.transportNode?.start();
|
this.transportNode?.start();
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -161,6 +158,7 @@ export class Clock {
|
|||||||
/**
|
/**
|
||||||
* Stops the TransportNode (stops the clock).
|
* Stops the TransportNode (stops the clock).
|
||||||
*/
|
*/
|
||||||
|
this.app.clock.tick = 0;
|
||||||
this.transportNode?.stop();
|
this.transportNode?.stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -8,17 +8,6 @@ export class TransportNode extends AudioWorkletNode {
|
|||||||
this.app = application
|
this.app = application
|
||||||
this.port.addEventListener("message", this.handleMessage);
|
this.port.addEventListener("message", this.handleMessage);
|
||||||
this.port.start();
|
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;
|
this.logicalTime = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -26,25 +15,26 @@ export class TransportNode extends AudioWorkletNode {
|
|||||||
handleMessage = (message) => {
|
handleMessage = (message) => {
|
||||||
if (message.data && message.data.type === "bang") {
|
if (message.data && message.data.type === "bang") {
|
||||||
this.logicalTime = message.data.logicalTime;
|
this.logicalTime = message.data.logicalTime;
|
||||||
this.app.clock.tick++
|
|
||||||
let futureTimeStamp = this.convertTicksToTimeposition(this.app.clock.tick);
|
let futureTimeStamp = this.convertTicksToTimeposition(this.app.clock.tick);
|
||||||
console.log("BANG", this.logicalTime, futureTimeStamp);
|
// 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);
|
|
||||||
|
|
||||||
|
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() {
|
start() {
|
||||||
this.port.postMessage("start");
|
this.port.postMessage("start");
|
||||||
}
|
}
|
||||||
@ -62,46 +52,7 @@ export class TransportNode extends AudioWorkletNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
stop() {
|
stop() {
|
||||||
this.app.clock.tick = 0;
|
|
||||||
// this.$clock.innerHTML = `[${1} | ${1} | ${zeroPad(1, '2')}]`;
|
|
||||||
this.port.postMessage("stop");
|
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};
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -48,15 +48,13 @@ class TransportProcessor extends AudioWorkletProcessor {
|
|||||||
this.startedAgainTime = currentTime;
|
this.startedAgainTime = currentTime;
|
||||||
this.wasStopped = false;
|
this.wasStopped = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const logicalTime = currentTime-this.totalPausedTime-this.startedAgainTime;
|
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 beatNumber = logicalTime / (60 / this.bpm);
|
||||||
const nextPulsePosition = Math.ceil(beatNumber * this.ppqn);
|
const currentPulsePosition = Math.ceil(beatNumber * this.ppqn);
|
||||||
|
|
||||||
if(nextPulsePosition > this.currentPulsePosition) {
|
if(currentPulsePosition > this.currentPulsePosition) {
|
||||||
this.currentPulsePosition = nextPulsePosition;
|
this.currentPulsePosition = currentPulsePosition;
|
||||||
this.port.postMessage({ type: "bang", logicalTime });
|
this.port.postMessage({ type: "bang", logicalTime });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,17 +11,19 @@ export type InputOptions = { [key: string]: string | number };
|
|||||||
export class Player extends Event {
|
export class Player extends Event {
|
||||||
input: string;
|
input: string;
|
||||||
ziffers: Ziffers;
|
ziffers: Ziffers;
|
||||||
initCallTime: number = 0;
|
initCallTime: number = 1;
|
||||||
startCallTime: number = 0;
|
startCallTime: number = 1;
|
||||||
lastCallTime: number = 0;
|
lastCallTime: number = 1;
|
||||||
waitTime = 0;
|
waitTime = 0;
|
||||||
startBeat: number = 0;
|
startBeat: number = 0;
|
||||||
played: boolean = false;
|
played: boolean = false;
|
||||||
current!: Pitch|Chord|ZRest;
|
current!: Pitch|Chord|ZRest;
|
||||||
retro: boolean = false;
|
retro: boolean = false;
|
||||||
index: number = -1;
|
index: number = -1;
|
||||||
zid: string|undefined = undefined;
|
zid: string = "";
|
||||||
options: InputOptions = {};
|
options: InputOptions = {};
|
||||||
|
skipIndex = 0;
|
||||||
|
endTime = 0;
|
||||||
|
|
||||||
constructor(input: string, options: InputOptions, public app: Editor) {
|
constructor(input: string, options: InputOptions, public app: Editor) {
|
||||||
super(app);
|
super(app);
|
||||||
@ -61,15 +63,15 @@ export class Player extends Event {
|
|||||||
}
|
}
|
||||||
|
|
||||||
firstRun = (): boolean => {
|
firstRun = (): boolean => {
|
||||||
return this.origin()<=0 && this.notStarted();
|
return this.notStarted();
|
||||||
}
|
}
|
||||||
|
|
||||||
atTheBeginning = (): boolean => {
|
atTheBeginning = (): boolean => {
|
||||||
return this.ziffers.index===0;
|
return this.skipIndex === 0 && this.ziffers.index<=0;
|
||||||
}
|
}
|
||||||
|
|
||||||
origin = (): number => {
|
origin = (): number => {
|
||||||
return this.app.clock.pulses_since_origin+1;
|
return this.app.clock.pulses_since_origin;
|
||||||
}
|
}
|
||||||
|
|
||||||
pulse = (): number => {
|
pulse = (): number => {
|
||||||
@ -86,10 +88,13 @@ export class Player extends Event {
|
|||||||
|
|
||||||
// Check if it's time to play the event
|
// Check if it's time to play the event
|
||||||
areWeThereYet = (): boolean => {
|
areWeThereYet = (): boolean => {
|
||||||
|
|
||||||
// If clock has stopped
|
// If clock has stopped
|
||||||
if(this.app.clock.pulses_since_origin<this.lastCallTime) {
|
if(this.app.clock.pulses_since_origin<this.lastCallTime) {
|
||||||
this.lastCallTime = 0;
|
this.lastCallTime = 1;
|
||||||
|
this.startCallTime = 1;
|
||||||
this.index = 0;
|
this.index = 0;
|
||||||
|
this.waitTime = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Main logic
|
// Main logic
|
||||||
@ -97,24 +102,28 @@ export class Player extends Event {
|
|||||||
( // If pattern is just starting
|
( // If pattern is just starting
|
||||||
this.notStarted() &&
|
this.notStarted() &&
|
||||||
(this.app.clock.time_position.pulse === 1 ||
|
(this.app.clock.time_position.pulse === 1 ||
|
||||||
this.app.clock.pulses_since_origin+1 >= this.app.clock.next_beat_in_ticks) &&
|
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.waitTime)
|
||||||
)
|
)
|
||||||
||
|
||
|
||||||
( // If pattern is already playing
|
( // If pattern is already playing
|
||||||
this.current &&
|
this.current &&
|
||||||
(this.pulseToSecond(this.app.clock.pulses_since_origin+1) >=
|
(this.pulseToSecond(this.app.clock.pulses_since_origin) >=
|
||||||
this.pulseToSecond(this.lastCallTime) +
|
this.pulseToSecond(this.lastCallTime) +
|
||||||
(this.current.duration*4) * this.pulseToSecond(this.app.api.ppqn())) &&
|
(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
|
// Increment index of how many times sound/midi have been called
|
||||||
this.index = howAboutNow ? this.index+1 : this.index;
|
this.index = howAboutNow ? this.index+1 : this.index;
|
||||||
|
|
||||||
|
|
||||||
if(howAboutNow && this.notStarted()) {
|
if(howAboutNow && this.notStarted()) {
|
||||||
this.initCallTime = this.app.clock.pulses_since_origin+1;
|
this.initCallTime = this.app.clock.pulses_since_origin;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(this.atTheBeginning()) {
|
if(this.atTheBeginning()) {
|
||||||
@ -159,10 +168,7 @@ export class Player extends Event {
|
|||||||
}
|
}
|
||||||
|
|
||||||
key(name: string) {
|
key(name: string) {
|
||||||
if(this.firstRun() || this.atTheBeginning()) {
|
if(this.atTheBeginning()) this.ziffers.key(name);
|
||||||
console.log("At", this.app.clock.time_position);
|
|
||||||
this.ziffers.key(name);
|
|
||||||
}
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,23 +182,14 @@ export class Player extends Event {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
wait(value: number) {
|
wait(value: number|Function) {
|
||||||
if(this.index === -1 && this.ziffers.index === -1) {
|
if(this.atTheBeginning()) {
|
||||||
|
if(typeof value === "function") {
|
||||||
// TODO: THIS LATER!
|
const refPat = this.app.api.patternCache.get(value.name) as Player;
|
||||||
|
if(refPat) this.waitTime = refPat.nextEndTime();
|
||||||
/* if(typeof value === "string") {
|
return this;
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} */
|
|
||||||
|
|
||||||
this.waitTime = this.origin() + Math.ceil(value*4*this.app.clock.ppqn);
|
this.waitTime = this.origin() + Math.ceil(value*4*this.app.clock.ppqn);
|
||||||
|
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user