adding the slice and seqslice functions
This commit is contained in:
351
src/API.ts
351
src/API.ts
@ -2,10 +2,10 @@ import { Pitch, Chord, Rest, Event, cachedPattern } from "zifferjs";
|
||||
import { MidiConnection } from "./IO/MidiConnection";
|
||||
import { tryEvaluate } from "./Evaluator";
|
||||
import { DrunkWalk } from "./Utils/Drunk";
|
||||
import { LRUCache } from 'lru-cache';
|
||||
import { LRUCache } from "lru-cache";
|
||||
import { scale } from "./Scales";
|
||||
import { Editor } from "./main";
|
||||
import { Sound } from './Sound';
|
||||
import { Sound } from "./Sound";
|
||||
import {
|
||||
samples,
|
||||
initAudioOnFirstClick,
|
||||
@ -14,14 +14,13 @@ import {
|
||||
} from "superdough";
|
||||
|
||||
// This is an LRU cache used for storing persistent patterns
|
||||
const cache = new LRUCache({max: 1000, ttl: 1000 * 60 * 5});
|
||||
const cache = new LRUCache({ max: 1000, ttl: 1000 * 60 * 5 });
|
||||
|
||||
interface ControlChange {
|
||||
channel: number
|
||||
control: number
|
||||
value: number
|
||||
}
|
||||
|
||||
channel: number;
|
||||
control: number;
|
||||
value: number;
|
||||
}
|
||||
|
||||
interface Pattern<T> {
|
||||
pattern: any[];
|
||||
@ -42,7 +41,6 @@ Array.prototype.in = function <T>(this: T[], value: T): boolean {
|
||||
return this.includes(value);
|
||||
};
|
||||
|
||||
|
||||
async function loadSamples() {
|
||||
const ds = "https://raw.githubusercontent.com/felixroos/dough-samples/main/";
|
||||
return Promise.all([
|
||||
@ -57,8 +55,7 @@ async function loadSamples() {
|
||||
]);
|
||||
}
|
||||
|
||||
loadSamples()
|
||||
|
||||
loadSamples();
|
||||
|
||||
export class UserAPI {
|
||||
/**
|
||||
@ -88,7 +85,7 @@ export class UserAPI {
|
||||
* @returns the current AudioContext time (wall clock)
|
||||
*/
|
||||
return this.app.audioContext.currentTime;
|
||||
}
|
||||
};
|
||||
|
||||
// =============================================================
|
||||
// Mouse functions
|
||||
@ -99,14 +96,14 @@ export class UserAPI {
|
||||
* @returns The current x position of the mouse
|
||||
*/
|
||||
return this.app._mouseX;
|
||||
}
|
||||
};
|
||||
|
||||
public mouseY = (): number => {
|
||||
/**
|
||||
* @returns The current y position of the mouse
|
||||
*/
|
||||
return this.app._mouseY;
|
||||
}
|
||||
};
|
||||
|
||||
// =============================================================
|
||||
// Utility functions
|
||||
@ -125,7 +122,7 @@ export class UserAPI {
|
||||
this.app.universes[this.app.selected_universe].locals[arg]
|
||||
);
|
||||
});
|
||||
}
|
||||
};
|
||||
s = this.script;
|
||||
|
||||
clear_script = (script: number): void => {
|
||||
@ -139,7 +136,7 @@ export class UserAPI {
|
||||
committed: "",
|
||||
evaluations: 0,
|
||||
};
|
||||
}
|
||||
};
|
||||
cs = this.clear_script;
|
||||
|
||||
copy_script = (from: number, to: number): void => {
|
||||
@ -151,7 +148,7 @@ export class UserAPI {
|
||||
*/
|
||||
this.app.universes[this.app.selected_universe].locals[to] =
|
||||
this.app.universes[this.app.selected_universe].locals[from];
|
||||
}
|
||||
};
|
||||
cps = this.copy_script;
|
||||
|
||||
// =============================================================
|
||||
@ -166,7 +163,7 @@ export class UserAPI {
|
||||
*/
|
||||
console.log(this.MidiConnection.listMidiOutputs());
|
||||
return this.MidiConnection.midiOutputs;
|
||||
}
|
||||
};
|
||||
|
||||
public midi_output = (outputName: string): void => {
|
||||
/**
|
||||
@ -179,9 +176,12 @@ export class UserAPI {
|
||||
} else {
|
||||
this.MidiConnection.switchMidiOutput(outputName);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public note = (note: number, options: { [key: string]: number } = {}): void => {
|
||||
public note = (
|
||||
note: number,
|
||||
options: { [key: string]: number } = {}
|
||||
): void => {
|
||||
/**
|
||||
* Sends a MIDI note to the current MIDI output.
|
||||
*
|
||||
@ -193,7 +193,7 @@ export class UserAPI {
|
||||
const velocity = options.velocity ? options.velocity : 100;
|
||||
const duration = options.duration ? options.duration : 0.5;
|
||||
this.MidiConnection.sendMidiNote(note, channel, velocity, duration);
|
||||
}
|
||||
};
|
||||
|
||||
public sysex = (data: Array<number>): void => {
|
||||
/**
|
||||
@ -202,7 +202,7 @@ export class UserAPI {
|
||||
* @param data - The sysex data to send
|
||||
*/
|
||||
this.MidiConnection.sendSysExMessage(data);
|
||||
}
|
||||
};
|
||||
|
||||
public pitch_bend = (value: number, channel: number): void => {
|
||||
/**
|
||||
@ -214,7 +214,7 @@ export class UserAPI {
|
||||
* @returns The value of the pitch bend
|
||||
*/
|
||||
this.MidiConnection.sendPitchBend(value, channel);
|
||||
}
|
||||
};
|
||||
|
||||
public program_change = (program: number, channel: number): void => {
|
||||
/**
|
||||
@ -224,17 +224,20 @@ export class UserAPI {
|
||||
* @param channel - The MIDI channel to send the program change on
|
||||
*/
|
||||
this.MidiConnection.sendProgramChange(program, channel);
|
||||
}
|
||||
};
|
||||
|
||||
public midi_clock = (): void => {
|
||||
/**
|
||||
* Sends a MIDI clock to the current MIDI output.
|
||||
*/
|
||||
this.MidiConnection.sendMidiClock();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
public control_change = ({control= 20, value= 0, channel=0 }: ControlChange): void => {
|
||||
public control_change = ({
|
||||
control = 20,
|
||||
value = 0,
|
||||
channel = 0,
|
||||
}: ControlChange): void => {
|
||||
/**
|
||||
* Sends a MIDI control change to the current MIDI output.
|
||||
*
|
||||
@ -242,53 +245,65 @@ export class UserAPI {
|
||||
* @param value - The value of the control
|
||||
*/
|
||||
this.MidiConnection.sendMidiControlChange(control, value, channel);
|
||||
}
|
||||
};
|
||||
|
||||
public midi_panic = (): void => {
|
||||
/**
|
||||
* Sends a MIDI panic message to the current MIDI output.
|
||||
*/
|
||||
this.MidiConnection.panic();
|
||||
}
|
||||
};
|
||||
|
||||
// =============================================================
|
||||
// Ziffers related functions
|
||||
// =============================================================
|
||||
|
||||
public zn = (input: string,
|
||||
options: {[key: string]: string|number} = {}): Event => {
|
||||
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;
|
||||
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);
|
||||
} else if(node instanceof Chord) {
|
||||
node.pitches.forEach((pitch: Pitch) => {
|
||||
if(pitch.bend) this.MidiConnection.sendPitchBend(pitch.bend, channel);
|
||||
this.MidiConnection.sendMidiNote(pitch.note!, channel, velocity, sustain);
|
||||
if(pitch.bend) this.MidiConnection.sendPitchBend(8192, channel);
|
||||
});
|
||||
} else if(node instanceof Rest) {
|
||||
// do nothing for now ...
|
||||
}
|
||||
|
||||
// Remove old modified event
|
||||
if(event!.modifiedEvent) event!.modifiedEvent = undefined;
|
||||
public zn = (
|
||||
input: string,
|
||||
options: { [key: string]: string | number } = {}
|
||||
): Event => {
|
||||
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;
|
||||
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);
|
||||
} else if (node instanceof Chord) {
|
||||
node.pitches.forEach((pitch: Pitch) => {
|
||||
if (pitch.bend)
|
||||
this.MidiConnection.sendPitchBend(pitch.bend, channel);
|
||||
this.MidiConnection.sendMidiNote(
|
||||
pitch.note!,
|
||||
channel,
|
||||
velocity,
|
||||
sustain
|
||||
);
|
||||
if (pitch.bend) this.MidiConnection.sendPitchBend(8192, channel);
|
||||
});
|
||||
} else if (node instanceof Rest) {
|
||||
// do nothing for now ...
|
||||
}
|
||||
//@ts-ignore
|
||||
return pattern.next();
|
||||
}
|
||||
|
||||
// Remove old modified event
|
||||
if (event!.modifiedEvent) event!.modifiedEvent = undefined;
|
||||
}
|
||||
//@ts-ignore
|
||||
return pattern.next();
|
||||
};
|
||||
|
||||
// =============================================================
|
||||
// Iterator related functions
|
||||
@ -339,7 +354,7 @@ export class UserAPI {
|
||||
|
||||
// Return current iterator value
|
||||
return this.iterators[name].value;
|
||||
}
|
||||
};
|
||||
$ = this.iterator;
|
||||
|
||||
// =============================================================
|
||||
@ -361,7 +376,7 @@ export class UserAPI {
|
||||
}
|
||||
this._drunk.step();
|
||||
return this._drunk.getPosition();
|
||||
}
|
||||
};
|
||||
|
||||
public drunk_max = (max: number) => {
|
||||
/**
|
||||
@ -370,7 +385,7 @@ export class UserAPI {
|
||||
* @param max - The maximum value of the drunk mechanism
|
||||
*/
|
||||
this._drunk.max = max;
|
||||
}
|
||||
};
|
||||
|
||||
public drunk_min = (min: number) => {
|
||||
/**
|
||||
@ -379,7 +394,7 @@ export class UserAPI {
|
||||
* @param min - The minimum value of the drunk mechanism
|
||||
*/
|
||||
this._drunk.min = min;
|
||||
}
|
||||
};
|
||||
|
||||
public drunk_wrap = (wrap: boolean) => {
|
||||
/**
|
||||
@ -388,7 +403,7 @@ export class UserAPI {
|
||||
* @param wrap - Whether the drunk mechanism should wrap around
|
||||
*/
|
||||
this._drunk.toggleWrap(wrap);
|
||||
}
|
||||
};
|
||||
|
||||
// =============================================================
|
||||
// Variable related functions
|
||||
@ -408,7 +423,7 @@ export class UserAPI {
|
||||
this.variables[a] = b;
|
||||
return this.variables[a];
|
||||
}
|
||||
}
|
||||
};
|
||||
v = this.variable;
|
||||
|
||||
public delete_variable = (name: string): void => {
|
||||
@ -418,7 +433,7 @@ export class UserAPI {
|
||||
* @param name - The name of the variable to delete
|
||||
*/
|
||||
delete this.variables[name];
|
||||
}
|
||||
};
|
||||
dv = this.delete_variable;
|
||||
|
||||
public clear_variables = (): void => {
|
||||
@ -430,7 +445,7 @@ export class UserAPI {
|
||||
* Use with caution.
|
||||
*/
|
||||
this.variables = {};
|
||||
}
|
||||
};
|
||||
cv = this.clear_variables;
|
||||
|
||||
// =============================================================
|
||||
@ -440,7 +455,7 @@ export class UserAPI {
|
||||
private _sequence_key_generator(pattern: any[]) {
|
||||
/**
|
||||
* Generates a key for the sequence function.
|
||||
*
|
||||
*
|
||||
* @param input - The input to generate a key for
|
||||
* @returns A key for the sequence function
|
||||
*/
|
||||
@ -448,6 +463,20 @@ export class UserAPI {
|
||||
return btoa(JSON.stringify(pattern));
|
||||
}
|
||||
|
||||
public slice = (chunk: number): boolean => {
|
||||
const time_pos = this.epulse();
|
||||
const current_chunk = Math.floor(time_pos / chunk);
|
||||
return current_chunk % 2 === 0;
|
||||
};
|
||||
|
||||
public seqslice = (...args: any): any => {
|
||||
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 timepos = epulse();
|
||||
const slice_count = Math.floor(timepos / chunk_size);
|
||||
return elements[slice_count % elements.length];
|
||||
};
|
||||
|
||||
public seqmod = (...input: any[]) => {
|
||||
if (cache.has(this._sequence_key_generator(input))) {
|
||||
let sequence = cache.get(
|
||||
@ -458,82 +487,83 @@ export class UserAPI {
|
||||
|
||||
if (sequence.options.currentIteration === sequence.options.nextTarget) {
|
||||
sequence.options.index++;
|
||||
sequence.options.nextTarget = input[sequence.options.index % input.length];
|
||||
sequence.options.nextTarget =
|
||||
input[sequence.options.index % input.length];
|
||||
sequence.options.currentIteration = 0;
|
||||
}
|
||||
|
||||
cache.set(this._sequence_key_generator(input), {
|
||||
pattern: input as any[],
|
||||
options: sequence.options
|
||||
pattern: input as any[],
|
||||
options: sequence.options,
|
||||
});
|
||||
|
||||
return sequence.options.currentIteration === 0;
|
||||
|
||||
} else {
|
||||
|
||||
let pattern_options = {
|
||||
index: -1, nextTarget: this.app.clock.ticks_before_new_bar,
|
||||
currentIteration: 0
|
||||
let pattern_options = {
|
||||
index: -1,
|
||||
nextTarget: this.app.clock.ticks_before_new_bar,
|
||||
currentIteration: 0,
|
||||
};
|
||||
if (typeof input[input.length - 1] === "object") {
|
||||
pattern_options = {
|
||||
...input.pop(),
|
||||
...pattern_options as object
|
||||
pattern_options = {
|
||||
...input.pop(),
|
||||
...(pattern_options as object),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// pattern_options.currentIteration++;
|
||||
// TEST
|
||||
pattern_options.nextTarget = this.app.clock.ticks_before_new_bar
|
||||
pattern_options.nextTarget = this.app.clock.ticks_before_new_bar;
|
||||
|
||||
if (pattern_options.currentIteration === pattern_options.nextTarget) {
|
||||
pattern_options.index++;
|
||||
pattern_options.nextTarget = input[pattern_options.index % input.length];
|
||||
pattern_options.nextTarget =
|
||||
input[pattern_options.index % input.length];
|
||||
pattern_options.currentIteration = 0;
|
||||
}
|
||||
|
||||
cache.set(this._sequence_key_generator(input), {
|
||||
pattern: input as any[],
|
||||
options: pattern_options
|
||||
pattern: input as any[],
|
||||
options: pattern_options,
|
||||
});
|
||||
|
||||
return pattern_options.currentIteration === 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public seq = (...input: any[]) => {
|
||||
/**
|
||||
* Returns a value in a sequence stored using an LRU Cache.
|
||||
* The sequence is stored in the cache with an hash identifier
|
||||
* made from a base64 encoding of the pattern. The pattern itself
|
||||
* is composed of the pattern itself (a list of arbitrary typed
|
||||
* is composed of the pattern itself (a list of arbitrary typed
|
||||
* values) and a set of options (an object) detailing how the pattern
|
||||
* should be iterated on.
|
||||
*
|
||||
*
|
||||
* @param input - The input to generate a key for
|
||||
* Note that the last element of the input can be an object
|
||||
* containing options for the sequence function.
|
||||
* @returns A value in a sequence stored using an LRU Cache
|
||||
*/
|
||||
if (cache.has(this._sequence_key_generator(input))) {
|
||||
let sequence = cache.get(this._sequence_key_generator(input)) as Pattern<any>;
|
||||
let sequence = cache.get(
|
||||
this._sequence_key_generator(input)
|
||||
) as Pattern<any>;
|
||||
sequence.options.index += 1;
|
||||
cache.set(this._sequence_key_generator(input), sequence);
|
||||
return sequence.pattern[
|
||||
sequence.options.index % sequence.pattern.length
|
||||
];
|
||||
return sequence.pattern[sequence.options.index % sequence.pattern.length];
|
||||
} else {
|
||||
let pattern_options = { index: 0 };
|
||||
if (typeof input[input.length - 1] === "object") {
|
||||
pattern_options = { ...input.pop(), ...pattern_options as object };
|
||||
}
|
||||
pattern_options = { ...input.pop(), ...(pattern_options as object) };
|
||||
}
|
||||
cache.set(this._sequence_key_generator(input), {
|
||||
pattern: input as any[],
|
||||
options: pattern_options
|
||||
pattern: input as any[],
|
||||
options: pattern_options,
|
||||
});
|
||||
return cache.get(this._sequence_key_generator(input));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
pick = <T>(...array: T[]): T => {
|
||||
/**
|
||||
@ -542,7 +572,7 @@ export class UserAPI {
|
||||
* @param array - The array of values to pick from
|
||||
*/
|
||||
return array[Math.floor(Math.random() * array.length)];
|
||||
}
|
||||
};
|
||||
|
||||
seqbeat = <T>(...array: T[]): T => {
|
||||
/**
|
||||
@ -551,7 +581,7 @@ export class UserAPI {
|
||||
* @param array - The array of values to pick from
|
||||
*/
|
||||
return array[this.ebeat() % array.length];
|
||||
}
|
||||
};
|
||||
|
||||
mel = <T>(iterator: number, array: T[]): T => {
|
||||
/**
|
||||
@ -561,7 +591,7 @@ export class UserAPI {
|
||||
* @param array - The array of values to pick from
|
||||
*/
|
||||
return array[iterator % array.length];
|
||||
}
|
||||
};
|
||||
|
||||
seqbar = <T>(...array: T[]): T => {
|
||||
/**
|
||||
@ -570,7 +600,7 @@ export class UserAPI {
|
||||
* @param array - The array of values to pick from
|
||||
*/
|
||||
return array[(this.app.clock.time_position.bar + 1) % array.length];
|
||||
}
|
||||
};
|
||||
|
||||
seqpulse = <T>(...array: T[]): T => {
|
||||
/**
|
||||
@ -579,7 +609,7 @@ export class UserAPI {
|
||||
* @param array - The array of values to pick from
|
||||
*/
|
||||
return array[this.app.clock.time_position.pulse % array.length];
|
||||
}
|
||||
};
|
||||
|
||||
// =============================================================
|
||||
// Randomness functions
|
||||
@ -594,7 +624,7 @@ export class UserAPI {
|
||||
* @returns A random integer between min and max
|
||||
*/
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
}
|
||||
};
|
||||
|
||||
rand = (min: number, max: number): number => {
|
||||
/**
|
||||
@ -605,7 +635,7 @@ export class UserAPI {
|
||||
* @returns A random float between min and max
|
||||
*/
|
||||
return Math.random() * (max - min) + min;
|
||||
}
|
||||
};
|
||||
rI = this.randI;
|
||||
r = this.rand;
|
||||
|
||||
@ -631,7 +661,7 @@ export class UserAPI {
|
||||
}
|
||||
});
|
||||
return closest;
|
||||
}
|
||||
};
|
||||
quant = this.quantize;
|
||||
|
||||
public clamp = (value: number, min: number, max: number): number => {
|
||||
@ -644,7 +674,7 @@ export class UserAPI {
|
||||
* @returns A value clamped between min and max
|
||||
*/
|
||||
return Math.min(Math.max(value, min), max);
|
||||
}
|
||||
};
|
||||
cmp = this.clamp;
|
||||
|
||||
// =============================================================
|
||||
@ -663,12 +693,12 @@ export class UserAPI {
|
||||
if (n < 1 || n > 500) console.log(`Setting bpm to ${n}`);
|
||||
this.app.clock.bpm = n;
|
||||
return n;
|
||||
}
|
||||
};
|
||||
tempo = this.bpm;
|
||||
|
||||
public bpb = (n?: number): number => {
|
||||
/**
|
||||
* Sets or returns the number of beats per bar.
|
||||
* Sets or returns the number of beats per bar.
|
||||
*
|
||||
* @param bpb - [optional] The number of beats per bar to set
|
||||
* @returns The current bpb
|
||||
@ -678,7 +708,7 @@ export class UserAPI {
|
||||
if (n < 1) console.log(`Setting bpb to ${n}`);
|
||||
this.app.clock.time_signature[0] = n;
|
||||
return n;
|
||||
}
|
||||
};
|
||||
|
||||
public ppqn = (n?: number) => {
|
||||
/**
|
||||
@ -689,7 +719,7 @@ export class UserAPI {
|
||||
if (n < 1) console.log(`Setting ppqn to ${n}`);
|
||||
this.app.clock.ppqn = n;
|
||||
return n;
|
||||
}
|
||||
};
|
||||
|
||||
public time_signature = (numerator: number, denominator: number): void => {
|
||||
/**
|
||||
@ -700,7 +730,7 @@ export class UserAPI {
|
||||
* @returns The current time signature
|
||||
*/
|
||||
this.app.clock.time_signature = [numerator, denominator];
|
||||
}
|
||||
};
|
||||
|
||||
// =============================================================
|
||||
// Probability functions
|
||||
@ -713,7 +743,7 @@ export class UserAPI {
|
||||
* @returns True 10% of the time
|
||||
*/
|
||||
return Math.random() > 0.9;
|
||||
}
|
||||
};
|
||||
|
||||
public sometimes = (): boolean => {
|
||||
/**
|
||||
@ -722,7 +752,7 @@ export class UserAPI {
|
||||
* @returns True 50% of the time
|
||||
*/
|
||||
return Math.random() > 0.5;
|
||||
}
|
||||
};
|
||||
|
||||
public rarely = (): boolean => {
|
||||
/**
|
||||
@ -731,7 +761,7 @@ export class UserAPI {
|
||||
* @returns True 25% of the time
|
||||
*/
|
||||
return Math.random() > 0.75;
|
||||
}
|
||||
};
|
||||
|
||||
public often = (): boolean => {
|
||||
/**
|
||||
@ -740,7 +770,7 @@ export class UserAPI {
|
||||
* @returns True 75% of the time
|
||||
*/
|
||||
return Math.random() > 0.25;
|
||||
}
|
||||
};
|
||||
|
||||
public almostAlways = (): boolean => {
|
||||
/**
|
||||
@ -749,7 +779,7 @@ export class UserAPI {
|
||||
* @returns True 90% of the time
|
||||
*/
|
||||
return Math.random() > 0.1;
|
||||
}
|
||||
};
|
||||
|
||||
public dice = (sides: number): number => {
|
||||
/**
|
||||
@ -759,7 +789,7 @@ export class UserAPI {
|
||||
* @returns The value of a dice roll with n sides
|
||||
*/
|
||||
return Math.floor(Math.random() * sides) + 1;
|
||||
}
|
||||
};
|
||||
|
||||
// =============================================================
|
||||
// Iterator functions (for loops, with evaluation count, etc...)
|
||||
@ -773,12 +803,11 @@ export class UserAPI {
|
||||
*/
|
||||
if (n !== undefined) {
|
||||
this.app.universes[this.app.selected_universe].global.evaluations = n;
|
||||
return this.app.universes[this.app.selected_universe]
|
||||
return this.app.universes[this.app.selected_universe];
|
||||
}
|
||||
return this.app.universes[this.app.selected_universe]
|
||||
.global
|
||||
return this.app.universes[this.app.selected_universe].global
|
||||
.evaluations as number;
|
||||
}
|
||||
};
|
||||
|
||||
// =============================================================
|
||||
// Time markers
|
||||
@ -791,7 +820,7 @@ export class UserAPI {
|
||||
* @returns The current bar number
|
||||
*/
|
||||
return this.app.clock.time_position.bar;
|
||||
}
|
||||
};
|
||||
|
||||
tick = (): number => {
|
||||
/**
|
||||
@ -800,7 +829,7 @@ export class UserAPI {
|
||||
* @returns The current tick number
|
||||
*/
|
||||
return this.app.clock.tick;
|
||||
}
|
||||
};
|
||||
|
||||
pulse = (): number => {
|
||||
/**
|
||||
@ -809,7 +838,7 @@ export class UserAPI {
|
||||
* @returns The current pulse number
|
||||
*/
|
||||
return this.app.clock.time_position.pulse;
|
||||
}
|
||||
};
|
||||
|
||||
beat = (): number => {
|
||||
/**
|
||||
@ -818,28 +847,28 @@ export class UserAPI {
|
||||
* @returns The current beat number
|
||||
*/
|
||||
return this.app.clock.time_position.beat;
|
||||
}
|
||||
};
|
||||
|
||||
ebeat = (): number => {
|
||||
/**
|
||||
* Returns the current beat number since the origin of time
|
||||
*/
|
||||
return this.app.clock.beats_since_origin;
|
||||
}
|
||||
};
|
||||
|
||||
epulse = (): number => {
|
||||
/**
|
||||
* Returns the current number of pulses elapsed since origin of time
|
||||
*/
|
||||
return this.app.clock.pulses_since_origin;
|
||||
}
|
||||
};
|
||||
|
||||
onbar = (n: number, ...bar: number[]): boolean => {
|
||||
// n is acting as a modulo on the bar number
|
||||
const bar_list = [...Array(n).keys()].map((i) => i + 1);
|
||||
console.log(bar.some((b) => bar_list.includes(b % n)));
|
||||
return bar.some((b) => bar_list.includes(b % n));
|
||||
}
|
||||
};
|
||||
|
||||
onbeat = (...beat: number[]): boolean => {
|
||||
/**
|
||||
@ -853,7 +882,7 @@ export class UserAPI {
|
||||
*/
|
||||
let final_pulses: boolean[] = [];
|
||||
beat.forEach((b) => {
|
||||
b = (b % this.app.clock.time_signature[0]) + 1;
|
||||
b = (b % this.app.clock.time_signature[0]) + 1;
|
||||
let integral_part = Math.floor(b);
|
||||
let decimal_part = b - integral_part;
|
||||
final_pulses.push(
|
||||
@ -863,7 +892,7 @@ export class UserAPI {
|
||||
);
|
||||
});
|
||||
return final_pulses.some((p) => p == true);
|
||||
}
|
||||
};
|
||||
|
||||
stop = (): void => {
|
||||
/**
|
||||
@ -874,7 +903,7 @@ export class UserAPI {
|
||||
*/
|
||||
this.app.clock.pause();
|
||||
this.app.setButtonHighlighting("pause", true);
|
||||
}
|
||||
};
|
||||
silence = this.stop;
|
||||
hush = this.stop;
|
||||
|
||||
@ -886,7 +915,7 @@ export class UserAPI {
|
||||
* @returns True p% of the time
|
||||
*/
|
||||
return Math.random() * 100 < p;
|
||||
}
|
||||
};
|
||||
|
||||
toss = (): boolean => {
|
||||
/**
|
||||
@ -900,7 +929,7 @@ export class UserAPI {
|
||||
* @see almostNever
|
||||
*/
|
||||
return Math.random() > 0.5;
|
||||
}
|
||||
};
|
||||
|
||||
min = (...values: number[]): number => {
|
||||
/**
|
||||
@ -910,7 +939,7 @@ export class UserAPI {
|
||||
* @returns The minimum value of the list of numbers
|
||||
*/
|
||||
return Math.min(...values);
|
||||
}
|
||||
};
|
||||
|
||||
max = (...values: number[]): number => {
|
||||
/**
|
||||
@ -920,7 +949,7 @@ export class UserAPI {
|
||||
* @returns The maximum value of the list of numbers
|
||||
*/
|
||||
return Math.max(...values);
|
||||
}
|
||||
};
|
||||
|
||||
limit = (value: number, min: number, max: number): number => {
|
||||
/**
|
||||
@ -932,7 +961,7 @@ export class UserAPI {
|
||||
* @returns The limited value
|
||||
*/
|
||||
return Math.min(Math.max(value, min), max);
|
||||
}
|
||||
};
|
||||
|
||||
delay = (ms: number, func: Function): void => {
|
||||
/**
|
||||
@ -943,7 +972,7 @@ export class UserAPI {
|
||||
* @returns The current time signature
|
||||
*/
|
||||
setTimeout(func, ms);
|
||||
}
|
||||
};
|
||||
|
||||
delayr = (ms: number, nb: number, func: Function): void => {
|
||||
/**
|
||||
@ -958,7 +987,7 @@ export class UserAPI {
|
||||
list.forEach((ms, _) => {
|
||||
setTimeout(func, ms);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
mod = (...pulse: number[]): boolean => {
|
||||
/**
|
||||
@ -968,7 +997,7 @@ export class UserAPI {
|
||||
* @returns True if the current pulse is a modulo of any of the given pulses
|
||||
*/
|
||||
return pulse.some((p) => this.app.clock.time_position.pulse % p === 0);
|
||||
}
|
||||
};
|
||||
|
||||
modbar = (...bar: number[]): boolean => {
|
||||
/**
|
||||
@ -979,7 +1008,7 @@ export class UserAPI {
|
||||
*
|
||||
*/
|
||||
return bar.some((b) => this.app.clock.time_position.bar % b === 0);
|
||||
}
|
||||
};
|
||||
|
||||
// =============================================================
|
||||
// Rythmic generators
|
||||
@ -1001,7 +1030,7 @@ export class UserAPI {
|
||||
* @returns boolean value based on the euclidian sequence
|
||||
*/
|
||||
return this._euclidean_cycle(pulses, length, rotate)[iterator % length];
|
||||
}
|
||||
};
|
||||
|
||||
_euclidean_cycle(
|
||||
pulses: number,
|
||||
@ -1037,7 +1066,7 @@ export class UserAPI {
|
||||
let convert: string = n.toString(2);
|
||||
let tobin: boolean[] = convert.split("").map((x: string) => x === "1");
|
||||
return tobin[iterator % tobin.length];
|
||||
}
|
||||
};
|
||||
|
||||
// =============================================================
|
||||
// Low Frequency Oscillators
|
||||
@ -1063,7 +1092,7 @@ export class UserAPI {
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
sine = (freq: number = 1, offset: number = 0): number => {
|
||||
/**
|
||||
@ -1076,19 +1105,19 @@ export class UserAPI {
|
||||
return (
|
||||
Math.sin(this.app.clock.ctx.currentTime * Math.PI * 2 * freq) + offset
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
usine = (freq: number = 1, offset: number = 0): number => {
|
||||
/**
|
||||
* Returns a sine wave between 0 and 1.
|
||||
*
|
||||
*
|
||||
* @param freq - The frequency of the sine wave
|
||||
* @param offset - The offset of the sine wave
|
||||
* @returns A sine wave between 0 and 1
|
||||
* @see sine
|
||||
*/
|
||||
return (this.sine(freq, offset) + 1) / 2;
|
||||
}
|
||||
};
|
||||
|
||||
saw = (freq: number = 1, offset: number = 0): number => {
|
||||
/**
|
||||
@ -1103,19 +1132,19 @@ export class UserAPI {
|
||||
* @see noise
|
||||
*/
|
||||
return ((this.app.clock.ctx.currentTime * freq) % 1) * 2 - 1 + offset;
|
||||
}
|
||||
};
|
||||
|
||||
usaw = (freq: number = 1, offset: number = 0): number => {
|
||||
/**
|
||||
* Returns a saw wave between 0 and 1.
|
||||
*
|
||||
*
|
||||
* @param freq - The frequency of the saw wave
|
||||
* @param offset - The offset of the saw wave
|
||||
* @returns A saw wave between 0 and 1
|
||||
* @see saw
|
||||
*/
|
||||
return (this.saw(freq, offset) + 1) / 2;
|
||||
}
|
||||
};
|
||||
|
||||
triangle = (freq: number = 1, offset: number = 0): number => {
|
||||
/**
|
||||
@ -1128,19 +1157,19 @@ export class UserAPI {
|
||||
* @see noise
|
||||
*/
|
||||
return Math.abs(this.saw(freq, offset)) * 2 - 1;
|
||||
}
|
||||
};
|
||||
|
||||
utriangle = (freq: number = 1, offset: number = 0): number => {
|
||||
/**
|
||||
* Returns a triangle wave between 0 and 1.
|
||||
*
|
||||
*
|
||||
* @param freq - The frequency of the triangle wave
|
||||
* @param offset - The offset of the triangle wave
|
||||
* @returns A triangle wave between 0 and 1
|
||||
* @see triangle
|
||||
*/
|
||||
return (this.triangle(freq, offset) + 1) / 2;
|
||||
}
|
||||
};
|
||||
|
||||
square = (freq: number = 1, offset: number = 0): number => {
|
||||
/**
|
||||
@ -1153,19 +1182,19 @@ export class UserAPI {
|
||||
* @see noise
|
||||
*/
|
||||
return this.saw(freq, offset) > 0 ? 1 : -1;
|
||||
}
|
||||
};
|
||||
|
||||
usquare = (freq: number = 1, offset: number = 0): number => {
|
||||
/**
|
||||
* Returns a square wave between 0 and 1.
|
||||
*
|
||||
*
|
||||
* @param freq - The frequency of the square wave
|
||||
* @param offset - The offset of the square wave
|
||||
* @returns A square wave between 0 and 1
|
||||
* @see square
|
||||
*/
|
||||
return (this.square(freq, offset) + 1) / 2;
|
||||
}
|
||||
};
|
||||
|
||||
noise = (): number => {
|
||||
/**
|
||||
@ -1179,7 +1208,7 @@ export class UserAPI {
|
||||
* @see noise
|
||||
*/
|
||||
return Math.random() * 2 - 1;
|
||||
}
|
||||
};
|
||||
|
||||
// =============================================================
|
||||
// Math functions
|
||||
@ -1193,7 +1222,7 @@ export class UserAPI {
|
||||
|
||||
sound = (sound: string) => {
|
||||
return new Sound(sound, this.app);
|
||||
}
|
||||
};
|
||||
|
||||
samples = samples;
|
||||
|
||||
@ -1206,7 +1235,5 @@ export class UserAPI {
|
||||
// TODO: Implement this. This function should change the rate at which the global script
|
||||
// is evaluated. This is useful for slowing down the script, or speeding it up. The default
|
||||
// would be 1.0, which is the current rate (very speedy).
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user