Change clock starting point and add oncount method as alternative to onbeat
This commit is contained in:
76
src/API.ts
76
src/API.ts
@ -862,7 +862,7 @@ export class UserAPI {
|
|||||||
*
|
*
|
||||||
* @returns The current bar number
|
* @returns The current bar number
|
||||||
*/
|
*/
|
||||||
return this.app.clock.time_position.bar;
|
return this.app.clock.time_position.bar + 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
tick = (): number => {
|
tick = (): number => {
|
||||||
@ -871,7 +871,7 @@ export class UserAPI {
|
|||||||
*
|
*
|
||||||
* @returns The current tick number
|
* @returns The current tick number
|
||||||
*/
|
*/
|
||||||
return this.app.clock.tick;
|
return this.app.clock.tick + 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
pulse = (): number => {
|
pulse = (): number => {
|
||||||
@ -880,7 +880,7 @@ export class UserAPI {
|
|||||||
*
|
*
|
||||||
* @returns The current pulse number
|
* @returns The current pulse number
|
||||||
*/
|
*/
|
||||||
return this.app.clock.time_position.pulse;
|
return this.app.clock.time_position.pulse + 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
beat = (): number => {
|
beat = (): number => {
|
||||||
@ -889,57 +889,66 @@ export class UserAPI {
|
|||||||
*
|
*
|
||||||
* @returns The current beat number
|
* @returns The current beat number
|
||||||
*/
|
*/
|
||||||
return this.app.clock.time_position.beat;
|
return this.app.clock.time_position.beat + 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
ebeat = (): number => {
|
ebeat = (): number => {
|
||||||
/**
|
/**
|
||||||
* Returns the current beat number since the origin of time
|
* Returns the current beat number since the origin of time
|
||||||
*/
|
*/
|
||||||
return this.app.clock.beats_since_origin;
|
return this.app.clock.beats_since_origin + 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
epulse = (): number => {
|
epulse = (): number => {
|
||||||
/**
|
/**
|
||||||
* Returns the current number of pulses elapsed since origin of time
|
* Returns the current number of pulses elapsed since origin of time
|
||||||
*/
|
*/
|
||||||
return this.app.clock.pulses_since_origin;
|
return this.app.clock.pulses_since_origin + 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
signature = (): number[] => {
|
nominator = (): number => {
|
||||||
/**
|
/**
|
||||||
* Returns the current time signature
|
* Returns the current nominator of the time signature
|
||||||
*/
|
*/
|
||||||
return this.app.clock.time_signature;
|
return this.app.clock.time_signature[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
meter = (): number => {
|
||||||
|
/**
|
||||||
|
* Returns the current meter (denominator of the time signature)
|
||||||
|
*/
|
||||||
|
return this.app.clock.time_signature[1];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
denominator = this.meter;
|
||||||
|
|
||||||
// =============================================================
|
// =============================================================
|
||||||
// Time Filters
|
// Time Filters
|
||||||
// =============================================================
|
// =============================================================
|
||||||
|
|
||||||
public mod = (...n: number[]): boolean => {
|
public mod = (...n: number[]): boolean => {
|
||||||
const results: boolean[] = n.map(
|
const results: boolean[] = n.map(
|
||||||
(value) => this.epulse() % Math.floor(value * this.ppqn()) === 0
|
(value) => this.app.clock.pulses_since_origin % Math.floor(value * this.ppqn()) === 0
|
||||||
);
|
);
|
||||||
return results.some((value) => value === true);
|
return results.some((value) => value === true);
|
||||||
};
|
};
|
||||||
|
|
||||||
public modpulse = (...n: number[]): boolean => {
|
public modpulse = (...n: number[]): boolean => {
|
||||||
const results: boolean[] = n.map((value) => this.epulse() % value === 0);
|
const results: boolean[] = n.map((value) => this.app.clock.pulses_since_origin % value === 0);
|
||||||
return results.some((value) => value === true);
|
return results.some((value) => value === true);
|
||||||
};
|
};
|
||||||
modp = this.modpulse;
|
pmod = this.modpulse;
|
||||||
|
|
||||||
public modbar = (...n: number[]): boolean => {
|
public modbar = (...n: number[]): boolean => {
|
||||||
const results: boolean[] = n.map(
|
const results: boolean[] = n.map(
|
||||||
(value) => this.bar() % Math.floor(value * this.ppqn()) === 0
|
(value) => this.app.clock.time_position.bar % Math.floor(value * this.ppqn()) === 0
|
||||||
);
|
);
|
||||||
return results.some((value) => value === true);
|
return results.some((value) => value === true);
|
||||||
};
|
};
|
||||||
bmod = this.modbar;
|
bmod = this.modbar;
|
||||||
|
|
||||||
public div = (chunk: number): boolean => {
|
public div = (chunk: number): boolean => {
|
||||||
const time_pos = this.epulse();
|
const time_pos = this.app.clock.pulses_since_origin;
|
||||||
const current_chunk = Math.floor(
|
const current_chunk = Math.floor(
|
||||||
time_pos / Math.floor(chunk * this.ppqn())
|
time_pos / Math.floor(chunk * this.ppqn())
|
||||||
);
|
);
|
||||||
@ -947,7 +956,7 @@ export class UserAPI {
|
|||||||
};
|
};
|
||||||
|
|
||||||
public divbar = (chunk: number): boolean => {
|
public divbar = (chunk: number): boolean => {
|
||||||
const time_pos = this.bar() - 1;
|
const time_pos = this.app.clock.time_position.bar - 1;
|
||||||
const current_chunk = Math.floor(time_pos / chunk);
|
const current_chunk = Math.floor(time_pos / chunk);
|
||||||
return current_chunk % 2 === 0;
|
return current_chunk % 2 === 0;
|
||||||
};
|
};
|
||||||
@ -956,7 +965,7 @@ export class UserAPI {
|
|||||||
bars: number[] | number,
|
bars: number[] | number,
|
||||||
n: number = this.app.clock.time_signature[0]
|
n: number = this.app.clock.time_signature[0]
|
||||||
): boolean => {
|
): boolean => {
|
||||||
let current_bar = (this.bar() % n) + 1;
|
let current_bar = (this.app.clock.time_position.bar % n) + 1;
|
||||||
return typeof bars === "number"
|
return typeof bars === "number"
|
||||||
? bars === current_bar
|
? bars === current_bar
|
||||||
: bars.some((b) => b == current_bar);
|
: bars.some((b) => b == current_bar);
|
||||||
@ -972,14 +981,33 @@ export class UserAPI {
|
|||||||
* @param beat - The beats to check
|
* @param beat - The beats to check
|
||||||
* @returns True if the current beat is in the given list of beats
|
* @returns True if the current beat is in the given list of beats
|
||||||
*/
|
*/
|
||||||
|
const origin = this.app.clock.pulses_since_origin;
|
||||||
let final_pulses: boolean[] = [];
|
let final_pulses: boolean[] = [];
|
||||||
beat.forEach((b) => {
|
beat.forEach((b) => {
|
||||||
const beat = b % this.signature()[0] || this.signature()[0];
|
const pulses = Math.floor(b * this.ppqn());
|
||||||
const integral_part = Math.floor(beat);
|
return final_pulses.push(origin % pulses === 0);
|
||||||
const decimal_part = (beat - integral_part) * this.ppqn() + 1;
|
});
|
||||||
final_pulses.push(
|
return final_pulses.some((p) => p == true);
|
||||||
integral_part === this.beat() && this.pulse() === decimal_part
|
};
|
||||||
);
|
|
||||||
|
oncount = (beats: number[]|number, count: number): boolean => {
|
||||||
|
/**
|
||||||
|
* Returns true if the current beat is in the given list of beats.
|
||||||
|
*
|
||||||
|
* @remarks
|
||||||
|
* This function can also operate with decimal beats!
|
||||||
|
*
|
||||||
|
* @param beat - The beats to check
|
||||||
|
* @returns True if the current beat is in the given list of beats
|
||||||
|
*/
|
||||||
|
if(typeof beats === "number") beats = [beats];
|
||||||
|
const origin = this.app.clock.pulses_since_origin;
|
||||||
|
let final_pulses: boolean[] = [];
|
||||||
|
beats.forEach((b) => {
|
||||||
|
b = b<1 ? 0 : b-1;
|
||||||
|
const beatInTicks = Math.ceil(b * this.ppqn());
|
||||||
|
const meterPosition = origin % (this.ppqn() * count);
|
||||||
|
return final_pulses.push(meterPosition === beatInTicks);
|
||||||
});
|
});
|
||||||
return final_pulses.some((p) => p == true);
|
return final_pulses.some((p) => p == true);
|
||||||
};
|
};
|
||||||
@ -1342,7 +1370,7 @@ export class UserAPI {
|
|||||||
public divseq = (...args: any): any => {
|
public divseq = (...args: any): any => {
|
||||||
const chunk_size = args[0]; // Get the first argument (chunk size)
|
const chunk_size = args[0]; // Get the first argument (chunk size)
|
||||||
const elements = args.slice(1); // Get the rest of the arguments as an array
|
const elements = args.slice(1); // Get the rest of the arguments as an array
|
||||||
const timepos = this.epulse();
|
const timepos = this.app.clock.pulses_since_origin;
|
||||||
const slice_count = Math.floor(
|
const slice_count = Math.floor(
|
||||||
timepos / Math.floor(chunk_size * this.ppqn())
|
timepos / Math.floor(chunk_size * this.ppqn())
|
||||||
);
|
);
|
||||||
@ -1355,7 +1383,7 @@ export class UserAPI {
|
|||||||
*
|
*
|
||||||
* @param array - The array of values to pick from
|
* @param array - The array of values to pick from
|
||||||
*/
|
*/
|
||||||
return array[this.ebeat() % array.length];
|
return array[this.app.clock.time_position.beat % array.length];
|
||||||
};
|
};
|
||||||
|
|
||||||
public seqbar = <T>(...array: T[]): T => {
|
public seqbar = <T>(...array: T[]): T => {
|
||||||
|
|||||||
@ -98,7 +98,7 @@ export const makeArrayExtensions = (api: UserAPI) => {
|
|||||||
*
|
*
|
||||||
* @returns The element corresponding to the current beat
|
* @returns The element corresponding to the current beat
|
||||||
*/
|
*/
|
||||||
return this[(api.ebeat() / beat) % this.length];
|
return this[(api.app.clock.beats_since_origin / beat) % this.length];
|
||||||
};
|
};
|
||||||
|
|
||||||
Array.prototype.bar = function () {
|
Array.prototype.bar = function () {
|
||||||
|
|||||||
@ -40,9 +40,9 @@ export class Clock {
|
|||||||
tick: number;
|
tick: number;
|
||||||
|
|
||||||
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: -1, beat: -1, pulse: -1 };
|
||||||
this.time_signature = [4, 4];
|
this.time_signature = [4, 4];
|
||||||
this.tick = 0;
|
this.tick = -1;
|
||||||
this._bpm = 120;
|
this._bpm = 120;
|
||||||
this._ppqn = 48;
|
this._ppqn = 48;
|
||||||
this.transportNode = null;
|
this.transportNode = null;
|
||||||
@ -157,7 +157,7 @@ export class Clock {
|
|||||||
/**
|
/**
|
||||||
* Stops the TransportNode (stops the clock).
|
* Stops the TransportNode (stops the clock).
|
||||||
*/
|
*/
|
||||||
this.app.clock.tick = 0;
|
this.app.clock.tick = -1;
|
||||||
this.transportNode?.stop();
|
this.transportNode?.stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,9 +15,11 @@ 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++
|
||||||
|
|
||||||
const futureTimeStamp = this.convertTicksToTimeposition(this.app.clock.tick);
|
const futureTimeStamp = this.convertTicksToTimeposition(this.app.clock.tick);
|
||||||
// console.log("BANG", this.logicalTime, futureTimeStamp);
|
//console.log("BANG", this.logicalTime, futureTimeStamp);
|
||||||
|
|
||||||
this.app.clock.time_position = futureTimeStamp;
|
this.app.clock.time_position = futureTimeStamp;
|
||||||
tryEvaluate(this.app, this.app.global_buffer);
|
tryEvaluate(this.app, this.app.global_buffer);
|
||||||
@ -27,11 +29,10 @@ export class TransportNode extends AudioWorkletNode {
|
|||||||
|
|
||||||
convertTicksToTimeposition(ticks) {
|
convertTicksToTimeposition(ticks) {
|
||||||
const beatsPerBar = this.app.clock.time_signature[0];
|
const beatsPerBar = this.app.clock.time_signature[0];
|
||||||
const ppqnPosition = (ticks % this.app.clock.ppqn)+1;
|
const ppqnPosition = (ticks % this.app.clock.ppqn);
|
||||||
const beatNumber = Math.floor(ticks / this.app.clock.ppqn);
|
const beatNumber = Math.floor(ticks / this.app.clock.ppqn);
|
||||||
const barNumber = Math.floor(beatNumber / beatsPerBar)+1;
|
const barNumber = Math.floor(beatNumber / beatsPerBar);
|
||||||
const beatWithinBar = Math.floor(beatNumber % beatsPerBar)+1;
|
const beatWithinBar = Math.floor(beatNumber % beatsPerBar);
|
||||||
this.app.clock.tick++
|
|
||||||
return {bar: barNumber, beat: beatWithinBar, pulse: ppqnPosition};
|
return {bar: barNumber, beat: beatWithinBar, pulse: ppqnPosition};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -30,9 +30,9 @@ class TransportProcessor extends AudioWorkletProcessor {
|
|||||||
this.lastPausedTime = 0;
|
this.lastPausedTime = 0;
|
||||||
this.wasStopped = true;
|
this.wasStopped = true;
|
||||||
this.currentPulsePosition = 0;
|
this.currentPulsePosition = 0;
|
||||||
} else if(message.data === 'bpm') {
|
} else if(message.data.type === 'bpm') {
|
||||||
this.bpm = message.data.value;
|
this.bpm = message.data.value;
|
||||||
} else if(message.data === 'ppqn') {
|
} else if(message.data.type === 'ppqn') {
|
||||||
this.ppqn = message.data.value;
|
this.ppqn = message.data.value;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -94,8 +94,8 @@ export class Player extends 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 = 1;
|
this.lastCallTime = 0;
|
||||||
this.startCallTime = 1;
|
this.startCallTime = 0;
|
||||||
this.index = 0;
|
this.index = 0;
|
||||||
this.waitTime = 0;
|
this.waitTime = 0;
|
||||||
}
|
}
|
||||||
@ -104,7 +104,7 @@ export class Player extends Event {
|
|||||||
const howAboutNow =
|
const howAboutNow =
|
||||||
// If pattern is just starting
|
// If pattern is just starting
|
||||||
(this.notStarted() &&
|
(this.notStarted() &&
|
||||||
(this.pulse() === 1 || this.origin() >= this.nextBeatInTicks()) &&
|
(this.pulse() === 0 || this.origin() >= this.nextBeatInTicks()) &&
|
||||||
this.origin() >= this.waitTime) ||
|
this.origin() >= this.waitTime) ||
|
||||||
// If pattern is already playing
|
// If pattern is already playing
|
||||||
(this.current &&
|
(this.current &&
|
||||||
|
|||||||
Reference in New Issue
Block a user