mirror of
https://codeberg.org/uzu/strudel
synced 2026-10-02 08:00:06 -04:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 98dd364ab0 | |||
| ebd1c2f564 | |||
| e15eef9a16 | |||
| bf72908dc9 | |||
| 4bfeaa47bf | |||
| 9a4d8036a6 | |||
| a50bd6375d | |||
| 14508e91a9 |
+74
-52
@@ -5,20 +5,24 @@ This program is free software: you can redistribute it and/or modify it under th
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Pattern, sequence } from './pattern.mjs';
|
import { Pattern, sequence } from './pattern.mjs';
|
||||||
|
import { zipWith } from './util.mjs';
|
||||||
|
|
||||||
const controls = {};
|
const controls = {};
|
||||||
const generic_params = [
|
const generic_params = [
|
||||||
/**
|
/**
|
||||||
* Select a sound / sample by name.
|
* Select a sound / sample by name. When using mininotation, you can also optionally supply 'n' and 'gain' parameters
|
||||||
|
* separated by ':'.
|
||||||
*
|
*
|
||||||
* @name s
|
* @name s
|
||||||
* @param {string | Pattern} sound The sound / pattern of sounds to pick
|
* @param {string | Pattern} sound The sound / pattern of sounds to pick
|
||||||
* @synonyms sound
|
* @synonyms sound
|
||||||
* @example
|
* @example
|
||||||
* s("bd hh")
|
* s("bd hh")
|
||||||
|
* @example
|
||||||
|
* s("bd:0 bd:1 bd:0:0.3 bd:1:1.4")
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
['s', 'sound'],
|
[['s', 'n', 'gain'], 'sound'],
|
||||||
/**
|
/**
|
||||||
* Selects the given index from the sample map.
|
* Selects the given index from the sample map.
|
||||||
* Numbers too high will wrap around.
|
* Numbers too high will wrap around.
|
||||||
@@ -50,7 +54,7 @@ const generic_params = [
|
|||||||
* @example
|
* @example
|
||||||
* note("60 69 65 64")
|
* note("60 69 65 64")
|
||||||
*/
|
*/
|
||||||
['note'],
|
[['note', 'n']],
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A pattern of numbers that speed up (or slow down) samples while they play. Currently only supported by osc / superdirt.
|
* A pattern of numbers that speed up (or slow down) samples while they play. Currently only supported by osc / superdirt.
|
||||||
@@ -143,21 +147,20 @@ const generic_params = [
|
|||||||
['hold'],
|
['hold'],
|
||||||
// TODO: in tidal, it seems to be normalized
|
// TODO: in tidal, it seems to be normalized
|
||||||
/**
|
/**
|
||||||
* Sets the center frequency of the **b**and-**p**ass **f**ilter.
|
* Sets the center frequency of the **b**and-**p**ass **f**ilter. When using mininotation, you
|
||||||
|
* can also optionally supply the 'bpq' parameter separated by ':'.
|
||||||
*
|
*
|
||||||
* @name bpf
|
* @name bpf
|
||||||
* @param {number | Pattern} frequency center frequency
|
* @param {number | Pattern} frequency center frequency
|
||||||
* @synonyms bandf
|
* @synonyms bandf, bp
|
||||||
* @example
|
* @example
|
||||||
* s("bd sd,hh*3").bpf("<1000 2000 4000 8000>")
|
* s("bd sd,hh*3").bpf("<1000 2000 4000 8000>")
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
// currently an alias of 'bandf' https://github.com/tidalcycles/strudel/issues/496
|
[['bandf', 'bandq'], 'bpf', 'bp'],
|
||||||
// ['bpf'],
|
|
||||||
['bandf', 'bpf'],
|
|
||||||
// TODO: in tidal, it seems to be normalized
|
// TODO: in tidal, it seems to be normalized
|
||||||
/**
|
/**
|
||||||
* Sets the **b**and-**p**ass **q**-factor (resonance)
|
* Sets the **b**and-**p**ass **q**-factor (resonance).
|
||||||
*
|
*
|
||||||
* @name bpq
|
* @name bpq
|
||||||
* @param {number | Pattern} q q factor
|
* @param {number | Pattern} q q factor
|
||||||
@@ -193,33 +196,16 @@ const generic_params = [
|
|||||||
*/
|
*/
|
||||||
['end'],
|
['end'],
|
||||||
/**
|
/**
|
||||||
* Loops the sample from `loopBegin` to `loopEnd`. If one or both of those are set,
|
* Loops the sample (from `begin` to `end`) the specified number of times.
|
||||||
* the sample is looped to fill the event duration, instead of playing the whole sample.
|
* Note that the tempo of the loop is not synced with the cycle tempo.
|
||||||
* If only `loopBegin` is set, `loopEnd` defaults to 1.
|
|
||||||
* If only `loopEnd` is set, `loopBegin` defaults to 0.
|
|
||||||
*
|
*
|
||||||
* @name loopBegin
|
* @name loop
|
||||||
* @param {number | Pattern} position position from 0 - 1 where the loop starts
|
* @param {number | Pattern} times How often the sample is looped
|
||||||
* @example
|
* @example
|
||||||
* note("<c a f e>").s("piano")
|
* s("bd").loop("<1 2 3 4>").osc()
|
||||||
* .loopBegin("<0 .24 .32>").loopEnd(.5)
|
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
['loopBegin'],
|
['loop'],
|
||||||
/**
|
|
||||||
* Loops the sample from `loopBegin` to `loopEnd`. If one or both of those are set,
|
|
||||||
* the sample is looped to fill the event duration, instead of playing the whole sample.
|
|
||||||
* If only `loopBegin` is set, `loopEnd` defaults to 1.
|
|
||||||
* If only `loopEnd` is set, `loopBegin` defaults to 0.
|
|
||||||
*
|
|
||||||
* @name loopEnd
|
|
||||||
* @param {number | Pattern} position position from 0 - 1 where the loop ends
|
|
||||||
* @example
|
|
||||||
* note("<c a f e>").s("piano")
|
|
||||||
* .loopBegin(.2).loopEnd("<.3 .4 .5 .6>")
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
['loopEnd'],
|
|
||||||
// TODO: currently duplicated with "native" legato
|
// TODO: currently duplicated with "native" legato
|
||||||
// TODO: superdirt legato will do more: https://youtu.be/dQPmE1WaD1k?t=419
|
// TODO: superdirt legato will do more: https://youtu.be/dQPmE1WaD1k?t=419
|
||||||
/**
|
/**
|
||||||
@@ -275,27 +261,35 @@ const generic_params = [
|
|||||||
/**
|
/**
|
||||||
* Applies the cutoff frequency of the **l**ow-**p**ass **f**ilter.
|
* Applies the cutoff frequency of the **l**ow-**p**ass **f**ilter.
|
||||||
*
|
*
|
||||||
|
* When using mininotation, you can also optionally add the 'lpq' parameter, separated by ':'.
|
||||||
|
*
|
||||||
* @name lpf
|
* @name lpf
|
||||||
* @param {number | Pattern} frequency audible between 0 and 20000
|
* @param {number | Pattern} frequency audible between 0 and 20000
|
||||||
* @synonyms cutoff, ctf
|
* @synonyms cutoff, ctf, lp
|
||||||
* @example
|
* @example
|
||||||
* s("bd sd,hh*3").lpf("<4000 2000 1000 500 200 100>")
|
* s("bd sd,hh*3").lpf("<4000 2000 1000 500 200 100>")
|
||||||
|
* @example
|
||||||
|
* s("bd*8").lpf("1000:0 1000:10 1000:20 1000:30")
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
['cutoff', 'ctf', 'lpf'],
|
[['cutoff', 'resonance'], 'ctf', 'lpf', 'lp'],
|
||||||
/**
|
/**
|
||||||
* Applies the cutoff frequency of the **h**igh-**p**ass **f**ilter.
|
* Applies the cutoff frequency of the **h**igh-**p**ass **f**ilter.
|
||||||
*
|
*
|
||||||
|
* When using mininotation, you can also optionally add the 'hpq' parameter, separated by ':'.
|
||||||
|
*
|
||||||
* @name hpf
|
* @name hpf
|
||||||
* @param {number | Pattern} frequency audible between 0 and 20000
|
* @param {number | Pattern} frequency audible between 0 and 20000
|
||||||
* @synonyms hcutoff
|
* @synonyms hp, hcutoff
|
||||||
* @example
|
* @example
|
||||||
* s("bd sd,hh*4").hpf("<4000 2000 1000 500 200 100>")
|
* s("bd sd,hh*4").hpf("<4000 2000 1000 500 200 100>")
|
||||||
|
* @example
|
||||||
|
* s("bd sd,hh*4").hpf("<2000 2000:25>")
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
// currently an alias of 'hcutoff' https://github.com/tidalcycles/strudel/issues/496
|
// currently an alias of 'hcutoff' https://github.com/tidalcycles/strudel/issues/496
|
||||||
// ['hpf'],
|
// ['hpf'],
|
||||||
['hcutoff', 'hpf'],
|
[['hcutoff', 'hresonance'], 'hpf', 'hp'],
|
||||||
/**
|
/**
|
||||||
* Controls the **h**igh-**p**ass **q**-value.
|
* Controls the **h**igh-**p**ass **q**-value.
|
||||||
*
|
*
|
||||||
@@ -334,13 +328,19 @@ const generic_params = [
|
|||||||
/**
|
/**
|
||||||
* Sets the level of the delay signal.
|
* Sets the level of the delay signal.
|
||||||
*
|
*
|
||||||
|
* When using mininotation, you can also optionally add the 'delaytime' and 'delayfeedback' parameter,
|
||||||
|
* separated by ':'.
|
||||||
|
*
|
||||||
|
*
|
||||||
* @name delay
|
* @name delay
|
||||||
* @param {number | Pattern} level between 0 and 1
|
* @param {number | Pattern} level between 0 and 1
|
||||||
* @example
|
* @example
|
||||||
* s("bd").delay("<0 .25 .5 1>")
|
* s("bd").delay("<0 .25 .5 1>")
|
||||||
|
* @example
|
||||||
|
* s("bd bd").delay("0.65:0.25:0.9 0.65:0.125:0.7")
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
['delay'],
|
[['delay', 'delaytime', 'delayfeedback']],
|
||||||
/**
|
/**
|
||||||
* Sets the level of the signal that is fed back into the delay.
|
* Sets the level of the signal that is fed back into the delay.
|
||||||
* Caution: Values >= 1 will result in a signal that gets louder and louder! Don't do it
|
* Caution: Values >= 1 will result in a signal that gets louder and louder! Don't do it
|
||||||
@@ -566,13 +566,17 @@ const generic_params = [
|
|||||||
/**
|
/**
|
||||||
* Sets the level of reverb.
|
* Sets the level of reverb.
|
||||||
*
|
*
|
||||||
|
* When using mininotation, you can also optionally add the 'size' parameter, separated by ':'.
|
||||||
|
*
|
||||||
* @name room
|
* @name room
|
||||||
* @param {number | Pattern} level between 0 and 1
|
* @param {number | Pattern} level between 0 and 1
|
||||||
* @example
|
* @example
|
||||||
* s("bd sd").room("<0 .2 .4 .6 .8 1>")
|
* s("bd sd").room("<0 .2 .4 .6 .8 1>")
|
||||||
|
* @example
|
||||||
|
* s("bd sd").room("<0.9:1 0.9:4>")
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
['room'],
|
[['room', 'size']],
|
||||||
/**
|
/**
|
||||||
* Sets the room size of the reverb, see {@link room}.
|
* Sets the room size of the reverb, see {@link room}.
|
||||||
*
|
*
|
||||||
@@ -750,32 +754,50 @@ const generic_params = [
|
|||||||
|
|
||||||
// TODO: slice / splice https://www.youtube.com/watch?v=hKhPdO0RKDQ&list=PL2lW1zNIIwj3bDkh-Y3LUGDuRcoUigoDs&index=13
|
// TODO: slice / splice https://www.youtube.com/watch?v=hKhPdO0RKDQ&list=PL2lW1zNIIwj3bDkh-Y3LUGDuRcoUigoDs&index=13
|
||||||
|
|
||||||
const _name = (name, ...pats) => sequence(...pats).withValue((x) => ({ [name]: x }));
|
controls.createParam = function (names) {
|
||||||
|
const name = Array.isArray(names) ? names[0] : names;
|
||||||
|
|
||||||
const _setter = (func, name) =>
|
var withVal;
|
||||||
function (...pats) {
|
if (Array.isArray(names)) {
|
||||||
|
withVal = (xs) => {
|
||||||
|
if (Array.isArray(xs)) {
|
||||||
|
const result = {};
|
||||||
|
xs.forEach((x, i) => {
|
||||||
|
if (i < names.length) {
|
||||||
|
result[names[i]] = x;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
return { [name]: xs };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
withVal = (x) => ({ [name]: x });
|
||||||
|
}
|
||||||
|
|
||||||
|
const func = (...pats) => sequence(...pats).withValue(withVal);
|
||||||
|
|
||||||
|
const setter = function (...pats) {
|
||||||
if (!pats.length) {
|
if (!pats.length) {
|
||||||
return this.fmap((value) => ({ [name]: value }));
|
return this.fmap(withVal);
|
||||||
}
|
}
|
||||||
return this.set(func(...pats));
|
return this.set(func(...pats));
|
||||||
};
|
};
|
||||||
|
Pattern.prototype[name] = setter;
|
||||||
|
return func;
|
||||||
|
};
|
||||||
|
|
||||||
|
generic_params.forEach(([names, ...aliases]) => {
|
||||||
|
const name = Array.isArray(names) ? names[0] : names;
|
||||||
|
controls[name] = controls.createParam(names);
|
||||||
|
|
||||||
generic_params.forEach(([name, ...aliases]) => {
|
|
||||||
controls[name] = (...pats) => _name(name, ...pats);
|
|
||||||
Pattern.prototype[name] = _setter(controls[name], name);
|
|
||||||
aliases.forEach((alias) => {
|
aliases.forEach((alias) => {
|
||||||
controls[alias] = controls[name];
|
controls[alias] = controls[name];
|
||||||
Pattern.prototype[alias] = Pattern.prototype[name];
|
Pattern.prototype[alias] = Pattern.prototype[name];
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// create custom param
|
|
||||||
controls.createParam = (name) => {
|
|
||||||
const func = (...pats) => _name(name, ...pats);
|
|
||||||
Pattern.prototype[name] = _setter(func, name);
|
|
||||||
return (...pats) => _name(name, ...pats);
|
|
||||||
};
|
|
||||||
|
|
||||||
controls.createParams = (...names) =>
|
controls.createParams = (...names) =>
|
||||||
names.reduce((acc, name) => Object.assign(acc, { [name]: controls.createParam(name) }), {});
|
names.reduce((acc, name) => Object.assign(acc, { [name]: controls.createParam(name) }), {});
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
controls.test.mjs - <short description TODO>
|
||||||
|
Copyright (C) 2023 Strudel contributors - see <https://github.com/tidalcycles/strudel/blob/main/packages/core/test/controls.test.mjs>
|
||||||
|
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 controls from '../controls.mjs';
|
||||||
|
import { mini } from '../../mini/mini.mjs';
|
||||||
|
import { describe, it, expect } from 'vitest';
|
||||||
|
|
||||||
|
describe('controls', () => {
|
||||||
|
it('should support controls', () => {
|
||||||
|
expect(controls.s('bd').firstCycleValues).toEqual([{ s: 'bd' }]);
|
||||||
|
});
|
||||||
|
it('should support compound controls', () => {
|
||||||
|
expect(controls.s(mini('bd:3')).firstCycleValues).toEqual([{ s: 'bd', n: 3 }]);
|
||||||
|
expect(controls.s(mini('bd:3 sd:4:1.4')).firstCycleValues).toEqual([
|
||||||
|
{ s: 'bd', n: 3 },
|
||||||
|
{ s: 'sd', n: 4, gain: 1.4 },
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
it('should support ignore extra elements in compound controls', () => {
|
||||||
|
expect(controls.s(mini('bd:3:0.4 sd:4:0.5:3:17')).firstCycleValues).toEqual([
|
||||||
|
{ s: 'bd', n: 3, gain: 0.4 },
|
||||||
|
{ s: 'sd', n: 4, gain: 0.5 },
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
+383
-283
File diff suppressed because it is too large
Load Diff
@@ -19,6 +19,13 @@ This program is free software: you can redistribute it and/or modify it under th
|
|||||||
this.location_ = location();
|
this.location_ = location();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var MemoryStub = function(source)
|
||||||
|
{
|
||||||
|
this.type_ = "memory";
|
||||||
|
this.source_ = source;
|
||||||
|
this.location_ = location();
|
||||||
|
}
|
||||||
|
|
||||||
var PatternStub = function(source, alignment)
|
var PatternStub = function(source, alignment)
|
||||||
{
|
{
|
||||||
this.type_ = "pattern";
|
this.type_ = "pattern";
|
||||||
@@ -96,9 +103,11 @@ quote = '"' / "'"
|
|||||||
// ------------------ steps and cycles ---------------------------
|
// ------------------ steps and cycles ---------------------------
|
||||||
|
|
||||||
// single step definition (e.g bd)
|
// single step definition (e.g bd)
|
||||||
step_char = [0-9a-zA-Z~] / "-" / "#" / "." / "^" / "_" / ":"
|
step_char = [0-9a-zA-Z~] / "-" / "#" / "." / "_" / "^"
|
||||||
step = ws chars:step_char+ ws { return new AtomStub(chars.join("")) }
|
step = ws chars:step_char+ ws { return new AtomStub(chars.join("")) }
|
||||||
|
|
||||||
|
memory = ws "^" h:[A-Za-z] t:[A-Za-z0-9_]+ { return new MemoryStub(h + t.join("")) }
|
||||||
|
|
||||||
// define a sub cycle e.g. [1 2, 3 [4]]
|
// define a sub cycle e.g. [1 2, 3 [4]]
|
||||||
sub_cycle = ws "[" ws s:stack_or_choose ws "]" ws { return s }
|
sub_cycle = ws "[" ws s:stack_or_choose ws "]" ws { return s }
|
||||||
|
|
||||||
@@ -115,11 +124,11 @@ slow_sequence = ws "<" ws s:sequence ws ">" ws
|
|||||||
{ s.arguments_.alignment = 'slowcat'; return s; }
|
{ s.arguments_.alignment = 'slowcat'; return s; }
|
||||||
|
|
||||||
// a slice is either a single step or a sub cycle
|
// a slice is either a single step or a sub cycle
|
||||||
slice = step / sub_cycle / polymeter / slow_sequence
|
slice = memory / step / sub_cycle / polymeter / slow_sequence
|
||||||
|
|
||||||
// slice modifier affects the timing/size of a slice (e.g. [a b c]@3)
|
// slice modifier affects the timing/size of a slice (e.g. [a b c]@3)
|
||||||
// at this point, we assume we can represent them as regular sequence operators
|
// at this point, we assume we can represent them as regular sequence operators
|
||||||
slice_op = op_weight / op_bjorklund / op_slow / op_fast / op_replicate / op_degrade
|
slice_op = op_weight / op_bjorklund / op_slow / op_fast / op_replicate / op_degrade / op_tail
|
||||||
|
|
||||||
op_weight = "@" a:number
|
op_weight = "@" a:number
|
||||||
{ return x => x.options_['weight'] = a }
|
{ return x => x.options_['weight'] = a }
|
||||||
@@ -139,6 +148,9 @@ op_fast = "*"a:slice
|
|||||||
op_degrade = "?"a:number?
|
op_degrade = "?"a:number?
|
||||||
{ return x => x.options_['ops'].push({ type_: "degradeBy", arguments_ :{ amount:a } }) }
|
{ return x => x.options_['ops'].push({ type_: "degradeBy", arguments_ :{ amount:a } }) }
|
||||||
|
|
||||||
|
op_tail = ":" s:slice
|
||||||
|
{ return x => x.options_['ops'].push({ type_: "tail", arguments_ :{ element:s } }) }
|
||||||
|
|
||||||
// a slice with an modifier applied i.e [bd@4 sd@3]@2 hh]
|
// a slice with an modifier applied i.e [bd@4 sd@3]@2 hh]
|
||||||
slice_with_ops = s:slice ops:slice_op*
|
slice_with_ops = s:slice ops:slice_op*
|
||||||
{ const result = new ElementStub(s, {ops: [], weight: 1, reps: 1});
|
{ const result = new ElementStub(s, {ops: [], weight: 1, reps: 1});
|
||||||
|
|||||||
@@ -14,10 +14,22 @@ function _nextSeed() {
|
|||||||
return _seedState++;
|
return _seedState++;
|
||||||
} */
|
} */
|
||||||
|
|
||||||
|
const memory = {};
|
||||||
|
|
||||||
|
export const remember = (name, pat) => {
|
||||||
|
if (pat) {
|
||||||
|
memory[name] = pat;
|
||||||
|
} else {
|
||||||
|
pat = memory[name];
|
||||||
|
}
|
||||||
|
return pat;
|
||||||
|
};
|
||||||
|
|
||||||
const applyOptions = (parent, code) => (pat, i) => {
|
const applyOptions = (parent, code) => (pat, i) => {
|
||||||
const ast = parent.source_[i];
|
const ast = parent.source_[i];
|
||||||
const options = ast.options_;
|
const options = ast.options_;
|
||||||
const ops = options?.ops;
|
const ops = options?.ops;
|
||||||
|
|
||||||
if (ops) {
|
if (ops) {
|
||||||
for (const op of ops) {
|
for (const op of ops) {
|
||||||
switch (op.type_) {
|
switch (op.type_) {
|
||||||
@@ -66,6 +78,11 @@ const applyOptions = (parent, code) => (pat, i) => {
|
|||||||
pat = strudel.reify(pat).degradeBy(op.arguments_.amount === null ? 0.5 : op.arguments_.amount);
|
pat = strudel.reify(pat).degradeBy(op.arguments_.amount === null ? 0.5 : op.arguments_.amount);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 'tail': {
|
||||||
|
const friend = patternifyAST(op.arguments_.element, code);
|
||||||
|
pat = pat.fmap((a) => (b) => Array.isArray(a) ? [...a, b] : [a, b]).appLeft(friend);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default: {
|
default: {
|
||||||
console.warn(`operator "${op.type_}" not implemented`);
|
console.warn(`operator "${op.type_}" not implemented`);
|
||||||
}
|
}
|
||||||
@@ -132,6 +149,16 @@ export function patternifyAST(ast, code) {
|
|||||||
case 'element': {
|
case 'element': {
|
||||||
return patternifyAST(ast.source_, code);
|
return patternifyAST(ast.source_, code);
|
||||||
}
|
}
|
||||||
|
case 'memory': {
|
||||||
|
const name = ast.source_;
|
||||||
|
if (name in memory) {
|
||||||
|
return new strudel.Pattern((state) => {
|
||||||
|
return memory[name].query(state);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// TODO - how to default a memory.. via a list?
|
||||||
|
return strudel.pure(undefined);
|
||||||
|
}
|
||||||
case 'atom': {
|
case 'atom': {
|
||||||
if (ast.source_ === '~') {
|
if (ast.source_ === '~') {
|
||||||
return strudel.silence;
|
return strudel.silence;
|
||||||
|
|||||||
@@ -140,6 +140,9 @@ describe('mini', () => {
|
|||||||
expect(haps.length < 230).toBe(true);
|
expect(haps.length < 230).toBe(true);
|
||||||
// 'Had too many cycles remaining after degradeBy 0.8');
|
// 'Had too many cycles remaining after degradeBy 0.8');
|
||||||
});
|
});
|
||||||
|
it('supports lists', () => {
|
||||||
|
expect(minV('a:b c:d:[e:f] g')).toEqual([['a', 'b'], ['c', 'd', ['e', 'f']], 'g']);
|
||||||
|
});
|
||||||
/*it('supports the random choice operator ("|") with nesting', () => {
|
/*it('supports the random choice operator ("|") with nesting', () => {
|
||||||
const numCycles = 900;
|
const numCycles = 900;
|
||||||
const haps = mini('a | [b | c] | [d | e | f]').queryArc(0, numCycles);
|
const haps = mini('a | [b | c] | [d | e | f]').queryArc(0, numCycles);
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ This program is free software: you can redistribute it and/or modify it under th
|
|||||||
import '../tonal.mjs'; // need to import this to add prototypes
|
import '../tonal.mjs'; // need to import this to add prototypes
|
||||||
import { pure, controls, seq } from '@strudel.cycles/core';
|
import { pure, controls, seq } from '@strudel.cycles/core';
|
||||||
import { describe, it, expect } from 'vitest';
|
import { describe, it, expect } from 'vitest';
|
||||||
|
import { mini } from '../../mini/mini.mjs';
|
||||||
const { n } = controls;
|
const { n } = controls;
|
||||||
|
|
||||||
describe('tonal', () => {
|
describe('tonal', () => {
|
||||||
@@ -30,4 +31,18 @@ describe('tonal', () => {
|
|||||||
.firstCycleValues.map((h) => h.note),
|
.firstCycleValues.map((h) => h.note),
|
||||||
).toEqual(['C3', 'D3', 'E3']);
|
).toEqual(['C3', 'D3', 'E3']);
|
||||||
});
|
});
|
||||||
|
it('scale with colon', () => {
|
||||||
|
expect(
|
||||||
|
n(0, 1, 2)
|
||||||
|
.scale('C:major')
|
||||||
|
.firstCycleValues.map((h) => h.note),
|
||||||
|
).toEqual(['C3', 'D3', 'E3']);
|
||||||
|
});
|
||||||
|
it('scale with mininotation colon', () => {
|
||||||
|
expect(
|
||||||
|
n(0, 1, 2)
|
||||||
|
.scale(mini('C:major'))
|
||||||
|
.firstCycleValues.map((h) => h.note),
|
||||||
|
).toEqual(['C3', 'D3', 'E3']);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -123,29 +123,37 @@ export const scaleTranspose = register('scaleTranspose', function (offset /* : n
|
|||||||
/**
|
/**
|
||||||
* Turns numbers into notes in the scale (zero indexed). Also sets scale for other scale operations, like {@link Pattern#scaleTranspose}.
|
* Turns numbers into notes in the scale (zero indexed). Also sets scale for other scale operations, like {@link Pattern#scaleTranspose}.
|
||||||
*
|
*
|
||||||
* A scale consists of a root note (e.g. `c4`, `c`, `f#`, `bb4`) followed by a [scale type](https://github.com/tonaljs/tonal/blob/main/packages/scale-type/data.ts).
|
* A scale consists of a root note (e.g. `c4`, `c`, `f#`, `bb4`) followed by semicolon (':') and then a [scale type](https://github.com/tonaljs/tonal/blob/main/packages/scale-type/data.ts).
|
||||||
|
*
|
||||||
* The root note defaults to octave 3, if no octave number is given.
|
* The root note defaults to octave 3, if no octave number is given.
|
||||||
* Note that you currently cannot pattern `scale` with the mini notation, because the scale name includes a space.
|
|
||||||
* This will be improved in the future. Until then, use a sequence function like `cat` or `seq`.
|
|
||||||
*
|
*
|
||||||
* @memberof Pattern
|
* @memberof Pattern
|
||||||
* @name scale
|
* @name scale
|
||||||
* @param {string} scale Name of scale
|
* @param {string} scale Name of scale
|
||||||
* @returns Pattern
|
* @returns Pattern
|
||||||
* @example
|
* @example
|
||||||
* "0 2 4 6 4 2".scale('C2 major').note()
|
* "0 2 4 6 4 2".scale("C2:major").note()
|
||||||
* @example
|
* @example
|
||||||
* "0 2 4 6 4 2"
|
* "0 2 4 6 4 2"
|
||||||
* .scale(seq('C2 major', 'C2 minor').slow(2))
|
* .scale("C2:<major minor>")
|
||||||
* .note()
|
* .note()
|
||||||
|
* @example
|
||||||
|
* "0 1 2 3 4 5 6 7".rev().scale("C2:<major minor>").note()
|
||||||
|
* .s("folkharp")
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export const scale = register('scale', function (scale /* : string */, pat) {
|
export const scale = register('scale', function (scale, pat) {
|
||||||
|
// Supports ':' list syntax in mininotation
|
||||||
|
if (Array.isArray(scale)) {
|
||||||
|
scale = scale.join(' ');
|
||||||
|
}
|
||||||
return pat.withHap((hap) => {
|
return pat.withHap((hap) => {
|
||||||
const isObject = typeof hap.value === 'object';
|
const isObject = typeof hap.value === 'object';
|
||||||
let note = isObject ? hap.value.n : hap.value;
|
let note = isObject ? hap.value.n : hap.value;
|
||||||
const asNumber = Number(note);
|
const asNumber = Number(note);
|
||||||
if (!isNaN(asNumber)) {
|
if (!isNaN(asNumber)) {
|
||||||
|
// TODO: worth keeping for supporting ':' in (non-mininotation) strings?
|
||||||
|
scale = scale.replaceAll(':', ' ');
|
||||||
let [tonic, scaleName] = Scale.tokenize(scale);
|
let [tonic, scaleName] = Scale.tokenize(scale);
|
||||||
const { pc, oct = 3 } = Note.get(tonic);
|
const { pc, oct = 3 } = Note.get(tonic);
|
||||||
note = scaleOffset(pc + ' ' + scaleName, asNumber, pc + oct);
|
note = scaleOffset(pc + ' ' + scaleName, asNumber, pc + oct);
|
||||||
|
|||||||
@@ -97,17 +97,6 @@ const getSoundfontKey = (s) => {
|
|||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
const splitSN = (s, n) => {
|
|
||||||
if (!s.includes(':')) {
|
|
||||||
return [s, n];
|
|
||||||
}
|
|
||||||
let [s2, n2] = s.split(':');
|
|
||||||
if (isNaN(Number(n2))) {
|
|
||||||
return [s, n];
|
|
||||||
}
|
|
||||||
return [s2, n2];
|
|
||||||
};
|
|
||||||
|
|
||||||
let workletsLoading;
|
let workletsLoading;
|
||||||
function loadWorklets() {
|
function loadWorklets() {
|
||||||
if (workletsLoading) {
|
if (workletsLoading) {
|
||||||
@@ -231,8 +220,7 @@ export const webaudioOutput = async (hap, deadline, hapDuration, cps) => {
|
|||||||
unit,
|
unit,
|
||||||
nudge = 0, // TODO: is this in seconds?
|
nudge = 0, // TODO: is this in seconds?
|
||||||
cut,
|
cut,
|
||||||
loopBegin,
|
loop,
|
||||||
loopEnd,
|
|
||||||
orbit = 1,
|
orbit = 1,
|
||||||
room,
|
room,
|
||||||
size = 2,
|
size = 2,
|
||||||
@@ -244,12 +232,6 @@ export const webaudioOutput = async (hap, deadline, hapDuration, cps) => {
|
|||||||
if (bank && s) {
|
if (bank && s) {
|
||||||
s = `${bank}_${s}`;
|
s = `${bank}_${s}`;
|
||||||
}
|
}
|
||||||
if (typeof s === 'string') {
|
|
||||||
[s, n] = splitSN(s, n);
|
|
||||||
}
|
|
||||||
if (typeof note === 'string') {
|
|
||||||
[note, n] = splitSN(note, n);
|
|
||||||
}
|
|
||||||
if (!s || ['sine', 'square', 'triangle', 'sawtooth'].includes(s)) {
|
if (!s || ['sine', 'square', 'triangle', 'sawtooth'].includes(s)) {
|
||||||
// destructure adsr here, because the default should be different for synths and samples
|
// destructure adsr here, because the default should be different for synths and samples
|
||||||
const { attack = 0.001, decay = 0.05, sustain = 0.6, release = 0.01 } = hap.value;
|
const { attack = 0.001, decay = 0.05, sustain = 0.6, release = 0.01 } = hap.value;
|
||||||
@@ -308,21 +290,17 @@ export const webaudioOutput = async (hap, deadline, hapDuration, cps) => {
|
|||||||
// are there other units?
|
// are there other units?
|
||||||
bufferSource.playbackRate.value = bufferSource.playbackRate.value * bufferSource.buffer.duration * cps;
|
bufferSource.playbackRate.value = bufferSource.playbackRate.value * bufferSource.buffer.duration * cps;
|
||||||
}
|
}
|
||||||
const loop = loopBegin !== undefined || loopEnd !== undefined;
|
let duration = soundfont || clip ? hapDuration : bufferSource.buffer.duration / bufferSource.playbackRate.value;
|
||||||
let duration =
|
|
||||||
soundfont || clip || loop ? hapDuration : bufferSource.buffer.duration / bufferSource.playbackRate.value;
|
|
||||||
// "The computation of the offset into the sound is performed using the sound buffer's natural sample rate,
|
// "The computation of the offset into the sound is performed using the sound buffer's natural sample rate,
|
||||||
// rather than the current playback rate, so even if the sound is playing at twice its normal speed,
|
// rather than the current playback rate, so even if the sound is playing at twice its normal speed,
|
||||||
// the midway point through a 10-second audio buffer is still 5."
|
// the midway point through a 10-second audio buffer is still 5."
|
||||||
const offset = begin * duration * bufferSource.playbackRate.value;
|
const offset = begin * duration * bufferSource.playbackRate.value;
|
||||||
duration = (end - begin) * duration;
|
duration = (end - begin) * duration;
|
||||||
if (loop) {
|
if (loop) {
|
||||||
loopBegin = loopBegin ?? 0;
|
|
||||||
loopEnd = loopEnd ?? 1;
|
|
||||||
bufferSource.loop = true;
|
bufferSource.loop = true;
|
||||||
bufferSource.loopStart = offset + loopBegin * duration;
|
bufferSource.loopStart = offset;
|
||||||
bufferSource.loopEnd = offset + duration - (1 - loopEnd) * duration;
|
bufferSource.loopEnd = offset + duration;
|
||||||
duration = hapDuration;
|
duration = loop * duration;
|
||||||
}
|
}
|
||||||
t += nudge;
|
t += nudge;
|
||||||
|
|
||||||
|
|||||||
@@ -1399,6 +1399,19 @@ exports[`runs examples > example "delay" example index 0 1`] = `
|
|||||||
]
|
]
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`runs examples > example "delay" example index 1 1`] = `
|
||||||
|
[
|
||||||
|
"[ 0/1 → 1/2 | s:bd delay:0.65 delaytime:0.25 delayfeedback:0.9 ]",
|
||||||
|
"[ 1/2 → 1/1 | s:bd delay:0.65 delaytime:0.125 delayfeedback:0.7 ]",
|
||||||
|
"[ 1/1 → 3/2 | s:bd delay:0.65 delaytime:0.25 delayfeedback:0.9 ]",
|
||||||
|
"[ 3/2 → 2/1 | s:bd delay:0.65 delaytime:0.125 delayfeedback:0.7 ]",
|
||||||
|
"[ 2/1 → 5/2 | s:bd delay:0.65 delaytime:0.25 delayfeedback:0.9 ]",
|
||||||
|
"[ 5/2 → 3/1 | s:bd delay:0.65 delaytime:0.125 delayfeedback:0.7 ]",
|
||||||
|
"[ 3/1 → 7/2 | s:bd delay:0.65 delaytime:0.25 delayfeedback:0.9 ]",
|
||||||
|
"[ 7/2 → 4/1 | s:bd delay:0.65 delaytime:0.125 delayfeedback:0.7 ]",
|
||||||
|
]
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`runs examples > example "delayfeedback" example index 0 1`] = `
|
exports[`runs examples > example "delayfeedback" example index 0 1`] = `
|
||||||
[
|
[
|
||||||
"[ (0/1 → 1/1) ⇝ 2/1 | s:bd delay:0.25 delayfeedback:0.25 ]",
|
"[ (0/1 → 1/1) ⇝ 2/1 | s:bd delay:0.25 delayfeedback:0.25 ]",
|
||||||
@@ -1923,6 +1936,35 @@ exports[`runs examples > example "hpf" example index 0 1`] = `
|
|||||||
]
|
]
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`runs examples > example "hpf" example index 1 1`] = `
|
||||||
|
[
|
||||||
|
"[ 0/1 → 1/2 | s:bd hcutoff:2000 ]",
|
||||||
|
"[ 1/2 → 1/1 | s:sd hcutoff:2000 ]",
|
||||||
|
"[ 0/1 → 1/4 | s:hh hcutoff:2000 ]",
|
||||||
|
"[ 1/4 → 1/2 | s:hh hcutoff:2000 ]",
|
||||||
|
"[ 1/2 → 3/4 | s:hh hcutoff:2000 ]",
|
||||||
|
"[ 3/4 → 1/1 | s:hh hcutoff:2000 ]",
|
||||||
|
"[ 1/1 → 3/2 | s:bd hcutoff:2000 hresonance:25 ]",
|
||||||
|
"[ 3/2 → 2/1 | s:sd hcutoff:2000 hresonance:25 ]",
|
||||||
|
"[ 1/1 → 5/4 | s:hh hcutoff:2000 hresonance:25 ]",
|
||||||
|
"[ 5/4 → 3/2 | s:hh hcutoff:2000 hresonance:25 ]",
|
||||||
|
"[ 3/2 → 7/4 | s:hh hcutoff:2000 hresonance:25 ]",
|
||||||
|
"[ 7/4 → 2/1 | s:hh hcutoff:2000 hresonance:25 ]",
|
||||||
|
"[ 2/1 → 5/2 | s:bd hcutoff:2000 ]",
|
||||||
|
"[ 5/2 → 3/1 | s:sd hcutoff:2000 ]",
|
||||||
|
"[ 2/1 → 9/4 | s:hh hcutoff:2000 ]",
|
||||||
|
"[ 9/4 → 5/2 | s:hh hcutoff:2000 ]",
|
||||||
|
"[ 5/2 → 11/4 | s:hh hcutoff:2000 ]",
|
||||||
|
"[ 11/4 → 3/1 | s:hh hcutoff:2000 ]",
|
||||||
|
"[ 3/1 → 7/2 | s:bd hcutoff:2000 hresonance:25 ]",
|
||||||
|
"[ 7/2 → 4/1 | s:sd hcutoff:2000 hresonance:25 ]",
|
||||||
|
"[ 3/1 → 13/4 | s:hh hcutoff:2000 hresonance:25 ]",
|
||||||
|
"[ 13/4 → 7/2 | s:hh hcutoff:2000 hresonance:25 ]",
|
||||||
|
"[ 7/2 → 15/4 | s:hh hcutoff:2000 hresonance:25 ]",
|
||||||
|
"[ 15/4 → 4/1 | s:hh hcutoff:2000 hresonance:25 ]",
|
||||||
|
]
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`runs examples > example "hpq" example index 0 1`] = `
|
exports[`runs examples > example "hpq" example index 0 1`] = `
|
||||||
[
|
[
|
||||||
"[ 0/1 → 1/2 | s:bd hcutoff:2000 hresonance:0 ]",
|
"[ 0/1 → 1/2 | s:bd hcutoff:2000 hresonance:0 ]",
|
||||||
@@ -1955,19 +1997,19 @@ exports[`runs examples > example "hpq" example index 0 1`] = `
|
|||||||
exports[`runs examples > example "hurry" example index 0 1`] = `
|
exports[`runs examples > example "hurry" example index 0 1`] = `
|
||||||
[
|
[
|
||||||
"[ 0/1 → 3/4 | s:bd speed:1 ]",
|
"[ 0/1 → 3/4 | s:bd speed:1 ]",
|
||||||
"[ (3/4 → 1/1) ⇝ 3/2 | s:sd:2 speed:1 ]",
|
"[ (3/4 → 1/1) ⇝ 3/2 | s:sd n:2 speed:1 ]",
|
||||||
"[ 3/4 ⇜ (1/1 → 3/2) | s:sd:2 speed:1 ]",
|
"[ 3/4 ⇜ (1/1 → 3/2) | s:sd n:2 speed:1 ]",
|
||||||
"[ 3/2 → 15/8 | s:bd speed:2 ]",
|
"[ 3/2 → 15/8 | s:bd speed:2 ]",
|
||||||
"[ (15/8 → 2/1) ⇝ 9/4 | s:sd:2 speed:2 ]",
|
"[ (15/8 → 2/1) ⇝ 9/4 | s:sd n:2 speed:2 ]",
|
||||||
"[ 15/8 ⇜ (2/1 → 9/4) | s:sd:2 speed:2 ]",
|
"[ 15/8 ⇜ (2/1 → 9/4) | s:sd n:2 speed:2 ]",
|
||||||
"[ 9/4 → 21/8 | s:bd speed:2 ]",
|
"[ 9/4 → 21/8 | s:bd speed:2 ]",
|
||||||
"[ 21/8 → 3/1 | s:sd:2 speed:2 ]",
|
"[ 21/8 → 3/1 | s:sd n:2 speed:2 ]",
|
||||||
"[ 3/1 → 51/16 | s:bd speed:4 ]",
|
"[ 3/1 → 51/16 | s:bd speed:4 ]",
|
||||||
"[ 51/16 → 27/8 | s:sd:2 speed:4 ]",
|
"[ 51/16 → 27/8 | s:sd n:2 speed:4 ]",
|
||||||
"[ 27/8 → 57/16 | s:bd speed:4 ]",
|
"[ 27/8 → 57/16 | s:bd speed:4 ]",
|
||||||
"[ 57/16 → 15/4 | s:sd:2 speed:4 ]",
|
"[ 57/16 → 15/4 | s:sd n:2 speed:4 ]",
|
||||||
"[ 15/4 → 63/16 | s:bd speed:4 ]",
|
"[ 15/4 → 63/16 | s:bd speed:4 ]",
|
||||||
"[ (63/16 → 4/1) ⇝ 33/8 | s:sd:2 speed:4 ]",
|
"[ (63/16 → 4/1) ⇝ 33/8 | s:sd n:2 speed:4 ]",
|
||||||
]
|
]
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@@ -2354,6 +2396,15 @@ exports[`runs examples > example "linger" example index 0 1`] = `
|
|||||||
]
|
]
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`runs examples > example "loop" example index 0 1`] = `
|
||||||
|
[
|
||||||
|
"[ 0/1 → 1/1 | s:bd loop:1 ]",
|
||||||
|
"[ 1/1 → 2/1 | s:bd loop:2 ]",
|
||||||
|
"[ 2/1 → 3/1 | s:bd loop:3 ]",
|
||||||
|
"[ 3/1 → 4/1 | s:bd loop:4 ]",
|
||||||
|
]
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`runs examples > example "loopAt" example index 0 1`] = `
|
exports[`runs examples > example "loopAt" example index 0 1`] = `
|
||||||
[
|
[
|
||||||
"[ (0/1 → 1/1) ⇝ 4/1 | s:rhodes speed:0.25 unit:c ]",
|
"[ (0/1 → 1/1) ⇝ 4/1 | s:rhodes speed:0.25 unit:c ]",
|
||||||
@@ -2372,24 +2423,6 @@ exports[`runs examples > example "loopAtCps" example index 0 1`] = `
|
|||||||
]
|
]
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`runs examples > example "loopBegin" example index 0 1`] = `
|
|
||||||
[
|
|
||||||
"[ 0/1 → 1/1 | note:c s:piano loopBegin:0 loopEnd:0.5 ]",
|
|
||||||
"[ 1/1 → 2/1 | note:a s:piano loopBegin:0.24 loopEnd:0.5 ]",
|
|
||||||
"[ 2/1 → 3/1 | note:f s:piano loopBegin:0.32 loopEnd:0.5 ]",
|
|
||||||
"[ 3/1 → 4/1 | note:e s:piano loopBegin:0 loopEnd:0.5 ]",
|
|
||||||
]
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`runs examples > example "loopEnd" example index 0 1`] = `
|
|
||||||
[
|
|
||||||
"[ 0/1 → 1/1 | note:c s:piano loopBegin:0.2 loopEnd:0.3 ]",
|
|
||||||
"[ 1/1 → 2/1 | note:a s:piano loopBegin:0.2 loopEnd:0.4 ]",
|
|
||||||
"[ 2/1 → 3/1 | note:f s:piano loopBegin:0.2 loopEnd:0.5 ]",
|
|
||||||
"[ 3/1 → 4/1 | note:e s:piano loopBegin:0.2 loopEnd:0.6 ]",
|
|
||||||
]
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`runs examples > example "lpf" example index 0 1`] = `
|
exports[`runs examples > example "lpf" example index 0 1`] = `
|
||||||
[
|
[
|
||||||
"[ 0/1 → 1/2 | s:bd cutoff:4000 ]",
|
"[ 0/1 → 1/2 | s:bd cutoff:4000 ]",
|
||||||
@@ -2415,6 +2448,43 @@ exports[`runs examples > example "lpf" example index 0 1`] = `
|
|||||||
]
|
]
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`runs examples > example "lpf" example index 1 1`] = `
|
||||||
|
[
|
||||||
|
"[ 0/1 → 1/8 | s:bd cutoff:1000 resonance:0 ]",
|
||||||
|
"[ 1/8 → 1/4 | s:bd cutoff:1000 resonance:0 ]",
|
||||||
|
"[ 1/4 → 3/8 | s:bd cutoff:1000 resonance:10 ]",
|
||||||
|
"[ 3/8 → 1/2 | s:bd cutoff:1000 resonance:10 ]",
|
||||||
|
"[ 1/2 → 5/8 | s:bd cutoff:1000 resonance:20 ]",
|
||||||
|
"[ 5/8 → 3/4 | s:bd cutoff:1000 resonance:20 ]",
|
||||||
|
"[ 3/4 → 7/8 | s:bd cutoff:1000 resonance:30 ]",
|
||||||
|
"[ 7/8 → 1/1 | s:bd cutoff:1000 resonance:30 ]",
|
||||||
|
"[ 1/1 → 9/8 | s:bd cutoff:1000 resonance:0 ]",
|
||||||
|
"[ 9/8 → 5/4 | s:bd cutoff:1000 resonance:0 ]",
|
||||||
|
"[ 5/4 → 11/8 | s:bd cutoff:1000 resonance:10 ]",
|
||||||
|
"[ 11/8 → 3/2 | s:bd cutoff:1000 resonance:10 ]",
|
||||||
|
"[ 3/2 → 13/8 | s:bd cutoff:1000 resonance:20 ]",
|
||||||
|
"[ 13/8 → 7/4 | s:bd cutoff:1000 resonance:20 ]",
|
||||||
|
"[ 7/4 → 15/8 | s:bd cutoff:1000 resonance:30 ]",
|
||||||
|
"[ 15/8 → 2/1 | s:bd cutoff:1000 resonance:30 ]",
|
||||||
|
"[ 2/1 → 17/8 | s:bd cutoff:1000 resonance:0 ]",
|
||||||
|
"[ 17/8 → 9/4 | s:bd cutoff:1000 resonance:0 ]",
|
||||||
|
"[ 9/4 → 19/8 | s:bd cutoff:1000 resonance:10 ]",
|
||||||
|
"[ 19/8 → 5/2 | s:bd cutoff:1000 resonance:10 ]",
|
||||||
|
"[ 5/2 → 21/8 | s:bd cutoff:1000 resonance:20 ]",
|
||||||
|
"[ 21/8 → 11/4 | s:bd cutoff:1000 resonance:20 ]",
|
||||||
|
"[ 11/4 → 23/8 | s:bd cutoff:1000 resonance:30 ]",
|
||||||
|
"[ 23/8 → 3/1 | s:bd cutoff:1000 resonance:30 ]",
|
||||||
|
"[ 3/1 → 25/8 | s:bd cutoff:1000 resonance:0 ]",
|
||||||
|
"[ 25/8 → 13/4 | s:bd cutoff:1000 resonance:0 ]",
|
||||||
|
"[ 13/4 → 27/8 | s:bd cutoff:1000 resonance:10 ]",
|
||||||
|
"[ 27/8 → 7/2 | s:bd cutoff:1000 resonance:10 ]",
|
||||||
|
"[ 7/2 → 29/8 | s:bd cutoff:1000 resonance:20 ]",
|
||||||
|
"[ 29/8 → 15/4 | s:bd cutoff:1000 resonance:20 ]",
|
||||||
|
"[ 15/4 → 31/8 | s:bd cutoff:1000 resonance:30 ]",
|
||||||
|
"[ 31/8 → 4/1 | s:bd cutoff:1000 resonance:30 ]",
|
||||||
|
]
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`runs examples > example "lpq" example index 0 1`] = `
|
exports[`runs examples > example "lpq" example index 0 1`] = `
|
||||||
[
|
[
|
||||||
"[ 0/1 → 1/2 | s:bd cutoff:2000 resonance:0 ]",
|
"[ 0/1 → 1/2 | s:bd cutoff:2000 resonance:0 ]",
|
||||||
@@ -3240,6 +3310,19 @@ exports[`runs examples > example "room" example index 0 1`] = `
|
|||||||
]
|
]
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`runs examples > example "room" example index 1 1`] = `
|
||||||
|
[
|
||||||
|
"[ 0/1 → 1/2 | s:bd room:0.9 size:1 ]",
|
||||||
|
"[ 1/2 → 1/1 | s:sd room:0.9 size:1 ]",
|
||||||
|
"[ 1/1 → 3/2 | s:bd room:0.9 size:4 ]",
|
||||||
|
"[ 3/2 → 2/1 | s:sd room:0.9 size:4 ]",
|
||||||
|
"[ 2/1 → 5/2 | s:bd room:0.9 size:1 ]",
|
||||||
|
"[ 5/2 → 3/1 | s:sd room:0.9 size:1 ]",
|
||||||
|
"[ 3/1 → 7/2 | s:bd room:0.9 size:4 ]",
|
||||||
|
"[ 7/2 → 4/1 | s:sd room:0.9 size:4 ]",
|
||||||
|
]
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`runs examples > example "roomsize" example index 0 1`] = `
|
exports[`runs examples > example "roomsize" example index 0 1`] = `
|
||||||
[
|
[
|
||||||
"[ 0/1 → 1/2 | s:bd room:0.8 size:0 ]",
|
"[ 0/1 → 1/2 | s:bd room:0.8 size:0 ]",
|
||||||
@@ -3313,6 +3396,27 @@ exports[`runs examples > example "s" example index 0 1`] = `
|
|||||||
]
|
]
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`runs examples > example "s" example index 1 1`] = `
|
||||||
|
[
|
||||||
|
"[ 0/1 → 1/4 | s:bd n:0 ]",
|
||||||
|
"[ 1/4 → 1/2 | s:bd n:1 ]",
|
||||||
|
"[ 1/2 → 3/4 | s:bd n:0 gain:0.3 ]",
|
||||||
|
"[ 3/4 → 1/1 | s:bd n:1 gain:1.4 ]",
|
||||||
|
"[ 1/1 → 5/4 | s:bd n:0 ]",
|
||||||
|
"[ 5/4 → 3/2 | s:bd n:1 ]",
|
||||||
|
"[ 3/2 → 7/4 | s:bd n:0 gain:0.3 ]",
|
||||||
|
"[ 7/4 → 2/1 | s:bd n:1 gain:1.4 ]",
|
||||||
|
"[ 2/1 → 9/4 | s:bd n:0 ]",
|
||||||
|
"[ 9/4 → 5/2 | s:bd n:1 ]",
|
||||||
|
"[ 5/2 → 11/4 | s:bd n:0 gain:0.3 ]",
|
||||||
|
"[ 11/4 → 3/1 | s:bd n:1 gain:1.4 ]",
|
||||||
|
"[ 3/1 → 13/4 | s:bd n:0 ]",
|
||||||
|
"[ 13/4 → 7/2 | s:bd n:1 ]",
|
||||||
|
"[ 7/2 → 15/4 | s:bd n:0 gain:0.3 ]",
|
||||||
|
"[ 15/4 → 4/1 | s:bd n:1 gain:1.4 ]",
|
||||||
|
]
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`runs examples > example "samples" example index 0 1`] = `
|
exports[`runs examples > example "samples" example index 0 1`] = `
|
||||||
[
|
[
|
||||||
"[ 0/1 → 1/4 | s:bd ]",
|
"[ 0/1 → 1/4 | s:bd ]",
|
||||||
@@ -3463,6 +3567,43 @@ exports[`runs examples > example "scale" example index 1 1`] = `
|
|||||||
]
|
]
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`runs examples > example "scale" example index 2 1`] = `
|
||||||
|
[
|
||||||
|
"[ 7/8 → 1/1 | note:C2 s:folkharp ]",
|
||||||
|
"[ 3/4 → 7/8 | note:D2 s:folkharp ]",
|
||||||
|
"[ 5/8 → 3/4 | note:E2 s:folkharp ]",
|
||||||
|
"[ 1/2 → 5/8 | note:F2 s:folkharp ]",
|
||||||
|
"[ 3/8 → 1/2 | note:G2 s:folkharp ]",
|
||||||
|
"[ 1/4 → 3/8 | note:A2 s:folkharp ]",
|
||||||
|
"[ 1/8 → 1/4 | note:B2 s:folkharp ]",
|
||||||
|
"[ 0/1 → 1/8 | note:C3 s:folkharp ]",
|
||||||
|
"[ 15/8 → 2/1 | note:C2 s:folkharp ]",
|
||||||
|
"[ 7/4 → 15/8 | note:D2 s:folkharp ]",
|
||||||
|
"[ 13/8 → 7/4 | note:Eb2 s:folkharp ]",
|
||||||
|
"[ 3/2 → 13/8 | note:F2 s:folkharp ]",
|
||||||
|
"[ 11/8 → 3/2 | note:G2 s:folkharp ]",
|
||||||
|
"[ 5/4 → 11/8 | note:Ab2 s:folkharp ]",
|
||||||
|
"[ 9/8 → 5/4 | note:Bb2 s:folkharp ]",
|
||||||
|
"[ 1/1 → 9/8 | note:C3 s:folkharp ]",
|
||||||
|
"[ 23/8 → 3/1 | note:C2 s:folkharp ]",
|
||||||
|
"[ 11/4 → 23/8 | note:D2 s:folkharp ]",
|
||||||
|
"[ 21/8 → 11/4 | note:E2 s:folkharp ]",
|
||||||
|
"[ 5/2 → 21/8 | note:F2 s:folkharp ]",
|
||||||
|
"[ 19/8 → 5/2 | note:G2 s:folkharp ]",
|
||||||
|
"[ 9/4 → 19/8 | note:A2 s:folkharp ]",
|
||||||
|
"[ 17/8 → 9/4 | note:B2 s:folkharp ]",
|
||||||
|
"[ 2/1 → 17/8 | note:C3 s:folkharp ]",
|
||||||
|
"[ 31/8 → 4/1 | note:C2 s:folkharp ]",
|
||||||
|
"[ 15/4 → 31/8 | note:D2 s:folkharp ]",
|
||||||
|
"[ 29/8 → 15/4 | note:Eb2 s:folkharp ]",
|
||||||
|
"[ 7/2 → 29/8 | note:F2 s:folkharp ]",
|
||||||
|
"[ 27/8 → 7/2 | note:G2 s:folkharp ]",
|
||||||
|
"[ 13/4 → 27/8 | note:Ab2 s:folkharp ]",
|
||||||
|
"[ 25/8 → 13/4 | note:Bb2 s:folkharp ]",
|
||||||
|
"[ 3/1 → 25/8 | note:C3 s:folkharp ]",
|
||||||
|
]
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`runs examples > example "scaleTranspose" example index 0 1`] = `
|
exports[`runs examples > example "scaleTranspose" example index 0 1`] = `
|
||||||
[
|
[
|
||||||
"[ 0/1 → 1/2 | note:C3 ]",
|
"[ 0/1 → 1/2 | note:C3 ]",
|
||||||
|
|||||||
@@ -298,11 +298,11 @@ exports[`renders tunes > tune: bassFuge 1`] = `
|
|||||||
"[ -3/4 ⇜ (0/1 → 3/4) ⇝ 5/4 | note:C5 s:flbass n:0 gain:0.3 cutoff:2924.3791043233605 resonance:10 clip:1 ]",
|
"[ -3/4 ⇜ (0/1 → 3/4) ⇝ 5/4 | note:C5 s:flbass n:0 gain:0.3 cutoff:2924.3791043233605 resonance:10 clip:1 ]",
|
||||||
"[ -3/4 ⇜ (3/4 → 1/1) ⇝ 5/4 | note:A4 s:flbass n:0 gain:0.3 cutoff:2924.3791043233605 resonance:10 clip:1 ]",
|
"[ -3/4 ⇜ (3/4 → 1/1) ⇝ 5/4 | note:A4 s:flbass n:0 gain:0.3 cutoff:2924.3791043233605 resonance:10 clip:1 ]",
|
||||||
"[ -3/4 ⇜ (3/4 → 1/1) ⇝ 5/4 | note:C5 s:flbass n:0 gain:0.3 cutoff:2924.3791043233605 resonance:10 clip:1 ]",
|
"[ -3/4 ⇜ (3/4 → 1/1) ⇝ 5/4 | note:C5 s:flbass n:0 gain:0.3 cutoff:2924.3791043233605 resonance:10 clip:1 ]",
|
||||||
"[ 0/1 → 1/2 | s:bd:1 ]",
|
"[ 0/1 → 1/2 | s:bd n:1 ]",
|
||||||
"[ 1/2 → 1/1 | s:bd:1 ]",
|
"[ 1/2 → 1/1 | s:bd n:1 ]",
|
||||||
"[ 1/2 → 1/1 | s:sd:0 ]",
|
"[ 1/2 → 1/1 | s:sd n:0 ]",
|
||||||
"[ 1/4 → 1/2 | s:hh:0 ]",
|
"[ 1/4 → 1/2 | s:hh n:0 ]",
|
||||||
"[ 3/4 → 1/1 | s:hh:0 ]",
|
"[ 3/4 → 1/1 | s:hh n:0 ]",
|
||||||
]
|
]
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@@ -313,7 +313,7 @@ exports[`renders tunes > tune: belldub 1`] = `
|
|||||||
"[ (5/8 → 1/1) ⇝ 5/4 | s:hh room:0 end:0.04483079938329212 ]",
|
"[ (5/8 → 1/1) ⇝ 5/4 | s:hh room:0 end:0.04483079938329212 ]",
|
||||||
"[ 0/1 → 5/16 | s:mt gain:0.5 room:0.5 ]",
|
"[ 0/1 → 5/16 | s:mt gain:0.5 room:0.5 ]",
|
||||||
"[ (15/16 → 1/1) ⇝ 5/4 | s:lt gain:0.5 room:0.5 ]",
|
"[ (15/16 → 1/1) ⇝ 5/4 | s:lt gain:0.5 room:0.5 ]",
|
||||||
"[ (0/1 → 1/1) ⇝ 5/1 | s:misc:2 speed:1 delay:0.5 delaytime:0.3333333333333333 gain:0.4 ]",
|
"[ (0/1 → 1/1) ⇝ 5/1 | s:misc n:2 speed:1 delay:0.5 delaytime:0.3333333333333333 gain:0.4 ]",
|
||||||
"[ (5/8 → 1/1) ⇝ 5/4 | note:F3 s:sawtooth gain:0.5 cutoff:400.16785462816676 decay:0.05380063255866716 sustain:0 delay:0.9 room:1 ]",
|
"[ (5/8 → 1/1) ⇝ 5/4 | note:F3 s:sawtooth gain:0.5 cutoff:400.16785462816676 decay:0.05380063255866716 sustain:0 delay:0.9 room:1 ]",
|
||||||
"[ (5/8 → 1/1) ⇝ 5/4 | note:A3 s:sawtooth gain:0.5 cutoff:400.16785462816676 decay:0.05380063255866716 sustain:0 delay:0.9 room:1 ]",
|
"[ (5/8 → 1/1) ⇝ 5/4 | note:A3 s:sawtooth gain:0.5 cutoff:400.16785462816676 decay:0.05380063255866716 sustain:0 delay:0.9 room:1 ]",
|
||||||
"[ (5/8 → 1/1) ⇝ 5/4 | note:Bb3 s:sawtooth gain:0.5 cutoff:400.16785462816676 decay:0.05380063255866716 sustain:0 delay:0.9 room:1 ]",
|
"[ (5/8 → 1/1) ⇝ 5/4 | note:Bb3 s:sawtooth gain:0.5 cutoff:400.16785462816676 decay:0.05380063255866716 sustain:0 delay:0.9 room:1 ]",
|
||||||
@@ -6974,16 +6974,16 @@ exports[`renders tunes > tune: flatrave 1`] = `
|
|||||||
"[ 1/2 → 1/1 | s:bd bank:RolandTR909 ]",
|
"[ 1/2 → 1/1 | s:bd bank:RolandTR909 ]",
|
||||||
"[ 1/2 → 1/1 | s:cp bank:RolandTR909 ]",
|
"[ 1/2 → 1/1 | s:cp bank:RolandTR909 ]",
|
||||||
"[ 1/2 → 1/1 | s:sd bank:RolandTR909 ]",
|
"[ 1/2 → 1/1 | s:sd bank:RolandTR909 ]",
|
||||||
"[ 0/1 → 1/4 | s:hh:1 end:0.02000058072071123 bank:RolandTR909 room:0.5 gain:0.4 ]",
|
"[ 0/1 → 1/4 | s:hh n:1 end:0.02000058072071123 bank:RolandTR909 room:0.5 gain:0.4 ]",
|
||||||
"[ 0/1 ⇜ (1/8 → 1/4) | s:hh:1 end:0.02000058072071123 bank:RolandTR909 room:0.5 gain:0.4 ]",
|
"[ 0/1 ⇜ (1/8 → 1/4) | s:hh n:1 end:0.02000058072071123 bank:RolandTR909 room:0.5 gain:0.4 ]",
|
||||||
"[ 1/4 → 3/8 | s:hh:1 end:0.02000875429921906 bank:RolandTR909 room:0.5 gain:0.4 ]",
|
"[ 1/4 → 3/8 | s:hh n:1 end:0.02000875429921906 bank:RolandTR909 room:0.5 gain:0.4 ]",
|
||||||
"[ 1/4 → 3/8 | s:hh:1 end:0.02000875429921906 bank:RolandTR909 room:0.5 gain:0.4 ]",
|
"[ 1/4 → 3/8 | s:hh n:1 end:0.02000875429921906 bank:RolandTR909 room:0.5 gain:0.4 ]",
|
||||||
"[ 3/8 → 1/2 | s:hh:1 end:0.020023446730265706 bank:RolandTR909 room:0.5 gain:0.4 ]",
|
"[ 3/8 → 1/2 | s:hh n:1 end:0.020023446730265706 bank:RolandTR909 room:0.5 gain:0.4 ]",
|
||||||
"[ 5/8 → 3/4 | s:hh:1 end:0.020086608138500644 bank:RolandTR909 room:0.5 gain:0.4 ]",
|
"[ 5/8 → 3/4 | s:hh n:1 end:0.020086608138500644 bank:RolandTR909 room:0.5 gain:0.4 ]",
|
||||||
"[ 5/8 → 3/4 | s:hh:1 end:0.020086608138500644 bank:RolandTR909 room:0.5 gain:0.4 ]",
|
"[ 5/8 → 3/4 | s:hh n:1 end:0.020086608138500644 bank:RolandTR909 room:0.5 gain:0.4 ]",
|
||||||
"[ 3/4 → 7/8 | s:hh:1 end:0.02013941880355398 bank:RolandTR909 room:0.5 gain:0.4 ]",
|
"[ 3/4 → 7/8 | s:hh n:1 end:0.02013941880355398 bank:RolandTR909 room:0.5 gain:0.4 ]",
|
||||||
"[ 1/8 → 1/4 | s:hh:1 speed:0.5 delay:0.5 end:0.020001936784171157 bank:RolandTR909 room:0.5 gain:0.4 ]",
|
"[ 1/8 → 1/4 | s:hh n:1 speed:0.5 delay:0.5 end:0.020001936784171157 bank:RolandTR909 room:0.5 gain:0.4 ]",
|
||||||
"[ 1/8 → 1/4 | s:hh:1 speed:0.5 delay:0.5 end:0.020001936784171157 bank:RolandTR909 room:0.5 gain:0.4 ]",
|
"[ 1/8 → 1/4 | s:hh n:1 speed:0.5 delay:0.5 end:0.020001936784171157 bank:RolandTR909 room:0.5 gain:0.4 ]",
|
||||||
"[ 1/8 → 1/4 | note:G1 s:sawtooth decay:0.1 sustain:0 ]",
|
"[ 1/8 → 1/4 | note:G1 s:sawtooth decay:0.1 sustain:0 ]",
|
||||||
"[ 1/4 → 3/8 | note:G1 s:sawtooth decay:0.1 sustain:0 ]",
|
"[ 1/4 → 3/8 | note:G1 s:sawtooth decay:0.1 sustain:0 ]",
|
||||||
"[ 1/2 → 5/8 | note:G1 s:sawtooth decay:0.1 sustain:0 ]",
|
"[ 1/2 → 5/8 | note:G1 s:sawtooth decay:0.1 sustain:0 ]",
|
||||||
@@ -8127,8 +8127,8 @@ exports[`renders tunes > tune: loungeSponge 1`] = `
|
|||||||
|
|
||||||
exports[`renders tunes > tune: meltingsubmarine 1`] = `
|
exports[`renders tunes > tune: meltingsubmarine 1`] = `
|
||||||
[
|
[
|
||||||
"[ (0/1 → 1/1) ⇝ 3/2 | s:bd:5 speed:0.7519542165100574 ]",
|
"[ (0/1 → 1/1) ⇝ 3/2 | s:bd n:5 speed:0.7519542165100574 ]",
|
||||||
"[ (3/4 → 1/1) ⇝ 3/2 | s:sd:1 speed:0.7931522866332671 ]",
|
"[ (3/4 → 1/1) ⇝ 3/2 | s:sd n:1 speed:0.7931522866332671 ]",
|
||||||
"[ 3/8 → 3/4 | s:hh27 speed:0.7285963821098448 ]",
|
"[ 3/8 → 3/4 | s:hh27 speed:0.7285963821098448 ]",
|
||||||
"[ (3/4 → 1/1) ⇝ 9/8 | s:hh27 speed:0.77531205091027 ]",
|
"[ (3/4 → 1/1) ⇝ 9/8 | s:hh27 speed:0.77531205091027 ]",
|
||||||
"[ (0/1 → 1/1) ⇝ 3/2 | note:33.129885541275144 decay:0.15 sustain:0 s:sawtooth gain:0.4 cutoff:3669.6267869262615 ]",
|
"[ (0/1 → 1/1) ⇝ 3/2 | note:33.129885541275144 decay:0.15 sustain:0 s:sawtooth gain:0.4 cutoff:3669.6267869262615 ]",
|
||||||
@@ -8364,15 +8364,15 @@ exports[`renders tunes > tune: randomBells 1`] = `
|
|||||||
|
|
||||||
exports[`renders tunes > tune: sampleDemo 1`] = `
|
exports[`renders tunes > tune: sampleDemo 1`] = `
|
||||||
[
|
[
|
||||||
"[ 0/1 → 1/4 | s:woodblock:1 ]",
|
"[ 0/1 → 1/4 | s:woodblock n:1 ]",
|
||||||
"[ 1/4 → 3/8 | s:woodblock:2 ]",
|
"[ 1/4 → 3/8 | s:woodblock n:2 ]",
|
||||||
"[ 0/1 → 1/8 | s:brakedrum:1 ]",
|
"[ 0/1 → 1/8 | s:brakedrum n:1 ]",
|
||||||
"[ 3/4 → 7/8 | s:brakedrum:1 ]",
|
"[ 3/4 → 7/8 | s:brakedrum n:1 ]",
|
||||||
"[ 3/8 → 1/2 | s:woodblock:2 speed:2 ]",
|
"[ 3/8 → 1/2 | s:woodblock n:2 speed:2 ]",
|
||||||
"[ 1/2 → 1/1 | s:snare_rim:0 speed:2 ]",
|
"[ 1/2 → 1/1 | s:snare_rim n:0 speed:2 ]",
|
||||||
"[ (0/1 → 1/1) ⇝ 8/1 | s:gong speed:2 ]",
|
"[ (0/1 → 1/1) ⇝ 8/1 | s:gong speed:2 ]",
|
||||||
"[ 3/8 → 1/2 | s:brakedrum:1 speed:2 ]",
|
"[ 3/8 → 1/2 | s:brakedrum n:1 speed:2 ]",
|
||||||
"[ 3/4 → 1/1 | s:cowbell:3 speed:2 ]",
|
"[ 3/4 → 1/1 | s:cowbell n:3 speed:2 ]",
|
||||||
"[ -3/4 ⇜ (0/1 → 1/4) | note:Bb3 s:clavisynth gain:0.2 delay:0.25 pan:0 ]",
|
"[ -3/4 ⇜ (0/1 → 1/4) | note:Bb3 s:clavisynth gain:0.2 delay:0.25 pan:0 ]",
|
||||||
"[ (3/4 → 1/1) ⇝ 7/4 | note:Bb3 s:clavisynth gain:0.2 delay:0.25 pan:1 ]",
|
"[ (3/4 → 1/1) ⇝ 7/4 | note:Bb3 s:clavisynth gain:0.2 delay:0.25 pan:1 ]",
|
||||||
"[ -1/4 ⇜ (0/1 → 3/4) | note:F3 s:clavisynth gain:0.2 delay:0.25 pan:1 ]",
|
"[ -1/4 ⇜ (0/1 → 3/4) | note:F3 s:clavisynth gain:0.2 delay:0.25 pan:1 ]",
|
||||||
|
|||||||
Reference in New Issue
Block a user