Repair BPM setter
This commit is contained in:
@ -21,7 +21,7 @@ import { type SkipEvent } from '../Classes/SkipEvent';
|
|||||||
import { OscilloscopeConfig } from "../DOM/Visuals/Oscilloscope";
|
import { OscilloscopeConfig } from "../DOM/Visuals/Oscilloscope";
|
||||||
import { Player } from "../Classes/ZPlayer";
|
import { Player } from "../Classes/ZPlayer";
|
||||||
import { InputOptions } from "../Classes/ZPlayer";
|
import { InputOptions } from "../Classes/ZPlayer";
|
||||||
import { type ShapeObject } from "../DOM/Visuals/CanvasVisuals";
|
import { type ShapeObject } from "../API/DOM/Canvas";
|
||||||
import { nearScales } from "zifferjs";
|
import { nearScales } from "zifferjs";
|
||||||
import { MidiConnection } from "../IO/MidiConnection";
|
import { MidiConnection } from "../IO/MidiConnection";
|
||||||
import { evaluateOnce } from "../Evaluator";
|
import { evaluateOnce } from "../Evaluator";
|
||||||
@ -112,7 +112,6 @@ export class UserAPI {
|
|||||||
noteX: () => number;
|
noteX: () => number;
|
||||||
noteY: () => number;
|
noteY: () => number;
|
||||||
tempo: (n?: number | undefined) => number;
|
tempo: (n?: number | undefined) => number;
|
||||||
bpb: (n?: number | undefined) => number;
|
|
||||||
ppqn: (n?: number | undefined) => number;
|
ppqn: (n?: number | undefined) => number;
|
||||||
time_signature: (numerator: number, denominator: number) => void;
|
time_signature: (numerator: number, denominator: number) => void;
|
||||||
theme: (color_scheme: string) => void;
|
theme: (color_scheme: string) => void;
|
||||||
@ -282,7 +281,6 @@ export class UserAPI {
|
|||||||
this.stop = Transport.stop(this);
|
this.stop = Transport.stop(this);
|
||||||
this.silence = Transport.silence(this);
|
this.silence = Transport.silence(this);
|
||||||
this.tempo = Transport.tempo(this.app);
|
this.tempo = Transport.tempo(this.app);
|
||||||
this.bpb = Transport.bpb(this.app);
|
|
||||||
this.ppqn = Transport.ppqn(this.app);
|
this.ppqn = Transport.ppqn(this.app);
|
||||||
this.time_signature = Transport.time_signature(this.app);
|
this.time_signature = Transport.time_signature(this.app);
|
||||||
this.mouseX = Mouse.mouseX(this.app);
|
this.mouseX = Mouse.mouseX(this.app);
|
||||||
@ -527,8 +525,10 @@ export class UserAPI {
|
|||||||
const match = line.match(/<anonymous>:(\d+):(\d+)/);
|
const match = line.match(/<anonymous>:(\d+):(\d+)/);
|
||||||
if (match as RegExpMatchArray)
|
if (match as RegExpMatchArray)
|
||||||
return {
|
return {
|
||||||
|
// @ts-ignore
|
||||||
line: parseInt(match[1], 10),
|
line: parseInt(match[1], 10),
|
||||||
column: parseInt(match[2], 10),
|
// @ts-ignore
|
||||||
|
column: parseInt(match[2]!, 10),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -583,13 +583,13 @@ export class UserAPI {
|
|||||||
if (quantization.length === 0) {
|
if (quantization.length === 0) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
let closest = quantization[0];
|
let closest: number | undefined = quantization[0];
|
||||||
quantization.forEach((q) => {
|
quantization.forEach((q) => {
|
||||||
if (Math.abs(q - value) < Math.abs(closest - value)) {
|
if (Math.abs(q - value) < Math.abs(closest! - value)) {
|
||||||
closest = q;
|
closest = q;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return closest;
|
return closest!;
|
||||||
};
|
};
|
||||||
quant = this.quantize;
|
quant = this.quantize;
|
||||||
|
|
||||||
@ -621,7 +621,7 @@ export class UserAPI {
|
|||||||
|
|
||||||
public cue = (functionName: string | Function): void => {
|
public cue = (functionName: string | Function): void => {
|
||||||
functionName = typeof functionName === "function" ? functionName.name : functionName;
|
functionName = typeof functionName === "function" ? functionName.name : functionName;
|
||||||
this.cueTimes[functionName] = this.app.clock.pulses_since_origin;
|
this.cueTimes[functionName] = this.app.clock.grain;
|
||||||
};
|
};
|
||||||
|
|
||||||
onmousemove = (e: MouseEvent) => {
|
onmousemove = (e: MouseEvent) => {
|
||||||
|
|||||||
@ -65,7 +65,7 @@ export const bar = (app: Editor) => (n: number | number[] = 1, nudge: number = 0
|
|||||||
const nudgeInPulses = Math.floor(nudge * barLength);
|
const nudgeInPulses = Math.floor(nudge * barLength);
|
||||||
const results: boolean[] = nArray.map(
|
const results: boolean[] = nArray.map(
|
||||||
(value) =>
|
(value) =>
|
||||||
(app.clock.pulses_since_origin - nudgeInPulses) %
|
(app.clock.grain - nudgeInPulses) %
|
||||||
Math.floor(value * barLength) === 0,
|
Math.floor(value * barLength) === 0,
|
||||||
);
|
);
|
||||||
return results.some((value) => value === true);
|
return results.some((value) => value === true);
|
||||||
@ -74,7 +74,7 @@ export const bar = (app: Editor) => (n: number | number[] = 1, nudge: number = 0
|
|||||||
export const pulse = (app: Editor) => (n: number | number[] = 1, nudge: number = 0): boolean => {
|
export const pulse = (app: Editor) => (n: number | number[] = 1, nudge: number = 0): boolean => {
|
||||||
const nArray = Array.isArray(n) ? n : [n];
|
const nArray = Array.isArray(n) ? n : [n];
|
||||||
const results: boolean[] = nArray.map(
|
const results: boolean[] = nArray.map(
|
||||||
(value) => (app.clock.pulses_since_origin - nudge) % value === 0,
|
(value) => (app.clock.grain - nudge) % value === 0,
|
||||||
);
|
);
|
||||||
return results.some((value) => value === true);
|
return results.some((value) => value === true);
|
||||||
};
|
};
|
||||||
@ -95,7 +95,7 @@ export const dur = (app: Editor) => (n: number | number[]): boolean => {
|
|||||||
|
|
||||||
export const flip = (app: Editor) => (chunk: number, ratio: number = 50): boolean => {
|
export const flip = (app: Editor) => (chunk: number, ratio: number = 50): boolean => {
|
||||||
let realChunk = chunk * 2;
|
let realChunk = chunk * 2;
|
||||||
const time_pos = app.clock.pulses_since_origin;
|
const time_pos = app.clock.grain;
|
||||||
const full_chunk = Math.floor(realChunk * app.clock.ppqn);
|
const full_chunk = Math.floor(realChunk * app.clock.ppqn);
|
||||||
const threshold = Math.floor((ratio / 100) * full_chunk);
|
const threshold = Math.floor((ratio / 100) * full_chunk);
|
||||||
const pos_within_chunk = time_pos % full_chunk;
|
const pos_within_chunk = time_pos % full_chunk;
|
||||||
@ -137,7 +137,7 @@ export const onbeat = (api: UserAPI) => (...beat: number[]): boolean => {
|
|||||||
|
|
||||||
export const oncount = (app: Editor) => (beats: number[] | number, count: number): boolean => {
|
export const oncount = (app: Editor) => (beats: number[] | number, count: number): boolean => {
|
||||||
if (typeof beats === "number") beats = [beats];
|
if (typeof beats === "number") beats = [beats];
|
||||||
const origin = app.clock.pulses_since_origin;
|
const origin = app.clock.grain;
|
||||||
let final_pulses: boolean[] = [];
|
let final_pulses: boolean[] = [];
|
||||||
beats.forEach((b) => {
|
beats.forEach((b) => {
|
||||||
b = b < 1 ? 0 : b - 1;
|
b = b < 1 ? 0 : b - 1;
|
||||||
|
|||||||
@ -39,20 +39,6 @@ export const tempo = (app: Editor) => (n?: number): number => {
|
|||||||
return n;
|
return n;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const bpb = (app: Editor) => (n?: number): number => {
|
|
||||||
/**
|
|
||||||
* Sets or returns the number of beats per bar.
|
|
||||||
*/
|
|
||||||
if (n === undefined) return app.clock.time_signature[0] || 4;
|
|
||||||
|
|
||||||
if (n >= 1) {
|
|
||||||
app.clock.time_signature[0] = n;
|
|
||||||
} else {
|
|
||||||
console.error("Beats per bar must be at least 1.");
|
|
||||||
}
|
|
||||||
return n;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const ppqn = (app: Editor) => (n?: number): number => {
|
export const ppqn = (app: Editor) => (n?: number): number => {
|
||||||
/**
|
/**
|
||||||
* Sets or returns the number of pulses per quarter note.
|
* Sets or returns the number of pulses per quarter note.
|
||||||
@ -74,7 +60,7 @@ export const time_signature = (app: Editor) => (numerator: number, denominator:
|
|||||||
if (numerator < 1 || denominator < 1) {
|
if (numerator < 1 || denominator < 1) {
|
||||||
console.error("Time signature values must be at least 1.");
|
console.error("Time signature values must be at least 1.");
|
||||||
} else {
|
} else {
|
||||||
app.clock.time_signature = [numerator, denominator];
|
app.clock.setSignature(numerator, denominator);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -83,11 +69,11 @@ export const cbar = (app: Editor) => (): number => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const ctick = (app: Editor) => (): number => {
|
export const ctick = (app: Editor) => (): number => {
|
||||||
return app.clock.tick + 1;
|
return app.clock.grain + 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const cpulse = (app: Editor) => (): number => {
|
export const cpulse = (app: Editor) => (): number => {
|
||||||
return app.clock.time_position.pulse + 1;
|
return app.clock.time_position.tick + 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const cbeat = (app: Editor) => (): number => {
|
export const cbeat = (app: Editor) => (): number => {
|
||||||
@ -99,15 +85,15 @@ export const ebeat = (app: Editor) => (): number => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const epulse = (app: Editor) => (): number => {
|
export const epulse = (app: Editor) => (): number => {
|
||||||
return app.clock.pulses_since_origin + 1;
|
return app.clock.grain + 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const nominator = (app: Editor) => (): number => {
|
export const nominator = (app: Editor) => (): number => {
|
||||||
return app.clock.time_signature[0] || 4;
|
return app.clock.time_position.num;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const meter = (app: Editor) => (): number => {
|
export const meter = (app: Editor) => (): number => {
|
||||||
return app.clock.time_signature[1] || 4;
|
return app.clock.time_position.den;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const denominator = meter;
|
export const denominator = meter;
|
||||||
|
|||||||
@ -4,7 +4,7 @@ export const warp = (app: Editor) => (n: number): void => {
|
|||||||
/**
|
/**
|
||||||
* Time-warp the clock by using the tick you wish to jump to.
|
* Time-warp the clock by using the tick you wish to jump to.
|
||||||
*/
|
*/
|
||||||
app.clock.tick = n;
|
app.clock.time_position.tick = n;
|
||||||
app.clock.time_position = app.clock.convertTicksToTimeposition(n);
|
app.clock.time_position = app.clock.convertTicksToTimeposition(n);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -13,6 +13,6 @@ export const beat_warp = (app: Editor) => (beat: number): void => {
|
|||||||
* Time-warp the clock by using the tick you wish to jump to.
|
* Time-warp the clock by using the tick you wish to jump to.
|
||||||
*/
|
*/
|
||||||
const ticks = beat * app.clock.ppqn;
|
const ticks = beat * app.clock.ppqn;
|
||||||
app.clock.tick = ticks;
|
app.clock.time_position.tick = ticks;
|
||||||
app.clock.time_position = app.clock.convertTicksToTimeposition(ticks);
|
app.clock.time_position = app.clock.convertTicksToTimeposition(ticks);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -38,7 +38,7 @@ export const blinkScript = (
|
|||||||
) => {
|
) => {
|
||||||
if (no !== undefined && no < 1 && no > 9) return;
|
if (no !== undefined && no < 1 && no > 9) return;
|
||||||
const blinkDuration =
|
const blinkDuration =
|
||||||
(app.clock.bpm / 60 / app.clock.time_signature[1]!) * 200;
|
(app.clock.bpm / 60 / app.clock.time_position.num) * 200;
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const ctx = app.interface.feedback.getContext("2d");
|
const ctx = app.interface.feedback.getContext("2d");
|
||||||
|
|
||||||
|
|||||||
@ -93,7 +93,7 @@ export class Player extends AbstractEvent {
|
|||||||
|
|
||||||
updateLastCallTime(): void {
|
updateLastCallTime(): void {
|
||||||
if (this.notStarted() || this.played) {
|
if (this.notStarted() || this.played) {
|
||||||
this.lastCallTime = this.app.clock.pulses_since_origin;
|
this.lastCallTime = this.app.clock.grain;
|
||||||
this.played = false;
|
this.played = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -121,11 +121,11 @@ export class Player extends AbstractEvent {
|
|||||||
};
|
};
|
||||||
|
|
||||||
origin = (): number => {
|
origin = (): number => {
|
||||||
return this.app.clock.pulses_since_origin + 1;
|
return this.app.clock.grain + 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
pulse = (): number => {
|
pulse = (): number => {
|
||||||
return this.app.clock.time_position.pulse;
|
return this.app.clock.time_position.tick;
|
||||||
};
|
};
|
||||||
|
|
||||||
beat = (): number => {
|
beat = (): number => {
|
||||||
@ -143,7 +143,7 @@ export class Player extends AbstractEvent {
|
|||||||
// 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.grain < this.lastCallTime) {
|
||||||
this.app.api.resetAllFromCache();
|
this.app.api.resetAllFromCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,11 +171,11 @@ export class Player extends AbstractEvent {
|
|||||||
this.index = areWeThereYet ? this.index + 1 : this.index;
|
this.index = areWeThereYet ? this.index + 1 : this.index;
|
||||||
|
|
||||||
if (areWeThereYet && this.notStarted()) {
|
if (areWeThereYet && this.notStarted()) {
|
||||||
this.initCallTime = this.app.clock.pulses_since_origin;
|
this.initCallTime = this.app.clock.grain;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.atTheBeginning()) {
|
if (this.atTheBeginning()) {
|
||||||
this.startCallTime = this.app.clock.pulses_since_origin;
|
this.startCallTime = this.app.clock.grain;
|
||||||
}
|
}
|
||||||
|
|
||||||
return areWeThereYet;
|
return areWeThereYet;
|
||||||
@ -470,7 +470,7 @@ export class Player extends AbstractEvent {
|
|||||||
if(typeof value === "string") {
|
if(typeof value === "string") {
|
||||||
const cueTime = this.app.api.cueTimes[value];
|
const cueTime = this.app.api.cueTimes[value];
|
||||||
this.cueName = value;
|
this.cueName = value;
|
||||||
if(cueTime && this.app.clock.pulses_since_origin <= cueTime) {
|
if(cueTime && this.app.clock.grain <= cueTime) {
|
||||||
this.waitTime = cueTime;
|
this.waitTime = cueTime;
|
||||||
} else {
|
} else {
|
||||||
this.waitTime = -1;
|
this.waitTime = -1;
|
||||||
@ -485,7 +485,7 @@ export class Player extends AbstractEvent {
|
|||||||
if(typeof value === "string") {
|
if(typeof value === "string") {
|
||||||
const cueTime = this.app.api.cueTimes[value];
|
const cueTime = this.app.api.cueTimes[value];
|
||||||
this.cueName = value;
|
this.cueName = value;
|
||||||
if(cueTime && this.app.clock.pulses_since_origin <= cueTime) {
|
if(cueTime && this.app.clock.grain <= cueTime) {
|
||||||
this.waitTime = cueTime;
|
this.waitTime = cueTime;
|
||||||
} else if(this.atTheBeginning()){
|
} else if(this.atTheBeginning()){
|
||||||
this.waitTime = -1;
|
this.waitTime = -1;
|
||||||
@ -521,7 +521,7 @@ export class Player extends AbstractEvent {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
if (this.atTheBeginning() && this.notStarted()) {
|
if (this.atTheBeginning() && this.notStarted()) {
|
||||||
const origin = this.app.clock.pulses_since_origin;
|
const origin = this.app.clock.grain;
|
||||||
if (origin > 0) {
|
if (origin > 0) {
|
||||||
const syncName = typeof value === "function" ? value.name : value;
|
const syncName = typeof value === "function" ? value.name : value;
|
||||||
const syncPattern = this.app.api.patternCache.get(syncName) as Player;
|
const syncPattern = this.app.api.patternCache.get(syncName) as Player;
|
||||||
|
|||||||
@ -132,6 +132,22 @@ export class Clock {
|
|||||||
|
|
||||||
return remainingTime;
|
return remainingTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public convertTicksToTimeposition(n: number): TimePosition {
|
||||||
|
/**
|
||||||
|
* TODO: probably incorrect
|
||||||
|
*/
|
||||||
|
const ppqn = this.time_position.ppqn;
|
||||||
|
const bpm = this.time_position.bpm;
|
||||||
|
const num = this.time_position.num;
|
||||||
|
const den = this.time_position.den;
|
||||||
|
const tick = n % ppqn;
|
||||||
|
const grain = n;
|
||||||
|
const beat = Math.floor(n / ppqn) % num;
|
||||||
|
const bar = Math.floor(n / ppqn / num);
|
||||||
|
const time = n * this.pulse_duration;
|
||||||
|
return { bpm, ppqn, time, tick, beat, bar, num, den, grain };
|
||||||
|
}
|
||||||
|
|
||||||
public convertPulseToSecond(n: number): number {
|
public convertPulseToSecond(n: number): number {
|
||||||
/**
|
/**
|
||||||
@ -155,7 +171,7 @@ export class Clock {
|
|||||||
this.transportNode?.pause()
|
this.transportNode?.pause()
|
||||||
}
|
}
|
||||||
|
|
||||||
public signature(num: number, den: number): void {
|
public setSignature(num: number, den: number): void {
|
||||||
this.transportNode?.setSignature(num, den);
|
this.transportNode?.setSignature(num, den);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -48,7 +48,6 @@ export class ClockNode extends AudioWorkletNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setBPM(bpm) {
|
setBPM(bpm) {
|
||||||
console.log("Changement du bpm")
|
|
||||||
this.port.postMessage({ type: "bpm", value: bpm });
|
this.port.postMessage({ type: "bpm", value: bpm });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -37,6 +37,8 @@ class TransportProcessor extends AudioWorkletProcessor {
|
|||||||
this.currentPulsePosition = 0;
|
this.currentPulsePosition = 0;
|
||||||
} else if (message.data.type === "bpm") {
|
} else if (message.data.type === "bpm") {
|
||||||
this.bpm = message.data.value;
|
this.bpm = message.data.value;
|
||||||
|
this.startTime = currentTime;
|
||||||
|
this.currentPulsePosition = 0;
|
||||||
} else if (message.data.type === "ppqn") {
|
} else if (message.data.type === "ppqn") {
|
||||||
this.ppqn = message.data.value;
|
this.ppqn = message.data.value;
|
||||||
} else if (message.data.type === "timeSignature") {
|
} else if (message.data.type === "timeSignature") {
|
||||||
|
|||||||
@ -162,7 +162,7 @@ export const makeArrayExtensions = (api: UserAPI) => {
|
|||||||
|
|
||||||
Array.prototype.beat = function(divisor: number = 1) {
|
Array.prototype.beat = function(divisor: number = 1) {
|
||||||
const chunk_size = divisor;
|
const chunk_size = divisor;
|
||||||
const timepos = api.app.clock.pulses_since_origin;
|
const timepos = api.app.clock.grain;
|
||||||
const slice_count = Math.floor(
|
const slice_count = Math.floor(
|
||||||
timepos / Math.floor(chunk_size * api.ppqn()),
|
timepos / Math.floor(chunk_size * api.ppqn()),
|
||||||
);
|
);
|
||||||
@ -171,7 +171,7 @@ export const makeArrayExtensions = (api: UserAPI) => {
|
|||||||
Array.prototype.b = Array.prototype.beat;
|
Array.prototype.b = Array.prototype.beat;
|
||||||
|
|
||||||
Array.prototype.dur = function(...durations: number[]) {
|
Array.prototype.dur = function(...durations: number[]) {
|
||||||
const timepos = api.app.clock.pulses_since_origin;
|
const timepos = api.app.clock.grain;
|
||||||
const ppqn = api.ppqn();
|
const ppqn = api.ppqn();
|
||||||
const adjustedDurations = this.map(
|
const adjustedDurations = this.map(
|
||||||
(_, index) => durations[index % durations.length],
|
(_, index) => durations[index % durations.length],
|
||||||
|
|||||||
Reference in New Issue
Block a user