Pre-update
This commit is contained in:
509
src/API.ts
509
src/API.ts
@ -22,244 +22,6 @@ interface ControlChange {
|
|||||||
value: number;
|
value: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ======================================================================
|
|
||||||
// Array prototype extensions: easier work with lists
|
|
||||||
// ======================================================================
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface Array<T> {
|
|
||||||
palindrome(): T[];
|
|
||||||
random(index: number): T;
|
|
||||||
rand(index: number): T;
|
|
||||||
degrade(amount: number): T;
|
|
||||||
repeatAll(amount: number): T;
|
|
||||||
repeatPair(amount: number): T;
|
|
||||||
repeatOdd(amount: number): T;
|
|
||||||
loop(index: number): T;
|
|
||||||
div(division: number): T;
|
|
||||||
shuffle(): this;
|
|
||||||
rotate(steps: number): this;
|
|
||||||
unique(): this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Array.prototype.shuffle = function () {
|
|
||||||
/**
|
|
||||||
* Shuffles the array in place.
|
|
||||||
*
|
|
||||||
* @returns The shuffled array
|
|
||||||
*/
|
|
||||||
let currentIndex = this.length,
|
|
||||||
randomIndex;
|
|
||||||
while (currentIndex !== 0) {
|
|
||||||
randomIndex = Math.floor(Math.random() * currentIndex);
|
|
||||||
currentIndex--;
|
|
||||||
[this[currentIndex], this[randomIndex]] = [
|
|
||||||
this[randomIndex],
|
|
||||||
this[currentIndex],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
Array.prototype.rotate = function (steps: number) {
|
|
||||||
/**
|
|
||||||
* Rotates the array in place.
|
|
||||||
*
|
|
||||||
* @param steps - The number of steps to rotate the array by
|
|
||||||
* @returns The rotated array
|
|
||||||
*/
|
|
||||||
const length = this.length;
|
|
||||||
if (steps < 0) {
|
|
||||||
steps = length + (steps % length);
|
|
||||||
} else if (steps > 0) {
|
|
||||||
steps = steps % length;
|
|
||||||
} else {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
const rotated = this.splice(-steps, steps);
|
|
||||||
this.unshift(...rotated);
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
Array.prototype.unique = function () {
|
|
||||||
/**
|
|
||||||
* Removes duplicate elements from the array in place.
|
|
||||||
*
|
|
||||||
* @returns The array without duplicates
|
|
||||||
*/
|
|
||||||
const seen = new Set();
|
|
||||||
let writeIndex = 0;
|
|
||||||
for (let readIndex = 0; readIndex < this.length; readIndex++) {
|
|
||||||
const value = this[readIndex];
|
|
||||||
if (!seen.has(value)) {
|
|
||||||
seen.add(value);
|
|
||||||
this[writeIndex++] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.length = writeIndex;
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
Array.prototype.degrade = function <T>(this: T[], amount: number) {
|
|
||||||
/**
|
|
||||||
* Removes elements from the array at random. If the array has
|
|
||||||
* only one element left, it will not be removed.
|
|
||||||
*
|
|
||||||
* @param amount - The amount of elements to remove
|
|
||||||
* @returns The degraded array
|
|
||||||
*/
|
|
||||||
if (amount < 0 || amount > 100) {
|
|
||||||
throw new Error("Amount should be between 0 and 100");
|
|
||||||
}
|
|
||||||
if (this.length <= 1) {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
for (let i = 0; i < this.length; ) {
|
|
||||||
const rand = Math.random() * 100;
|
|
||||||
if (rand < amount) {
|
|
||||||
if (this.length > 1) {
|
|
||||||
this.splice(i, 1);
|
|
||||||
} else {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
Array.prototype.repeatAll = function <T>(this: T[], amount: number) {
|
|
||||||
/**
|
|
||||||
* Repeats all elements in the array n times.
|
|
||||||
*
|
|
||||||
* @param amount - The amount of times to repeat the elements
|
|
||||||
* @returns The repeated array
|
|
||||||
*/
|
|
||||||
if (amount < 1) {
|
|
||||||
throw new Error("Amount should be at least 1");
|
|
||||||
}
|
|
||||||
let result = [];
|
|
||||||
for (let i = 0; i < this.length; i++) {
|
|
||||||
for (let j = 0; j < amount; j++) {
|
|
||||||
result.push(this[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.length = 0;
|
|
||||||
this.push(...result);
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
Array.prototype.repeatPair = function <T>(this: T[], amount: number) {
|
|
||||||
/**
|
|
||||||
* Repeats all elements in the array n times, except for the
|
|
||||||
* elements at odd indexes.
|
|
||||||
*
|
|
||||||
* @param amount - The amount of times to repeat the elements
|
|
||||||
* @returns The repeated array
|
|
||||||
*/
|
|
||||||
if (amount < 1) {
|
|
||||||
throw new Error("Amount should be at least 1");
|
|
||||||
}
|
|
||||||
|
|
||||||
let result = [];
|
|
||||||
|
|
||||||
for (let i = 0; i < this.length; i++) {
|
|
||||||
// If the index is even, repeat the element
|
|
||||||
if (i % 2 === 0) {
|
|
||||||
for (let j = 0; j < amount; j++) {
|
|
||||||
result.push(this[i]);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
result.push(this[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.length = 0;
|
|
||||||
this.push(...result);
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
Array.prototype.repeatOdd = function <T>(this: T[], amount: number) {
|
|
||||||
/**
|
|
||||||
* Repeats all elements in the array n times, except for the
|
|
||||||
* elements at even indexes.
|
|
||||||
*
|
|
||||||
* @param amount - The amount of times to repeat the elements
|
|
||||||
* @returns The repeated array
|
|
||||||
*
|
|
||||||
* @remarks
|
|
||||||
* This function is the opposite of repeatPair.
|
|
||||||
*/
|
|
||||||
if (amount < 1) {
|
|
||||||
throw new Error("Amount should be at least 1");
|
|
||||||
}
|
|
||||||
|
|
||||||
let result = [];
|
|
||||||
|
|
||||||
for (let i = 0; i < this.length; i++) {
|
|
||||||
// If the index is odd, repeat the element
|
|
||||||
if (i % 2 !== 0) {
|
|
||||||
for (let j = 0; j < amount; j++) {
|
|
||||||
result.push(this[i]);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
result.push(this[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the original array
|
|
||||||
this.length = 0;
|
|
||||||
this.push(...result);
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
Array.prototype.palindrome = function <T>() {
|
|
||||||
/**
|
|
||||||
* Returns a palindrome of the array.
|
|
||||||
*
|
|
||||||
* @returns The palindrome of the array
|
|
||||||
*/
|
|
||||||
let left_to_right = Array.from(this);
|
|
||||||
let right_to_left = Array.from(this.reverse());
|
|
||||||
return left_to_right.concat(right_to_left);
|
|
||||||
};
|
|
||||||
|
|
||||||
Array.prototype.loop = function <T>(this: T[], index: number): T {
|
|
||||||
/**
|
|
||||||
* Returns an element from the array based on the index.
|
|
||||||
* The index will wrap over the array.
|
|
||||||
*
|
|
||||||
* @param index - The index of the element to return
|
|
||||||
* @returns The element at the given index
|
|
||||||
*/
|
|
||||||
return this[index % this.length];
|
|
||||||
};
|
|
||||||
|
|
||||||
Array.prototype.random = function () {
|
|
||||||
/**
|
|
||||||
* Returns a random element from the array.
|
|
||||||
*
|
|
||||||
* @returns A random element from the array
|
|
||||||
*/
|
|
||||||
return this[Math.floor(Math.random() * this.length)];
|
|
||||||
};
|
|
||||||
Array.prototype.rand = Array.prototype.random;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is an override of the basic "includes" method.
|
|
||||||
*/
|
|
||||||
declare global {
|
|
||||||
interface Array<T> {
|
|
||||||
in(value: T): boolean;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Array.prototype.in = function <T>(this: T[], value: T): boolean {
|
|
||||||
return this.includes(value);
|
|
||||||
};
|
|
||||||
|
|
||||||
export async function loadSamples() {
|
export async function loadSamples() {
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
initAudioOnFirstClick(),
|
initAudioOnFirstClick(),
|
||||||
@ -270,10 +32,6 @@ export async function loadSamples() {
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const generateCacheKey = (...args: any[]): string => {
|
|
||||||
return args.map((arg) => JSON.stringify(arg)).join(",");
|
|
||||||
};
|
|
||||||
|
|
||||||
export class UserAPI {
|
export class UserAPI {
|
||||||
/**
|
/**
|
||||||
* The UserAPI class is the interface between the user's code and the backend. It provides
|
* The UserAPI class is the interface between the user's code and the backend. It provides
|
||||||
@ -546,6 +304,10 @@ export class UserAPI {
|
|||||||
input: string,
|
input: string,
|
||||||
options: { [key: string]: string | number } = {}
|
options: { [key: string]: string | number } = {}
|
||||||
) => {
|
) => {
|
||||||
|
const generateCacheKey = (...args: any[]): string => {
|
||||||
|
return args.map((arg) => JSON.stringify(arg)).join(",");
|
||||||
|
};
|
||||||
|
|
||||||
const key = generateCacheKey(input, options);
|
const key = generateCacheKey(input, options);
|
||||||
let player;
|
let player;
|
||||||
if (this.app.api.patternCache.has(key)) {
|
if (this.app.api.patternCache.has(key)) {
|
||||||
@ -562,7 +324,7 @@ export class UserAPI {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// =============================================================
|
// =============================================================
|
||||||
// Counter related functions
|
// Counter and iteration
|
||||||
// =============================================================
|
// =============================================================
|
||||||
|
|
||||||
public counter = (
|
public counter = (
|
||||||
@ -617,6 +379,24 @@ export class UserAPI {
|
|||||||
};
|
};
|
||||||
$ = this.counter;
|
$ = this.counter;
|
||||||
|
|
||||||
|
// =============================================================
|
||||||
|
// Iterator functions (for loops, with evaluation count, etc...)
|
||||||
|
// =============================================================
|
||||||
|
|
||||||
|
i = (n?: number) => {
|
||||||
|
/**
|
||||||
|
* Returns the current iteration of global file.
|
||||||
|
*
|
||||||
|
* @returns The current iteration of global file
|
||||||
|
*/
|
||||||
|
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].global
|
||||||
|
.evaluations as number;
|
||||||
|
};
|
||||||
|
|
||||||
// =============================================================
|
// =============================================================
|
||||||
// Drunk mechanism
|
// Drunk mechanism
|
||||||
// =============================================================
|
// =============================================================
|
||||||
@ -708,80 +488,6 @@ export class UserAPI {
|
|||||||
};
|
};
|
||||||
cv = this.clear_variables;
|
cv = this.clear_variables;
|
||||||
|
|
||||||
// =============================================================
|
|
||||||
// Sequencer related functions
|
|
||||||
// =============================================================
|
|
||||||
|
|
||||||
public div = (chunk: number): boolean => {
|
|
||||||
const time_pos = this.epulse();
|
|
||||||
const current_chunk = Math.floor(
|
|
||||||
time_pos / Math.floor(chunk * this.ppqn())
|
|
||||||
);
|
|
||||||
return current_chunk % 2 === 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
public divbar = (chunk: number): boolean => {
|
|
||||||
const time_pos = this.bar() - 1;
|
|
||||||
const current_chunk = Math.floor(time_pos / chunk);
|
|
||||||
return current_chunk % 2 === 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
public divseq = (...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 = this.epulse();
|
|
||||||
const slice_count = Math.floor(
|
|
||||||
timepos / Math.floor(chunk_size * this.ppqn())
|
|
||||||
);
|
|
||||||
return elements[slice_count % elements.length];
|
|
||||||
};
|
|
||||||
|
|
||||||
pick = <T>(...array: T[]): T => {
|
|
||||||
/**
|
|
||||||
* Returns a random element from an array.
|
|
||||||
*
|
|
||||||
* @param array - The array of values to pick from
|
|
||||||
*/
|
|
||||||
return array[Math.floor(this.randomGen() * array.length)];
|
|
||||||
};
|
|
||||||
|
|
||||||
seqbeat = <T>(...array: T[]): T => {
|
|
||||||
/**
|
|
||||||
* Returns an element from an array based on the current beat.
|
|
||||||
*
|
|
||||||
* @param array - The array of values to pick from
|
|
||||||
*/
|
|
||||||
return array[this.ebeat() % array.length];
|
|
||||||
};
|
|
||||||
|
|
||||||
mel = <T>(iterator: number, array: T[]): T => {
|
|
||||||
/**
|
|
||||||
* Returns an element from an array based on the current value of an iterator.
|
|
||||||
*
|
|
||||||
* @param iterator - The name of the iterator
|
|
||||||
* @param array - The array of values to pick from
|
|
||||||
*/
|
|
||||||
return array[iterator % array.length];
|
|
||||||
};
|
|
||||||
|
|
||||||
seqbar = <T>(...array: T[]): T => {
|
|
||||||
/**
|
|
||||||
* Returns an element from an array based on the current bar.
|
|
||||||
*
|
|
||||||
* @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 => {
|
|
||||||
/**
|
|
||||||
* Returns an element from an array based on the current pulse.
|
|
||||||
*
|
|
||||||
* @param array - The array of values to pick from
|
|
||||||
*/
|
|
||||||
return array[this.app.clock.time_position.pulse % array.length];
|
|
||||||
};
|
|
||||||
|
|
||||||
// =============================================================
|
// =============================================================
|
||||||
// Randomness functions
|
// Randomness functions
|
||||||
// =============================================================
|
// =============================================================
|
||||||
@ -807,6 +513,7 @@ export class UserAPI {
|
|||||||
*/
|
*/
|
||||||
return this.randomGen() * (max - min) + min;
|
return this.randomGen() * (max - min) + min;
|
||||||
};
|
};
|
||||||
|
|
||||||
irand = this.randI;
|
irand = this.randI;
|
||||||
rI = this.randI;
|
rI = this.randI;
|
||||||
r = this.rand;
|
r = this.rand;
|
||||||
@ -1049,24 +756,6 @@ export class UserAPI {
|
|||||||
return Math.floor(this.randomGen() * sides) + 1;
|
return Math.floor(this.randomGen() * sides) + 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
// =============================================================
|
|
||||||
// Iterator functions (for loops, with evaluation count, etc...)
|
|
||||||
// =============================================================
|
|
||||||
|
|
||||||
i = (n?: number) => {
|
|
||||||
/**
|
|
||||||
* Returns the current iteration of global file.
|
|
||||||
*
|
|
||||||
* @returns The current iteration of global file
|
|
||||||
*/
|
|
||||||
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].global
|
|
||||||
.evaluations as number;
|
|
||||||
};
|
|
||||||
|
|
||||||
// =============================================================
|
// =============================================================
|
||||||
// Time markers
|
// Time markers
|
||||||
// =============================================================
|
// =============================================================
|
||||||
@ -1125,6 +814,41 @@ export class UserAPI {
|
|||||||
// Time Filters
|
// Time Filters
|
||||||
// =============================================================
|
// =============================================================
|
||||||
|
|
||||||
|
public mod = (...n: number[]): boolean => {
|
||||||
|
const results: boolean[] = n.map(
|
||||||
|
(value) => this.epulse() % Math.floor(value * this.ppqn()) === 0
|
||||||
|
);
|
||||||
|
return results.some((value) => value === true);
|
||||||
|
};
|
||||||
|
|
||||||
|
public modpulse = (...n: number[]): boolean => {
|
||||||
|
const results: boolean[] = n.map((value) => this.epulse() % value === 0);
|
||||||
|
return results.some((value) => value === true);
|
||||||
|
};
|
||||||
|
pmod = this.modpulse;
|
||||||
|
|
||||||
|
public modbar = (...n: number[]): boolean => {
|
||||||
|
const results: boolean[] = n.map(
|
||||||
|
(value) => this.bar() % Math.floor(value * this.ppqn()) === 0
|
||||||
|
);
|
||||||
|
return results.some((value) => value === true);
|
||||||
|
};
|
||||||
|
bmod = this.modbar;
|
||||||
|
|
||||||
|
public div = (chunk: number): boolean => {
|
||||||
|
const time_pos = this.epulse();
|
||||||
|
const current_chunk = Math.floor(
|
||||||
|
time_pos / Math.floor(chunk * this.ppqn())
|
||||||
|
);
|
||||||
|
return current_chunk % 2 === 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
public divbar = (chunk: number): boolean => {
|
||||||
|
const time_pos = this.bar() - 1;
|
||||||
|
const current_chunk = Math.floor(time_pos / chunk);
|
||||||
|
return current_chunk % 2 === 0;
|
||||||
|
};
|
||||||
|
|
||||||
onbar = (n: number, ...bar: number[]): boolean => {
|
onbar = (n: number, ...bar: number[]): boolean => {
|
||||||
// n is acting as a modulo on the bar number
|
// n is acting as a modulo on the bar number
|
||||||
const bar_list = [...Array(n).keys()].map((i) => i + 1);
|
const bar_list = [...Array(n).keys()].map((i) => i + 1);
|
||||||
@ -1157,51 +881,9 @@ export class UserAPI {
|
|||||||
return final_pulses.some((p) => p == true);
|
return final_pulses.some((p) => p == true);
|
||||||
};
|
};
|
||||||
|
|
||||||
public min = (...values: number[]): number => {
|
// ======================================================================
|
||||||
/**
|
// Delay related functions
|
||||||
* Returns the minimum value of a list of numbers.
|
// ======================================================================
|
||||||
*
|
|
||||||
* @param values - The list of numbers
|
|
||||||
* @returns The minimum value of the list of numbers
|
|
||||||
*/
|
|
||||||
return Math.min(...values);
|
|
||||||
};
|
|
||||||
|
|
||||||
public max = (...values: number[]): number => {
|
|
||||||
/**
|
|
||||||
* Returns the maximum value of a list of numbers.
|
|
||||||
*
|
|
||||||
* @param values - The list of numbers
|
|
||||||
* @returns The maximum value of the list of numbers
|
|
||||||
*/
|
|
||||||
return Math.max(...values);
|
|
||||||
};
|
|
||||||
|
|
||||||
public mean = (...values: number[]): number => {
|
|
||||||
/**
|
|
||||||
* Returns the mean of a list of numbers.
|
|
||||||
*
|
|
||||||
* @param values - The list of numbers
|
|
||||||
* @returns The mean value of the list of numbers
|
|
||||||
*/
|
|
||||||
const sum = values.reduce(
|
|
||||||
(accumulator, currentValue) => accumulator + currentValue,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
return sum / values.length;
|
|
||||||
};
|
|
||||||
|
|
||||||
limit = (value: number, min: number, max: number): number => {
|
|
||||||
/**
|
|
||||||
* Limits a value between a minimum and a maximum.
|
|
||||||
*
|
|
||||||
* @param value - The value to limit
|
|
||||||
* @param min - The minimum value
|
|
||||||
* @param max - The maximum value
|
|
||||||
* @returns The limited value
|
|
||||||
*/
|
|
||||||
return Math.min(Math.max(value, min), max);
|
|
||||||
};
|
|
||||||
|
|
||||||
delay = (ms: number, func: Function): void => {
|
delay = (ms: number, func: Function): void => {
|
||||||
/**
|
/**
|
||||||
@ -1229,27 +911,6 @@ export class UserAPI {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
public mod = (...n: number[]): boolean => {
|
|
||||||
const results: boolean[] = n.map(
|
|
||||||
(value) => this.epulse() % Math.floor(value * this.ppqn()) === 0
|
|
||||||
);
|
|
||||||
return results.some((value) => value === true);
|
|
||||||
};
|
|
||||||
|
|
||||||
public modpulse = (...n: number[]): boolean => {
|
|
||||||
const results: boolean[] = n.map((value) => this.epulse() % value === 0);
|
|
||||||
return results.some((value) => value === true);
|
|
||||||
};
|
|
||||||
pmod = this.modpulse;
|
|
||||||
|
|
||||||
public modbar = (...n: number[]): boolean => {
|
|
||||||
const results: boolean[] = n.map(
|
|
||||||
(value) => this.bar() % Math.floor(value * this.ppqn()) === 0
|
|
||||||
);
|
|
||||||
return results.some((value) => value === true);
|
|
||||||
};
|
|
||||||
bmod = this.modbar;
|
|
||||||
|
|
||||||
// =============================================================
|
// =============================================================
|
||||||
// Rythmic generators
|
// Rythmic generators
|
||||||
// =============================================================
|
// =============================================================
|
||||||
@ -1465,6 +1126,52 @@ export class UserAPI {
|
|||||||
// Math functions
|
// Math functions
|
||||||
// =============================================================
|
// =============================================================
|
||||||
|
|
||||||
|
public min = (...values: number[]): number => {
|
||||||
|
/**
|
||||||
|
* Returns the minimum value of a list of numbers.
|
||||||
|
*
|
||||||
|
* @param values - The list of numbers
|
||||||
|
* @returns The minimum value of the list of numbers
|
||||||
|
*/
|
||||||
|
return Math.min(...values);
|
||||||
|
};
|
||||||
|
|
||||||
|
public max = (...values: number[]): number => {
|
||||||
|
/**
|
||||||
|
* Returns the maximum value of a list of numbers.
|
||||||
|
*
|
||||||
|
* @param values - The list of numbers
|
||||||
|
* @returns The maximum value of the list of numbers
|
||||||
|
*/
|
||||||
|
return Math.max(...values);
|
||||||
|
};
|
||||||
|
|
||||||
|
public mean = (...values: number[]): number => {
|
||||||
|
/**
|
||||||
|
* Returns the mean of a list of numbers.
|
||||||
|
*
|
||||||
|
* @param values - The list of numbers
|
||||||
|
* @returns The mean value of the list of numbers
|
||||||
|
*/
|
||||||
|
const sum = values.reduce(
|
||||||
|
(accumulator, currentValue) => accumulator + currentValue,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
return sum / values.length;
|
||||||
|
};
|
||||||
|
|
||||||
|
limit = (value: number, min: number, max: number): number => {
|
||||||
|
/**
|
||||||
|
* Limits a value between a minimum and a maximum.
|
||||||
|
*
|
||||||
|
* @param value - The value to limit
|
||||||
|
* @param min - The minimum value
|
||||||
|
* @param max - The maximum value
|
||||||
|
* @returns The limited value
|
||||||
|
*/
|
||||||
|
return Math.min(Math.max(value, min), max);
|
||||||
|
};
|
||||||
|
|
||||||
abs = Math.abs;
|
abs = Math.abs;
|
||||||
|
|
||||||
// =============================================================
|
// =============================================================
|
||||||
|
|||||||
280
src/ArrayExtensions.ts
Normal file
280
src/ArrayExtensions.ts
Normal file
@ -0,0 +1,280 @@
|
|||||||
|
import { type UserAPI } from "./API";
|
||||||
|
export {};
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface Array<T> {
|
||||||
|
palindrome(): T[];
|
||||||
|
random(index: number): T;
|
||||||
|
rand(index: number): T;
|
||||||
|
degrade(amount: number): T;
|
||||||
|
repeatAll(amount: number): T;
|
||||||
|
repeatPair(amount: number): T;
|
||||||
|
repeatOdd(amount: number): T;
|
||||||
|
beat(): T;
|
||||||
|
bar(): T;
|
||||||
|
pulse(): T;
|
||||||
|
pick(): T;
|
||||||
|
loop(index: number): T;
|
||||||
|
div(division: number): T;
|
||||||
|
shuffle(): this;
|
||||||
|
rotate(steps: number): this;
|
||||||
|
unique(): this;
|
||||||
|
in(value: T): boolean;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const makeArrayExtensions = (api: UserAPI) => {
|
||||||
|
Array.prototype.in = function <T>(this: T[], value: T): boolean {
|
||||||
|
return this.includes(value);
|
||||||
|
};
|
||||||
|
|
||||||
|
Array.prototype.pick = function () {
|
||||||
|
/**
|
||||||
|
* Returns a random element from an array.
|
||||||
|
*
|
||||||
|
* @param array - The array of values to pick from
|
||||||
|
*/
|
||||||
|
return this[Math.floor(api.randomGen() * this.length)];
|
||||||
|
};
|
||||||
|
|
||||||
|
Array.prototype.beat = function () {
|
||||||
|
/**
|
||||||
|
* Returns the element corresponding to the current beat
|
||||||
|
*
|
||||||
|
* @returns The element corresponding to the current beat
|
||||||
|
*/
|
||||||
|
return this[api.ebeat() % this.length];
|
||||||
|
};
|
||||||
|
|
||||||
|
Array.prototype.bar = function () {
|
||||||
|
/**
|
||||||
|
* Returns an element from an array based on the current bar.
|
||||||
|
*
|
||||||
|
* @param array - The array of values to pick from
|
||||||
|
*/
|
||||||
|
return this[(api.app.clock.time_position.bar + 1) % this.length];
|
||||||
|
};
|
||||||
|
|
||||||
|
Array.prototype.pulse = function () {
|
||||||
|
/**
|
||||||
|
* Returns an element from an array based on the current pulse.
|
||||||
|
*
|
||||||
|
* @param array - The array of values to pick from
|
||||||
|
*/
|
||||||
|
return this[api.app.clock.time_position.pulse % this.length];
|
||||||
|
};
|
||||||
|
|
||||||
|
Array.prototype.div = function (divisor: number) {
|
||||||
|
const chunk_size = divisor; // Get the first argument (chunk size)
|
||||||
|
const timepos = api.epulse();
|
||||||
|
const slice_count = Math.floor(
|
||||||
|
timepos / Math.floor(chunk_size * api.ppqn())
|
||||||
|
);
|
||||||
|
return this[slice_count % this.length];
|
||||||
|
};
|
||||||
|
|
||||||
|
Array.prototype.shuffle = function () {
|
||||||
|
/**
|
||||||
|
* Shuffles the array in place.
|
||||||
|
*
|
||||||
|
* @returns The shuffled array
|
||||||
|
*/
|
||||||
|
let currentIndex = this.length,
|
||||||
|
randomIndex;
|
||||||
|
while (currentIndex !== 0) {
|
||||||
|
randomIndex = Math.floor(Math.random() * currentIndex);
|
||||||
|
currentIndex--;
|
||||||
|
[this[currentIndex], this[randomIndex]] = [
|
||||||
|
this[randomIndex],
|
||||||
|
this[currentIndex],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
Array.prototype.rotate = function (steps: number) {
|
||||||
|
/**
|
||||||
|
* Rotates the array in place.
|
||||||
|
*
|
||||||
|
* @param steps - The number of steps to rotate the array by
|
||||||
|
* @returns The rotated array
|
||||||
|
*/
|
||||||
|
const length = this.length;
|
||||||
|
if (steps < 0) {
|
||||||
|
steps = length + (steps % length);
|
||||||
|
} else if (steps > 0) {
|
||||||
|
steps = steps % length;
|
||||||
|
} else {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
const rotated = this.splice(-steps, steps);
|
||||||
|
this.unshift(...rotated);
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
Array.prototype.unique = function () {
|
||||||
|
/**
|
||||||
|
* Removes duplicate elements from the array in place.
|
||||||
|
*
|
||||||
|
* @returns The array without duplicates
|
||||||
|
*/
|
||||||
|
const seen = new Set();
|
||||||
|
let writeIndex = 0;
|
||||||
|
for (let readIndex = 0; readIndex < this.length; readIndex++) {
|
||||||
|
const value = this[readIndex];
|
||||||
|
if (!seen.has(value)) {
|
||||||
|
seen.add(value);
|
||||||
|
this[writeIndex++] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.length = writeIndex;
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
Array.prototype.degrade = function <T>(this: T[], amount: number) {
|
||||||
|
/**
|
||||||
|
* Removes elements from the array at random. If the array has
|
||||||
|
* only one element left, it will not be removed.
|
||||||
|
*
|
||||||
|
* @param amount - The amount of elements to remove
|
||||||
|
* @returns The degraded array
|
||||||
|
*/
|
||||||
|
if (amount < 0 || amount > 100) {
|
||||||
|
throw new Error("Amount should be between 0 and 100");
|
||||||
|
}
|
||||||
|
if (this.length <= 1) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
for (let i = 0; i < this.length; ) {
|
||||||
|
const rand = Math.random() * 100;
|
||||||
|
if (rand < amount) {
|
||||||
|
if (this.length > 1) {
|
||||||
|
this.splice(i, 1);
|
||||||
|
} else {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
Array.prototype.repeatAll = function <T>(this: T[], amount: number) {
|
||||||
|
/**
|
||||||
|
* Repeats all elements in the array n times.
|
||||||
|
*
|
||||||
|
* @param amount - The amount of times to repeat the elements
|
||||||
|
* @returns The repeated array
|
||||||
|
*/
|
||||||
|
if (amount < 1) {
|
||||||
|
throw new Error("Amount should be at least 1");
|
||||||
|
}
|
||||||
|
let result = [];
|
||||||
|
for (let i = 0; i < this.length; i++) {
|
||||||
|
for (let j = 0; j < amount; j++) {
|
||||||
|
result.push(this[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.length = 0;
|
||||||
|
this.push(...result);
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
Array.prototype.repeatPair = function <T>(this: T[], amount: number) {
|
||||||
|
/**
|
||||||
|
* Repeats all elements in the array n times, except for the
|
||||||
|
* elements at odd indexes.
|
||||||
|
*
|
||||||
|
* @param amount - The amount of times to repeat the elements
|
||||||
|
* @returns The repeated array
|
||||||
|
*/
|
||||||
|
if (amount < 1) {
|
||||||
|
throw new Error("Amount should be at least 1");
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < this.length; i++) {
|
||||||
|
// If the index is even, repeat the element
|
||||||
|
if (i % 2 === 0) {
|
||||||
|
for (let j = 0; j < amount; j++) {
|
||||||
|
result.push(this[i]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result.push(this[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.length = 0;
|
||||||
|
this.push(...result);
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
Array.prototype.repeatOdd = function <T>(this: T[], amount: number) {
|
||||||
|
/**
|
||||||
|
* Repeats all elements in the array n times, except for the
|
||||||
|
* elements at even indexes.
|
||||||
|
*
|
||||||
|
* @param amount - The amount of times to repeat the elements
|
||||||
|
* @returns The repeated array
|
||||||
|
*
|
||||||
|
* @remarks
|
||||||
|
* This function is the opposite of repeatPair.
|
||||||
|
*/
|
||||||
|
if (amount < 1) {
|
||||||
|
throw new Error("Amount should be at least 1");
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < this.length; i++) {
|
||||||
|
// If the index is odd, repeat the element
|
||||||
|
if (i % 2 !== 0) {
|
||||||
|
for (let j = 0; j < amount; j++) {
|
||||||
|
result.push(this[i]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result.push(this[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the original array
|
||||||
|
this.length = 0;
|
||||||
|
this.push(...result);
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
Array.prototype.palindrome = function <T>() {
|
||||||
|
/**
|
||||||
|
* Returns a palindrome of the array.
|
||||||
|
*
|
||||||
|
* @returns The palindrome of the array
|
||||||
|
*/
|
||||||
|
let left_to_right = Array.from(this);
|
||||||
|
let right_to_left = Array.from(this.reverse());
|
||||||
|
return left_to_right.concat(right_to_left);
|
||||||
|
};
|
||||||
|
|
||||||
|
Array.prototype.loop = function (index: number) {
|
||||||
|
/**
|
||||||
|
* Returns an element from the array based on the index.
|
||||||
|
* The index will wrap over the array.
|
||||||
|
*
|
||||||
|
* @param index - The index of the element to return
|
||||||
|
* @returns The element at the given index
|
||||||
|
*/
|
||||||
|
return this[index % this.length];
|
||||||
|
};
|
||||||
|
|
||||||
|
Array.prototype.random = function () {
|
||||||
|
/**
|
||||||
|
* Returns a random element from the array.
|
||||||
|
*
|
||||||
|
* @returns A random element from the array
|
||||||
|
*/
|
||||||
|
return this[Math.floor(Math.random() * this.length)];
|
||||||
|
};
|
||||||
|
Array.prototype.rand = Array.prototype.random;
|
||||||
|
};
|
||||||
@ -61,9 +61,9 @@ Press ${key_shortcut(
|
|||||||
bpm(80)
|
bpm(80)
|
||||||
mod(0.25) :: sound('sawtooth')
|
mod(0.25) :: sound('sawtooth')
|
||||||
.note(seqbar(
|
.note(seqbar(
|
||||||
pick(60, 67, 63) - 12, pick(60, 67, 63) - 12,
|
[60, 67, 63].pick() - 12, [60, 67, 63].pick() - 12,
|
||||||
pick(60, 67, 63) - 12 + 5, pick(60, 67, 63) - 12 + 5,
|
[60, 67, 63].pick() - 12 + 5, [60, 67, 63].pick() - 12 + 5,
|
||||||
pick(60, 67, 63) - 12 + 7, pick(60, 67, 63) - 12 + 7) + (sometimes() ? 24 : 12)
|
[60, 67, 63].pick() - 12 + 7, [60, 67, 63].pick() - 12 + 7) + (sometimes() ? 24 : 12)
|
||||||
)
|
)
|
||||||
.sustain(0.1).fmi(8).fmh(4).room(0.9)
|
.sustain(0.1).fmi(8).fmh(4).room(0.9)
|
||||||
.gain(0.75).cutoff(500 + usine(8) * 10000)
|
.gain(0.75).cutoff(500 + usine(8) * 10000)
|
||||||
@ -210,10 +210,10 @@ if (div(16)) {
|
|||||||
mod(1.5)::snd('kick').out()
|
mod(1.5)::snd('kick').out()
|
||||||
mod(2)::snd('snare').out()
|
mod(2)::snd('snare').out()
|
||||||
mod(.5)::snd('hh').out()
|
mod(.5)::snd('hh').out()
|
||||||
mod(.5)::snd('tabla').speed(pick(1,2)).end(0.5).out()
|
mod(.5)::snd('tabla').speed([1,2].pick()).end(0.5).out()
|
||||||
mod(2.34)::snd('birds').n(irand(1,10))
|
mod(2.34)::snd('birds').n(irand(1,10))
|
||||||
.delay(0.5).delaytime(0.5).delayfb(0.25).out()
|
.delay(0.5).delaytime(0.5).delayfb(0.25).out()
|
||||||
mod(.5)::snd('diphone').end(0.5).n(pick(1,2,3,4)).out()
|
mod(.5)::snd('diphone').end(0.5).n([1,2,3,4].pick()).out()
|
||||||
}
|
}
|
||||||
\`\`\`
|
\`\`\`
|
||||||
|
|
||||||
@ -295,7 +295,7 @@ You can use Topos to play MIDI thanks to the [WebMIDI API](https://developer.moz
|
|||||||
\`\`\`javascript
|
\`\`\`javascript
|
||||||
bpm(80) // Setting a default BPM
|
bpm(80) // Setting a default BPM
|
||||||
mod(.5) && midi(36 + seqbeat(0,12)).sustain(0.02).out()
|
mod(.5) && midi(36 + seqbeat(0,12)).sustain(0.02).out()
|
||||||
mod(.25) && midi(pick(64, 76)).sustain(0.05).out()
|
mod(.25) && midi([64, 76].pick()).sustain(0.05).out()
|
||||||
mod(.75) && midi(seqbeat(64, 67, 69)).sustain(0.05).out()
|
mod(.75) && midi(seqbeat(64, 67, 69)).sustain(0.05).out()
|
||||||
sometimes() && mod(.25) && midi(seqbeat(64, 67, 69) + 24).sustain(0.05).out()
|
sometimes() && mod(.25) && midi(seqbeat(64, 67, 69) + 24).sustain(0.05).out()
|
||||||
\`\`\`
|
\`\`\`
|
||||||
@ -318,15 +318,15 @@ mod(0.25) && midi(60)
|
|||||||
- <icode>control_change({control: number, value: number, channel: number})</icode>: send a MIDI Control Change. This function takes a single object argument to specify the control message (_e.g._ <icode>control_change({control: 1, value: 127, channel: 1})</icode>).
|
- <icode>control_change({control: number, value: number, channel: number})</icode>: send a MIDI Control Change. This function takes a single object argument to specify the control message (_e.g._ <icode>control_change({control: 1, value: 127, channel: 1})</icode>).
|
||||||
|
|
||||||
\`\`\`javascript
|
\`\`\`javascript
|
||||||
control_change({control: pick(24,25), value: rI(1,120), channel: 1}))})
|
control_change({control: [24,25].pick(), value: rI(1,120), channel: 1}))})
|
||||||
control_change({control: pick(30,35), value: rI(1,120) / 2, channel: 1}))})
|
control_change({control: [30,35].pick(), value: rI(1,120) / 2, channel: 1}))})
|
||||||
\`\`\`
|
\`\`\`
|
||||||
|
|
||||||
|
|
||||||
- <icode>program_change(program: number, channel: number)</icode>: send a MIDI Program Change. This function takes two arguments to specify the program and the channel (_e.g._ <icode>program_change(1, 1)</icode>).
|
- <icode>program_change(program: number, channel: number)</icode>: send a MIDI Program Change. This function takes two arguments to specify the program and the channel (_e.g._ <icode>program_change(1, 1)</icode>).
|
||||||
|
|
||||||
\`\`\`javascript
|
\`\`\`javascript
|
||||||
program_change(pick(1,2,3,4,5,6,7,8), 1)
|
program_change([1,2,3,4,5,6,7,8].pick(), 1)
|
||||||
\`\`\`
|
\`\`\`
|
||||||
|
|
||||||
|
|
||||||
@ -410,7 +410,7 @@ When you type <icode>kick</icode> in the <icode>sound('kick').out()</icode> expr
|
|||||||
The <icode>.n(number)</icode> method can be used to pick a sample from the currently selected sample folder. For instance, the following script will play a random sample from the _kick_ folder:
|
The <icode>.n(number)</icode> method can be used to pick a sample from the currently selected sample folder. For instance, the following script will play a random sample from the _kick_ folder:
|
||||||
|
|
||||||
\`\`\`javascript
|
\`\`\`javascript
|
||||||
mod(1) && sound('kick').n(pick(1,2,3,4,5,6,7,8)).out()
|
mod(1) && sound('kick').n([1,2,3,4,5,6,7,8].pick()).out()
|
||||||
\`\`\`
|
\`\`\`
|
||||||
|
|
||||||
Don't worry about the number. If it gets too big, it will be automatically wrapped to the number of samples in the folder. You can type any number, it will always fall on a sample. Let's use our mouse to select a sample number in a folder:
|
Don't worry about the number. If it gets too big, it will be automatically wrapped to the number of samples in the folder. You can type any number, it will always fall on a sample. Let's use our mouse to select a sample number in a folder:
|
||||||
@ -427,7 +427,7 @@ mod(.25) && sound('numbers').n(Math.floor(mouseX())).out()
|
|||||||
As we said earlier, the <icode>sound('sample_name')</icode> function can be chained to _specify_ a sound more. For instance, you can add a filter and some effects to your high-hat:
|
As we said earlier, the <icode>sound('sample_name')</icode> function can be chained to _specify_ a sound more. For instance, you can add a filter and some effects to your high-hat:
|
||||||
\`\`\`javascript
|
\`\`\`javascript
|
||||||
mod(0.5) && sound('hh')
|
mod(0.5) && sound('hh')
|
||||||
.sometimes(s=>s.speed(pick(1,5,10)))
|
.sometimes(s=>s.speed([1,5,10].pick()))
|
||||||
.room(0.5)
|
.room(0.5)
|
||||||
.cutoff(usine(2) * 5000)
|
.cutoff(usine(2) * 5000)
|
||||||
.out()
|
.out()
|
||||||
@ -479,7 +479,7 @@ Note that the **sustain** value is not a duration but an amplitude value (how lo
|
|||||||
mod(4)::sound('sawtooth').note(50).decay(0.5).sustain(0.5).release(2).out();
|
mod(4)::sound('sawtooth').note(50).decay(0.5).sustain(0.5).release(2).out();
|
||||||
mod(2)::sound('sawtooth').note(50+7).decay(0.5).sustain(0.6).release(2).out();
|
mod(2)::sound('sawtooth').note(50+7).decay(0.5).sustain(0.6).release(2).out();
|
||||||
mod(1)::sound('sawtooth').note(50+12).decay(0.5).sustain(0.7).release(2).out();
|
mod(1)::sound('sawtooth').note(50+12).decay(0.5).sustain(0.7).release(2).out();
|
||||||
mod(.25)::sound('sawtooth').note(pick(50,57,62)+divseq(2, 12, 24, 0))
|
mod(.25)::sound('sawtooth').note([50,57,62].pick() + [12, 24, 0].div(2))
|
||||||
.cutoff(5000).sustain(0.5).release(0.1).out()
|
.cutoff(5000).sustain(0.5).release(0.1).out()
|
||||||
\`\`\`
|
\`\`\`
|
||||||
|
|
||||||
@ -500,8 +500,8 @@ There are some basic controls over the playback of each sample. This allows you
|
|||||||
\`\`\`javascript
|
\`\`\`javascript
|
||||||
// Using some of the modifiers described above :)
|
// Using some of the modifiers described above :)
|
||||||
mod(.5)::snd('pad').begin(0.2)
|
mod(.5)::snd('pad').begin(0.2)
|
||||||
.speed(divseq(4, 1, 0.9, 0.8))
|
.speed([1, 0.9, 0.8].div(4))
|
||||||
.n(divseq(2, 0, 0, 2, 4)).pan(usine(.5))
|
.n([0, 0, 2, 4].div(4)).pan(usine(.5))
|
||||||
.end(rand(0.3,0.8))
|
.end(rand(0.3,0.8))
|
||||||
.room(0.8).size(0.5)
|
.room(0.8).size(0.5)
|
||||||
.clip(1).out()
|
.clip(1).out()
|
||||||
@ -524,8 +524,8 @@ There are three basic filters: a _lowpass_, _highpass_ and _bandpass_ filters wi
|
|||||||
|
|
||||||
\`\`\`javascript
|
\`\`\`javascript
|
||||||
mod(.5) && snd('sawtooth')
|
mod(.5) && snd('sawtooth')
|
||||||
.cutoff(pick(2000,500) + usine(.5) * 4000)
|
.cutoff([2000,500].pick() + usine(.5) * 4000)
|
||||||
.resonance(0.9).freq(pick(100,150))
|
.resonance(0.9).freq([100,150].pick())
|
||||||
.out()
|
.out()
|
||||||
\`\`\`
|
\`\`\`
|
||||||
|
|
||||||
@ -569,7 +569,7 @@ mod(1)::snd('kick').out()
|
|||||||
|
|
||||||
\`\`\`javascript
|
\`\`\`javascript
|
||||||
mod(.5)::snd('pad').coarse($(1) % 16).clip(.5).out(); // Comment me
|
mod(.5)::snd('pad').coarse($(1) % 16).clip(.5).out(); // Comment me
|
||||||
mod(.5)::snd('pad').crush(divseq(2, 16, 8, 4)).clip(.5).out()
|
mod(.5)::snd('pad').crush([16, 8, 4].div(2)).clip(.5).out()
|
||||||
\`\`\`
|
\`\`\`
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@ -589,9 +589,15 @@ ${injectAvailableSamples(application)}
|
|||||||
const patterns: string = `
|
const patterns: string = `
|
||||||
# Patterns
|
# Patterns
|
||||||
|
|
||||||
|
## New array methods
|
||||||
|
|
||||||
|
- <icode>beat</icode>
|
||||||
|
|
||||||
|
|
||||||
## Simple patterns
|
## Simple patterns
|
||||||
|
|
||||||
- <icode>divseq(div: number, ...values:any[])</icode>
|
- <icode>divseq(div: number, ...values:any[])</icode>
|
||||||
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const synths: string = `
|
const synths: string = `
|
||||||
@ -611,8 +617,8 @@ Here is a simple example of a substractive synth:
|
|||||||
|
|
||||||
\`\`\`javascript
|
\`\`\`javascript
|
||||||
mod(.5) && snd('sawtooth')
|
mod(.5) && snd('sawtooth')
|
||||||
.cutoff(pick(2000,500) + usine(.5) * 4000)
|
.cutoff([2000,500].pick() + usine(.5) * 4000)
|
||||||
.resonance(0.9).freq(pick(100,150))
|
.resonance(0.9).freq([100,150].pick())
|
||||||
.out()
|
.out()
|
||||||
\`\`\`
|
\`\`\`
|
||||||
|
|
||||||
@ -628,9 +634,9 @@ And here is a simple example:
|
|||||||
|
|
||||||
\`\`\`javascript
|
\`\`\`javascript
|
||||||
mod(.25) && snd('sine')
|
mod(.25) && snd('sine')
|
||||||
.fmi(pick(1,2,4,8))
|
.fmi([1,2,4,8].pick())
|
||||||
.fmh(divseq(2, 1,2,4,8))
|
.fmh([1,2,4,8].div(8))
|
||||||
.freq(pick(100,150))
|
.freq([100,150].pick())
|
||||||
.sustain(0.1)
|
.sustain(0.1)
|
||||||
.out()
|
.out()
|
||||||
\`\`\`
|
\`\`\`
|
||||||
|
|||||||
@ -183,6 +183,7 @@ export class SoundEvent extends AudibleEvent {
|
|||||||
this.values["delay"] = value;
|
this.values["delay"] = value;
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
del = this.delay;
|
||||||
|
|
||||||
delayfeedback = (value: number): this => {
|
delayfeedback = (value: number): this => {
|
||||||
this.values["delayfeedback"] = value;
|
this.values["delayfeedback"] = value;
|
||||||
@ -200,6 +201,7 @@ export class SoundEvent extends AudibleEvent {
|
|||||||
this.values["orbit"] = value;
|
this.values["orbit"] = value;
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
o = this.orbit;
|
||||||
|
|
||||||
room = (value: number): this => {
|
room = (value: number): this => {
|
||||||
this.values["room"] = value;
|
this.values["room"] = value;
|
||||||
@ -210,6 +212,7 @@ export class SoundEvent extends AudibleEvent {
|
|||||||
this.values["size"] = value;
|
this.values["size"] = value;
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
sz = this.size;
|
||||||
|
|
||||||
velocity = (value: number): this => {
|
velocity = (value: number): this => {
|
||||||
this.values["velocity"] = value;
|
this.values["velocity"] = value;
|
||||||
|
|||||||
@ -18,6 +18,7 @@ import { documentation_factory } from "./Documentation";
|
|||||||
import { EditorView } from "codemirror";
|
import { EditorView } from "codemirror";
|
||||||
import { Clock } from "./Clock";
|
import { Clock } from "./Clock";
|
||||||
import { loadSamples, UserAPI } from "./API";
|
import { loadSamples, UserAPI } from "./API";
|
||||||
|
import { makeArrayExtensions } from "./ArrayExtensions";
|
||||||
import "./style.css";
|
import "./style.css";
|
||||||
import {
|
import {
|
||||||
Universes,
|
Universes,
|
||||||
@ -200,6 +201,7 @@ export class Editor {
|
|||||||
// ================================================================================
|
// ================================================================================
|
||||||
|
|
||||||
this.api = new UserAPI(this);
|
this.api = new UserAPI(this);
|
||||||
|
makeArrayExtensions(this.api);
|
||||||
|
|
||||||
// ================================================================================
|
// ================================================================================
|
||||||
// CodeMirror Management
|
// CodeMirror Management
|
||||||
|
|||||||
Reference in New Issue
Block a user