mirror of
https://codeberg.org/uzu/strudel
synced 2026-07-13 14:26:58 -04:00
Merge pull request 'scale & xen parity' (#1955) from tyow/localstrudel:xen-feats into main
Reviewed-on: https://codeberg.org/uzu/strudel/pulls/1955
This commit is contained in:
@@ -394,6 +394,18 @@ export const { source, src } = registerControl('source', 'src');
|
||||
*/
|
||||
// also see https://codeberg.org/uzu/strudel/pulls/63
|
||||
export const { n } = registerControl('n');
|
||||
|
||||
/**
|
||||
* Selects the given degree. Currently used in `xen` and `tune`:
|
||||
*
|
||||
* @name i
|
||||
* @tags tonal
|
||||
* @param {number | Pattern} value
|
||||
* @example
|
||||
* i("0 1 2 3 4 5 6 7").xen("<5edo 10edo 15edo hexany15>")
|
||||
*/
|
||||
export const { i } = registerControl('i');
|
||||
|
||||
/**
|
||||
* Plays the given note name or midi number. A note name consists of
|
||||
*
|
||||
|
||||
+12
-5
@@ -8,23 +8,23 @@ import Tune from './tunejs.js';
|
||||
import { register } from '@strudel/core';
|
||||
|
||||
/**
|
||||
* Assumes a numerical pattern of EDO steps. Accepts a scale name or list of frequencies (see all available names at the link on the reference). Returns a new pattern with all values mapped to a frequency ratio. Similar to `xen`.
|
||||
* Assumes pattern contains numerical scale degrees on the `i` control (see examples below). Accepts a scale name or list of frequencies (see all available names at the link on the reference). Returns a new pattern with all values mapped to a frequency ratio. Similar to `xen`.
|
||||
* @name tune
|
||||
* @returns Pattern
|
||||
* @memberof Pattern
|
||||
* @param {(string | number[] )} scale
|
||||
* @example
|
||||
* "0 1 2 3 4 5".tune("hexany15").mul("220").freq()
|
||||
* i("0 1 2 3 4 5").tune("hexany15").mul("220").freq()
|
||||
* @example
|
||||
* // You can set your root to be a
|
||||
* // particular note with getFreq:
|
||||
* "4 8 9 10 - - 5 7 9 11 - -".tune("tranh3")
|
||||
* i("4 8 9 10 - - 5 7 9 11 - -").tune("tranh3")
|
||||
* .mul(getFreq('c3'))
|
||||
* .freq().clip(.5).room(1)
|
||||
* @example
|
||||
* // You can also give tune a list of
|
||||
* // frequencies to use as the scale:
|
||||
* "0 1 2 3 4".tune([
|
||||
* i("0 1 2 3 4").tune([
|
||||
* 261.6255653006,
|
||||
* 302.72962012827,
|
||||
* 350.29154279212,
|
||||
@@ -32,6 +32,7 @@ import { register } from '@strudel/core';
|
||||
* 469.00678383895,
|
||||
* 523.2511306012
|
||||
* ]).mul(220).freq();
|
||||
*
|
||||
* @tags tonal
|
||||
*/
|
||||
|
||||
@@ -45,6 +46,12 @@ export const tune = register('tune', (scale, pat) => {
|
||||
// if the tonic is a frequency, why are we putting in "1"
|
||||
tune.tonicize(1);
|
||||
return pat.withHap((hap) => {
|
||||
return hap.withValue(() => tune.note(hap.value));
|
||||
if (typeof hap.value !== 'object') {
|
||||
throw new Error(`Expected hap to have control 'i' set, but received ${hap.value.i}, try wrapping input in i()`);
|
||||
}
|
||||
// const { i, ...otherValues } = hap.value;
|
||||
// hap.value = { ...otherValues, freq: tune.note(i)}
|
||||
// return hap
|
||||
return hap.withValue(() => tune.note(hap.value.i));
|
||||
});
|
||||
});
|
||||
|
||||
+138
-19
@@ -4,7 +4,7 @@ Copyright (C) 2022 Strudel contributors - see <https://codeberg.org/uzu/strudel/
|
||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { register, _mod, parseNumeral } from '@strudel/core';
|
||||
import { register, _mod, parseNumeral, removeUndefineds } from '@strudel/core';
|
||||
import Tune from './tunejs.js';
|
||||
|
||||
// returns a list of frequency ratios for given edo scale
|
||||
@@ -22,18 +22,20 @@ const presets = {
|
||||
|
||||
// Given a base frequency such as 220 and an edo scale, returns
|
||||
// an array of frequencies representing the given edo scale in that base
|
||||
function withBase(freq, scale) {
|
||||
function _withBase(freq, scale) {
|
||||
return scale.map((r) => r * freq);
|
||||
}
|
||||
|
||||
const defaultBase = 220;
|
||||
|
||||
const isEdo = (scale) => /^[1-9]+[0-9]*edo$/.test(scale);
|
||||
|
||||
// Assumes a base of 220. Returns a filtered scale based on 'indices'
|
||||
// NOTE: indices functionality is unused
|
||||
function getXenScale(scale, indices) {
|
||||
let tune = new Tune();
|
||||
if (typeof scale === 'string') {
|
||||
if (/^[1-9]+[0-9]*edo$/.test(scale)) {
|
||||
if (isEdo(scale)) {
|
||||
scale = edo(scale);
|
||||
} else if (presets[scale]) {
|
||||
scale = presets[scale];
|
||||
@@ -44,7 +46,7 @@ function getXenScale(scale, indices) {
|
||||
throw new Error('unknown scale name: "' + scale + '"');
|
||||
}
|
||||
}
|
||||
scale = withBase(defaultBase, scale);
|
||||
scale = _withBase(defaultBase, scale);
|
||||
if (!indices) {
|
||||
return scale;
|
||||
}
|
||||
@@ -57,6 +59,8 @@ function xenOffset(xenScale, offset, index = 0) {
|
||||
return xenScale[i] * Math.pow(2, oct);
|
||||
}
|
||||
|
||||
const trimFreq = (freq) => parseFloat(freq.toPrecision(10));
|
||||
|
||||
// accepts a scale name such as 31edo, and a pattern
|
||||
// pattern expected to follow format such that a value can be mapped
|
||||
// to an edostep within the scale. Returns the pattern with
|
||||
@@ -72,39 +76,154 @@ function xenOffset(xenScale, offset, index = 0) {
|
||||
* @param {(string | number[] )} scaleNameOrRatios
|
||||
* @tags tonal
|
||||
* @example
|
||||
* // A major triad in 31edo:
|
||||
* "0 8 18".xen("31edo").freq().piano()
|
||||
* // A minor triad in 31edo:
|
||||
* i("0 8 18").xen("31edo").piano()
|
||||
* @example
|
||||
* // You can also use xen with frequency ratios.
|
||||
* // This is equivalent to the above:
|
||||
* "0 1 2".xen([
|
||||
* i("0 1 2").xen([
|
||||
* Math.pow(2, 0/31),
|
||||
* Math.pow(2, 8/31),
|
||||
* Math.pow(2, 18/31),
|
||||
* ]).freq().piano()
|
||||
* ]).piano()
|
||||
* @example
|
||||
* // xen also supports all scale names that
|
||||
* // tune does:
|
||||
* "0 1 2 3 4 5".xen("hexany15").freq()
|
||||
* i("0 1 2 3 4 5").xen("hexany15")
|
||||
* // equiv to:
|
||||
* // "0 1 2 3 4 5".tune("hexany15").mul("220").freq()
|
||||
* @example
|
||||
* i("0 1 2 3 4 5 6 7").xen("<5edo 10edo 15edo hexany15>")
|
||||
*/
|
||||
|
||||
// TODO feat: change root frequency
|
||||
// TODO add explanation for what "31edo" etc. are
|
||||
// TODO (maybe): should this return freq ratios like tune does, for parity's sake?
|
||||
export const xen = register('xen', function (scaleNameOrRatios, pat) {
|
||||
return pat.withHap((hap) => {
|
||||
const scale = getXenScale(scaleNameOrRatios);
|
||||
let frequency = xenOffset(scale, parseNumeral(hap.value));
|
||||
// 10 is somewhat arbitrary
|
||||
frequency = parseFloat(frequency.toPrecision(10));
|
||||
return hap.withValue(() => frequency);
|
||||
return pat.withHaps((haps) => {
|
||||
haps = haps.map((hap) => {
|
||||
let hVal = hap.value;
|
||||
const isObject = typeof hVal === 'object';
|
||||
if (!isObject) {
|
||||
throw new Error(`Expected hap to have control 'i' set, but received ${hap.value.i}, try wrapping input in i()`);
|
||||
}
|
||||
const { i, ...otherValues } = hVal;
|
||||
const scale = getXenScale(scaleNameOrRatios);
|
||||
let freq = xenOffset(scale, parseNumeral(hVal.i));
|
||||
// 10 is somewhat arbitrary
|
||||
freq = trimFreq(freq);
|
||||
hap.value = { ...otherValues, freq };
|
||||
return isEdo(scaleNameOrRatios)
|
||||
? hap.setContext({ ...hap.context, edoSize: scaleNameOrRatios.match(/^([1-9]+[0-9]*)edo$/)[1] })
|
||||
: hap;
|
||||
});
|
||||
return removeUndefineds(haps);
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Assumes pattern of frequencies tuned to some `base` frequency, such as the output of `xen`
|
||||
* Because `xen` defaults to `220Hz`, so will `withBase`.
|
||||
* but you can specify a different original base with the standard optional array syntax '`:`'
|
||||
* @name withBase
|
||||
* @param {number} base
|
||||
* @param {number} (optional) originalBase
|
||||
* @tags tonal
|
||||
*
|
||||
* @example
|
||||
* i("[0 1 2 3] [3 4] [4 3 2 1]").xen("hexany23").withBase("<220 [300 200]>")
|
||||
* @example
|
||||
* mini([1 / 1, 16 / 15, 9 / 8, 6 / 5, 5 / 4].join(' ')).withBase("220:1")
|
||||
* // mini([1 / 1, 16 / 15, 9 / 8, 6 / 5, 5 / 4].join(' ')).mul(220).freq()
|
||||
*
|
||||
* @returns Pattern
|
||||
*/
|
||||
export const withBase = register('withBase', (b, pat) => {
|
||||
let base;
|
||||
let originalBase = 220;
|
||||
if (Array.isArray(b)) {
|
||||
base = b[0];
|
||||
originalBase = b[1];
|
||||
} else {
|
||||
base = b;
|
||||
}
|
||||
return pat.withHaps((haps) => {
|
||||
haps = haps.map((hap) => {
|
||||
let hVal = hap.value;
|
||||
const isObject = typeof hVal === 'object';
|
||||
let freq = isObject ? hVal.freq : hVal;
|
||||
freq = (freq * base) / originalBase;
|
||||
hap.value = isObject ? { ...hap.value, freq } : { freq };
|
||||
return hap;
|
||||
});
|
||||
return removeUndefineds(haps);
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Frequency transpose. Assumes pattern either has `freq` set, or has values that can be interpreted as frequencies
|
||||
* amt has optional `edoSize` param, defaults to 12.
|
||||
* If haps have edoSize param set, such as from the output of `xen("31edo")`,
|
||||
* `ftrans` will fallback to that instead of 12 as the default.
|
||||
*
|
||||
* Transposes the frequency by `amt` edoSteps
|
||||
* @name ftranspose
|
||||
* @synonyms ftrans, fTrans, ftranspose, fTranspose
|
||||
* @tags tonal
|
||||
* @param {number} amt
|
||||
* @param {number} edoSize (optional)
|
||||
* @returns {Pattern}
|
||||
*
|
||||
* @example
|
||||
* i("0 1 2").xen("12edo").ftrans("7")
|
||||
* // n("0 1 2").scale("A:chromatic").trans("7")
|
||||
* @example
|
||||
* i("0 8 18").xen("31edo").ftrans("<8 -8>")
|
||||
* @example
|
||||
* // to transpose by steps of an edo, use "step:edo" :
|
||||
* i("0 7 8 18").xen("31edo").ftrans("<0 1:31 1:12>")
|
||||
* @example
|
||||
* // it can also work with frequency values directly
|
||||
* freq("200 300 400").ftrans("<0 7:31 7>")
|
||||
*/
|
||||
|
||||
/* f = frequency (Hz)
|
||||
n = edo (steps per octave)
|
||||
x = number of steps
|
||||
if 0\n = f, then x\n = f * 2^(x/n)
|
||||
example: 5edo, 0\5 = 220 Hz, then 2\5 = 220*2^(2/5) = 290.29 Hz */
|
||||
|
||||
export const { ftrans, fTrans, ftranspose, fTranspose } = register(
|
||||
['ftrans', 'fTrans', 'ftranspose', 'fTranspose'],
|
||||
(amt, pat) => {
|
||||
let edoSize;
|
||||
let numSteps;
|
||||
if (Array.isArray(amt)) {
|
||||
edoSize = amt[1];
|
||||
numSteps = amt[0];
|
||||
} else {
|
||||
numSteps = amt;
|
||||
}
|
||||
return pat.withHaps((haps) => {
|
||||
haps = haps.map((hap) => {
|
||||
let hVal = hap.value;
|
||||
const isObject = typeof hVal === 'object';
|
||||
hVal = isObject ? hVal : { freq: hVal };
|
||||
let { freq, ...otherValues } = hVal;
|
||||
if (edoSize == undefined && hap.context.edoSize != undefined) {
|
||||
edoSize = hap.context.edoSize;
|
||||
} else if (edoSize == undefined) {
|
||||
edoSize = 12;
|
||||
}
|
||||
freq = freq * Math.pow(2, numSteps / edoSize);
|
||||
freq = trimFreq(freq);
|
||||
hap.value = isObject ? { ...otherValues, freq } : freq;
|
||||
return hap.setContext({ ...hap.context, edoSize });
|
||||
});
|
||||
return removeUndefineds(haps);
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
// not sure there's a point to having this and the above, seems like a proto version of the above.
|
||||
export const tuning = register('tuning', function (ratios, pat) {
|
||||
const tuning = register('tuning', function (ratios, pat) {
|
||||
return pat.withHap((hap) => {
|
||||
const frequency = xenOffset(ratios, parseNumeral(hap.value));
|
||||
return hap.withValue(() => frequency);
|
||||
|
||||
@@ -4950,6 +4950,78 @@ exports[`runs examples > example "fscope" example index 0 1`] = `
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`runs examples > example "ftranspose" example index 0 1`] = `
|
||||
[
|
||||
"[ 0/1 → 1/3 | freq:329.6275569 ]",
|
||||
"[ 1/3 → 2/3 | freq:349.2282315 ]",
|
||||
"[ 2/3 → 1/1 | freq:369.9944227 ]",
|
||||
"[ 1/1 → 4/3 | freq:329.6275569 ]",
|
||||
"[ 4/3 → 5/3 | freq:349.2282315 ]",
|
||||
"[ 5/3 → 2/1 | freq:369.9944227 ]",
|
||||
"[ 2/1 → 7/3 | freq:329.6275569 ]",
|
||||
"[ 7/3 → 8/3 | freq:349.2282315 ]",
|
||||
"[ 8/3 → 3/1 | freq:369.9944227 ]",
|
||||
"[ 3/1 → 10/3 | freq:329.6275569 ]",
|
||||
"[ 10/3 → 11/3 | freq:349.2282315 ]",
|
||||
"[ 11/3 → 4/1 | freq:369.9944227 ]",
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`runs examples > example "ftranspose" example index 1 1`] = `
|
||||
[
|
||||
"[ 0/1 → 1/3 | freq:263.0921203 ]",
|
||||
"[ 1/3 → 2/3 | freq:314.6248353 ]",
|
||||
"[ 2/3 → 1/1 | freq:393.4589706 ]",
|
||||
"[ 1/1 → 4/3 | freq:183.965981 ]",
|
||||
"[ 4/3 → 5/3 | freq:220 ]",
|
||||
"[ 5/3 → 2/1 | freq:275.1244143 ]",
|
||||
"[ 2/1 → 7/3 | freq:263.0921203 ]",
|
||||
"[ 7/3 → 8/3 | freq:314.6248353 ]",
|
||||
"[ 8/3 → 3/1 | freq:393.4589706 ]",
|
||||
"[ 3/1 → 10/3 | freq:183.965981 ]",
|
||||
"[ 10/3 → 11/3 | freq:220 ]",
|
||||
"[ 11/3 → 4/1 | freq:275.1244143 ]",
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`runs examples > example "ftranspose" example index 2 1`] = `
|
||||
[
|
||||
"[ 0/1 → 1/4 | freq:220 ]",
|
||||
"[ 1/4 → 1/2 | freq:257.2747684 ]",
|
||||
"[ 1/2 → 3/4 | freq:263.0921203 ]",
|
||||
"[ 3/4 → 1/1 | freq:329.0139341 ]",
|
||||
"[ 1/1 → 5/4 | freq:224.9745158 ]",
|
||||
"[ 5/4 → 3/2 | freq:263.0921203 ]",
|
||||
"[ 3/2 → 7/4 | freq:269.0410108 ]",
|
||||
"[ 7/4 → 2/1 | freq:336.4534115 ]",
|
||||
"[ 2/1 → 9/4 | freq:233.0818808 ]",
|
||||
"[ 9/4 → 5/2 | freq:272.5731222 ]",
|
||||
"[ 5/2 → 11/4 | freq:278.7363919 ]",
|
||||
"[ 11/4 → 3/1 | freq:348.5781207 ]",
|
||||
"[ 3/1 → 13/4 | freq:220 ]",
|
||||
"[ 13/4 → 7/2 | freq:257.2747684 ]",
|
||||
"[ 7/2 → 15/4 | freq:263.0921203 ]",
|
||||
"[ 15/4 → 4/1 | freq:329.0139341 ]",
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`runs examples > example "ftranspose" example index 3 1`] = `
|
||||
[
|
||||
"[ 0/1 → 1/3 | freq:200 ]",
|
||||
"[ 1/3 → 2/3 | freq:300 ]",
|
||||
"[ 2/3 → 1/1 | freq:400 ]",
|
||||
"[ 1/1 → 4/3 | freq:233.8861531 ]",
|
||||
"[ 4/3 → 5/3 | freq:350.8292297 ]",
|
||||
"[ 5/3 → 2/1 | freq:467.7723062 ]",
|
||||
"[ 2/1 → 7/3 | freq:299.6614154 ]",
|
||||
"[ 7/3 → 8/3 | freq:449.4921231 ]",
|
||||
"[ 8/3 → 3/1 | freq:599.3228308 ]",
|
||||
"[ 3/1 → 10/3 | freq:200 ]",
|
||||
"[ 10/3 → 11/3 | freq:300 ]",
|
||||
"[ 11/3 → 4/1 | freq:400 ]",
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`runs examples > example "ftype" example index 0 1`] = `
|
||||
[
|
||||
"[ 0/1 → 1/8 | note:f s:sawtooth lpenv:4 cutoff:500 ftype:0 resonance:1 ]",
|
||||
@@ -5634,6 +5706,43 @@ exports[`runs examples > example "hush" example index 0 1`] = `
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`runs examples > example "i" example index 0 1`] = `
|
||||
[
|
||||
"[ 0/1 → 1/8 | freq:220 ]",
|
||||
"[ 1/8 → 1/4 | freq:252.7136381 ]",
|
||||
"[ 1/4 → 3/8 | freq:290.2917404 ]",
|
||||
"[ 3/8 → 1/2 | freq:333.4576446 ]",
|
||||
"[ 1/2 → 5/8 | freq:383.0422479 ]",
|
||||
"[ 5/8 → 3/4 | freq:440 ]",
|
||||
"[ 3/4 → 7/8 | freq:505.4272762 ]",
|
||||
"[ 7/8 → 1/1 | freq:580.5834807 ]",
|
||||
"[ 1/1 → 9/8 | freq:220 ]",
|
||||
"[ 9/8 → 5/4 | freq:235.7901618 ]",
|
||||
"[ 5/4 → 11/8 | freq:252.7136381 ]",
|
||||
"[ 11/8 → 3/2 | freq:270.8517709 ]",
|
||||
"[ 3/2 → 13/8 | freq:290.2917404 ]",
|
||||
"[ 13/8 → 7/4 | freq:311.1269837 ]",
|
||||
"[ 7/4 → 15/8 | freq:333.4576446 ]",
|
||||
"[ 15/8 → 2/1 | freq:357.3910544 ]",
|
||||
"[ 2/1 → 17/8 | freq:220 ]",
|
||||
"[ 17/8 → 9/4 | freq:230.404707 ]",
|
||||
"[ 9/4 → 19/8 | freq:241.3014955 ]",
|
||||
"[ 19/8 → 5/2 | freq:252.7136381 ]",
|
||||
"[ 5/2 → 21/8 | freq:264.6655079 ]",
|
||||
"[ 21/8 → 11/4 | freq:277.182631 ]",
|
||||
"[ 11/4 → 23/8 | freq:290.2917404 ]",
|
||||
"[ 23/8 → 3/1 | freq:304.0208336 ]",
|
||||
"[ 3/1 → 25/8 | freq:220 ]",
|
||||
"[ 25/8 → 13/4 | freq:275 ]",
|
||||
"[ 13/4 → 27/8 | freq:293.3333333 ]",
|
||||
"[ 27/8 → 7/2 | freq:330 ]",
|
||||
"[ 7/2 → 29/8 | freq:352 ]",
|
||||
"[ 29/8 → 15/4 | freq:440 ]",
|
||||
"[ 15/4 → 31/8 | freq:550 ]",
|
||||
"[ 31/8 → 4/1 | freq:586.6666667 ]",
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`runs examples > example "inhabit" example index 0 1`] = `
|
||||
[
|
||||
"[ 0/1 → 1/8 | s:bd ]",
|
||||
@@ -13217,92 +13326,92 @@ exports[`runs examples > example "tri" example index 0 1`] = `
|
||||
|
||||
exports[`runs examples > example "tune" example index 0 1`] = `
|
||||
[
|
||||
"[ 0/1 → 1/6 | freq:0 ]",
|
||||
"[ 1/6 → 1/3 | freq:220 ]",
|
||||
"[ 1/3 → 1/2 | freq:440 ]",
|
||||
"[ 1/2 → 2/3 | freq:660 ]",
|
||||
"[ 2/3 → 5/6 | freq:880 ]",
|
||||
"[ 5/6 → 1/1 | freq:1100 ]",
|
||||
"[ 1/1 → 7/6 | freq:0 ]",
|
||||
"[ 7/6 → 4/3 | freq:220 ]",
|
||||
"[ 4/3 → 3/2 | freq:440 ]",
|
||||
"[ 3/2 → 5/3 | freq:660 ]",
|
||||
"[ 5/3 → 11/6 | freq:880 ]",
|
||||
"[ 11/6 → 2/1 | freq:1100 ]",
|
||||
"[ 2/1 → 13/6 | freq:0 ]",
|
||||
"[ 13/6 → 7/3 | freq:220 ]",
|
||||
"[ 7/3 → 5/2 | freq:440 ]",
|
||||
"[ 5/2 → 8/3 | freq:660 ]",
|
||||
"[ 8/3 → 17/6 | freq:880 ]",
|
||||
"[ 17/6 → 3/1 | freq:1100 ]",
|
||||
"[ 3/1 → 19/6 | freq:0 ]",
|
||||
"[ 19/6 → 10/3 | freq:220 ]",
|
||||
"[ 10/3 → 7/2 | freq:440 ]",
|
||||
"[ 7/2 → 11/3 | freq:660 ]",
|
||||
"[ 11/3 → 23/6 | freq:880 ]",
|
||||
"[ 23/6 → 4/1 | freq:1100 ]",
|
||||
"[ 0/1 → 1/6 | freq:{i:0} ]",
|
||||
"[ 1/6 → 1/3 | freq:{i:1} ]",
|
||||
"[ 1/3 → 1/2 | freq:{i:2} ]",
|
||||
"[ 1/2 → 2/3 | freq:{i:3} ]",
|
||||
"[ 2/3 → 5/6 | freq:{i:4} ]",
|
||||
"[ 5/6 → 1/1 | freq:{i:5} ]",
|
||||
"[ 1/1 → 7/6 | freq:{i:0} ]",
|
||||
"[ 7/6 → 4/3 | freq:{i:1} ]",
|
||||
"[ 4/3 → 3/2 | freq:{i:2} ]",
|
||||
"[ 3/2 → 5/3 | freq:{i:3} ]",
|
||||
"[ 5/3 → 11/6 | freq:{i:4} ]",
|
||||
"[ 11/6 → 2/1 | freq:{i:5} ]",
|
||||
"[ 2/1 → 13/6 | freq:{i:0} ]",
|
||||
"[ 13/6 → 7/3 | freq:{i:1} ]",
|
||||
"[ 7/3 → 5/2 | freq:{i:2} ]",
|
||||
"[ 5/2 → 8/3 | freq:{i:3} ]",
|
||||
"[ 8/3 → 17/6 | freq:{i:4} ]",
|
||||
"[ 17/6 → 3/1 | freq:{i:5} ]",
|
||||
"[ 3/1 → 19/6 | freq:{i:0} ]",
|
||||
"[ 19/6 → 10/3 | freq:{i:1} ]",
|
||||
"[ 10/3 → 7/2 | freq:{i:2} ]",
|
||||
"[ 7/2 → 11/3 | freq:{i:3} ]",
|
||||
"[ 11/3 → 23/6 | freq:{i:4} ]",
|
||||
"[ 23/6 → 4/1 | freq:{i:5} ]",
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`runs examples > example "tune" example index 1 1`] = `
|
||||
[
|
||||
"[ 0/1 → 1/12 | freq:523.2511306011972 clip:0.5 room:1 ]",
|
||||
"[ 1/12 → 1/6 | freq:1046.5022612023945 clip:0.5 room:1 ]",
|
||||
"[ 1/6 → 1/4 | freq:1177.3150438526939 clip:0.5 room:1 ]",
|
||||
"[ 1/4 → 1/3 | freq:1308.1278265029932 clip:0.5 room:1 ]",
|
||||
"[ 1/2 → 7/12 | freq:654.0639132514966 clip:0.5 room:1 ]",
|
||||
"[ 7/12 → 2/3 | freq:915.6894785520951 clip:0.5 room:1 ]",
|
||||
"[ 2/3 → 3/4 | freq:1177.3150438526939 clip:0.5 room:1 ]",
|
||||
"[ 3/4 → 5/6 | freq:1438.9406091532924 clip:0.5 room:1 ]",
|
||||
"[ 1/1 → 13/12 | freq:523.2511306011972 clip:0.5 room:1 ]",
|
||||
"[ 13/12 → 7/6 | freq:1046.5022612023945 clip:0.5 room:1 ]",
|
||||
"[ 7/6 → 5/4 | freq:1177.3150438526939 clip:0.5 room:1 ]",
|
||||
"[ 5/4 → 4/3 | freq:1308.1278265029932 clip:0.5 room:1 ]",
|
||||
"[ 3/2 → 19/12 | freq:654.0639132514966 clip:0.5 room:1 ]",
|
||||
"[ 19/12 → 5/3 | freq:915.6894785520951 clip:0.5 room:1 ]",
|
||||
"[ 5/3 → 7/4 | freq:1177.3150438526939 clip:0.5 room:1 ]",
|
||||
"[ 7/4 → 11/6 | freq:1438.9406091532924 clip:0.5 room:1 ]",
|
||||
"[ 2/1 → 25/12 | freq:523.2511306011972 clip:0.5 room:1 ]",
|
||||
"[ 25/12 → 13/6 | freq:1046.5022612023945 clip:0.5 room:1 ]",
|
||||
"[ 13/6 → 9/4 | freq:1177.3150438526939 clip:0.5 room:1 ]",
|
||||
"[ 9/4 → 7/3 | freq:1308.1278265029932 clip:0.5 room:1 ]",
|
||||
"[ 5/2 → 31/12 | freq:654.0639132514966 clip:0.5 room:1 ]",
|
||||
"[ 31/12 → 8/3 | freq:915.6894785520951 clip:0.5 room:1 ]",
|
||||
"[ 8/3 → 11/4 | freq:1177.3150438526939 clip:0.5 room:1 ]",
|
||||
"[ 11/4 → 17/6 | freq:1438.9406091532924 clip:0.5 room:1 ]",
|
||||
"[ 3/1 → 37/12 | freq:523.2511306011972 clip:0.5 room:1 ]",
|
||||
"[ 37/12 → 19/6 | freq:1046.5022612023945 clip:0.5 room:1 ]",
|
||||
"[ 19/6 → 13/4 | freq:1177.3150438526939 clip:0.5 room:1 ]",
|
||||
"[ 13/4 → 10/3 | freq:1308.1278265029932 clip:0.5 room:1 ]",
|
||||
"[ 7/2 → 43/12 | freq:654.0639132514966 clip:0.5 room:1 ]",
|
||||
"[ 43/12 → 11/3 | freq:915.6894785520951 clip:0.5 room:1 ]",
|
||||
"[ 11/3 → 15/4 | freq:1177.3150438526939 clip:0.5 room:1 ]",
|
||||
"[ 15/4 → 23/6 | freq:1438.9406091532924 clip:0.5 room:1 ]",
|
||||
"[ 0/1 → 1/12 | freq:{i:4} clip:0.5 room:1 ]",
|
||||
"[ 1/12 → 1/6 | freq:{i:8} clip:0.5 room:1 ]",
|
||||
"[ 1/6 → 1/4 | freq:{i:9} clip:0.5 room:1 ]",
|
||||
"[ 1/4 → 1/3 | freq:{i:10} clip:0.5 room:1 ]",
|
||||
"[ 1/2 → 7/12 | freq:{i:5} clip:0.5 room:1 ]",
|
||||
"[ 7/12 → 2/3 | freq:{i:7} clip:0.5 room:1 ]",
|
||||
"[ 2/3 → 3/4 | freq:{i:9} clip:0.5 room:1 ]",
|
||||
"[ 3/4 → 5/6 | freq:{i:11} clip:0.5 room:1 ]",
|
||||
"[ 1/1 → 13/12 | freq:{i:4} clip:0.5 room:1 ]",
|
||||
"[ 13/12 → 7/6 | freq:{i:8} clip:0.5 room:1 ]",
|
||||
"[ 7/6 → 5/4 | freq:{i:9} clip:0.5 room:1 ]",
|
||||
"[ 5/4 → 4/3 | freq:{i:10} clip:0.5 room:1 ]",
|
||||
"[ 3/2 → 19/12 | freq:{i:5} clip:0.5 room:1 ]",
|
||||
"[ 19/12 → 5/3 | freq:{i:7} clip:0.5 room:1 ]",
|
||||
"[ 5/3 → 7/4 | freq:{i:9} clip:0.5 room:1 ]",
|
||||
"[ 7/4 → 11/6 | freq:{i:11} clip:0.5 room:1 ]",
|
||||
"[ 2/1 → 25/12 | freq:{i:4} clip:0.5 room:1 ]",
|
||||
"[ 25/12 → 13/6 | freq:{i:8} clip:0.5 room:1 ]",
|
||||
"[ 13/6 → 9/4 | freq:{i:9} clip:0.5 room:1 ]",
|
||||
"[ 9/4 → 7/3 | freq:{i:10} clip:0.5 room:1 ]",
|
||||
"[ 5/2 → 31/12 | freq:{i:5} clip:0.5 room:1 ]",
|
||||
"[ 31/12 → 8/3 | freq:{i:7} clip:0.5 room:1 ]",
|
||||
"[ 8/3 → 11/4 | freq:{i:9} clip:0.5 room:1 ]",
|
||||
"[ 11/4 → 17/6 | freq:{i:11} clip:0.5 room:1 ]",
|
||||
"[ 3/1 → 37/12 | freq:{i:4} clip:0.5 room:1 ]",
|
||||
"[ 37/12 → 19/6 | freq:{i:8} clip:0.5 room:1 ]",
|
||||
"[ 19/6 → 13/4 | freq:{i:9} clip:0.5 room:1 ]",
|
||||
"[ 13/4 → 10/3 | freq:{i:10} clip:0.5 room:1 ]",
|
||||
"[ 7/2 → 43/12 | freq:{i:5} clip:0.5 room:1 ]",
|
||||
"[ 43/12 → 11/3 | freq:{i:7} clip:0.5 room:1 ]",
|
||||
"[ 11/3 → 15/4 | freq:{i:9} clip:0.5 room:1 ]",
|
||||
"[ 15/4 → 23/6 | freq:{i:11} clip:0.5 room:1 ]",
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`runs examples > example "tune" example index 2 1`] = `
|
||||
[
|
||||
"[ 0/1 → 1/5 | freq:0 ]",
|
||||
"[ 1/5 → 2/5 | freq:220 ]",
|
||||
"[ 2/5 → 3/5 | freq:440 ]",
|
||||
"[ 3/5 → 4/5 | freq:660 ]",
|
||||
"[ 4/5 → 1/1 | freq:880 ]",
|
||||
"[ 1/1 → 6/5 | freq:0 ]",
|
||||
"[ 6/5 → 7/5 | freq:220 ]",
|
||||
"[ 7/5 → 8/5 | freq:440 ]",
|
||||
"[ 8/5 → 9/5 | freq:660 ]",
|
||||
"[ 9/5 → 2/1 | freq:880 ]",
|
||||
"[ 2/1 → 11/5 | freq:0 ]",
|
||||
"[ 11/5 → 12/5 | freq:220 ]",
|
||||
"[ 12/5 → 13/5 | freq:440 ]",
|
||||
"[ 13/5 → 14/5 | freq:660 ]",
|
||||
"[ 14/5 → 3/1 | freq:880 ]",
|
||||
"[ 3/1 → 16/5 | freq:0 ]",
|
||||
"[ 16/5 → 17/5 | freq:220 ]",
|
||||
"[ 17/5 → 18/5 | freq:440 ]",
|
||||
"[ 18/5 → 19/5 | freq:660 ]",
|
||||
"[ 19/5 → 4/1 | freq:880 ]",
|
||||
"[ 0/1 → 1/5 | freq:{i:0} ]",
|
||||
"[ 1/5 → 2/5 | freq:{i:1} ]",
|
||||
"[ 2/5 → 3/5 | freq:{i:2} ]",
|
||||
"[ 3/5 → 4/5 | freq:{i:3} ]",
|
||||
"[ 4/5 → 1/1 | freq:{i:4} ]",
|
||||
"[ 1/1 → 6/5 | freq:{i:0} ]",
|
||||
"[ 6/5 → 7/5 | freq:{i:1} ]",
|
||||
"[ 7/5 → 8/5 | freq:{i:2} ]",
|
||||
"[ 8/5 → 9/5 | freq:{i:3} ]",
|
||||
"[ 9/5 → 2/1 | freq:{i:4} ]",
|
||||
"[ 2/1 → 11/5 | freq:{i:0} ]",
|
||||
"[ 11/5 → 12/5 | freq:{i:1} ]",
|
||||
"[ 12/5 → 13/5 | freq:{i:2} ]",
|
||||
"[ 13/5 → 14/5 | freq:{i:3} ]",
|
||||
"[ 14/5 → 3/1 | freq:{i:4} ]",
|
||||
"[ 3/1 → 16/5 | freq:{i:0} ]",
|
||||
"[ 16/5 → 17/5 | freq:{i:1} ]",
|
||||
"[ 17/5 → 18/5 | freq:{i:2} ]",
|
||||
"[ 18/5 → 19/5 | freq:{i:3} ]",
|
||||
"[ 19/5 → 4/1 | freq:{i:4} ]",
|
||||
]
|
||||
`;
|
||||
|
||||
@@ -14079,6 +14188,76 @@ exports[`runs examples > example "when" example index 0 1`] = `
|
||||
|
||||
exports[`runs examples > example "whenKey" example index 0 1`] = `[]`;
|
||||
|
||||
exports[`runs examples > example "withBase" example index 0 1`] = `
|
||||
[
|
||||
"[ 0/1 → 1/12 | freq:220 ]",
|
||||
"[ 1/12 → 1/6 | freq:293.3333333 ]",
|
||||
"[ 1/6 → 1/4 | freq:302.5 ]",
|
||||
"[ 1/4 → 1/3 | freq:320 ]",
|
||||
"[ 1/3 → 1/2 | freq:320 ]",
|
||||
"[ 1/2 → 2/3 | freq:330 ]",
|
||||
"[ 2/3 → 3/4 | freq:330 ]",
|
||||
"[ 3/4 → 5/6 | freq:320 ]",
|
||||
"[ 5/6 → 11/12 | freq:302.5 ]",
|
||||
"[ 11/12 → 1/1 | freq:293.3333333 ]",
|
||||
"[ 1/1 → 13/12 | freq:300 ]",
|
||||
"[ 13/12 → 7/6 | freq:399.99999995454544 ]",
|
||||
"[ 7/6 → 5/4 | freq:412.5 ]",
|
||||
"[ 5/4 → 4/3 | freq:436.3636363636364 ]",
|
||||
"[ 4/3 → 3/2 | freq:436.3636363636364 ]",
|
||||
"[ 3/2 → 5/3 | freq:300 ]",
|
||||
"[ 5/3 → 7/4 | freq:300 ]",
|
||||
"[ 7/4 → 11/6 | freq:290.90909090909093 ]",
|
||||
"[ 11/6 → 23/12 | freq:275 ]",
|
||||
"[ 23/12 → 2/1 | freq:266.66666663636363 ]",
|
||||
"[ 2/1 → 25/12 | freq:220 ]",
|
||||
"[ 25/12 → 13/6 | freq:293.3333333 ]",
|
||||
"[ 13/6 → 9/4 | freq:302.5 ]",
|
||||
"[ 9/4 → 7/3 | freq:320 ]",
|
||||
"[ 7/3 → 5/2 | freq:320 ]",
|
||||
"[ 5/2 → 8/3 | freq:330 ]",
|
||||
"[ 8/3 → 11/4 | freq:330 ]",
|
||||
"[ 11/4 → 17/6 | freq:320 ]",
|
||||
"[ 17/6 → 35/12 | freq:302.5 ]",
|
||||
"[ 35/12 → 3/1 | freq:293.3333333 ]",
|
||||
"[ 3/1 → 37/12 | freq:300 ]",
|
||||
"[ 37/12 → 19/6 | freq:399.99999995454544 ]",
|
||||
"[ 19/6 → 13/4 | freq:412.5 ]",
|
||||
"[ 13/4 → 10/3 | freq:436.3636363636364 ]",
|
||||
"[ 10/3 → 7/2 | freq:436.3636363636364 ]",
|
||||
"[ 7/2 → 11/3 | freq:300 ]",
|
||||
"[ 11/3 → 15/4 | freq:300 ]",
|
||||
"[ 15/4 → 23/6 | freq:290.90909090909093 ]",
|
||||
"[ 23/6 → 47/12 | freq:275 ]",
|
||||
"[ 47/12 → 4/1 | freq:266.66666663636363 ]",
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`runs examples > example "withBase" example index 1 1`] = `
|
||||
[
|
||||
"[ 0/1 → 1/5 | freq:220 ]",
|
||||
"[ 1/5 → 2/5 | freq:234.66666666666666 ]",
|
||||
"[ 2/5 → 3/5 | freq:247.5 ]",
|
||||
"[ 3/5 → 4/5 | freq:264 ]",
|
||||
"[ 4/5 → 1/1 | freq:275 ]",
|
||||
"[ 1/1 → 6/5 | freq:220 ]",
|
||||
"[ 6/5 → 7/5 | freq:234.66666666666666 ]",
|
||||
"[ 7/5 → 8/5 | freq:247.5 ]",
|
||||
"[ 8/5 → 9/5 | freq:264 ]",
|
||||
"[ 9/5 → 2/1 | freq:275 ]",
|
||||
"[ 2/1 → 11/5 | freq:220 ]",
|
||||
"[ 11/5 → 12/5 | freq:234.66666666666666 ]",
|
||||
"[ 12/5 → 13/5 | freq:247.5 ]",
|
||||
"[ 13/5 → 14/5 | freq:264 ]",
|
||||
"[ 14/5 → 3/1 | freq:275 ]",
|
||||
"[ 3/1 → 16/5 | freq:220 ]",
|
||||
"[ 16/5 → 17/5 | freq:234.66666666666666 ]",
|
||||
"[ 17/5 → 18/5 | freq:247.5 ]",
|
||||
"[ 18/5 → 19/5 | freq:264 ]",
|
||||
"[ 19/5 → 4/1 | freq:275 ]",
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`runs examples > example "withValue" example index 0 1`] = `
|
||||
[
|
||||
"[ 0/1 → 1/3 | 10 ]",
|
||||
@@ -14281,6 +14460,43 @@ exports[`runs examples > example "xen" example index 2 1`] = `
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`runs examples > example "xen" example index 3 1`] = `
|
||||
[
|
||||
"[ 0/1 → 1/8 | freq:220 ]",
|
||||
"[ 1/8 → 1/4 | freq:252.7136381 ]",
|
||||
"[ 1/4 → 3/8 | freq:290.2917404 ]",
|
||||
"[ 3/8 → 1/2 | freq:333.4576446 ]",
|
||||
"[ 1/2 → 5/8 | freq:383.0422479 ]",
|
||||
"[ 5/8 → 3/4 | freq:440 ]",
|
||||
"[ 3/4 → 7/8 | freq:505.4272762 ]",
|
||||
"[ 7/8 → 1/1 | freq:580.5834807 ]",
|
||||
"[ 1/1 → 9/8 | freq:220 ]",
|
||||
"[ 9/8 → 5/4 | freq:235.7901618 ]",
|
||||
"[ 5/4 → 11/8 | freq:252.7136381 ]",
|
||||
"[ 11/8 → 3/2 | freq:270.8517709 ]",
|
||||
"[ 3/2 → 13/8 | freq:290.2917404 ]",
|
||||
"[ 13/8 → 7/4 | freq:311.1269837 ]",
|
||||
"[ 7/4 → 15/8 | freq:333.4576446 ]",
|
||||
"[ 15/8 → 2/1 | freq:357.3910544 ]",
|
||||
"[ 2/1 → 17/8 | freq:220 ]",
|
||||
"[ 17/8 → 9/4 | freq:230.404707 ]",
|
||||
"[ 9/4 → 19/8 | freq:241.3014955 ]",
|
||||
"[ 19/8 → 5/2 | freq:252.7136381 ]",
|
||||
"[ 5/2 → 21/8 | freq:264.6655079 ]",
|
||||
"[ 21/8 → 11/4 | freq:277.182631 ]",
|
||||
"[ 11/4 → 23/8 | freq:290.2917404 ]",
|
||||
"[ 23/8 → 3/1 | freq:304.0208336 ]",
|
||||
"[ 3/1 → 25/8 | freq:220 ]",
|
||||
"[ 25/8 → 13/4 | freq:275 ]",
|
||||
"[ 13/4 → 27/8 | freq:293.3333333 ]",
|
||||
"[ 27/8 → 7/2 | freq:330 ]",
|
||||
"[ 7/2 → 29/8 | freq:352 ]",
|
||||
"[ 29/8 → 15/4 | freq:440 ]",
|
||||
"[ 15/4 → 31/8 | freq:550 ]",
|
||||
"[ 31/8 → 4/1 | freq:586.6666667 ]",
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`runs examples > example "xfade" example index 0 1`] = `
|
||||
[
|
||||
"[ 0/1 → 1/8 | s:hh gain:0 ]",
|
||||
|
||||
@@ -20,7 +20,7 @@ These functions allow the use of scales other than your typical chromatic 12 bas
|
||||
|
||||
Here's an example of how to configure a basic hexany scale:
|
||||
|
||||
<MiniRepl client:idle tune={`"0 1 2 3 4 5".tune("hexany15").mul("220").freq()`} />
|
||||
<MiniRepl client:idle tune={`i("0 1 2 3 4 5").tune("hexany15").mul("220").freq()`} />
|
||||
|
||||
Try other scales like `hexany1`, `iraq`, `gumbeng`, `gunkali`, or `tranh3`
|
||||
|
||||
@@ -30,7 +30,7 @@ You can set your root to be a particular note with `getFreq`
|
||||
|
||||
<MiniRepl
|
||||
client:idle
|
||||
tune={`"4 8 9 10 - - 5 7 9 11 - -".tune("tranh3")
|
||||
tune={`i("4 8 9 10 - - 5 7 9 11 - -").tune("tranh3")
|
||||
.mul(getFreq('c3'))
|
||||
.freq().clip(.5).room(1)`}
|
||||
/>
|
||||
@@ -39,7 +39,7 @@ Some tunings become more pronounced with a longer reverb decay:
|
||||
|
||||
<MiniRepl
|
||||
client:idle
|
||||
tune={`"<[5 6 8 10] - [5 7 9 12] -> -".tune("gumbeng")
|
||||
tune={`i("<[5 6 8 10] - [5 7 9 12] -> -").tune("gumbeng")
|
||||
.mul(getFreq('c3'))
|
||||
.freq().clip(.8).room("3:10").rdim(10000).rfade(5)`}
|
||||
/>
|
||||
@@ -48,7 +48,7 @@ Additionally, you can combo this with `fmap` so that the base note changes:
|
||||
|
||||
<MiniRepl
|
||||
client:idle
|
||||
tune={`"9 11 12 10 - - -".tune("gunkali")
|
||||
tune={`i("9 11 12 10 - - -").tune("gunkali")
|
||||
.mul("<c3 c3 a3 d#3>".fmap(getFreq))
|
||||
.freq().legato("2 .7").room("1:15").rdim(8500).rlp(14000).rfade(8)`}
|
||||
/>
|
||||
@@ -57,8 +57,7 @@ Combining this with various polyrhythm tricks can become very evocative:
|
||||
|
||||
<MiniRepl
|
||||
client:idle
|
||||
tune={`"<[0 3 1 -] [-1 4 2 8]> ~ ~,<-4 -5>"
|
||||
.transpose(4)
|
||||
tune={`i("<[0 3 1 -] [-1 4 2 8]> ~ ~,<-4 -5>".add(4))
|
||||
.tune("iraq")
|
||||
.mul("<c3 d3 c#3>".fmap(getFreq))
|
||||
.freq().clip(.5).room(1).rfade(9)`}
|
||||
@@ -71,7 +70,7 @@ Take the `sanza` tuning:
|
||||
|
||||
<MiniRepl
|
||||
client:idle
|
||||
tune={`"4 5 6 7 8 9".tune("sanza")
|
||||
tune={`i("4 5 6 7 8 9").tune("sanza")
|
||||
.mul(getFreq('c3'))
|
||||
.freq()`}
|
||||
/>
|
||||
@@ -79,15 +78,15 @@ Take the `sanza` tuning:
|
||||
Notes 7 and 9 will clash quite a bit if you arp them normally. Many tunings will have this sort of sound, and it can feel distracting on its own.
|
||||
See how close they are on the pitch wheel?
|
||||
|
||||
<MiniRepl client:idle tune={`"[7 9]!3".tune("sanza").mul(getFreq('c3')).freq()._pitchwheel()`} />
|
||||
<MiniRepl client:idle tune={`i("[7 9]!3").tune("sanza").mul(getFreq('c3')).freq()._pitchwheel()`} />
|
||||
|
||||
This quality is often due to how the tunings were formed with instruments that were played differently than a piano.
|
||||
As such, some tunings are much better strummed, with the subtle clash of the detuned notes actually making the sound much more magical:
|
||||
|
||||
<MiniRepl
|
||||
client:idle
|
||||
tune={`"[0 1 2 3 4 5 6]@0.3 -"
|
||||
.transpose("<2 5 8 1>")
|
||||
tune={`i("[0 1 2 3 4 5 6]@0.3 -"
|
||||
.add("<2 5 8 1>"))
|
||||
.tune("sanza")
|
||||
.mul(getFreq('c3')).freq()
|
||||
.legato("3").room(1).rfade(5)`}
|
||||
@@ -102,7 +101,7 @@ You can also give tune a list of frequencies to use as the scale:
|
||||
|
||||
<MiniRepl
|
||||
client:idle
|
||||
tune={`"0 1 2 3 4".tune([
|
||||
tune={`i("0 1 2 3 4").tune([
|
||||
261.6255653006,
|
||||
302.72962012827,
|
||||
350.29154279212,
|
||||
|
||||
Reference in New Issue
Block a user