Event superclass for Note and Sound
This commit is contained in:
@ -37,7 +37,7 @@
|
||||
"tailwindcss": "^3.3.3",
|
||||
"tone": "^14.8.49",
|
||||
"vite-plugin-markdown": "^2.1.0",
|
||||
"zifferjs": "^0.0.8",
|
||||
"zifferjs": "^0.0.9",
|
||||
"zzfx": "^1.2.0"
|
||||
}
|
||||
}
|
||||
|
||||
104
src/API.ts
104
src/API.ts
@ -1,4 +1,4 @@
|
||||
import { Pitch, Chord, Rest, Event, cachedPattern } from "zifferjs";
|
||||
import { Pitch, Chord, Rest, Event, cachedPattern, seededRandom } from "zifferjs";
|
||||
import { MidiConnection } from "./IO/MidiConnection";
|
||||
import { tryEvaluate } from "./Evaluator";
|
||||
import { DrunkWalk } from "./Utils/Drunk";
|
||||
@ -6,6 +6,7 @@ import { LRUCache } from "lru-cache";
|
||||
import { scale } from "./Scales";
|
||||
import { Editor } from "./main";
|
||||
import { Sound } from "./Sound";
|
||||
import { Note } from "./Note";
|
||||
import {
|
||||
samples,
|
||||
initAudioOnFirstClick,
|
||||
@ -68,6 +69,9 @@ export class UserAPI {
|
||||
private variables: { [key: string]: any } = {};
|
||||
private iterators: { [key: string]: any } = {};
|
||||
private _drunk: DrunkWalk = new DrunkWalk(-100, 100, false);
|
||||
public randomGen = Math.random;
|
||||
public currentSeed: string|undefined = undefined;
|
||||
public localSeeds = new Map<string, Function>();
|
||||
|
||||
MidiConnection: MidiConnection = new MidiConnection();
|
||||
load: samples;
|
||||
@ -105,6 +109,21 @@ export class UserAPI {
|
||||
return this.app._mouseY;
|
||||
};
|
||||
|
||||
public noteX = (): number => {
|
||||
/**
|
||||
* @returns The current x position scaled to 0-127 using screen width
|
||||
*/
|
||||
return Math.floor((this.app._mouseX / document.body.clientWidth) * 127);
|
||||
};
|
||||
|
||||
public noteY = (): number => {
|
||||
/**
|
||||
* @returns The current y position scaled to 0-127 using screen height
|
||||
*/
|
||||
return Math.floor((this.app._mouseY / document.body.clientHeight) * 127);
|
||||
};
|
||||
|
||||
|
||||
// =============================================================
|
||||
// Utility functions
|
||||
// =============================================================
|
||||
@ -179,9 +198,8 @@ export class UserAPI {
|
||||
};
|
||||
|
||||
public note = (
|
||||
note: number,
|
||||
options: { [key: string]: number } = {}
|
||||
): void => {
|
||||
value: number = 60
|
||||
): Note => {
|
||||
/**
|
||||
* Sends a MIDI note to the current MIDI output.
|
||||
*
|
||||
@ -189,10 +207,7 @@ export class UserAPI {
|
||||
* @param options - an object containing options for that note
|
||||
* { channel: 0, velocity: 100, duration: 0.5 }
|
||||
*/
|
||||
const channel = options.channel ? options.channel : 0;
|
||||
const velocity = options.velocity ? options.velocity : 100;
|
||||
const duration = options.duration ? options.duration : 0.5;
|
||||
this.MidiConnection.sendMidiNote(note, channel, velocity, duration);
|
||||
return new Note(value, this.app);
|
||||
};
|
||||
|
||||
public sysex = (data: Array<number>): void => {
|
||||
@ -261,27 +276,26 @@ export class UserAPI {
|
||||
public zn = (
|
||||
input: string,
|
||||
options: { [key: string]: string | number } = {}
|
||||
): Event => {
|
||||
): Event|object => {
|
||||
const pattern = cachedPattern(input, options);
|
||||
//@ts-ignore
|
||||
if (pattern.hasStarted()) {
|
||||
const event = pattern.peek();
|
||||
|
||||
// Check if event is modified
|
||||
const node = event!.modifiedEvent ? event!.modifiedEvent : event;
|
||||
// Check if event is modified
|
||||
const node = event.modifiedEvent ? event.modifiedEvent : event;
|
||||
const channel = (options.channel ? options.channel : 0) as number;
|
||||
const velocity = (options.velocity ? options.velocity : 100) as number;
|
||||
const sustain = (options.sustain ? options.sustain : 0.5) as number;
|
||||
|
||||
if (node instanceof Pitch) {
|
||||
if (node.bend) this.MidiConnection.sendPitchBend(node.bend, channel);
|
||||
this.MidiConnection.sendMidiNote(
|
||||
node.note!,
|
||||
channel,
|
||||
velocity,
|
||||
sustain
|
||||
);
|
||||
if (node.bend) this.MidiConnection.sendPitchBend(8192, channel);
|
||||
this.MidiConnection.sendMidiNote(
|
||||
node.note!,
|
||||
channel,
|
||||
velocity,
|
||||
sustain
|
||||
);
|
||||
if (node.bend) this.MidiConnection.sendPitchBend(8192, channel);
|
||||
} else if (node instanceof Chord) {
|
||||
node.pitches.forEach((pitch: Pitch) => {
|
||||
if (pitch.bend)
|
||||
@ -299,7 +313,7 @@ export class UserAPI {
|
||||
}
|
||||
|
||||
// Remove old modified event
|
||||
if (event!.modifiedEvent) event!.modifiedEvent = undefined;
|
||||
if (event.modifiedEvent) event.modifiedEvent = undefined;
|
||||
}
|
||||
//@ts-ignore
|
||||
return pattern.next();
|
||||
@ -577,7 +591,7 @@ export class UserAPI {
|
||||
*
|
||||
* @param array - The array of values to pick from
|
||||
*/
|
||||
return array[Math.floor(Math.random() * array.length)];
|
||||
return array[Math.floor(this.randomGen() * array.length)];
|
||||
};
|
||||
|
||||
seqbeat = <T>(...array: T[]): T => {
|
||||
@ -629,7 +643,7 @@ export class UserAPI {
|
||||
* @param max - The maximum value of the random number
|
||||
* @returns A random integer between min and max
|
||||
*/
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
return Math.floor(this.randomGen() * (max - min + 1)) + min;
|
||||
};
|
||||
|
||||
rand = (min: number, max: number): number => {
|
||||
@ -640,11 +654,37 @@ export class UserAPI {
|
||||
* @param max - The maximum value of the random number
|
||||
* @returns A random float between min and max
|
||||
*/
|
||||
return Math.random() * (max - min) + min;
|
||||
return this.randomGen() * (max - min) + min;
|
||||
};
|
||||
irand = this.randI
|
||||
rI = this.randI;
|
||||
r = this.rand;
|
||||
|
||||
seed = (seed: string | number): void => {
|
||||
/**
|
||||
* Seed the random numbers globally in UserAPI.
|
||||
* @param seed - The seed to use
|
||||
*/
|
||||
if(typeof seed === "number") seed = seed.toString();
|
||||
if(this.currentSeed!==seed) {
|
||||
this.currentSeed = seed;
|
||||
this.randomGen = seededRandom(seed);
|
||||
}
|
||||
}
|
||||
|
||||
localSeededRandom = (seed: string | number): Function => {
|
||||
if(typeof seed === "number") seed = seed.toString();
|
||||
if(this.localSeeds.has(seed)) return this.localSeeds.get(seed) as Function;
|
||||
const newSeededRandom = seededRandom(seed)
|
||||
this.localSeeds.set(seed,newSeededRandom);
|
||||
return newSeededRandom;
|
||||
}
|
||||
|
||||
clearLocalSeed = (seed: string | number | undefined = undefined): void => {
|
||||
if(seed) this.localSeeds.delete(seed.toString());
|
||||
this.localSeeds.clear();
|
||||
}
|
||||
|
||||
// =============================================================
|
||||
// Quantification functions
|
||||
// =============================================================
|
||||
@ -748,7 +788,7 @@ export class UserAPI {
|
||||
*
|
||||
* @returns True 10% of the time
|
||||
*/
|
||||
return Math.random() > 0.9;
|
||||
return this.randomGen() > 0.9;
|
||||
};
|
||||
|
||||
public sometimes = (): boolean => {
|
||||
@ -757,7 +797,7 @@ export class UserAPI {
|
||||
*
|
||||
* @returns True 50% of the time
|
||||
*/
|
||||
return Math.random() > 0.5;
|
||||
return this.randomGen() > 0.5;
|
||||
};
|
||||
|
||||
public rarely = (): boolean => {
|
||||
@ -766,7 +806,7 @@ export class UserAPI {
|
||||
*
|
||||
* @returns True 25% of the time
|
||||
*/
|
||||
return Math.random() > 0.75;
|
||||
return this.randomGen() > 0.75;
|
||||
};
|
||||
|
||||
public often = (): boolean => {
|
||||
@ -775,7 +815,7 @@ export class UserAPI {
|
||||
*
|
||||
* @returns True 75% of the time
|
||||
*/
|
||||
return Math.random() > 0.25;
|
||||
return this.randomGen() > 0.25;
|
||||
};
|
||||
|
||||
public almostAlways = (): boolean => {
|
||||
@ -784,7 +824,7 @@ export class UserAPI {
|
||||
*
|
||||
* @returns True 90% of the time
|
||||
*/
|
||||
return Math.random() > 0.1;
|
||||
return this.randomGen() > 0.1;
|
||||
};
|
||||
|
||||
public dice = (sides: number): number => {
|
||||
@ -794,7 +834,7 @@ export class UserAPI {
|
||||
* @param sides - The number of sides on the dice
|
||||
* @returns The value of a dice roll with n sides
|
||||
*/
|
||||
return Math.floor(Math.random() * sides) + 1;
|
||||
return Math.floor(this.randomGen() * sides) + 1;
|
||||
};
|
||||
|
||||
// =============================================================
|
||||
@ -920,7 +960,7 @@ export class UserAPI {
|
||||
* @param p - The probability of returning true
|
||||
* @returns True p% of the time
|
||||
*/
|
||||
return Math.random() * 100 < p;
|
||||
return this.randomGen() * 100 < p;
|
||||
};
|
||||
|
||||
toss = (): boolean => {
|
||||
@ -934,7 +974,7 @@ export class UserAPI {
|
||||
* @see almostAlways
|
||||
* @see almostNever
|
||||
*/
|
||||
return Math.random() > 0.5;
|
||||
return this.randomGen() > 0.5;
|
||||
};
|
||||
|
||||
min = (...values: number[]): number => {
|
||||
@ -1212,7 +1252,7 @@ export class UserAPI {
|
||||
* @see sine
|
||||
* @see noise
|
||||
*/
|
||||
return Math.random() * 2 - 1;
|
||||
return this.randomGen() * 2 - 1;
|
||||
};
|
||||
|
||||
// =============================================================
|
||||
|
||||
53
src/Event.ts
Normal file
53
src/Event.ts
Normal file
@ -0,0 +1,53 @@
|
||||
import { type Editor } from './main';
|
||||
|
||||
export class Event {
|
||||
seedValue: string|undefined = undefined;
|
||||
randomGen: Function = Math.random;
|
||||
app: Editor;
|
||||
|
||||
constructor(app: Editor) {
|
||||
this.app = app;
|
||||
if(this.app.api.currentSeed) {
|
||||
this.randomGen = this.app.api.randomGen;
|
||||
}
|
||||
}
|
||||
|
||||
sometimesBy = (probability: number, func: Function): Event => {
|
||||
if(this.randomGen() < probability) {
|
||||
return this.modify(func);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
sometimes = (func: Function): Event => {
|
||||
return this.sometimesBy(0.5, func);
|
||||
}
|
||||
|
||||
rarely = (func: Function): Event => {
|
||||
return this.sometimesBy(0.1, func);
|
||||
}
|
||||
|
||||
often = (func: Function): Event => {
|
||||
return this.sometimesBy(0.9, func);
|
||||
}
|
||||
|
||||
modify = (func: Function): Event => {
|
||||
return func(this);
|
||||
}
|
||||
|
||||
seed = (value: string|number): Event => {
|
||||
this.seedValue = value.toString();
|
||||
this.randomGen = this.app.api.localSeededRandom(this.seedValue);
|
||||
return this;
|
||||
}
|
||||
|
||||
clear = (): Event => {
|
||||
this.app.api.clearLocalSeed(this.seedValue);
|
||||
return this;
|
||||
}
|
||||
|
||||
apply = (func: Function): Event => {
|
||||
return this.modify(func);
|
||||
}
|
||||
|
||||
}
|
||||
@ -30,6 +30,7 @@ export class MidiConnection{
|
||||
this.midiOutputs = Array.from(this.midiAccess.outputs.values());
|
||||
if (this.midiOutputs.length === 0) {
|
||||
console.warn('No MIDI outputs available.');
|
||||
this.currentOutputIndex = -1;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to initialize MIDI:', error);
|
||||
@ -50,6 +51,20 @@ export class MidiConnection{
|
||||
}
|
||||
}
|
||||
|
||||
public getCurrentMidiPortIndex(): number {
|
||||
/**
|
||||
* Returns the index of the currently selected MIDI output.
|
||||
*
|
||||
* @returns Index of the currently selected MIDI output or -1 if no MIDI output is selected or available.
|
||||
*/
|
||||
if(this.midiOutputs.length > 0 && this.currentOutputIndex >= 0 && this.currentOutputIndex < this.midiOutputs.length) {
|
||||
return this.currentOutputIndex;
|
||||
} else {
|
||||
console.error('No MIDI output selected or available.');
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public sendMidiClock(): void {
|
||||
/**
|
||||
* Sends a single MIDI clock message to the currently selected MIDI output.
|
||||
@ -69,15 +84,40 @@ export class MidiConnection{
|
||||
* @param outputName Name of the MIDI output to switch to
|
||||
* @returns True if the MIDI output was found and switched to, false otherwise
|
||||
*/
|
||||
const index = this.midiOutputs.findIndex((output) => output.name === outputName);
|
||||
const index = this.getMidiOutputIndex(outputName);
|
||||
if (index !== -1) {
|
||||
this.currentOutputIndex = index;
|
||||
return true;
|
||||
} else {
|
||||
console.error(`MIDI output "${outputName}" not found.`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public getMidiOutputIndex(output: string|number): number {
|
||||
/**
|
||||
* Returns the index of the MIDI output with the specified name.
|
||||
*
|
||||
* @param outputName Name of the MIDI output
|
||||
* @returns Index of the new MIDI output or current output if new is not valid
|
||||
*
|
||||
*/
|
||||
if(typeof output === 'number') {
|
||||
if (output < 0 || output >= this.midiOutputs.length) {
|
||||
console.error(`Invalid MIDI output index. Index must be in the range 0-${this.midiOutputs.length - 1}.`);
|
||||
return this.currentOutputIndex;
|
||||
} else {
|
||||
return output;
|
||||
}
|
||||
} else {
|
||||
const index = this.midiOutputs.findIndex((o) => o.name === output);
|
||||
if (index !== -1) {
|
||||
return index;
|
||||
} else {
|
||||
console.error(`MIDI output "${output}" not found.`);
|
||||
return this.currentOutputIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public listMidiOutputs(): void {
|
||||
/**
|
||||
@ -89,7 +129,7 @@ export class MidiConnection{
|
||||
});
|
||||
}
|
||||
|
||||
public sendMidiNote(noteNumber: number, channel: number, velocity: number, duration: number): void {
|
||||
public sendMidiNote(noteNumber: number, channel: number, velocity: number, duration: number, port: number|string = this.currentOutputIndex): void {
|
||||
/**
|
||||
* Sending a MIDI Note on/off message with the same note number and channel. Automatically manages
|
||||
* the note off message after the specified duration.
|
||||
@ -100,7 +140,9 @@ export class MidiConnection{
|
||||
* @param duration Duration in milliseconds
|
||||
*
|
||||
*/
|
||||
const output = this.midiOutputs[this.currentOutputIndex];
|
||||
|
||||
if(typeof port === 'string') port = this.getMidiOutputIndex(port);
|
||||
const output = this.midiOutputs[port];
|
||||
noteNumber = Math.min(Math.max(noteNumber, 0), 127);
|
||||
if (output) {
|
||||
const noteOnMessage = [0x90 + channel, noteNumber, velocity];
|
||||
|
||||
78
src/Note.ts
Normal file
78
src/Note.ts
Normal file
@ -0,0 +1,78 @@
|
||||
import { Event } from './Event';
|
||||
import { type Editor } from './main';
|
||||
import { MidiConnection } from "./IO/MidiConnection";
|
||||
export class Note extends Event {
|
||||
values: { [key: string]: any };
|
||||
midiConnection: MidiConnection;
|
||||
|
||||
constructor(input: number|object, public app: Editor) {
|
||||
super(app);
|
||||
if(typeof input === 'number') input = { 'note': input };
|
||||
this.values = input;
|
||||
this.midiConnection = app.api.MidiConnection
|
||||
}
|
||||
|
||||
note = (value: number): this => {
|
||||
this.values['note'] = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
channel = (value: number): this => {
|
||||
this.values['channel'] = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
port = (value: number|string): this => {
|
||||
this.values['port'] = this.midiConnection.getMidiOutputIndex(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
add = (value: number): this => {
|
||||
this.values.note += value;
|
||||
return this;
|
||||
}
|
||||
|
||||
modify = (func: Function): this => {
|
||||
const funcResult = func(this);
|
||||
if(funcResult instanceof Object) return funcResult;
|
||||
else {
|
||||
func(this.values);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Add bend
|
||||
freq = (value: number): this => {
|
||||
this.values['freq'] = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
bend = (value: number): this => {
|
||||
this.values['bend'] = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
random = (min: number = 0, max: number = 127): this => {
|
||||
min = Math.min(Math.max(min, 0), 127);
|
||||
max = Math.min(Math.max(max, 0), 127);
|
||||
this.values['note'] = Math.floor(this.randomGen() * (max - min + 1)) + min;
|
||||
return this;
|
||||
}
|
||||
|
||||
out = (): void => {
|
||||
const note = this.values.note ? this.values.note : 60;
|
||||
const channel = this.values.channel ? this.values.channel : 0;
|
||||
const velocity = this.values.velocity ? this.values.velocity : 100;
|
||||
const duration = this.values.duration ? this.values.duration : 0.5;
|
||||
const bend = this.values.bend ? this.values.bend : undefined;
|
||||
|
||||
const port = this.values.port ?
|
||||
this.midiConnection.getMidiOutputIndex(this.values.port) :
|
||||
this.midiConnection.getCurrentMidiPortIndex();
|
||||
|
||||
if (bend) this.midiConnection.sendPitchBend(bend, channel);
|
||||
this.midiConnection.sendMidiNote(note, channel, velocity, duration, port);
|
||||
if (bend) this.midiConnection.sendPitchBend(8192, channel);
|
||||
}
|
||||
|
||||
}
|
||||
101
src/Pattern.ts
101
src/Pattern.ts
@ -1,101 +0,0 @@
|
||||
export class Pattern {
|
||||
|
||||
events: Event[];
|
||||
_current : Event | undefined = undefined;
|
||||
|
||||
constructor(values: number[]) {
|
||||
this.events = values.map((value) => new Event(value));
|
||||
this.buildLinks();
|
||||
}
|
||||
|
||||
// Create links cyclic links between events
|
||||
buildLinks(): void {
|
||||
this.events.forEach((event, index) => {
|
||||
event._next = index < this.events.length - 1 ? this.events[index + 1] : this.events[0];
|
||||
});
|
||||
}
|
||||
|
||||
// Get the current event for this pattern
|
||||
current(): Event {
|
||||
if(this._current) this._current = this._current.next();
|
||||
else this._current = this.events[0];
|
||||
return this._current;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class Event {
|
||||
/**
|
||||
* Simple Event class with simple numerical value and link to next event
|
||||
*/
|
||||
_next!: Event;
|
||||
_value: number;
|
||||
// Used to store a modified version of the event
|
||||
modifiedEvent: Event | undefined = undefined;
|
||||
|
||||
constructor(value: number) {
|
||||
this._value = value;
|
||||
}
|
||||
|
||||
get value(): number {
|
||||
if(this.modifiedEvent) return this.modifiedEvent._value;
|
||||
return this._value;
|
||||
}
|
||||
|
||||
add(value: number): Event {
|
||||
if(!this.modifiedEvent) this.modifiedEvent = this.clone();
|
||||
this.modifiedEvent._value += value;
|
||||
return this;
|
||||
}
|
||||
|
||||
next() {
|
||||
if(this.modifiedEvent) {
|
||||
const next = this.modifiedEvent._next;
|
||||
// Set modifiedEvent to undefined, cos we dont want to apply methods to earlier modified events
|
||||
this.modifiedEvent = undefined;
|
||||
return next;
|
||||
}
|
||||
return this._next;
|
||||
}
|
||||
|
||||
clone(): Event {
|
||||
const event = new Event(this._value);
|
||||
event._next = this._next;
|
||||
return event;
|
||||
}
|
||||
}
|
||||
|
||||
// Simple cache for patterns
|
||||
let cache = new Map<string, Pattern>();
|
||||
|
||||
// Create a cache key from the values of a pattern somehow
|
||||
const createCacheKey = (values: number[]) => values.join('-');
|
||||
|
||||
// Get a cached pattern or create a new one
|
||||
const getCachedPattern = (values: number[]) => {
|
||||
const key = createCacheKey(values);
|
||||
const cachedPattern = cache.get(key);
|
||||
if(cachedPattern) return cachedPattern;
|
||||
const newPattern = new Pattern(values);
|
||||
cache.set(key, newPattern);
|
||||
return newPattern;
|
||||
}
|
||||
|
||||
// Cached event function that includes the main logic
|
||||
const cachedEvent = (values: number[]): Event => {
|
||||
const pattern = getCachedPattern(values);
|
||||
if(pattern._current) { console.log("Play: ", pattern._current.value) }
|
||||
else { console.log("Current is undefined so just starting!") }
|
||||
return pattern.current();
|
||||
}
|
||||
|
||||
// Test it out
|
||||
|
||||
let i = 0;
|
||||
while(true) {
|
||||
|
||||
cachedEvent([1, 2, 3]).add(1).add(-2);
|
||||
|
||||
if(i++>10) break;
|
||||
|
||||
}
|
||||
29
src/Sound.ts
29
src/Sound.ts
@ -1,18 +1,28 @@
|
||||
import { type Editor } from './main';
|
||||
import { Event } from './Event';
|
||||
|
||||
import {
|
||||
superdough,
|
||||
// @ts-ignore
|
||||
} from "superdough";
|
||||
|
||||
export class Sound {
|
||||
export class Sound extends Event {
|
||||
|
||||
values: { [key: string]: any }
|
||||
|
||||
constructor(sound: string, public app: Editor) {
|
||||
this.values = { 's': sound }
|
||||
constructor(sound: string|object, public app: Editor) {
|
||||
super(app);
|
||||
if (typeof sound === 'string') this.values = { 's': sound };
|
||||
else this.values = sound;
|
||||
}
|
||||
|
||||
sound = (value: string): this => {
|
||||
this.values['s'] = value
|
||||
return this;
|
||||
}
|
||||
|
||||
snd = this.sound;
|
||||
|
||||
unit = (value: number): this => {
|
||||
this.values['unit'] = value
|
||||
return this;
|
||||
@ -163,7 +173,16 @@ export class Sound {
|
||||
return this;
|
||||
}
|
||||
|
||||
out = (): object => {
|
||||
return superdough(this.values, this.app.clock.pulse_duration);
|
||||
modify = (func: Function): this => {
|
||||
const funcResult = func(this);
|
||||
if(funcResult instanceof Object) return funcResult;
|
||||
else {
|
||||
func(this.values);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
out = (): void => {
|
||||
superdough(this.values, this.app.clock.pulse_duration);
|
||||
}
|
||||
}
|
||||
@ -1441,10 +1441,10 @@ yaml@^2.1.1:
|
||||
resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.1.tgz#02fe0975d23cd441242aa7204e09fc28ac2ac33b"
|
||||
integrity sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==
|
||||
|
||||
zifferjs@^0.0.8:
|
||||
version "0.0.8"
|
||||
resolved "https://registry.yarnpkg.com/zifferjs/-/zifferjs-0.0.8.tgz#4e165679f37d81f2a02399f617ddb3c7fc1738ba"
|
||||
integrity sha512-yxRo+BVZiHDoZksLHtAgkE/e5qeRboj3jcx1DDmdr9zrQUGBea+WQzfeo0IOrFnzbN/D7A7g9Vy4acJ+1R6z6g==
|
||||
zifferjs@^0.0.9:
|
||||
version "0.0.9"
|
||||
resolved "https://registry.yarnpkg.com/zifferjs/-/zifferjs-0.0.9.tgz#47037cee6dd161838dd236bdbc3eda9b099e2281"
|
||||
integrity sha512-XS/JAc9nkmoiRaT/YFuX7r1ROvApQnY5BxOKyenAeDATvKZ80sIoXUw48U27KTsuJIsiPInNm5RieJGCJkoVmQ==
|
||||
dependencies:
|
||||
lru-cache "^10.0.0"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user