Change clock starting point and add oncount method as alternative to onbeat

This commit is contained in:
2023-08-31 18:03:07 +03:00
parent 3c335a50a9
commit 86739faa77
6 changed files with 67 additions and 38 deletions

View File

@ -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 => {

View File

@ -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 () {

View File

@ -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();
} }
} }

View File

@ -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};
} }

View File

@ -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;
} }
}; };

View File

@ -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 &&