Merge branch 'main' into separate-alignment-methods

This commit is contained in:
Alex McLean
2022-12-05 13:22:43 +00:00
committed by GitHub
53 changed files with 5831 additions and 6292 deletions
+14
View File
@@ -0,0 +1,14 @@
krill-parser.js
krill.pegjs
.eslintrc.json
server.js
tidal-sniffer.js
*.jsx
tunejs.js
out/**
postcss.config.js
postcss.config.cjs
tailwind.config.js
vite.config.js
/**/dist/**/*
!**/*.mjs
+16
View File
@@ -0,0 +1,16 @@
{
"env": {
"browser": true,
"es2021": true
},
"extends": ["eslint:recommended"],
"overrides": [],
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module"
},
"plugins": [],
"rules": {
"no-unused-vars": ["warn", { "destructuredArrayIgnorePattern": ".", "ignoreRestSiblings": false }]
}
}
+2574 -5391
View File
File diff suppressed because it is too large Load Diff
+4 -2
View File
@@ -5,7 +5,7 @@
"description": "Port of tidalcycles to javascript",
"scripts": {
"pretest": "cd tutorial && npm run jsdoc-json",
"test": "vitest run --version",
"test": "npm run lint && vitest run --version",
"test-ui": "vitest --ui",
"test-coverage": "vitest --coverage",
"bootstrap": "lerna bootstrap",
@@ -17,7 +17,8 @@
"preview": "npx serve ./out",
"deploy": "NODE_DEBUG=gh-pages gh-pages -d out",
"jsdoc": "jsdoc packages/ -c jsdoc.config.json",
"jsdoc-json": "jsdoc packages/ --template ./node_modules/jsdoc-json --destination doc.json -c jsdoc.config.json"
"jsdoc-json": "jsdoc packages/ --template ./node_modules/jsdoc-json --destination doc.json -c jsdoc.config.json",
"lint": "npx eslint . --ext mjs,js --quiet"
},
"workspaces": [
"packages/*"
@@ -42,6 +43,7 @@
"devDependencies": {
"@vitest/ui": "^0.21.1",
"c8": "^7.12.0",
"eslint": "^8.28.0",
"events": "^3.3.0",
"gh-pages": "^4.0.0",
"jsdoc": "^3.6.10",
+1 -1
View File
@@ -788,6 +788,6 @@ controls.createParam = (name) => {
};
controls.createParams = (...names) =>
names.reduce((acc, name) => Object.assign(acc, { [name]: createParam(name) }), {});
names.reduce((acc, name) => Object.assign(acc, { [name]: controls.createParam(name) }), {});
export default controls;
+3
View File
@@ -6,6 +6,9 @@ This program is free software: you can redistribute it and/or modify it under th
import pattern from './pattern.mjs';
const Pattern = pattern.Pattern;
import { getTime } from './time.mjs';
import { State } from './state.mjs';
import { TimeSpan } from './timespan.mjs';
export const getDrawContext = (id = 'test-canvas') => {
let canvas = document.querySelector('#' + id);
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@strudel.cycles/core",
"version": "0.4.0",
"version": "0.4.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@strudel.cycles/core",
"version": "0.4.0",
"version": "0.4.1",
"description": "Port of Tidal Cycles to JavaScript",
"main": "index.mjs",
"type": "module",
+69 -34
View File
@@ -36,10 +36,9 @@ class Pattern {
this.query = query;
}
//////////////////////////////////////////////////////////////////////
// Haskell-style functor, applicative and monadic operations
/**
* Returns a new pattern, with the function applied to the value of
* each hap. It has the alias {@link Pattern#fmap}.
@@ -168,7 +167,6 @@ class Pattern {
return new Pattern(query);
}
bindWhole(choose_whole, func) {
const pat_val = this;
const query = function (state) {
@@ -209,7 +207,7 @@ class Pattern {
}
outerBind(func) {
return this.bindWhole((a, _) => a, func);
return this.bindWhole((a) => a, func);
}
outerJoin() {
@@ -317,7 +315,7 @@ class Pattern {
//////////////////////////////////////////////////////////////////////
// Utility methods mainly for internal use
/**
* Query haps inside the given time span.
*
@@ -538,7 +536,7 @@ class Pattern {
// removes continuous haps that don't have a 'whole' timespan
return this.filterHaps((hap) => hap.whole);
}
/**
* Queries the pattern for the first cycle, returning Haps. Mainly of use when
* debugging a pattern.
@@ -944,8 +942,8 @@ class Pattern {
//binary_pat = sequence(binary_pat)
const true_pat = binary_pat.filterValues(id);
const false_pat = binary_pat.filterValues((val) => !val);
const with_pat = true_pat.fmap((_) => (y) => y).appRight(func(this));
const without_pat = false_pat.fmap((_) => (y) => y).appRight(this);
const with_pat = true_pat.fmap(() => (y) => y).appRight(func(this));
const without_pat = false_pat.fmap(() => (y) => y).appRight(this);
return stack(with_pat, without_pat);
}
@@ -1011,7 +1009,7 @@ class Pattern {
every(n, func) {
return this.firstOf(n, func);
}
/**
* Returns a new pattern where every other cycle is played once, twice as
* fast, and offset in time by one quarter of a cycle. Creates a kind of
@@ -1055,7 +1053,6 @@ class Pattern {
return this.every(2, rev);
}
juxBy(by, func) {
by /= 2;
const elem_or = function (dict, key, dflt) {
@@ -1188,8 +1185,12 @@ class Pattern {
* note("0 1 2 3".scale('A minor')).iter(4)
*/
_iter(times, back = false) {
times = Fraction(times)
return slowcat(...listRange(0, times.sub(1)).map((i) => (back ? this.late(Fraction(i).div(times)) : this.early(Fraction(i).div(times)))));
times = Fraction(times);
return slowcat(
...listRange(0, times.sub(1)).map((i) =>
back ? this.late(Fraction(i).div(times)) : this.early(Fraction(i).div(times)),
),
);
}
/**
@@ -1235,10 +1236,10 @@ class Pattern {
on = Boolean(parseInt(on));
return on ? silence : this;
}
//////////////////////////////////////////////////////////////////////
// Control-related methods, which manipulate patterns of objects
/**
* Cuts each sample into the given number of parts, allowing you to explore a technique known as 'granular synthesis'.
* It turns a pattern of samples into a pattern of parts of samples.
@@ -1286,17 +1287,11 @@ class Pattern {
//////////////////////////////////////////////////////////////////////
// Context methods - ones that deal with metadata
_color(color) {
return this.withContext((context) => ({ ...context, color }));
}
log() {
return this.withHap((e) => {
return e.setContext({ ...e.context, logs: (e.context?.logs || []).concat([e.show()]) });
});
}
/**
*
* Sets the velocity from 0 to 1. Is multiplied together with gain.
@@ -1367,11 +1362,53 @@ class Pattern {
_legato(value) {
return this.withHapSpan((span) => new TimeSpan(span.begin, span.begin.add(span.end.sub(span.begin).mul(value))));
}
}
//////////////////////////////////////////////////////////////////////
// functions relating to chords/patterns of lists
// returns Array<Hap[]> where each list of haps satisfies eq
function groupHapsBy(eq, haps) {
let groups = [];
haps.forEach((hap) => {
const match = groups.findIndex(([other]) => eq(hap, other));
if (match === -1) {
groups.push([hap]);
} else {
groups[match].push(hap);
}
});
return groups;
}
pattern['Pattern'] = Pattern;
// congruent haps = haps with equal spans
const congruent = (a, b) => a.spanEquals(b);
// Pattern<Hap<T>> -> Pattern<Hap<T[]>>
// returned pattern contains arrays of congruent haps
Pattern.prototype.collect = function () {
return this.withHaps((haps) =>
groupHapsBy(congruent, haps).map((_haps) => new Hap(_haps[0].whole, _haps[0].part, _haps, {})),
);
};
// applies func to each array of congruent haps
Pattern.prototype.arpWith = function (func) {
return this.collect()
.fmap((v) => reify(func(v)))
.squeezeJoin()
.withHap((h) => new Hap(h.whole, h.part, h.value.value, h.combineContext(h.value)));
};
// applies pattern of indices to each array of congruent haps
Pattern.prototype.arp = function (pat) {
return this.arpWith((haps) => pat.fmap((i) => haps[i % haps.length]));
};
//////////////////////////////////////////////////////////////////////
// compose matrix functions
// TODO - adopt value.mjs fully..
function _composeOp(a, b, func) {
function _nonFunctionObject(x) {
@@ -1394,7 +1431,7 @@ function _composeOp(a, b, func) {
// pattern composers
const composers = {
set: [(a, b) => b],
keep: [(a, b) => a],
keep: [(a) => a],
keepif: [(a, b) => (b ? a : undefined)],
// numerical functions
@@ -1469,7 +1506,6 @@ function _composeOp(a, b, func) {
// generate methods to do what and how
for (const [what, [op, preprocess]] of Object.entries(composers)) {
Object.defineProperty(Pattern.prototype, what, {
// a getter that returns a function, so 'pat' can be
// accessed by closures that are methods of that function..
@@ -1576,7 +1612,7 @@ Pattern.prototype.factories = {
// Elemental patterns
// Nothing
const silence = new Pattern((_) => []);
const silence = new Pattern(() => []);
pattern['silence'] = silence;
/** A discrete value that repeats once per cycle.
@@ -1596,13 +1632,16 @@ pattern['pure'] = pure;
function isPattern(thing) {
// thing?.constructor?.name !== 'Pattern' // <- this will fail when code is mangled
const is = thing instanceof Pattern || thing?._Pattern;
if (!thing instanceof Pattern) {
// TODO: find out how to check wrong core dependency. below will never work !thing === 'undefined'
// wrapping it in (..) will result other checks to log that warning (e.g. isPattern('kalimba'))
/* if (!thing instanceof Pattern) {
console.warn(
`Found Pattern that fails "instanceof Pattern" check.
This may happen if you are using multiple versions of @strudel.cycles/core.
Please check by running "npm ls @strudel.cycles/core".`,
);
}
console.log(thing);
} */
return is;
}
pattern['isPattern'] = isPattern;
@@ -1773,7 +1812,7 @@ function polymeterSteps(steps, ...args) {
const pats = [];
for (const seq of seqs) {
if (seq[1] == 0) {
next;
continue;
}
if (steps == seq[1]) {
pats.push(seq[0]);
@@ -1930,10 +1969,9 @@ Pattern.prototype.bootstrap = function () {
this.patternified.forEach((prop) => {
// the following will patternify all functions in Pattern.prototype.patternified
Pattern.prototype[prop] = function (...args) {
return this.patternify(x => x.innerJoin(), Pattern.prototype['_' + prop])(...args);
return this.patternify((x) => x.innerJoin(), Pattern.prototype['_' + prop])(...args);
};
/*
const func = Pattern.prototype['_' + prop];
Pattern.prototype[prop] = function (...args) {
@@ -1959,7 +1997,7 @@ Pattern.prototype.bootstrap = function () {
}
});
*/
// with the following, you can do, e.g. `stack(c3).fast.slowcat(1, 2, 4, 8)` instead of `stack(c3).fast(slowcat(1, 2, 4, 8))`
// TODO: find a way to implement below outside of constructor (code only worked there)
/* Object.assign(
@@ -1992,8 +2030,5 @@ Pattern.prototype.define = (name, func, options = {}) => {
// Pattern.prototype.define('early', (a, pat) => pat.early(a), { patternified: true, composable: true });
Pattern.prototype.define('hush', (pat) => pat.hush(), { patternified: false, composable: true });
Pattern.prototype.define('bypass', (pat) => pat.bypass(on), { patternified: true, composable: true });
export default pattern;
+3
View File
@@ -7,6 +7,9 @@ This program is free software: you can redistribute it and/or modify it under th
import pattern from './pattern.mjs';
const { Pattern } = pattern;
import { toMidi } from './util.mjs';
import { getDrawContext } from './draw.mjs';
const scale = (normalized, min, max) => normalized * (max - min) + min;
const getValue = (e) => {
let value = typeof e.value === 'object' ? e.value.note ?? e.value.n : e.value;
+2 -2
View File
@@ -40,11 +40,11 @@ export function repl({
throw new Error('no code to evaluate');
}
try {
beforeEval({ code });
beforeEval?.({ code });
const { pattern } = await _evaluate(code, transpiler);
logger(`[eval] code updated`);
scheduler.setPattern(pattern, autostart);
afterEval({ code, pattern });
afterEval?.({ code, pattern });
return pattern;
} catch (err) {
// console.warn(`[repl] eval error: ${err.message}`);
+1 -1
View File
@@ -5,7 +5,7 @@ This program is free software: you can redistribute it and/or modify it under th
*/
import pattern from './pattern.mjs';
const {Pattern, patternify2} = pattern;
const {Pattern, patternify2, reify} = pattern;
let synth;
try {
+121
View File
@@ -0,0 +1,121 @@
import { getFrequency, logger, Pattern } from '@strudel.cycles/core';
import { getAudioContext } from '@strudel.cycles/webaudio';
import csd from './project.csd?raw';
// import livecodeOrc from './livecode.orc?raw';
import presetsOrc from './presets.orc?raw';
let csoundLoader, _csound;
// triggers given instrument name using csound.
Pattern.prototype._csound = function (instrument) {
instrument = instrument || 'triangle';
init(); // not async to support csound inside other patterns + to be able to call pattern methods after it
// TODO: find a alternative way to wait for csound to load (to wait with first time playback)
return this.onTrigger((time, hap) => {
if (!_csound) {
logger('[csound] not loaded yet', 'warning');
return;
}
if (typeof hap.value !== 'object') {
throw new Error('csound only support objects as hap values');
}
let { gain = 0.8 } = hap.value;
gain *= 0.2;
const freq = Math.round(getFrequency(hap));
const controls = Object.entries({ ...hap.value, freq })
.flat()
.join('/');
// TODO: find out how to send a precise ctx based time
// http://www.csounds.com/manual/html/i.html
const params = [
`"${instrument}"`, // p1: instrument name
time - getAudioContext().currentTime, //.toFixed(precision), // p2: starting time in arbitrary unit called beats
hap.duration + 0, // p3: duration in beats
// instrument specific params:
freq, //.toFixed(precision), // p4: frequency
gain, // p5: gain
`"${controls}"`, // p6 controls as string (like superdirt osc message)
];
const msg = `i ${params.join(' ')}`;
_csound.inputMessage(msg);
});
};
// initializes csound + can be used to reevaluate given instrument code
export async function csound(code = '') {
await init();
if (code) {
code = `${code}`;
// ^ ^
// wrapping in backticks makes sure it works when calling as templated function
await _csound?.evalCode(code);
}
}
Pattern.prototype.define('csound', (a, pat) => pat.csound(a), { composable: false, patternified: true });
function eventLogger(type, args) {
const [msg] = args;
if (
type === 'message' &&
(['[commit: HEAD]'].includes(msg) ||
msg.startsWith('--Csound version') ||
msg.startsWith('libsndfile') ||
msg.startsWith('sr =') ||
msg.startsWith('0dBFS') ||
msg.startsWith('audio buffered') ||
msg.startsWith('writing') ||
msg.startsWith('SECTION 1:'))
) {
// ignore
return;
}
let logType = 'info';
if (msg.startsWith('error:')) {
logType = 'error';
}
logger(`[csound] ${msg || ''}`, logType);
}
async function load() {
if (window.__csound__) {
// allows using some other csound instance
_csound = window.__csound__;
} else {
const { Csound } = await import('@csound/browser');
_csound = await Csound({ audioContext: getAudioContext() });
}
_csound.removeAllListeners('message');
['message'].forEach((k) => _csound.on(k, (...args) => eventLogger(k, args)));
await _csound.setOption('-m0d'); // see -m flag https://csound.com/docs/manual/CommandFlags.html
await _csound.setOption('--sample-accurate');
await _csound.compileCsdText(csd);
// await _csound.compileOrc(livecodeOrc);
await _csound.compileOrc(presetsOrc);
await _csound.start();
return _csound;
}
async function init() {
csoundLoader = csoundLoader || load();
return csoundLoader;
}
let orcCache = {};
export async function loadOrc(url) {
await init();
if (typeof url !== 'string') {
throw new Error('loadOrc: expected url string');
}
if (url.startsWith('github:')) {
const [_, path] = url.split('github:');
url = `https://raw.githubusercontent.com/${path}`;
}
if (!orcCache[url]) {
orcCache[url] = fetch(url)
.then((res) => res.text())
.then((code) => _csound.compileOrc(code));
}
await orcCache[url];
}
File diff suppressed because it is too large Load Diff
+32
View File
@@ -0,0 +1,32 @@
{
"name": "@strudel.cycles/csound",
"version": "0.3.0",
"description": "csound bindings for strudel",
"main": "csound.mjs",
"scripts": {
"test": "echo \"No tests present.\" && exit 0"
},
"repository": {
"type": "git",
"url": "git+https://github.com/tidalcycles/strudel.git"
},
"keywords": [
"tidalcycles",
"strudel",
"pattern",
"livecoding",
"algorave"
],
"author": "Felix Roos <flix91@gmail.com>",
"contributors": [
"Alex McLean <alex@slab.org>"
],
"license": "AGPL-3.0-or-later",
"bugs": {
"url": "https://github.com/tidalcycles/strudel/issues"
},
"homepage": "https://github.com/tidalcycles/strudel#readme",
"dependencies": {
"@csound/browser": "^6.18.3"
}
}
+96
View File
@@ -0,0 +1,96 @@
; returns value of given key in given "string map"
; keymap("freq", "note/c3/freq/220/gain/0.5")
; yields "220"
opcode keymap, S, SS
Skey, Smap xin
idelimiter = strindex(Smap, strcat(Skey, "/"))
ifrom = idelimiter + strlen(Skey) + 1
Svalue = strsub(Smap, ifrom, strlen(Smap))
Svalue = strsub(Svalue, 0, strindex(Svalue, "/"))
xout Svalue
endop
; TODO add incredibly dope synths
instr organ
iduration = p3
ifreq = p4
igain = p5
ioct = octcps(ifreq)
asig = vco2(igain, ifreq, 12, .5) ; my edit
kpwm = oscili(.1, 5)
asig = vco2(igain, ifreq, 4, .5 + kpwm)
asig += vco2(igain/4, ifreq * 2)
; filter
; idepth = 2
; acut = transegr:a(0, .005, 0, idepth, .06, -4.2, 0.001, .01, -4.2, 0) ; filter envelope
; asig = zdf_2pole(asig, cpsoct(ioct + acut), 0.5)
; amp envelope
iattack = .001
irelease = .05
asig *= linsegr:a(0, iattack, 1, iduration, 1, irelease, 0)
out(asig, asig)
endin
instr triangle
iduration = p3
ifreq = p4
igain = p5
ioct = octcps(ifreq)
asig = vco2(igain, ifreq, 12, .5)
; amp envelope
iattack = .001
irelease = .05
asig *= linsegr:a(0, iattack, 1, iduration, 1, irelease, 0)
out(asig, asig)
endin
instr pad
iduration = p3
ifreq = p4
igain = p5
ioct = octcps(ifreq)
asig = vco2(igain, ifreq, 0)
; amp envelope
iattack = .5
irelease = .1
asig *= linsegr:a(0, iattack, 1, iduration, 1, irelease, 0)
idepth = 2
acut = transegr:a(0, .005, 0, idepth, .06, -4.2, 0.001, .01, -4.2, 0)
asig = zdf_2pole(asig, 1000, 2)
out(asig, asig)
endin
gisine ftgen 0, 0, 4096, 10, 1
instr bow
kpres = 2
krat = 0.16
kvibf = 6.12723
kvib linseg 0, 0.5, 0, 1, 1, p3-0.5, 1
kvamp = kvib * 0.01
asig wgbow .7, p4, kpres, krat, kvibf, kvamp, gisine
asig = asig*p5
outs asig, asig
endin
instr Meta
Smap = strget(p6)
Sinstrument = keymap("s", Smap)
schedule(Sinstrument, 0, p3, p4, p5)
; TODO find a way to pipe Sinstrument through effects
endin
+10
View File
@@ -0,0 +1,10 @@
<CsoundSynthesizer>
<CsInstruments>
sr=48000
ksmps=64
nchnls=2
0dbfs=1
</CsInstruments>
</CsoundSynthesizer>
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@strudel.cycles/eval",
"version": "0.4.0",
"version": "0.4.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@strudel.cycles/eval",
"version": "0.4.0",
"version": "0.4.1",
"description": "Code evaluator for strudel",
"main": "index.mjs",
"type": "module",
@@ -28,7 +28,7 @@
},
"homepage": "https://github.com/tidalcycles/strudel#readme",
"dependencies": {
"@strudel.cycles/core": "^0.4.0",
"@strudel.cycles/core": "^0.4.1",
"estraverse": "^5.3.0",
"shift-ast": "^7.0.0",
"shift-codegen": "^8.1.0",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@strudel.cycles/midi",
"version": "0.4.0",
"version": "0.4.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@strudel.cycles/midi",
"version": "0.4.0",
"version": "0.4.1",
"description": "Midi API for strudel",
"main": "index.mjs",
"repository": {
@@ -21,7 +21,7 @@
},
"homepage": "https://github.com/tidalcycles/strudel#readme",
"dependencies": {
"@strudel.cycles/tone": "^0.4.0",
"@strudel.cycles/tone": "^0.4.1",
"tone": "^14.7.77",
"webmidi": "^3.0.21"
}
+6 -3
View File
@@ -23,9 +23,10 @@ const applyOptions = (parent) => (pat, i) => {
const operator = options?.operator;
if (operator) {
switch (operator.type_) {
case 'stretch':
case 'stretch': {
const speed = Fraction(operator.arguments_.amount).inverse();
return reify(pat).fast(speed);
}
case 'bjorklund':
return pat.euclid(operator.arguments_.pulse, operator.arguments_.step, operator.arguments_.rotation);
case 'degradeBy':
@@ -87,7 +88,7 @@ function resolveReplications(ast) {
export function patternifyAST(ast) {
switch (ast.type_) {
case 'pattern':
case 'pattern': {
resolveReplications(ast);
const children = ast.source_.map(patternifyAST).map(applyOptions(ast));
const alignment = ast.arguments_.alignment;
@@ -110,7 +111,8 @@ export function patternifyAST(ast) {
return pat;
}
return sequence(...children);
case 'element':
}
case 'element': {
if (ast.source_ === '~') {
return silence;
}
@@ -129,6 +131,7 @@ export function patternifyAST(ast) {
return pure(value).withLocation([start.line, start.column, start.offset], [end.line, end.column, end.offset]);
}
return patternifyAST(ast.source_);
}
case 'stretch':
return patternifyAST(ast.source_).slow(ast.arguments_.amount);
/* case 'scale':
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@strudel.cycles/mini",
"version": "0.4.0",
"version": "0.4.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
+4 -4
View File
@@ -1,6 +1,6 @@
{
"name": "@strudel.cycles/mini",
"version": "0.4.0",
"version": "0.4.1",
"description": "Mini notation for strudel",
"main": "index.mjs",
"type": "module",
@@ -26,9 +26,9 @@
},
"homepage": "https://github.com/tidalcycles/strudel#readme",
"dependencies": {
"@strudel.cycles/core": "^0.4.0",
"@strudel.cycles/eval": "^0.4.0",
"@strudel.cycles/tone": "^0.4.0"
"@strudel.cycles/core": "^0.4.1",
"@strudel.cycles/eval": "^0.4.1",
"@strudel.cycles/tone": "^0.4.1"
},
"devDependencies": {
"peggy": "^2.0.1"
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@strudel.cycles/osc",
"version": "0.3.0",
"version": "0.3.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@strudel.cycles/osc",
"version": "0.3.0",
"version": "0.3.1",
"description": "OSC messaging for strudel",
"main": "osc.mjs",
"scripts": {
+21 -21
View File
@@ -74,11 +74,11 @@ const B = $.define(), se = G.define({
for (let o of t.effects)
if (o.is(z)) {
const a = o.value.map(
(s) => (s.context.locations || []).map(({ start: f, end: d }) => {
const u = s.context.color || "#FFCA28";
let c = t.newDoc.line(f.line).from + f.column, i = t.newDoc.line(d.line).from + d.column;
(s) => (s.context.locations || []).map(({ start: u, end: d }) => {
const f = s.context.color || "#FFCA28";
let c = t.newDoc.line(u.line).from + u.column, i = t.newDoc.line(d.line).from + d.column;
const m = t.newDoc.length;
return c > m || i > m ? void 0 : E.mark({ attributes: { style: `outline: 1.5px solid ${u};` } }).range(c, i);
return c > m || i > m ? void 0 : E.mark({ attributes: { style: `outline: 1.5px solid ${f};` } }).range(c, i);
})
).flat().filter(Boolean) || [];
e = E.set(a, !0);
@@ -90,13 +90,13 @@ const B = $.define(), se = G.define({
},
provide: (e) => U.decorations.from(e)
}), le = [Y(), ae, ie, se];
function de({ value: e, onChange: t, onViewChanged: o, onSelectionChange: a, options: s, editorDidMount: f }) {
function de({ value: e, onChange: t, onViewChanged: o, onSelectionChange: a, options: s, editorDidMount: u }) {
const d = _(
(i) => {
t?.(i);
},
[t]
), u = _(
), f = _(
(i) => {
o?.(i);
},
@@ -110,7 +110,7 @@ function de({ value: e, onChange: t, onViewChanged: o, onSelectionChange: a, opt
return /* @__PURE__ */ n.createElement(n.Fragment, null, /* @__PURE__ */ n.createElement(X, {
value: e,
onChange: d,
onCreateEditor: u,
onCreateEditor: f,
onUpdate: c,
extensions: le
}));
@@ -119,21 +119,21 @@ function K(...e) {
return e.filter(Boolean).join(" ");
}
function ue({ view: e, pattern: t, active: o, getTime: a }) {
const s = H([]), f = H();
const s = H([]), u = H();
L(() => {
if (e)
if (t && o) {
let u = function() {
let d = requestAnimationFrame(function f() {
try {
const c = a(), m = [Math.max(f.current || c, c - 1 / 10, 0), c + 1 / 60];
f.current = m[1], s.current = s.current.filter((g) => g.whole.end > c);
const c = a(), m = [Math.max(u.current || c, c - 1 / 10, 0), c + 1 / 60];
u.current = m[1], s.current = s.current.filter((g) => g.whole.end > c);
const h = t.queryArc(...m).filter((g) => g.hasOnset());
s.current = s.current.concat(h), e.dispatch({ effects: z.of(s.current) });
} catch {
e.dispatch({ effects: z.of([]) });
}
d = requestAnimationFrame(u);
}, d = requestAnimationFrame(u);
d = requestAnimationFrame(f);
});
return () => {
cancelAnimationFrame(d);
};
@@ -184,9 +184,9 @@ function ye({
getTime: o,
evalOnMount: a = !1,
initialCode: s = "",
autolink: f = !1,
autolink: u = !1,
beforeEval: d,
afterEval: u,
afterEval: f,
onEvalError: c,
onToggle: i
}) {
@@ -204,7 +204,7 @@ function ye({
y(l), d?.();
},
afterEval: ({ pattern: l, code: P }) => {
S(P), D(l), N(), g(), f && (window.location.hash = "#" + encodeURIComponent(btoa(P))), u?.();
S(P), D(l), N(), g(), u && (window.location.hash = "#" + encodeURIComponent(btoa(P))), f?.();
},
onToggle: (l) => {
x(l), i?.(l);
@@ -251,9 +251,9 @@ const _e = () => re().currentTime;
function Te({ tune: e, hideOutsideView: t = !1, init: o, enableKeyboard: a }) {
const {
code: s,
setCode: f,
setCode: u,
evaluate: d,
activateCode: u,
activateCode: f,
error: c,
isDirty: i,
activeCode: m,
@@ -277,7 +277,7 @@ function Te({ tune: e, hideOutsideView: t = !1, init: o, enableKeyboard: a }) {
}), j(() => {
if (a) {
const x = async (b) => {
(b.ctrlKey || b.altKey) && (b.code === "Enter" ? (b.preventDefault(), ce(y), await u()) : b.code === "Period" && (p(), b.preventDefault()));
(b.ctrlKey || b.altKey) && (b.code === "Enter" ? (b.preventDefault(), ce(y), await f()) : b.code === "Period" && (p(), b.preventDefault()));
};
return window.addEventListener("keydown", x, !0), () => window.removeEventListener("keydown", x, !0);
}
@@ -295,7 +295,7 @@ function Te({ tune: e, hideOutsideView: t = !1, init: o, enableKeyboard: a }) {
type: g ? "pause" : "play"
})), /* @__PURE__ */ n.createElement("button", {
className: K(i ? v.button : v.buttonDisabled),
onClick: () => u()
onClick: () => f()
}, /* @__PURE__ */ n.createElement(O, {
type: "refresh"
}))), c && /* @__PURE__ */ n.createElement("div", {
@@ -304,7 +304,7 @@ function Te({ tune: e, hideOutsideView: t = !1, init: o, enableKeyboard: a }) {
className: v.body
}, F && /* @__PURE__ */ n.createElement(de, {
value: s,
onChange: f,
onChange: u,
onViewChanged: M
})));
}
+5 -5
View File
@@ -1,6 +1,6 @@
{
"name": "@strudel.cycles/react",
"version": "0.4.1",
"version": "0.4.2",
"description": "React components for strudel",
"main": "dist/index.cjs.js",
"module": "dist/index.es.js",
@@ -39,10 +39,10 @@
"homepage": "https://github.com/tidalcycles/strudel#readme",
"dependencies": {
"@codemirror/lang-javascript": "^6.1.1",
"@strudel.cycles/core": "^0.4.0",
"@strudel.cycles/tone": "^0.4.0",
"@strudel.cycles/transpiler": "^0.4.0",
"@strudel.cycles/webaudio": "^0.4.1",
"@strudel.cycles/core": "^0.4.1",
"@strudel.cycles/tone": "^0.4.1",
"@strudel.cycles/transpiler": "^0.4.1",
"@strudel.cycles/webaudio": "^0.4.2",
"@uiw/codemirror-themes": "^4.12.4",
"@uiw/react-codemirror": "^4.12.4",
"react-hook-inview": "^4.5.0"
+2 -5
View File
@@ -7,9 +7,7 @@ function useHighlighting({ view, pattern, active, getTime }) {
useEffect(() => {
if (view) {
if (pattern && active) {
let frame = requestAnimationFrame(updateHighlights);
function updateHighlights() {
let frame = requestAnimationFrame(function updateHighlights() {
try {
const audioTime = getTime();
// force min framerate of 10 fps => fixes crash on tab refocus, where lastEnd could be far away
@@ -25,8 +23,7 @@ function useHighlighting({ view, pattern, active, getTime }) {
view.dispatch({ effects: setHighlights.of([]) });
}
frame = requestAnimationFrame(updateHighlights);
}
});
return () => {
cancelAnimationFrame(frame);
};
+60 -17
View File
@@ -7,7 +7,7 @@ This program is free software: you can redistribute it and/or modify it under th
import core from '@strudel.cycles/core';
const { Pattern, isPattern } = core;
var serialWriter;
var writeMessage;
var choosing = false;
export async function getWriter(br = 38400) {
@@ -15,17 +15,30 @@ export async function getWriter(br = 38400) {
return;
}
choosing = true;
if (serialWriter) {
return serialWriter;
if (writeMessage) {
return writeMessage;
}
if ('serial' in navigator) {
const port = await navigator.serial.requestPort();
await port.open({ baudRate: br });
const textEncoder = new TextEncoderStream();
const writableStreamClosed = textEncoder.readable.pipeTo(port.writable);
const writer = textEncoder.writable.getWriter();
serialWriter = function (message) {
writer.write(message);
const encoder = new TextEncoder();
const writer = port.writable.getWriter();
writeMessage = function (message, chk) {
const encoded = encoder.encode(message)
if (!chk) {
writer.write(encoded);
}
else {
const bytes = new Uint8Array(4);
bytes[0] = 124; // | symbol
bytes[1] = (chk >> 8) & 0xFF;
bytes[2] = chk & 0xFF;
bytes[3] = 59; // semicolon
const withchk = new Uint8Array(encoded.length+4)
withchk.set(encoded);
withchk.set(bytes, encoded.length);
writer.write(withchk);
}
};
} else {
throw 'Webserial is not available in this browser.';
@@ -34,18 +47,41 @@ export async function getWriter(br = 38400) {
const latency = 0.1;
Pattern.prototype.serial = function (...args) {
return this._withHap((hap) => {
if (!serialWriter) {
getWriter(...args);
// crc16 (CCITT-FALSE) https://gist.github.com/tijnkooijmans/10981093
function crc16(data) {
const length = data.length
if (length == 0) {
return 0;
}
var crc = 0xFFFF;
for (var i = 0; i < length; ++i) {
crc ^= data.charCodeAt(i) << 8;
for (var j = 0; j < 8; ++j) {
crc = (crc & 0x8000) > 0 ? (crc << 1) ^ 0x1021 : crc << 1;
}
}
return crc & 0xffff;
}
Pattern.prototype.serial = function (br=38400,sendcrc=false,singlecharids=false) {
return this.withHap((hap) => {
if (!writeMessage) {
getWriter(br);
}
const onTrigger = (time, hap, currentTime) => {
var message = '';
var chk = 0;
if (typeof hap.value === 'object') {
if ('action' in hap.value) {
message += hap.value['action'] + '(';
var action = hap.value['action'];
if (singlecharids) {
action = action.charAt(0);
}
message += action + '(';
var first = true;
for (const [key, val] of Object.entries(hap.value)) {
for (var [key, val] of Object.entries(hap.value)) {
if (key === 'action') {
continue;
}
@@ -54,19 +90,26 @@ Pattern.prototype.serial = function (...args) {
} else {
message += ',';
}
message += `${key}:${val}`;
if (singlecharids) {
key = key.charAt(0);
}
message += key + ':' + val;
}
message += ')';
if (sendcrc) {
chk = crc16(message)
}
} else {
for (const [key, val] of Object.entries(hap.value)) {
message += `${key}:${val};`;
message += `${key}:${val}`;
}
}
} else {
message = hap.value;
}
const offset = (time - currentTime + latency) * 1000;
window.setTimeout(serialWriter, offset, message);
window.setTimeout(function () {writeMessage(message, chk)}, offset);
};
return hap.setContext({ ...hap.context, onTrigger, dominantTrigger: true });
});
+2
View File
@@ -1,3 +1,5 @@
import { toMidi } from '@strudel.cycles/core';
let loadCache = {};
async function loadFont(name) {
if (loadCache[name]) {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@strudel.cycles/soundfonts",
"version": "0.4.1",
"version": "0.4.2",
"lockfileVersion": 2,
"requires": true,
"packages": {
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@strudel.cycles/soundfonts",
"version": "0.4.1",
"version": "0.4.2",
"description": "Soundsfont support for strudel",
"main": "index.mjs",
"type": "module",
@@ -22,8 +22,8 @@
},
"homepage": "https://github.com/tidalcycles/strudel#readme",
"dependencies": {
"@strudel.cycles/core": "^0.4.0",
"@strudel.cycles/webaudio": "^0.4.1",
"@strudel.cycles/core": "^0.4.1",
"@strudel.cycles/webaudio": "^0.4.2",
"sfumato": "^0.1.2",
"soundfont2": "^0.4.0"
},
+2 -2
View File
@@ -1,6 +1,6 @@
import strudel from '@strudel.cycles/core';
const { Pattern } = strudel;
const { Pattern, getPlayableNoteValue, toMidi } = strudel;
import { getAudioContext } from '@strudel.cycles/webaudio';
import { loadSoundfont as _loadSoundfont, startPresetNote } from 'sfumato';
Pattern.prototype.soundfont = function (sf, n = 0) {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@strudel.cycles/tonal",
"version": "0.4.0",
"version": "0.4.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@strudel.cycles/tonal",
"version": "0.4.0",
"version": "0.4.1",
"description": "Tonal functions for strudel",
"main": "index.mjs",
"type": "module",
@@ -25,8 +25,8 @@
},
"homepage": "https://github.com/tidalcycles/strudel#readme",
"dependencies": {
"@strudel.cycles/core": "^0.4.0",
"@tonaljs/tonal": "^4.6.5",
"@strudel.cycles/core": "^0.4.1",
"@tonaljs/tonal": "^4.7.2",
"chord-voicings": "^0.0.1",
"webmidi": "^3.0.21"
}
+1 -1
View File
@@ -61,7 +61,7 @@ Pattern.prototype.voicings = function (range) {
Pattern.prototype._rootNotes = function (octave = 2) {
return this.fmap((value) => {
const [_, root] = value.match(/^([a-gA-G][b#]?).*$/);
const root = value.match(/^([a-gA-G][b#]?).*$/)[1];
return root + octave;
});
};
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@strudel.cycles/tone",
"version": "0.4.0",
"version": "0.4.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@strudel.cycles/tone",
"version": "0.4.0",
"version": "0.4.1",
"description": "Tone.js API for strudel",
"main": "index.mjs",
"type": "module",
@@ -22,7 +22,7 @@
},
"homepage": "https://github.com/tidalcycles/strudel#readme",
"dependencies": {
"@strudel.cycles/core": "^0.4.0",
"@strudel.cycles/core": "^0.4.1",
"tone": "^14.7.77"
}
}
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@strudel.cycles/transpiler",
"version": "0.4.0",
"version": "0.4.1",
"description": "Transpiler for strudel user code. Converts syntactically correct but semantically meaningless JS into evaluatable strudel code.",
"main": "index.mjs",
"scripts": {
@@ -24,7 +24,7 @@
},
"homepage": "https://github.com/tidalcycles/strudel#readme",
"dependencies": {
"@strudel.cycles/core": "^0.4.0",
"@strudel.cycles/core": "^0.4.1",
"acorn": "^8.8.1",
"escodegen": "^2.0.0",
"estree-walker": "^3.0.1"
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@strudel.cycles/webaudio",
"version": "0.4.1",
"version": "0.4.2",
"lockfileVersion": 2,
"requires": true,
"packages": {
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@strudel.cycles/webaudio",
"version": "0.4.1",
"version": "0.4.2",
"description": "Web Audio helpers for Strudel",
"main": "index.mjs",
"type": "module",
@@ -30,6 +30,6 @@
},
"homepage": "https://github.com/tidalcycles/strudel#readme",
"dependencies": {
"@strudel.cycles/core": "^0.4.0"
"@strudel.cycles/core": "^0.4.1"
}
}
+2 -1
View File
@@ -1,5 +1,6 @@
import core from '@strudel.cycles/core';
const logger = core.logger;
const { logger, toMidi } = core;
import { getAudioContext } from './index.mjs';
const bufferCache = {}; // string: Promise<ArrayBuffer>
const loadCache = {}; // string: Promise<ArrayBuffer>
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@strudel.cycles/webdirt",
"version": "0.4.0",
"version": "0.4.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@strudel.cycles/webdirt",
"version": "0.4.0",
"version": "0.4.1",
"description": "WebDirt integration for Strudel",
"main": "index.mjs",
"type": "module",
@@ -22,7 +22,7 @@
},
"homepage": "https://github.com/tidalcycles/strudel#readme",
"dependencies": {
"@strudel.cycles/core": "^0.4.0",
"@strudel.cycles/core": "^0.4.1",
"WebDirt": "github:dktr0/WebDirt"
}
}
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@strudel.cycles/xen",
"version": "0.4.0",
"version": "0.4.1",
"description": "Xenharmonic API for strudel",
"main": "index.mjs",
"scripts": {
@@ -24,6 +24,6 @@
},
"homepage": "https://github.com/tidalcycles/strudel#readme",
"dependencies": {
"@strudel.cycles/core": "^0.4.0"
"@strudel.cycles/core": "^0.4.1"
}
}
+1
View File
@@ -43,6 +43,7 @@ const modules = [
import('@strudel.cycles/osc'),
import('@strudel.cycles/serial'),
import('@strudel.cycles/soundfonts'),
import('@strudel.cycles/csound'),
];
evalScope(
+5
View File
@@ -88,6 +88,9 @@ const toneHelpersMocked = {
Pattern.prototype.osc = function () {
return this;
};
Pattern.prototype.csound = function () {
return this;
};
Pattern.prototype.tone = function () {
return this;
};
@@ -170,6 +173,8 @@ evalScope(
{
// gist,
// euclid,
csound: id,
loadOrc: id,
mini,
getDrawContext,
getAudioContext,
+74 -401
View File
@@ -7,7 +7,7 @@ exports[`renders tunes > tune: amensister 1`] = `
"3/8 -> 1/2: {\\"n\\":1,\\"s\\":\\"amencutup\\",\\"room\\":0.5}",
"3/4 -> 7/8: {\\"n\\":3,\\"s\\":\\"amencutup\\",\\"room\\":0.5}",
"7/8 -> 1/1: {\\"n\\":3,\\"s\\":\\"amencutup\\",\\"room\\":0.5}",
"1/4 -> 3/8: {\\"n\\":1,\\"speed\\":-2,\\"delay\\":0.5,\\"s\\":\\"amencutup\\",\\"room\\":0.5}",
"1/4 -> 3/8: {\\"n\\":1,\\"speed\\":2,\\"delay\\":0.5,\\"s\\":\\"amencutup\\",\\"room\\":0.5}",
"0/1 -> 1/8: {\\"note\\":\\"Eb1\\",\\"s\\":\\"sawtooth\\",\\"decay\\":0.1,\\"sustain\\":0,\\"gain\\":0.4,\\"cutoff\\":300.0066107586751,\\"resonance\\":10}",
"0/1 -> 1/8: {\\"note\\":\\"F1\\",\\"s\\":\\"sawtooth\\",\\"decay\\":0.1,\\"sustain\\":0,\\"gain\\":0.4,\\"cutoff\\":300.0066107586751,\\"resonance\\":10}",
"1/4 -> 3/8: {\\"note\\":\\"A1\\",\\"s\\":\\"sawtooth\\",\\"decay\\":0.1,\\"sustain\\":0,\\"gain\\":0.4,\\"cutoff\\":300.7878869297153,\\"resonance\\":10}",
@@ -39,6 +39,35 @@ exports[`renders tunes > tune: amensister 1`] = `
]
`;
exports[`renders tunes > tune: arpoon 1`] = `
[
"0/1 -> 2/3: {\\"note\\":55.000528662214684,\\"cutoff\\":509.2515887569149,\\"resonance\\":12,\\"gain\\":0.5,\\"decay\\":0.16,\\"sustain\\":0.5,\\"delay\\":0.2,\\"room\\":0.5,\\"pan\\":0.5249999999999999,\\"s\\":\\"piano\\",\\"clip\\":1}",
"0/1 -> 2/3: {\\"note\\":55.000528662214684,\\"cutoff\\":509.2515887569149,\\"resonance\\":12,\\"gain\\":0.8,\\"decay\\":0.16,\\"sustain\\":0.5,\\"delay\\":0.2,\\"room\\":0.5,\\"pan\\":0.5249999999999999,\\"s\\":\\"piano\\",\\"clip\\":1}",
"0/1 -> 2/3: {\\"note\\":55.000528662214684,\\"cutoff\\":509.2515887569149,\\"resonance\\":12,\\"gain\\":0.5,\\"decay\\":0.16,\\"sustain\\":0.5,\\"delay\\":0.2,\\"room\\":0.5,\\"pan\\":0.5249999999999999,\\"s\\":\\"piano\\",\\"clip\\":1}",
"0/1 -> 2/3: {\\"note\\":64.00052866221468,\\"cutoff\\":509.2515887569149,\\"resonance\\":12,\\"gain\\":0.5,\\"decay\\":0.16,\\"sustain\\":0.5,\\"delay\\":0.2,\\"room\\":0.5,\\"pan\\":0.5249999999999999,\\"s\\":\\"piano\\",\\"clip\\":1}",
"0/1 -> 2/3: {\\"note\\":64.00052866221468,\\"cutoff\\":509.2515887569149,\\"resonance\\":12,\\"gain\\":0.8,\\"decay\\":0.16,\\"sustain\\":0.5,\\"delay\\":0.2,\\"room\\":0.5,\\"pan\\":0.5249999999999999,\\"s\\":\\"piano\\",\\"clip\\":1}",
"0/1 -> 2/3: {\\"note\\":64.00052866221468,\\"cutoff\\":509.2515887569149,\\"resonance\\":12,\\"gain\\":0.5,\\"decay\\":0.16,\\"sustain\\":0.5,\\"delay\\":0.2,\\"room\\":0.5,\\"pan\\":0.5249999999999999,\\"s\\":\\"piano\\",\\"clip\\":1}",
"1/3 -> 1/1: {\\"note\\":60.003688107962134,\\"cutoff\\":564.5418893373399,\\"resonance\\":12,\\"gain\\":0.8,\\"decay\\":0.16,\\"sustain\\":0.5,\\"delay\\":0.2,\\"room\\":0.5,\\"pan\\":0.5799038105676657,\\"s\\":\\"piano\\",\\"clip\\":1}",
"1/3 -> 1/1: {\\"note\\":60.003688107962134,\\"cutoff\\":564.5418893373399,\\"resonance\\":12,\\"gain\\":0.5,\\"decay\\":0.16,\\"sustain\\":0.5,\\"delay\\":0.2,\\"room\\":0.5,\\"pan\\":0.5799038105676657,\\"s\\":\\"piano\\",\\"clip\\":1}",
"1/3 -> 1/1: {\\"note\\":60.003688107962134,\\"cutoff\\":564.5418893373399,\\"resonance\\":12,\\"gain\\":0.8,\\"decay\\":0.16,\\"sustain\\":0.5,\\"delay\\":0.2,\\"room\\":0.5,\\"pan\\":0.5799038105676657,\\"s\\":\\"piano\\",\\"clip\\":1}",
"2/3 -> 4/3: {\\"note\\":59.010756146386846,\\"cutoff\\":688.232561769837,\\"resonance\\":12,\\"gain\\":0.5,\\"decay\\":0.16,\\"sustain\\":0.5,\\"delay\\":0.2,\\"room\\":0.5,\\"pan\\":0.6,\\"s\\":\\"piano\\",\\"clip\\":1}",
"2/3 -> 4/3: {\\"note\\":59.010756146386846,\\"cutoff\\":688.232561769837,\\"resonance\\":12,\\"gain\\":0.8,\\"decay\\":0.16,\\"sustain\\":0.5,\\"delay\\":0.2,\\"room\\":0.5,\\"pan\\":0.6,\\"s\\":\\"piano\\",\\"clip\\":1}",
"2/3 -> 4/3: {\\"note\\":59.010756146386846,\\"cutoff\\":688.232561769837,\\"resonance\\":12,\\"gain\\":0.5,\\"decay\\":0.16,\\"sustain\\":0.5,\\"delay\\":0.2,\\"room\\":0.5,\\"pan\\":0.6,\\"s\\":\\"piano\\",\\"clip\\":1}",
"2/3 -> 4/3: {\\"note\\":59.010756146386846,\\"cutoff\\":688.232561769837,\\"resonance\\":12,\\"gain\\":0.8,\\"decay\\":0.16,\\"sustain\\":0.5,\\"delay\\":0.2,\\"room\\":0.5,\\"pan\\":0.6,\\"s\\":\\"piano\\",\\"clip\\":1}",
"2/3 -> 4/3: {\\"note\\":64.01075614638685,\\"cutoff\\":688.232561769837,\\"resonance\\":12,\\"gain\\":0.5,\\"decay\\":0.16,\\"sustain\\":0.5,\\"delay\\":0.2,\\"room\\":0.5,\\"pan\\":0.6,\\"s\\":\\"piano\\",\\"clip\\":1}",
"2/3 -> 4/3: {\\"note\\":64.01075614638685,\\"cutoff\\":688.232561769837,\\"resonance\\":12,\\"gain\\":0.8,\\"decay\\":0.16,\\"sustain\\":0.5,\\"delay\\":0.2,\\"room\\":0.5,\\"pan\\":0.6,\\"s\\":\\"piano\\",\\"clip\\":1}",
"2/3 -> 4/3: {\\"note\\":64.01075614638685,\\"cutoff\\":688.232561769837,\\"resonance\\":12,\\"gain\\":0.5,\\"decay\\":0.16,\\"sustain\\":0.5,\\"delay\\":0.2,\\"room\\":0.5,\\"pan\\":0.6,\\"s\\":\\"piano\\",\\"clip\\":1}",
"2/3 -> 4/3: {\\"note\\":64.01075614638685,\\"cutoff\\":688.232561769837,\\"resonance\\":12,\\"gain\\":0.8,\\"decay\\":0.16,\\"sustain\\":0.5,\\"delay\\":0.2,\\"room\\":0.5,\\"pan\\":0.6,\\"s\\":\\"piano\\",\\"clip\\":1}",
"0/1 -> 1/1: {\\"note\\":33,\\"s\\":\\"sawtooth\\",\\"clip\\":1,\\"cutoff\\":300}",
"0/1 -> 1/1: {\\"note\\":33.12,\\"s\\":\\"sawtooth\\",\\"clip\\":1,\\"cutoff\\":300}",
"0/1 -> 1/2: {\\"s\\":\\"bd\\",\\"bank\\":\\"RolandTR909\\",\\"gain\\":0.5}",
"1/2 -> 1/1: {\\"s\\":\\"bd\\",\\"bank\\":\\"RolandTR909\\",\\"gain\\":0.5}",
"1/2 -> 2/3: {\\"s\\":\\"hh\\",\\"bank\\":\\"RolandTR909\\",\\"gain\\":0.5}",
"2/3 -> 5/6: {\\"s\\":\\"hh\\",\\"bank\\":\\"RolandTR909\\",\\"gain\\":0.5}",
"5/6 -> 1/1: {\\"s\\":\\"hh\\",\\"bank\\":\\"RolandTR909\\",\\"gain\\":0.5}",
]
`;
exports[`renders tunes > tune: barryHarris 1`] = `
[
"0/1 -> 2/1: {\\"note\\":\\"C3\\",\\"clip\\":1,\\"s\\":\\"piano\\",\\"release\\":0.1,\\"pan\\":0.4722222222222222}",
@@ -318,36 +347,6 @@ exports[`renders tunes > tune: blippyRhodes 1`] = `
]
`;
exports[`renders tunes > tune: bossa 1`] = `
[
"0/1 -> 1/4: {\\"note\\":\\"Bb3\\",\\"clip\\":1,\\"s\\":\\"piano\\",\\"release\\":0.1,\\"pan\\":0.5185185185185186}",
"0/1 -> 1/4: {\\"note\\":\\"D4\\",\\"clip\\":1,\\"s\\":\\"piano\\",\\"release\\":0.1,\\"pan\\":0.537037037037037}",
"0/1 -> 1/4: {\\"note\\":\\"Eb4\\",\\"clip\\":1,\\"s\\":\\"piano\\",\\"release\\":0.1,\\"pan\\":0.5416666666666667}",
"0/1 -> 1/4: {\\"note\\":\\"G4\\",\\"clip\\":1,\\"s\\":\\"piano\\",\\"release\\":0.1,\\"pan\\":0.5601851851851851}",
"1/2 -> 5/4: {\\"note\\":\\"Bb3\\",\\"clip\\":1,\\"s\\":\\"piano\\",\\"release\\":0.1,\\"pan\\":0.5185185185185186}",
"1/2 -> 5/4: {\\"note\\":\\"D4\\",\\"clip\\":1,\\"s\\":\\"piano\\",\\"release\\":0.1,\\"pan\\":0.537037037037037}",
"1/2 -> 5/4: {\\"note\\":\\"Eb4\\",\\"clip\\":1,\\"s\\":\\"piano\\",\\"release\\":0.1,\\"pan\\":0.5416666666666667}",
"1/2 -> 5/4: {\\"note\\":\\"G4\\",\\"clip\\":1,\\"s\\":\\"piano\\",\\"release\\":0.1,\\"pan\\":0.5601851851851851}",
"0/1 -> 1/2: {\\"note\\":\\"C2\\",\\"clip\\":1,\\"s\\":\\"piano\\",\\"release\\":0.1,\\"pan\\":0.41666666666666663}",
"3/4 -> 7/8: {\\"note\\":\\"G2\\",\\"clip\\":1,\\"s\\":\\"piano\\",\\"release\\":0.1,\\"pan\\":0.44907407407407407}",
]
`;
exports[`renders tunes > tune: bossaRandom 1`] = `
[
"0/1 -> 1/4: {\\"note\\":\\"G4\\",\\"clip\\":1,\\"s\\":\\"piano\\",\\"release\\":0.1,\\"pan\\":0.5601851851851851}",
"0/1 -> 1/4: {\\"note\\":\\"B4\\",\\"clip\\":1,\\"s\\":\\"piano\\",\\"release\\":0.1,\\"pan\\":0.5787037037037037}",
"0/1 -> 1/4: {\\"note\\":\\"C5\\",\\"clip\\":1,\\"s\\":\\"piano\\",\\"release\\":0.1,\\"pan\\":0.5833333333333333}",
"0/1 -> 1/4: {\\"note\\":\\"E5\\",\\"clip\\":1,\\"s\\":\\"piano\\",\\"release\\":0.1,\\"pan\\":0.6018518518518519}",
"3/4 -> 1/1: {\\"note\\":\\"G4\\",\\"clip\\":1,\\"s\\":\\"piano\\",\\"release\\":0.1,\\"pan\\":0.5601851851851851}",
"3/4 -> 1/1: {\\"note\\":\\"B4\\",\\"clip\\":1,\\"s\\":\\"piano\\",\\"release\\":0.1,\\"pan\\":0.5787037037037037}",
"3/4 -> 1/1: {\\"note\\":\\"C5\\",\\"clip\\":1,\\"s\\":\\"piano\\",\\"release\\":0.1,\\"pan\\":0.5833333333333333}",
"3/4 -> 1/1: {\\"note\\":\\"E5\\",\\"clip\\":1,\\"s\\":\\"piano\\",\\"release\\":0.1,\\"pan\\":0.6018518518518519}",
"0/1 -> 1/2: {\\"note\\":\\"A2\\",\\"clip\\":1,\\"s\\":\\"piano\\",\\"release\\":0.1,\\"pan\\":0.45833333333333337}",
"1/2 -> 1/1: {\\"note\\":\\"A2\\",\\"clip\\":1,\\"s\\":\\"piano\\",\\"release\\":0.1,\\"pan\\":0.45833333333333337}",
]
`;
exports[`renders tunes > tune: bridgeIsOver 1`] = `
[
"0/1 -> 5/26: {\\"note\\":\\"B2\\",\\"clip\\":1,\\"s\\":\\"piano\\",\\"release\\":0.1,\\"pan\\":0.46759259259259256}",
@@ -1409,6 +1408,20 @@ exports[`renders tunes > tune: chop 1`] = `
]
`;
exports[`renders tunes > tune: csoundDemo 1`] = `
[
"0/1 -> 1/1: {\\"note\\":\\"D3\\"}",
"-1/4 -> 1/4: {\\"note\\":\\"Bb3\\"}",
"1/4 -> 5/4: {\\"note\\":\\"F3\\"}",
"0/1 -> 1/2: {\\"note\\":\\"F4\\"}",
"1/2 -> 3/2: {\\"note\\":\\"C4\\"}",
"-1/4 -> 1/4: {\\"note\\":\\"A4\\"}",
"1/4 -> 3/4: {\\"note\\":\\"A4\\"}",
"1/4 -> 3/4: {\\"note\\":\\"A4\\"}",
"3/4 -> 7/4: {\\"note\\":\\"E4\\"}",
]
`;
exports[`renders tunes > tune: delay 1`] = `
[
"0/1 -> 1/2: {\\"s\\":\\"bd\\",\\"delay\\":0,\\"delaytime\\":0.16,\\"delayfeedback\\":0.8,\\"speed\\":-1}",
@@ -7244,257 +7257,6 @@ exports[`renders tunes > tune: giantSteps 1`] = `
]
`;
exports[`renders tunes > tune: giantStepsReggae 1`] = `
[
"0/1 -> 25/32: {\\"note\\":\\"F#5\\"}",
"25/32 -> 25/16: {\\"note\\":\\"D5\\"}",
"25/64 -> 75/128: {\\"note\\":\\"A#3\\"}",
"25/64 -> 75/128: {\\"note\\":\\"C#4\\"}",
"25/64 -> 75/128: {\\"note\\":\\"D#4\\"}",
"25/64 -> 75/128: {\\"note\\":\\"F#4\\"}",
"0/1 -> 25/64: {\\"note\\":\\"B2\\"}",
"25/32 -> 75/64: {\\"note\\":\\"D2\\"}",
"25/32 -> 25/16: {\\"note\\":\\"D5\\"}",
"25/16 -> 75/32: {\\"note\\":\\"B4\\"}",
"75/64 -> 175/128: {\\"note\\":\\"F#3\\"}",
"75/64 -> 175/128: {\\"note\\":\\"B3\\"}",
"75/64 -> 175/128: {\\"note\\":\\"C4\\"}",
"75/64 -> 175/128: {\\"note\\":\\"E4\\"}",
"125/64 -> 275/128: {\\"note\\":\\"F#3\\"}",
"125/64 -> 275/128: {\\"note\\":\\"A3\\"}",
"125/64 -> 275/128: {\\"note\\":\\"B3\\"}",
"125/64 -> 275/128: {\\"note\\":\\"D4\\"}",
"25/32 -> 75/64: {\\"note\\":\\"D2\\"}",
"25/16 -> 125/64: {\\"note\\":\\"G2\\"}",
"25/16 -> 75/32: {\\"note\\":\\"B4\\"}",
"75/32 -> 25/8: {\\"note\\":\\"G4\\"}",
"125/64 -> 275/128: {\\"note\\":\\"F#3\\"}",
"125/64 -> 275/128: {\\"note\\":\\"A3\\"}",
"125/64 -> 275/128: {\\"note\\":\\"B3\\"}",
"125/64 -> 275/128: {\\"note\\":\\"D4\\"}",
"175/64 -> 375/128: {\\"note\\":\\"Ab3\\"}",
"175/64 -> 375/128: {\\"note\\":\\"C4\\"}",
"175/64 -> 375/128: {\\"note\\":\\"D4\\"}",
"175/64 -> 375/128: {\\"note\\":\\"G4\\"}",
"75/32 -> 175/64: {\\"note\\":\\"D2\\"}",
"75/32 -> 25/8: {\\"note\\":\\"G4\\"}",
"25/8 -> 75/16: {\\"note\\":\\"Bb4\\"}",
"225/64 -> 475/128: {\\"note\\":\\"G3\\"}",
"225/64 -> 475/128: {\\"note\\":\\"Bb3\\"}",
"225/64 -> 475/128: {\\"note\\":\\"D4\\"}",
"225/64 -> 475/128: {\\"note\\":\\"F4\\"}",
"25/8 -> 225/64: {\\"note\\":\\"Eb2\\"}",
"125/32 -> 275/64: {\\"note\\":\\"Bb2\\"}",
"25/8 -> 75/16: {\\"note\\":\\"Bb4\\"}",
"75/16 -> 175/32: {\\"note\\":\\"B4\\"}",
"275/64 -> 575/128: {\\"note\\":\\"G3\\"}",
"275/64 -> 575/128: {\\"note\\":\\"Bb3\\"}",
"275/64 -> 575/128: {\\"note\\":\\"D4\\"}",
"275/64 -> 575/128: {\\"note\\":\\"F4\\"}",
"125/32 -> 275/64: {\\"note\\":\\"Bb2\\"}",
"75/16 -> 325/64: {\\"note\\":\\"A2\\"}",
"75/16 -> 175/32: {\\"note\\":\\"B4\\"}",
"175/32 -> 25/4: {\\"note\\":\\"A4\\"}",
"325/64 -> 675/128: {\\"note\\":\\"G3\\"}",
"325/64 -> 675/128: {\\"note\\":\\"B3\\"}",
"325/64 -> 675/128: {\\"note\\":\\"C4\\"}",
"325/64 -> 675/128: {\\"note\\":\\"E4\\"}",
"375/64 -> 775/128: {\\"note\\":\\"F#3\\"}",
"375/64 -> 775/128: {\\"note\\":\\"B3\\"}",
"375/64 -> 775/128: {\\"note\\":\\"C4\\"}",
"375/64 -> 775/128: {\\"note\\":\\"E4\\"}",
"75/16 -> 325/64: {\\"note\\":\\"A2\\"}",
"175/32 -> 375/64: {\\"note\\":\\"D2\\"}",
"175/32 -> 25/4: {\\"note\\":\\"A4\\"}",
"25/4 -> 225/32: {\\"note\\":\\"D5\\"}",
"375/64 -> 775/128: {\\"note\\":\\"F#3\\"}",
"375/64 -> 775/128: {\\"note\\":\\"B3\\"}",
"375/64 -> 775/128: {\\"note\\":\\"C4\\"}",
"375/64 -> 775/128: {\\"note\\":\\"E4\\"}",
"425/64 -> 875/128: {\\"note\\":\\"F#3\\"}",
"425/64 -> 875/128: {\\"note\\":\\"A3\\"}",
"425/64 -> 875/128: {\\"note\\":\\"B3\\"}",
"425/64 -> 875/128: {\\"note\\":\\"D4\\"}",
"25/4 -> 425/64: {\\"note\\":\\"G2\\"}",
"25/4 -> 225/32: {\\"note\\":\\"D5\\"}",
"225/32 -> 125/16: {\\"note\\":\\"Bb4\\"}",
"125/16 -> 275/32: {\\"note\\":\\"G4\\"}",
"475/64 -> 975/128: {\\"note\\":\\"Ab3\\"}",
"475/64 -> 975/128: {\\"note\\":\\"C4\\"}",
"475/64 -> 975/128: {\\"note\\":\\"D4\\"}",
"475/64 -> 975/128: {\\"note\\":\\"G4\\"}",
"225/32 -> 475/64: {\\"note\\":\\"Bb2\\"}",
"125/16 -> 525/64: {\\"note\\":\\"Eb2\\"}",
"125/16 -> 275/32: {\\"note\\":\\"G4\\"}",
"275/32 -> 75/8: {\\"note\\":\\"Eb4\\"}",
"525/64 -> 1075/128: {\\"note\\":\\"G3\\"}",
"525/64 -> 1075/128: {\\"note\\":\\"Bb3\\"}",
"525/64 -> 1075/128: {\\"note\\":\\"D4\\"}",
"525/64 -> 1075/128: {\\"note\\":\\"F4\\"}",
"575/64 -> 1175/128: {\\"note\\":\\"E3\\"}",
"575/64 -> 1175/128: {\\"note\\":\\"G#3\\"}",
"575/64 -> 1175/128: {\\"note\\":\\"A#3\\"}",
"575/64 -> 1175/128: {\\"note\\":\\"D#4\\"}",
"125/16 -> 525/64: {\\"note\\":\\"Eb2\\"}",
"275/32 -> 575/64: {\\"note\\":\\"F#2\\"}",
"275/32 -> 75/8: {\\"note\\":\\"Eb4\\"}",
"75/8 -> 175/16: {\\"note\\":\\"F#4\\"}",
"575/64 -> 1175/128: {\\"note\\":\\"E3\\"}",
"575/64 -> 1175/128: {\\"note\\":\\"G#3\\"}",
"575/64 -> 1175/128: {\\"note\\":\\"A#3\\"}",
"575/64 -> 1175/128: {\\"note\\":\\"D#4\\"}",
"625/64 -> 1275/128: {\\"note\\":\\"A#3\\"}",
"625/64 -> 1275/128: {\\"note\\":\\"C#4\\"}",
"625/64 -> 1275/128: {\\"note\\":\\"D#4\\"}",
"625/64 -> 1275/128: {\\"note\\":\\"F#4\\"}",
"75/8 -> 625/64: {\\"note\\":\\"B2\\"}",
"75/8 -> 175/16: {\\"note\\":\\"F#4\\"}",
"175/16 -> 375/32: {\\"note\\":\\"G4\\"}",
"675/64 -> 1375/128: {\\"note\\":\\"A#3\\"}",
"675/64 -> 1375/128: {\\"note\\":\\"C#4\\"}",
"675/64 -> 1375/128: {\\"note\\":\\"D#4\\"}",
"675/64 -> 1375/128: {\\"note\\":\\"F#4\\"}",
"325/32 -> 675/64: {\\"note\\":\\"F#2\\"}",
"175/16 -> 725/64: {\\"note\\":\\"F2\\"}",
"175/16 -> 375/32: {\\"note\\":\\"G4\\"}",
"375/32 -> 25/2: {\\"note\\":\\"F4\\"}",
"725/64 -> 1475/128: {\\"note\\":\\"Ab3\\"}",
"725/64 -> 1475/128: {\\"note\\":\\"C4\\"}",
"725/64 -> 1475/128: {\\"note\\":\\"Eb4\\"}",
"725/64 -> 1475/128: {\\"note\\":\\"G4\\"}",
"175/16 -> 725/64: {\\"note\\":\\"F2\\"}",
"375/32 -> 775/64: {\\"note\\":\\"Bb2\\"}",
"375/32 -> 25/2: {\\"note\\":\\"F4\\"}",
"25/2 -> 225/16: {\\"note\\":\\"Bb4\\"}",
"775/64 -> 1575/128: {\\"note\\":\\"Ab3\\"}",
"775/64 -> 1575/128: {\\"note\\":\\"C4\\"}",
"775/64 -> 1575/128: {\\"note\\":\\"D4\\"}",
"775/64 -> 1575/128: {\\"note\\":\\"G4\\"}",
"825/64 -> 1675/128: {\\"note\\":\\"G3\\"}",
"825/64 -> 1675/128: {\\"note\\":\\"Bb3\\"}",
"825/64 -> 1675/128: {\\"note\\":\\"D4\\"}",
"825/64 -> 1675/128: {\\"note\\":\\"F4\\"}",
"375/32 -> 775/64: {\\"note\\":\\"Bb2\\"}",
"25/2 -> 825/64: {\\"note\\":\\"Eb2\\"}",
"25/2 -> 225/16: {\\"note\\":\\"Bb4\\"}",
"825/64 -> 1675/128: {\\"note\\":\\"G3\\"}",
"825/64 -> 1675/128: {\\"note\\":\\"Bb3\\"}",
"825/64 -> 1675/128: {\\"note\\":\\"D4\\"}",
"825/64 -> 1675/128: {\\"note\\":\\"F4\\"}",
"875/64 -> 1775/128: {\\"note\\":\\"G3\\"}",
"875/64 -> 1775/128: {\\"note\\":\\"Bb3\\"}",
"875/64 -> 1775/128: {\\"note\\":\\"D4\\"}",
"875/64 -> 1775/128: {\\"note\\":\\"F4\\"}",
"425/32 -> 875/64: {\\"note\\":\\"Bb2\\"}",
"25/2 -> 225/16: {\\"note\\":\\"Bb4\\"}",
"225/16 -> 475/32: {\\"note\\":\\"B4\\"}",
"475/32 -> 125/8: {\\"note\\":\\"A4\\"}",
"925/64 -> 1875/128: {\\"note\\":\\"G3\\"}",
"925/64 -> 1875/128: {\\"note\\":\\"B3\\"}",
"925/64 -> 1875/128: {\\"note\\":\\"C4\\"}",
"925/64 -> 1875/128: {\\"note\\":\\"E4\\"}",
"225/16 -> 925/64: {\\"note\\":\\"A2\\"}",
"475/32 -> 975/64: {\\"note\\":\\"D2\\"}",
"475/32 -> 125/8: {\\"note\\":\\"A4\\"}",
"125/8 -> 275/16: {\\"note\\":\\"D5\\"}",
"975/64 -> 1975/128: {\\"note\\":\\"F#3\\"}",
"975/64 -> 1975/128: {\\"note\\":\\"B3\\"}",
"975/64 -> 1975/128: {\\"note\\":\\"C4\\"}",
"975/64 -> 1975/128: {\\"note\\":\\"E4\\"}",
"475/32 -> 975/64: {\\"note\\":\\"D2\\"}",
"125/8 -> 1025/64: {\\"note\\":\\"G2\\"}",
"125/8 -> 275/16: {\\"note\\":\\"D5\\"}",
"1025/64 -> 2075/128: {\\"note\\":\\"F#3\\"}",
"1025/64 -> 2075/128: {\\"note\\":\\"A3\\"}",
"1025/64 -> 2075/128: {\\"note\\":\\"B3\\"}",
"1025/64 -> 2075/128: {\\"note\\":\\"D4\\"}",
"1075/64 -> 2175/128: {\\"note\\":\\"F#3\\"}",
"1075/64 -> 2175/128: {\\"note\\":\\"A3\\"}",
"1075/64 -> 2175/128: {\\"note\\":\\"B3\\"}",
"1075/64 -> 2175/128: {\\"note\\":\\"D4\\"}",
"125/8 -> 1025/64: {\\"note\\":\\"G2\\"}",
"525/32 -> 1075/64: {\\"note\\":\\"D2\\"}",
"125/8 -> 275/16: {\\"note\\":\\"D5\\"}",
"275/16 -> 575/32: {\\"note\\":\\"D#5\\"}",
"575/32 -> 75/4: {\\"note\\":\\"C#5\\"}",
"1125/64 -> 2275/128: {\\"note\\":\\"E3\\"}",
"1125/64 -> 2275/128: {\\"note\\":\\"G#3\\"}",
"1125/64 -> 2275/128: {\\"note\\":\\"B3\\"}",
"1125/64 -> 2275/128: {\\"note\\":\\"D#4\\"}",
"275/16 -> 1125/64: {\\"note\\":\\"C#2\\"}",
"575/32 -> 1175/64: {\\"note\\":\\"F#2\\"}",
"575/32 -> 75/4: {\\"note\\":\\"C#5\\"}",
"75/4 -> 325/16: {\\"note\\":\\"F#5\\"}",
"1175/64 -> 2375/128: {\\"note\\":\\"E3\\"}",
"1175/64 -> 2375/128: {\\"note\\":\\"G#3\\"}",
"1175/64 -> 2375/128: {\\"note\\":\\"A#3\\"}",
"1175/64 -> 2375/128: {\\"note\\":\\"D#4\\"}",
"575/32 -> 1175/64: {\\"note\\":\\"F#2\\"}",
"75/4 -> 1225/64: {\\"note\\":\\"B2\\"}",
"75/4 -> 325/16: {\\"note\\":\\"F#5\\"}",
"1225/64 -> 2475/128: {\\"note\\":\\"A#3\\"}",
"1225/64 -> 2475/128: {\\"note\\":\\"C#4\\"}",
"1225/64 -> 2475/128: {\\"note\\":\\"D#4\\"}",
"1225/64 -> 2475/128: {\\"note\\":\\"F#4\\"}",
"1275/64 -> 2575/128: {\\"note\\":\\"A#3\\"}",
"1275/64 -> 2575/128: {\\"note\\":\\"C#4\\"}",
"1275/64 -> 2575/128: {\\"note\\":\\"D#4\\"}",
"1275/64 -> 2575/128: {\\"note\\":\\"F#4\\"}",
"75/4 -> 1225/64: {\\"note\\":\\"B2\\"}",
"625/32 -> 1275/64: {\\"note\\":\\"F#2\\"}",
"75/4 -> 325/16: {\\"note\\":\\"F#5\\"}",
"325/16 -> 675/32: {\\"note\\":\\"G5\\"}",
"1275/64 -> 2575/128: {\\"note\\":\\"A#3\\"}",
"1275/64 -> 2575/128: {\\"note\\":\\"C#4\\"}",
"1275/64 -> 2575/128: {\\"note\\":\\"D#4\\"}",
"1275/64 -> 2575/128: {\\"note\\":\\"F#4\\"}",
"1325/64 -> 2675/128: {\\"note\\":\\"Ab3\\"}",
"1325/64 -> 2675/128: {\\"note\\":\\"C4\\"}",
"1325/64 -> 2675/128: {\\"note\\":\\"Eb4\\"}",
"1325/64 -> 2675/128: {\\"note\\":\\"G4\\"}",
"325/16 -> 1325/64: {\\"note\\":\\"F2\\"}",
"325/16 -> 675/32: {\\"note\\":\\"G5\\"}",
"675/32 -> 175/8: {\\"note\\":\\"F5\\"}",
"175/8 -> 375/16: {\\"note\\":\\"Bb5\\"}",
"1375/64 -> 2775/128: {\\"note\\":\\"Ab3\\"}",
"1375/64 -> 2775/128: {\\"note\\":\\"C4\\"}",
"1375/64 -> 2775/128: {\\"note\\":\\"D4\\"}",
"1375/64 -> 2775/128: {\\"note\\":\\"G4\\"}",
"675/32 -> 1375/64: {\\"note\\":\\"Bb2\\"}",
"175/8 -> 1425/64: {\\"note\\":\\"Eb2\\"}",
"175/8 -> 375/16: {\\"note\\":\\"Bb5\\"}",
"1425/64 -> 2875/128: {\\"note\\":\\"G3\\"}",
"1425/64 -> 2875/128: {\\"note\\":\\"Bb3\\"}",
"1425/64 -> 2875/128: {\\"note\\":\\"D4\\"}",
"1425/64 -> 2875/128: {\\"note\\":\\"F4\\"}",
"175/8 -> 1425/64: {\\"note\\":\\"Eb2\\"}",
"725/32 -> 1475/64: {\\"note\\":\\"Bb2\\"}",
"175/8 -> 375/16: {\\"note\\":\\"Bb5\\"}",
"375/16 -> 775/32: {\\"note\\":\\"F#5\\"}",
"1475/64 -> 2975/128: {\\"note\\":\\"G3\\"}",
"1475/64 -> 2975/128: {\\"note\\":\\"Bb3\\"}",
"1475/64 -> 2975/128: {\\"note\\":\\"D4\\"}",
"1475/64 -> 2975/128: {\\"note\\":\\"F4\\"}",
"1525/64 -> 3075/128: {\\"note\\":\\"E3\\"}",
"1525/64 -> 3075/128: {\\"note\\":\\"G#3\\"}",
"1525/64 -> 3075/128: {\\"note\\":\\"B3\\"}",
"1525/64 -> 3075/128: {\\"note\\":\\"D#4\\"}",
"725/32 -> 1475/64: {\\"note\\":\\"Bb2\\"}",
"375/16 -> 1525/64: {\\"note\\":\\"C#2\\"}",
"375/16 -> 775/32: {\\"note\\":\\"F#5\\"}",
"775/32 -> 3125/128: {\\"note\\":\\"F#5\\"}",
"1525/64 -> 3075/128: {\\"note\\":\\"E3\\"}",
"1525/64 -> 3075/128: {\\"note\\":\\"G#3\\"}",
"1525/64 -> 3075/128: {\\"note\\":\\"B3\\"}",
"1525/64 -> 3075/128: {\\"note\\":\\"D#4\\"}",
"1575/64 -> 3175/128: {\\"note\\":\\"E3\\"}",
"1575/64 -> 3175/128: {\\"note\\":\\"G#3\\"}",
"1575/64 -> 3175/128: {\\"note\\":\\"A#3\\"}",
"1575/64 -> 3175/128: {\\"note\\":\\"D#4\\"}",
"775/32 -> 1575/64: {\\"note\\":\\"F#2\\"}",
]
`;
exports[`renders tunes > tune: goodTimes 1`] = `
[
"0/1 -> 1/2: {\\"note\\":\\"F3\\",\\"clip\\":1,\\"s\\":\\"piano\\",\\"release\\":0.1,\\"pan\\":0.49537037037037035}",
@@ -8335,6 +8097,36 @@ exports[`renders tunes > tune: juxUndTollerei 1`] = `
]
`;
exports[`renders tunes > tune: loungeSponge 1`] = `
[
"0/1 -> 3/8: {\\"note\\":\\"B3\\",\\"cutoff\\":1396}",
"0/1 -> 3/8: {\\"note\\":\\"D4\\",\\"cutoff\\":1396}",
"0/1 -> 3/8: {\\"note\\":\\"E4\\",\\"cutoff\\":1396}",
"0/1 -> 3/8: {\\"note\\":\\"G4\\",\\"cutoff\\":1396}",
"3/8 -> 3/4: {\\"note\\":\\"B3\\",\\"cutoff\\":1396}",
"3/8 -> 3/4: {\\"note\\":\\"D4\\",\\"cutoff\\":1396}",
"3/8 -> 3/4: {\\"note\\":\\"E4\\",\\"cutoff\\":1396}",
"3/8 -> 3/4: {\\"note\\":\\"G4\\",\\"cutoff\\":1396}",
"3/4 -> 1/1: {\\"note\\":\\"B3\\",\\"cutoff\\":1396}",
"3/4 -> 1/1: {\\"note\\":\\"D4\\",\\"cutoff\\":1396}",
"3/4 -> 1/1: {\\"note\\":\\"E4\\",\\"cutoff\\":1396}",
"3/4 -> 1/1: {\\"note\\":\\"G4\\",\\"cutoff\\":1396}",
"0/1 -> 1/4: {\\"note\\":\\"C2\\",\\"gain\\":1}",
"1/4 -> 1/2: {\\"note\\":\\"C2\\",\\"gain\\":4}",
"1/2 -> 3/4: {\\"note\\":\\"C2\\",\\"gain\\":1}",
"3/4 -> 1/1: {\\"note\\":\\"C2\\",\\"gain\\":4}",
"0/1 -> 3/16: {\\"note\\":\\"A4\\"}",
"3/4 -> 15/16: {\\"note\\":\\"A5\\"}",
"-1/4 -> -1/16: {\\"note\\":\\"E5\\"}",
"1/2 -> 11/16: {\\"note\\":\\"C5\\"}",
"0/1 -> 1/2: {\\"s\\":\\"bd\\",\\"bank\\":\\"RolandTR909\\"}",
"1/2 -> 1/1: {\\"s\\":\\"bd\\",\\"bank\\":\\"RolandTR909\\"}",
"1/4 -> 1/2: {\\"s\\":\\"hh\\",\\"bank\\":\\"RolandTR909\\"}",
"3/4 -> 1/1: {\\"s\\":\\"hh\\",\\"bank\\":\\"RolandTR909\\"}",
"1/2 -> 1/1: {\\"s\\":\\"cp\\",\\"bank\\":\\"RolandTR909\\"}",
]
`;
exports[`renders tunes > tune: meltingsubmarine 1`] = `
[
"0/1 -> 3/2: {\\"s\\":\\"bd\\",\\"speed\\":0.7519542165100574}",
@@ -9570,125 +9362,6 @@ exports[`renders tunes > tune: swimming 1`] = `
]
`;
exports[`renders tunes > tune: swimmingWithSoundfonts 1`] = `
[
"0/1 -> 3/4: {\\"n\\":\\"F4\\",\\"s\\":\\"Kalimba: Ethnic\\"}",
"0/1 -> 3/4: {\\"n\\":\\"Bb4\\",\\"s\\":\\"Kalimba: Ethnic\\"}",
"0/1 -> 3/4: {\\"n\\":\\"D5\\",\\"s\\":\\"Kalimba: Ethnic\\"}",
"3/4 -> 5/4: {\\"n\\":\\"D4\\",\\"s\\":\\"Kalimba: Ethnic\\"}",
"3/4 -> 5/4: {\\"n\\":\\"G4\\",\\"s\\":\\"Kalimba: Ethnic\\"}",
"3/4 -> 5/4: {\\"n\\":\\"Bb4\\",\\"s\\":\\"Kalimba: Ethnic\\"}",
"0/1 -> 3/4: {\\"n\\":\\"G3\\",\\"s\\":\\"Acoustic Bass: Bass\\"}",
"3/4 -> 3/2: {\\"n\\":\\"G3\\",\\"s\\":\\"Acoustic Bass: Bass\\"}",
]
`;
exports[`renders tunes > tune: tetrisMini 1`] = `
[
"0/1 -> 1/2: {\\"note\\":\\"e5\\"}",
"1/2 -> 3/4: {\\"note\\":\\"b4\\"}",
"3/4 -> 1/1: {\\"note\\":\\"c5\\"}",
"0/1 -> 1/4: {\\"note\\":\\"e2\\"}",
"1/4 -> 1/2: {\\"note\\":\\"e3\\"}",
"1/2 -> 3/4: {\\"note\\":\\"e2\\"}",
"3/4 -> 1/1: {\\"note\\":\\"e3\\"}",
"1/1 -> 3/2: {\\"note\\":\\"d5\\"}",
"3/2 -> 7/4: {\\"note\\":\\"c5\\"}",
"7/4 -> 2/1: {\\"note\\":\\"b4\\"}",
"1/1 -> 5/4: {\\"note\\":\\"e2\\"}",
"5/4 -> 3/2: {\\"note\\":\\"e3\\"}",
"3/2 -> 7/4: {\\"note\\":\\"e2\\"}",
"7/4 -> 2/1: {\\"note\\":\\"e3\\"}",
"2/1 -> 5/2: {\\"note\\":\\"a4\\"}",
"5/2 -> 11/4: {\\"note\\":\\"a4\\"}",
"11/4 -> 3/1: {\\"note\\":\\"c5\\"}",
"2/1 -> 9/4: {\\"note\\":\\"a2\\"}",
"9/4 -> 5/2: {\\"note\\":\\"a3\\"}",
"5/2 -> 11/4: {\\"note\\":\\"a2\\"}",
"11/4 -> 3/1: {\\"note\\":\\"a3\\"}",
"3/1 -> 7/2: {\\"note\\":\\"e5\\"}",
"7/2 -> 15/4: {\\"note\\":\\"d5\\"}",
"15/4 -> 4/1: {\\"note\\":\\"c5\\"}",
"3/1 -> 13/4: {\\"note\\":\\"a2\\"}",
"13/4 -> 7/2: {\\"note\\":\\"a3\\"}",
"7/2 -> 15/4: {\\"note\\":\\"a2\\"}",
"15/4 -> 4/1: {\\"note\\":\\"a3\\"}",
"4/1 -> 9/2: {\\"note\\":\\"b4\\"}",
"19/4 -> 5/1: {\\"note\\":\\"c5\\"}",
"4/1 -> 17/4: {\\"note\\":\\"g#2\\"}",
"17/4 -> 9/2: {\\"note\\":\\"g#3\\"}",
"9/2 -> 19/4: {\\"note\\":\\"g#2\\"}",
"19/4 -> 5/1: {\\"note\\":\\"g#3\\"}",
"5/1 -> 11/2: {\\"note\\":\\"d5\\"}",
"11/2 -> 6/1: {\\"note\\":\\"e5\\"}",
"5/1 -> 21/4: {\\"note\\":\\"e2\\"}",
"21/4 -> 11/2: {\\"note\\":\\"e3\\"}",
"11/2 -> 23/4: {\\"note\\":\\"e2\\"}",
"23/4 -> 6/1: {\\"note\\":\\"e3\\"}",
"6/1 -> 13/2: {\\"note\\":\\"c5\\"}",
"13/2 -> 7/1: {\\"note\\":\\"a4\\"}",
"6/1 -> 25/4: {\\"note\\":\\"a2\\"}",
"25/4 -> 13/2: {\\"note\\":\\"a3\\"}",
"13/2 -> 27/4: {\\"note\\":\\"a2\\"}",
"27/4 -> 7/1: {\\"note\\":\\"a3\\"}",
"7/1 -> 15/2: {\\"note\\":\\"a4\\"}",
"7/1 -> 29/4: {\\"note\\":\\"a2\\"}",
"29/4 -> 15/2: {\\"note\\":\\"a3\\"}",
"15/2 -> 31/4: {\\"note\\":\\"b1\\"}",
"31/4 -> 8/1: {\\"note\\":\\"c2\\"}",
"33/4 -> 17/2: {\\"note\\":\\"d5\\"}",
"35/4 -> 9/1: {\\"note\\":\\"f5\\"}",
"8/1 -> 33/4: {\\"note\\":\\"d2\\"}",
"33/4 -> 17/2: {\\"note\\":\\"d3\\"}",
"17/2 -> 35/4: {\\"note\\":\\"d2\\"}",
"35/4 -> 9/1: {\\"note\\":\\"d3\\"}",
"9/1 -> 19/2: {\\"note\\":\\"a5\\"}",
"19/2 -> 39/4: {\\"note\\":\\"g5\\"}",
"39/4 -> 10/1: {\\"note\\":\\"f5\\"}",
"9/1 -> 37/4: {\\"note\\":\\"d2\\"}",
"37/4 -> 19/2: {\\"note\\":\\"d3\\"}",
"19/2 -> 39/4: {\\"note\\":\\"d2\\"}",
"39/4 -> 10/1: {\\"note\\":\\"d3\\"}",
"10/1 -> 21/2: {\\"note\\":\\"e5\\"}",
"43/4 -> 11/1: {\\"note\\":\\"c5\\"}",
"10/1 -> 41/4: {\\"note\\":\\"c2\\"}",
"41/4 -> 21/2: {\\"note\\":\\"c3\\"}",
"21/2 -> 43/4: {\\"note\\":\\"c2\\"}",
"43/4 -> 11/1: {\\"note\\":\\"c3\\"}",
"11/1 -> 23/2: {\\"note\\":\\"e5\\"}",
"23/2 -> 47/4: {\\"note\\":\\"d5\\"}",
"47/4 -> 12/1: {\\"note\\":\\"c5\\"}",
"11/1 -> 45/4: {\\"note\\":\\"c2\\"}",
"45/4 -> 23/2: {\\"note\\":\\"c3\\"}",
"23/2 -> 47/4: {\\"note\\":\\"c2\\"}",
"47/4 -> 12/1: {\\"note\\":\\"c3\\"}",
"12/1 -> 25/2: {\\"note\\":\\"b4\\"}",
"25/2 -> 51/4: {\\"note\\":\\"b4\\"}",
"51/4 -> 13/1: {\\"note\\":\\"c5\\"}",
"12/1 -> 49/4: {\\"note\\":\\"b1\\"}",
"49/4 -> 25/2: {\\"note\\":\\"b2\\"}",
"25/2 -> 51/4: {\\"note\\":\\"b1\\"}",
"51/4 -> 13/1: {\\"note\\":\\"b2\\"}",
"13/1 -> 27/2: {\\"note\\":\\"d5\\"}",
"27/2 -> 14/1: {\\"note\\":\\"e5\\"}",
"13/1 -> 53/4: {\\"note\\":\\"e2\\"}",
"53/4 -> 27/2: {\\"note\\":\\"e3\\"}",
"27/2 -> 55/4: {\\"note\\":\\"e2\\"}",
"55/4 -> 14/1: {\\"note\\":\\"e3\\"}",
"14/1 -> 29/2: {\\"note\\":\\"c5\\"}",
"29/2 -> 15/1: {\\"note\\":\\"a4\\"}",
"14/1 -> 57/4: {\\"note\\":\\"a1\\"}",
"57/4 -> 29/2: {\\"note\\":\\"a2\\"}",
"29/2 -> 59/4: {\\"note\\":\\"a1\\"}",
"59/4 -> 15/1: {\\"note\\":\\"a2\\"}",
"15/1 -> 31/2: {\\"note\\":\\"a4\\"}",
"15/1 -> 61/4: {\\"note\\":\\"a1\\"}",
"61/4 -> 31/2: {\\"note\\":\\"a2\\"}",
"31/2 -> 63/4: {\\"note\\":\\"a1\\"}",
"63/4 -> 16/1: {\\"note\\":\\"a2\\"}",
]
`;
exports[`renders tunes > tune: undergroundPlumber 1`] = `
[
"0/1 -> 3/16: {\\"s\\":\\"bd\\",\\"gain\\":0.7}",
+287
View File
@@ -162,3 +162,290 @@ stack(
drums.fast(2),
synths
).slow(2)`; */
export const tetrisMini = `note(\`[[e5 [b4 c5] d5 [c5 b4]]
[a4 [a4 c5] e5 [d5 c5]]
[b4 [~ c5] d5 e5]
[c5 a4 a4 ~]
[[~ d5] [~ f5] a5 [g5 f5]]
[e5 [~ c5] e5 [d5 c5]]
[b4 [b4 c5] d5 e5]
[c5 a4 a4 ~]],
[[e2 e3]*4]
[[a2 a3]*4]
[[g#2 g#3]*2 [e2 e3]*2]
[a2 a3 a2 a3 a2 a3 b1 c2]
[[d2 d3]*4]
[[c2 c3]*4]
[[b1 b2]*2 [e2 e3]*2]
[[a1 a2]*4]\`).slow(16)
`;
export const giantStepsReggae = `stack(
// melody
seq(
"[F#5 D5] [B4 G4] Bb4 [B4 A4]",
"[D5 Bb4] [G4 Eb4] F#4 [G4 F4]",
"Bb4 [B4 A4] D5 [D#5 C#5]",
"F#5 [G5 F5] Bb5 [F#5 [F#5 ~@3]]",
),
// chords
seq(
"[B^7 D7] [G^7 Bb7] Eb^7 [Am7 D7]",
"[G^7 Bb7] [Eb^7 F#7] B^7 [Fm7 Bb7]",
"Eb^7 [Am7 D7] G^7 [C#m7 F#7]",
"B^7 [Fm7 Bb7] Eb^7 [C#m7 F#7]"
)
.struct("~ [x ~]".fast(4*8))
.voicings(['E3', 'G4']),
// bass
seq(
"[B2 D2] [G2 D2] [Eb2 Bb2] [A2 D2]",
"[G2 Bb2] [Eb2 F#2] [B2 F#2] [F2 Bb2]",
"[Eb2 Bb2] [A2 D2] [G2 D2] [C#2 F#2]",
"[B2 F#2] [F2 Bb2] [Eb2 Bb2] [C#2 F#2]"
)
.struct("x ~".fast(4*8))
).slow(25).note()`;
// TODO:
/*
export const xylophoneCalling = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// by Felix Roos
const t = x => x.scaleTranspose("<0 2 4 3>/4").transpose(-2)
const s = x => x.scale(cat('C3 minor pentatonic','G3 minor pentatonic').slow(4))
const delay = new FeedbackDelay(1/8, .6).chain(vol(0.1), out());
const chorus = new Chorus(1,2.5,0.5).start();
stack(
// melody
"<<10 7> <8 3>>/4".struct("x*3").apply(s)
.scaleTranspose("<0 3 2> <1 4 3>")
.superimpose(scaleTranspose(2).early(1/8))
.apply(t).tone(polysynth().set({
...osc('triangle4'),
...adsr(0,.08,0)
}).chain(vol(0.2).connect(delay),chorus,out())).mask("<~@3 x>/16".early(1/8)),
// pad
"[1,3]/4".scale('G3 minor pentatonic').apply(t).tone(polysynth().set({
...osc('square2'),
...adsr(0.1,.4,0.8)
}).chain(vol(0.2),chorus,out())).mask("<~ x>/32"),
// xylophone
"c3,g3,c4".struct("<x*2 x>").fast("<1 <2!3 [4 8]>>").apply(s).scaleTranspose("<0 <1 [2 [3 <4 5>]]>>").apply(t).tone(polysynth().set({
...osc('sawtooth4'),
...adsr(0,.1,0)
}).chain(vol(0.4).connect(delay),out())).mask("<x@3 ~>/16".early(1/8)),
// bass
"c2 [c2 ~]*2".scale('C hirajoshi').apply(t).tone(synth({
...osc('sawtooth6'),
...adsr(0,.03,.4,.1)
}).chain(vol(0.4),out())),
// kick
"<c1!3 [c1 ~]*2>*2".tone(membrane().chain(vol(0.8),out())),
// snare
"~ <c3!7 [c3 c3*2]>".tone(noise().chain(vol(0.8),out())),
// hihat
"c3*4".transpose("[-24 0]*2").tone(metal(adsr(0,.02)).chain(vol(0.5).connect(delay),out()))
).slow(1)
// strudel disable-highlighting`;
*/
// TODO:
/*
export const sowhatelse = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// by Felix Roos
// mixer
const mix = (key) => vol({
chords: .2,
lead: 0.8,
bass: .4,
snare: .95,
kick: .9,
hihat: .35,
}[key]||0);
const delay = new FeedbackDelay(1/6, .3).chain(vol(.7), out());
const delay2 = new FeedbackDelay(1/6, .2).chain(vol(.15), out());
const chorus = new Chorus(1,2.5,0.5).start();
// instruments
const instr = (instrument) => ({
organ: polysynth().set({...osc('sawtooth4'), ...adsr(.01,.2,0)}).chain(mix('chords').connect(delay),out()),
lead: polysynth().set({...osc('triangle4'),...adsr(0.01,.05,0)}).chain(mix('lead').connect(delay2), out()),
bass: polysynth().set({...osc('sawtooth8'),...adsr(.02,.05,.3,.2)}).chain(mix('bass'),lowpass(3000), out()),
pad: polysynth().set({...osc('square2'),...adsr(0.1,.4,0.8)}).chain(vol(0.15),chorus,out()),
hihat: metal(adsr(0, .02, 0)).chain(mix('hihat'), out()),
snare: noise(adsr(0, .15, 0.01)).chain(mix('snare'), lowpass(5000), out()),
kick: membrane().chain(mix('kick'), out())
}[instrument]);
// harmony
const t = transpose("<0 0 1 0>/8");
const sowhat = scaleTranspose("0,3,6,9,11");
// track
stack(
"[<0 4 [3 [2 1]]>]/4".struct("[x]*3").mask("[~ x ~]").scale('D5 dorian').off(1/6, scaleTranspose(-7)).off(1/3, scaleTranspose(-5)).apply(t).tone(instr('lead')).mask("<~ ~ x x>/8"),
"<<e3 [~@2 a3]> <[d3 ~] [c3 f3] g3>>".scale('D dorian').apply(sowhat).apply(t).tone(instr('organ')).mask("<x x x ~>/8"),
"<[d2 [d2 ~]*3]!3 <a1*2 c2*3 [a1 e2]>>".apply(t).tone(instr('bass')),
"c1*6".tone(instr('hihat')),
"~ c3".tone(instr('snare')),
"<[c1@5 c1] <c1 [[c1@2 c1] ~] [c1 ~ c1] [c1!2 ~ c1!3]>>".tone(instr('kick')),
"[2,4]/4".scale('D dorian').apply(t).tone(instr('pad')).mask("<x x x ~>/8")
).fast(6/8)
// strudel disable-highlighting`;
*/
// TODO: rework tune to use freq
/*
export const jemblung = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// by Felix Roos
const delay = new FeedbackDelay(1/8, .6).chain(vol(0.15), out());
const snare = noise({type:'white',...adsr(0,0.2,0)}).chain(lowpass(5000),vol(1.8),out());
const s = polysynth().set({...osc('sawtooth4'),...adsr(0.01,.2,.6,0.2)}).chain(vol(.23).connect(delay),out());
stack(
stack(
"0 1 4 [3!2 5]".layer(
// chords
x=>x.add("0,3").duration("0.05!3 0.02"),
// bass
x=>x.add("-8").struct("x*8").duration(0.1)
),
// melody
"12 11*3 12 ~".duration(0.005)
)
.add("<0 1>")
.tune("jemblung2")
//.mul(22/5).round().xen("22edo")
//.mul(12/5).round().xen("12edo")
.tone(s),
// kick
"[c2 ~]*2".duration(0.05).tone(membrane().chain(out())),
// snare
"[~ c1]*2".early(0.001).tone(snare),
// hihat
"c2*8".tone(noise().chain(highpass(6000),vol(0.5).connect(delay),out())),
).slow(3)`;
*/
/*
// TODO: does not work on linux (at least for me..)
export const speakerman = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// by Felix Roos
backgroundImage('https://external-content.duckduckgo.com/iu/?u=https%3A%2F%2Fi.ytimg.com%2Fvi%2FXR0rKqW3VwY%2Fmaxresdefault.jpg&f=1&nofb=1',
{ className:'darken', style:'background-size:cover'})
stack(
"[g3,bb3,d4] [f3,a3,c4] [c3,e3,g3]@2".slow(2).late(.1),
cat(
'Baker man',
'is baking bread',
'Baker man',
'is baking bread',
'Sagabona',
'kunjani wena',
'Sagabona',
'kunjani wena',
'The night train, is coming',
'got to keep on running',
'The night train, is coming',
'got to keep on running',
).speak("en zu en".slow(12), "<0 2 3 4 5 6>".slow(2)),
).slow(4)`;
*/
export const bossa = `const scales = sequence('C minor', ['D locrian', 'G phrygian'], 'Bb2 minor', ['C locrian','F phrygian']).slow(4)
stack(
"<Cm7 [Dm7b5 G7b9] Bbm7 [Cm7b5 F7b9]>".fast(2).struct("x ~ x@3 x ~ x ~ ~ ~ x ~ x@3".late(1/8)).early(1/8).slow(2).voicings(),
"[~ [0 ~]] 0 [~ [4 ~]] 4".sub(7).restart(scales).scale(scales).early(.25)
).note().piano().slow(2)`;
/*
export const customTrigger = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// by Felix Roos
stack(
freq("55 [110,165] 110 [220,275]".mul("<1 <3/4 2/3>>").struct("x(3,8)").layer(x=>x.mul("1.006,.995"))),
freq("440(5,8)".legato(.18).mul("<1 3/4 2 2/3>")).gain(perlin.range(.2,.8))
).s("<sawtooth square>/2")
.onTrigger((t,hap,ct)=>{
const ac = Tone.getContext().rawContext;
t = ac.currentTime + t - ct;
const { freq, s, gain = 1 } = hap.value;
const master = ac.createGain();
master.gain.value = 0.1 * gain;
master.connect(ac.destination);
const o = ac.createOscillator();
o.type = s || 'triangle';
o.frequency.value = Number(freq);
o.connect(master);
o.start(t);
o.stop(t + hap.duration);
}).stack(s("bd(3,8),hh*4,~ sd").webdirt())`; */
export const swimmingWithSoundfonts = `// Koji Kondo - Swimming (Super Mario World)
stack(
n(
"~",
"~",
"~",
"A5 [F5@2 C5] [D5@2 F5] F5",
"[C5@2 F5] [F5@2 C6] A5 G5",
"A5 [F5@2 C5] [D5@2 F5] F5",
"[C5@2 F5] [Bb5 A5 G5] F5@2",
"A5 [F5@2 C5] [D5@2 F5] F5",
"[C5@2 F5] [F5@2 C6] A5 G5",
"A5 [F5@2 C5] [D5@2 F5] F5",
"[C5@2 F5] [Bb5 A5 G5] F5@2",
"A5 [F5@2 C5] A5 F5",
"Ab5 [F5@2 Ab5] G5@2",
"A5 [F5@2 C5] A5 F5",
"Ab5 [F5@2 C5] C6@2",
"A5 [F5@2 C5] [D5@2 F5] F5",
"[C5@2 F5] [Bb5 A5 G5] F5@2"
).s('Sitar: Ethnic'),
n(
"[F4,Bb4,D5] [[D4,G4,Bb4]@2 [Bb3,D4,F4]] [[G3,C4,E4]@2 [[Ab3,F4] [A3,Gb4]]] [Bb3,E4,G4]",
"[~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, Bb3, D3] [F3, Bb3, D3]] [~ [F3, Bb3, Db3] [F3, Bb3, Db3]]",
"[~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, Bb3, D3] [F3, Bb3, D3]] [~ [F3, B3, D3] [F3, B3, D3]]",
"[~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, Bb3, D3] [F3, Bb3, D3]] [~ [F3, B3, D3] [F3, B3, D3]]",
"[~ [A3, C4, E4] [A3, C4, E4]] [~ [Ab3, C4, Eb4] [Ab3, C4, Eb4]] [~ [F3, Bb3, D3] [F3, Bb3, D3]] [~ [G3, C4, E4] [G3, C4, E4]]",
"[~ [F3, A3, C4] [F3, A3, C4]] [~ [F3, A3, C4] [F3, A3, C4]] [~ [F3, Bb3, D3] [F3, Bb3, D3]] [~ [F3, B3, D3] [F3, B3, D3]]",
"[~ [F3, Bb3, D4] [F3, Bb3, D4]] [~ [F3, Bb3, C4] [F3, Bb3, C4]] [~ [F3, A3, C4] [F3, A3, C4]] [~ [F3, A3, C4] [F3, A3, C4]]",
"[~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, Bb3, D3] [F3, Bb3, D3]] [~ [F3, B3, D3] [F3, B3, D3]]",
"[~ [A3, C4, E4] [A3, C4, E4]] [~ [Ab3, C4, Eb4] [Ab3, C4, Eb4]] [~ [F3, Bb3, D3] [F3, Bb3, D3]] [~ [G3, C4, E4] [G3, C4, E4]]",
"[~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, Bb3, D3] [F3, Bb3, D3]] [~ [F3, B3, D3] [F3, B3, D3]]",
"[~ [F3, Bb3, D4] [F3, Bb3, D4]] [~ [F3, Bb3, C4] [F3, Bb3, C4]] [~ [F3, A3, C4] [F3, A3, C4]] [~ [F3, A3, C4] [F3, A3, C4]]",
"[~ [Bb3, D3, F4] [Bb3, D3, F4]] [~ [Bb3, D3, F4] [Bb3, D3, F4]] [~ [A3, C4, F4] [A3, C4, F4]] [~ [A3, C4, F4] [A3, C4, F4]]",
"[~ [Ab3, B3, F4] [Ab3, B3, F4]] [~ [Ab3, B3, F4] [Ab3, B3, F4]] [~ [G3, Bb3, F4] [G3, Bb3, F4]] [~ [G3, Bb3, E4] [G3, Bb3, E4]]",
"[~ [Bb3, D3, F4] [Bb3, D3, F4]] [~ [Bb3, D3, F4] [Bb3, D3, F4]] [~ [A3, C4, F4] [A3, C4, F4]] [~ [A3, C4, F4] [A3, C4, F4]]",
"[~ [Ab3, B3, F4] [Ab3, B3, F4]] [~ [Ab3, B3, F4] [Ab3, B3, F4]] [~ [G3, Bb3, F4] [G3, Bb3, F4]] [~ [G3, Bb3, E4] [G3, Bb3, E4]]",
"[~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, Bb3, D3] [F3, Bb3, D3]] [~ [F3, B3, D3] [F3, B3, D3]]",
"[~ [F3, Bb3, D4] [F3, Bb3, D4]] [~ [F3, Bb3, C4] [F3, Bb3, C4]] [~ [F3, A3, C4] [F3, A3, C4]] [~ [F3, A3, C4] [F3, A3, C4]]"
).s('Kalimba: Ethnic'),
n(
"[G3 G3 C3 E3]",
"[F2 D2 G2 C2]",
"[F2 D2 G2 C2]",
"[F2 A2 Bb2 B2]",
"[A2 Ab2 G2 C2]",
"[F2 A2 Bb2 B2]",
"[G2 C2 F2 F2]",
"[F2 A2 Bb2 B2]",
"[A2 Ab2 G2 C2]",
"[F2 A2 Bb2 B2]",
"[G2 C2 F2 F2]",
"[Bb2 Bb2 A2 A2]",
"[Ab2 Ab2 G2 [C2 D2 E2]]",
"[Bb2 Bb2 A2 A2]",
"[Ab2 Ab2 G2 [C2 D2 E2]]",
"[F2 A2 Bb2 B2]",
"[G2 C2 F2 F2]"
).s('Acoustic Bass: Bass')
).slow(51)
`;
export const bossaRandom = `const chords = "<Am7 Am7 Dm7 E7>"
const roots = chords.rootNotes(2)
stack(
chords.voicings(['F4', 'A5']).struct(
\` x@2 ~ x ~ ~ ~ x |
x? ~ ~ x@3 ~ x |
x? ~ ~ x ~ x@3\`),
roots.struct("x [~ x?0.2] x [~ x?] | x!4 | x@2 ~ ~ ~ x x x").transpose("0 7")
).slow(2).pianoroll().note().piano()`;
+154 -309
View File
@@ -4,25 +4,8 @@ Copyright (C) 2022 Strudel contributors - see <https://github.com/tidalcycles/st
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/>.
*/
export const tetrisMini = `note(\`[[e5 [b4 c5] d5 [c5 b4]]
[a4 [a4 c5] e5 [d5 c5]]
[b4 [~ c5] d5 e5]
[c5 a4 a4 ~]
[[~ d5] [~ f5] a5 [g5 f5]]
[e5 [~ c5] e5 [d5 c5]]
[b4 [b4 c5] d5 e5]
[c5 a4 a4 ~]],
[[e2 e3]*4]
[[a2 a3]*4]
[[g#2 g#3]*2 [e2 e3]*2]
[a2 a3 a2 a3 a2 a3 b1 c2]
[[d2 d3]*4]
[[c2 c3]*4]
[[b1 b2]*2 [e2 e3]*2]
[[a1 a2]*4]\`).slow(16)
`;
export const swimming = `stack(
export const swimming = `// Koji Kondo - Swimming (Super Mario World)
stack(
seq(
"~",
"~",
@@ -83,7 +66,8 @@ export const swimming = `stack(
).note().slow(51);
`;
export const giantSteps = `stack(
export const giantSteps = `// John Coltrane - Giant Steps
stack(
// melody
seq(
"[F#5 D5] [B4 G4] Bb4 [B4 A4]",
@@ -107,34 +91,8 @@ export const giantSteps = `stack(
)
).slow(20).note()`;
export const giantStepsReggae = `stack(
// melody
seq(
"[F#5 D5] [B4 G4] Bb4 [B4 A4]",
"[D5 Bb4] [G4 Eb4] F#4 [G4 F4]",
"Bb4 [B4 A4] D5 [D#5 C#5]",
"F#5 [G5 F5] Bb5 [F#5 [F#5 ~@3]]",
),
// chords
seq(
"[B^7 D7] [G^7 Bb7] Eb^7 [Am7 D7]",
"[G^7 Bb7] [Eb^7 F#7] B^7 [Fm7 Bb7]",
"Eb^7 [Am7 D7] G^7 [C#m7 F#7]",
"B^7 [Fm7 Bb7] Eb^7 [C#m7 F#7]"
)
.struct("~ [x ~]".fast(4*8))
.voicings(['E3', 'G4']),
// bass
seq(
"[B2 D2] [G2 D2] [Eb2 Bb2] [A2 D2]",
"[G2 Bb2] [Eb2 F#2] [B2 F#2] [F2 Bb2]",
"[Eb2 Bb2] [A2 D2] [G2 D2] [C#2 F#2]",
"[B2 F#2] [F2 Bb2] [Eb2 Bb2] [C#2 F#2]"
)
.struct("x ~".fast(4*8))
).slow(25).note()`;
export const zeldasRescue = `stack(
export const zeldasRescue = `// Koji Kondo - Princess Zelda's Rescue
stack(
// melody
\`[B3@2 D4] [A3@2 [G3 A3]] [B3@2 D4] [A3]
[B3@2 D4] [A4@2 G4] [D4@2 [C4 B3]] [A3]
@@ -157,7 +115,9 @@ export const zeldasRescue = `stack(
.room(1)
`;
export const caverave = `const keys = x => x.s('sawtooth').cutoff(1200).gain(.5).attack(0).decay(.16).sustain(.3).release(.1);
export const caverave = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// by Felix Roos
const keys = x => x.s('sawtooth').cutoff(1200).gain(.5).attack(0).decay(.16).sustain(.3).release(.1);
const drums = stack(
s("bd*2").mask("<x@7 ~>/8").gain(.8),
@@ -201,90 +161,7 @@ stack(
).s()
`;
// TODO:
/*
export const xylophoneCalling = `const t = x => x.scaleTranspose("<0 2 4 3>/4").transpose(-2)
const s = x => x.scale(cat('C3 minor pentatonic','G3 minor pentatonic').slow(4))
const delay = new FeedbackDelay(1/8, .6).chain(vol(0.1), out());
const chorus = new Chorus(1,2.5,0.5).start();
stack(
// melody
"<<10 7> <8 3>>/4".struct("x*3").apply(s)
.scaleTranspose("<0 3 2> <1 4 3>")
.superimpose(scaleTranspose(2).early(1/8))
.apply(t).tone(polysynth().set({
...osc('triangle4'),
...adsr(0,.08,0)
}).chain(vol(0.2).connect(delay),chorus,out())).mask("<~@3 x>/16".early(1/8)),
// pad
"[1,3]/4".scale('G3 minor pentatonic').apply(t).tone(polysynth().set({
...osc('square2'),
...adsr(0.1,.4,0.8)
}).chain(vol(0.2),chorus,out())).mask("<~ x>/32"),
// xylophone
"c3,g3,c4".struct("<x*2 x>").fast("<1 <2!3 [4 8]>>").apply(s).scaleTranspose("<0 <1 [2 [3 <4 5>]]>>").apply(t).tone(polysynth().set({
...osc('sawtooth4'),
...adsr(0,.1,0)
}).chain(vol(0.4).connect(delay),out())).mask("<x@3 ~>/16".early(1/8)),
// bass
"c2 [c2 ~]*2".scale('C hirajoshi').apply(t).tone(synth({
...osc('sawtooth6'),
...adsr(0,.03,.4,.1)
}).chain(vol(0.4),out())),
// kick
"<c1!3 [c1 ~]*2>*2".tone(membrane().chain(vol(0.8),out())),
// snare
"~ <c3!7 [c3 c3*2]>".tone(noise().chain(vol(0.8),out())),
// hihat
"c3*4".transpose("[-24 0]*2").tone(metal(adsr(0,.02)).chain(vol(0.5).connect(delay),out()))
).slow(1)
// strudel disable-highlighting`;
*/
// TODO:
/*
export const sowhatelse = `// mixer
const mix = (key) => vol({
chords: .2,
lead: 0.8,
bass: .4,
snare: .95,
kick: .9,
hihat: .35,
}[key]||0);
const delay = new FeedbackDelay(1/6, .3).chain(vol(.7), out());
const delay2 = new FeedbackDelay(1/6, .2).chain(vol(.15), out());
const chorus = new Chorus(1,2.5,0.5).start();
// instruments
const instr = (instrument) => ({
organ: polysynth().set({...osc('sawtooth4'), ...adsr(.01,.2,0)}).chain(mix('chords').connect(delay),out()),
lead: polysynth().set({...osc('triangle4'),...adsr(0.01,.05,0)}).chain(mix('lead').connect(delay2), out()),
bass: polysynth().set({...osc('sawtooth8'),...adsr(.02,.05,.3,.2)}).chain(mix('bass'),lowpass(3000), out()),
pad: polysynth().set({...osc('square2'),...adsr(0.1,.4,0.8)}).chain(vol(0.15),chorus,out()),
hihat: metal(adsr(0, .02, 0)).chain(mix('hihat'), out()),
snare: noise(adsr(0, .15, 0.01)).chain(mix('snare'), lowpass(5000), out()),
kick: membrane().chain(mix('kick'), out())
}[instrument]);
// harmony
const t = transpose("<0 0 1 0>/8");
const sowhat = scaleTranspose("0,3,6,9,11");
// track
stack(
"[<0 4 [3 [2 1]]>]/4".struct("[x]*3").mask("[~ x ~]").scale('D5 dorian').off(1/6, scaleTranspose(-7)).off(1/3, scaleTranspose(-5)).apply(t).tone(instr('lead')).mask("<~ ~ x x>/8"),
"<<e3 [~@2 a3]> <[d3 ~] [c3 f3] g3>>".scale('D dorian').apply(sowhat).apply(t).tone(instr('organ')).mask("<x x x ~>/8"),
"<[d2 [d2 ~]*3]!3 <a1*2 c2*3 [a1 e2]>>".apply(t).tone(instr('bass')),
"c1*6".tone(instr('hihat')),
"~ c3".tone(instr('snare')),
"<[c1@5 c1] <c1 [[c1@2 c1] ~] [c1 ~ c1] [c1!2 ~ c1!3]>>".tone(instr('kick')),
"[2,4]/4".scale('D dorian').apply(t).tone(instr('pad')).mask("<x x x ~>/8")
).fast(6/8)
// strudel disable-highlighting`;
*/
export const barryHarris = `backgroundImage(
'https://media.npr.org/assets/img/2017/02/03/barryharris_600dpi_wide-7eb49998aa1af377d62bb098041624c0a0d1a454.jpg',
{style:'background-size:cover'})
export const barryHarris = `// adapted from a Barry Harris excercise
"0,2,[7 6]"
.add("<0 1 2 3 4 5 7 8>")
.scale('C bebop major')
@@ -293,7 +170,9 @@ export const barryHarris = `backgroundImage(
.note().piano()
`;
export const blippyRhodes = `samples({
export const blippyRhodes = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// by Felix Roos
samples({
bd: 'samples/tidal/bd/BT0A0D0.wav',
sn: 'samples/tidal/sn/ST0T0S3.wav',
hh: 'samples/tidal/hh/000_hh3closedhh.wav',
@@ -332,7 +211,9 @@ stack(
.s('sawtooth').cutoff(600),
).fast(3/2)`;
export const wavyKalimba = `samples({
export const wavyKalimba = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// by Felix Roos
samples({
'kalimba': { c5:'https://freesound.org/data/previews/536/536549_11935698-lq.mp3' }
})
const scales = cat('C major', 'C mixolydian', 'F lydian', ['F minor', 'Db major'])
@@ -360,37 +241,9 @@ stack(
.delay(.2)
`;
// TODO: rework tune to use freq
/*
export const jemblung = `const delay = new FeedbackDelay(1/8, .6).chain(vol(0.15), out());
const snare = noise({type:'white',...adsr(0,0.2,0)}).chain(lowpass(5000),vol(1.8),out());
const s = polysynth().set({...osc('sawtooth4'),...adsr(0.01,.2,.6,0.2)}).chain(vol(.23).connect(delay),out());
stack(
stack(
"0 1 4 [3!2 5]".layer(
// chords
x=>x.add("0,3").duration("0.05!3 0.02"),
// bass
x=>x.add("-8").struct("x*8").duration(0.1)
),
// melody
"12 11*3 12 ~".duration(0.005)
)
.add("<0 1>")
.tune("jemblung2")
//.mul(22/5).round().xen("22edo")
//.mul(12/5).round().xen("12edo")
.tone(s),
// kick
"[c2 ~]*2".duration(0.05).tone(membrane().chain(out())),
// snare
"[~ c1]*2".early(0.001).tone(snare),
// hihat
"c2*8".tone(noise().chain(highpass(6000),vol(0.5).connect(delay),out())),
).slow(3)`;
*/
export const festivalOfFingers = `const chords = "<Cm7 Fm7 G7 F#7>";
export const festivalOfFingers = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// by Felix Roos
const chords = "<Cm7 Fm7 G7 F#7>";
stack(
chords.voicings().struct("x(3,8,-1)").velocity(.5).off(1/7,x=>x.transpose(12).velocity(.2)),
chords.rootNotes(2).struct("x(4,8,-2)"),
@@ -403,7 +256,8 @@ stack(
.note().piano()`;
// iter, echo, echoWith
export const undergroundPlumber = `backgroundImage('https://images.nintendolife.com/news/2016/08/video_exploring_the_funky_inspiration_for_the_super_mario_bros_underground_theme/large.jpg',{ className:'darken' })
export const undergroundPlumber = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// by Felix Roos, inspired by Friendship - Let's not talk about it (1979) :)
samples({ bd: 'bd/BT0A0D0.wav', sn: 'sn/ST0T0S3.wav', hh: 'hh/000_hh3closedhh.wav', cp: 'cp/HANDCLP0.wav',
}, 'https://loophole-letters.vercel.app/samples/tidal/')
@@ -428,7 +282,9 @@ stack(
.fast(2/3)
.pianoroll({})`;
export const bridgeIsOver = `samples({mad:'https://freesound.org/data/previews/22/22274_109943-lq.mp3'})
export const bridgeIsOver = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// by Felix Roos, bassline by BDP - The Bridge Is Over
samples({mad:'https://freesound.org/data/previews/22/22274_109943-lq.mp3'})
stack(
stack(
"c3*2 [[c3@1.4 bb2] ab2] gb2*2 <[[gb2@1.4 ab2] bb2] gb2>".legato(".5 1".fast(2)).velocity(.8),
@@ -447,7 +303,9 @@ stack(
.pianoroll()
`;
export const goodTimes = `const scale = cat('C3 dorian','Bb2 major').slow(4);
export const goodTimes = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// by Felix Roos
const scale = cat('C3 dorian','Bb2 major').slow(4);
stack(
"2*4".add(12).scale(scale)
.off(1/8,x=>x.scaleTranspose("2")).fast(2)
@@ -467,7 +325,9 @@ stack(
.slow(2)
.pianoroll({maxMidi:100,minMidi:20})`;
export const echoPiano = `"<0 2 [4 6](3,4,1) 3*2>"
export const echoPiano = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// by Felix Roos
"<0 2 [4 6](3,4,1) 3*2>"
.scale('D minor')
.color('salmon')
.off(1/4, x=>x.scaleTranspose(2).color('green'))
@@ -477,7 +337,7 @@ export const echoPiano = `"<0 2 [4 6](3,4,1) 3*2>"
.note().piano()
.pianoroll()`;
export const sml1 = `
export const sml1 = `// Hirokazu Tanaka - World 1-1
stack(
// melody
\`<
@@ -512,30 +372,9 @@ stack(
.legato(.5)
).fast(2).note()`;
/*
// TODO: does not work on linux (at least for me..)
export const speakerman = `backgroundImage('https://external-content.duckduckgo.com/iu/?u=https%3A%2F%2Fi.ytimg.com%2Fvi%2FXR0rKqW3VwY%2Fmaxresdefault.jpg&f=1&nofb=1',
{ className:'darken', style:'background-size:cover'})
stack(
"[g3,bb3,d4] [f3,a3,c4] [c3,e3,g3]@2".slow(2).late(.1),
cat(
'Baker man',
'is baking bread',
'Baker man',
'is baking bread',
'Sagabona',
'kunjani wena',
'Sagabona',
'kunjani wena',
'The night train, is coming',
'got to keep on running',
'The night train, is coming',
'got to keep on running',
).speak("en zu en".slow(12), "<0 2 3 4 5 6>".slow(2)),
).slow(4)`;
*/
export const randomBells = `samples({
export const randomBells = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// by Felix Roos
samples({
bell: { c6: 'https://freesound.org/data/previews/411/411089_5121236-lq.mp3' },
bass: { d2: 'https://freesound.org/data/previews/608/608286_13074022-lq.mp3' }
})
@@ -556,7 +395,9 @@ stack(
.pianoroll({minMidi:20,maxMidi:120,background:'transparent'})
`;
export const waa2 = `n(
export const waa2 = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// by Felix Roos
n(
"a4 [a3 c3] a3 c3"
.sub("<7 12 5 12>".slow(2))
.off(1/4,x=>x.add(7))
@@ -570,7 +411,9 @@ export const waa2 = `n(
.room(.5)
`;
export const hyperpop = `const lfo = cosine.slow(15);
export const hyperpop = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// by Felix Roos
const lfo = cosine.slow(15);
const lfo2 = sine.slow(16);
const filter1 = x=>x.cutoff(lfo2.range(300,3000));
const filter2 = x=>x.hcutoff(lfo.range(1000,6000)).cutoff(4000)
@@ -619,7 +462,9 @@ stack(
).slow(2)
// strudel disable-highlighting`;
export const festivalOfFingers3 = `"[-7*3],0,2,6,[8 7]"
export const festivalOfFingers3 = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// by Felix Roos
"[-7*3],0,2,6,[8 7]"
.echoWith(4,1/4, (x,n)=>x
.add(n*7)
.velocity(1/(n+1))
@@ -635,33 +480,9 @@ export const festivalOfFingers3 = `"[-7*3],0,2,6,[8 7]"
.note().piano()
//.pianoroll({maxMidi:160})`;
export const bossa = `
const scales = sequence('C minor', ['D locrian', 'G phrygian'], 'Bb2 minor', ['C locrian','F phrygian']).slow(4)
stack(
"<Cm7 [Dm7b5 G7b9] Bbm7 [Cm7b5 F7b9]>".fast(2).struct("x ~ x@3 x ~ x ~ ~ ~ x ~ x@3".late(1/8)).early(1/8).slow(2).voicings(),
"[~ [0 ~]] 0 [~ [4 ~]] 4".sub(7).restart(scales).scale(scales).early(.25)
).note().piano().slow(2)`;
/*
export const customTrigger = `stack(
freq("55 [110,165] 110 [220,275]".mul("<1 <3/4 2/3>>").struct("x(3,8)").layer(x=>x.mul("1.006,.995"))),
freq("440(5,8)".legato(.18).mul("<1 3/4 2 2/3>")).gain(perlin.range(.2,.8))
).s("<sawtooth square>/2")
.onTrigger((t,hap,ct)=>{
const ac = Tone.getContext().rawContext;
t = ac.currentTime + t - ct;
const { freq, s, gain = 1 } = hap.value;
const master = ac.createGain();
master.gain.value = 0.1 * gain;
master.connect(ac.destination);
const o = ac.createOscillator();
o.type = s || 'triangle';
o.frequency.value = Number(freq);
o.connect(master);
o.start(t);
o.stop(t + hap.duration);
}).stack(s("bd(3,8),hh*4,~ sd").webdirt())`; */
export const meltingsubmarine = `samples({
export const meltingsubmarine = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// by Felix Roos
samples({
bd: ['bd/BT0AADA.wav','bd/BT0AAD0.wav','bd/BT0A0DA.wav','bd/BT0A0D3.wav','bd/BT0A0D0.wav','bd/BT0A0A7.wav'],
sd: ['sd/rytm-01-classic.wav','sd/rytm-00-hard.wav'],
hh: ['hh27/000_hh27closedhh.wav','hh/000_hh3closedhh.wav'],
@@ -701,68 +522,9 @@ stack(
)
.slow(3/2)`;
export const swimmingWithSoundfonts = `stack(
n(
"~",
"~",
"~",
"A5 [F5@2 C5] [D5@2 F5] F5",
"[C5@2 F5] [F5@2 C6] A5 G5",
"A5 [F5@2 C5] [D5@2 F5] F5",
"[C5@2 F5] [Bb5 A5 G5] F5@2",
"A5 [F5@2 C5] [D5@2 F5] F5",
"[C5@2 F5] [F5@2 C6] A5 G5",
"A5 [F5@2 C5] [D5@2 F5] F5",
"[C5@2 F5] [Bb5 A5 G5] F5@2",
"A5 [F5@2 C5] A5 F5",
"Ab5 [F5@2 Ab5] G5@2",
"A5 [F5@2 C5] A5 F5",
"Ab5 [F5@2 C5] C6@2",
"A5 [F5@2 C5] [D5@2 F5] F5",
"[C5@2 F5] [Bb5 A5 G5] F5@2"
).s('Sitar: Ethnic'),
n(
"[F4,Bb4,D5] [[D4,G4,Bb4]@2 [Bb3,D4,F4]] [[G3,C4,E4]@2 [[Ab3,F4] [A3,Gb4]]] [Bb3,E4,G4]",
"[~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, Bb3, D3] [F3, Bb3, D3]] [~ [F3, Bb3, Db3] [F3, Bb3, Db3]]",
"[~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, Bb3, D3] [F3, Bb3, D3]] [~ [F3, B3, D3] [F3, B3, D3]]",
"[~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, Bb3, D3] [F3, Bb3, D3]] [~ [F3, B3, D3] [F3, B3, D3]]",
"[~ [A3, C4, E4] [A3, C4, E4]] [~ [Ab3, C4, Eb4] [Ab3, C4, Eb4]] [~ [F3, Bb3, D3] [F3, Bb3, D3]] [~ [G3, C4, E4] [G3, C4, E4]]",
"[~ [F3, A3, C4] [F3, A3, C4]] [~ [F3, A3, C4] [F3, A3, C4]] [~ [F3, Bb3, D3] [F3, Bb3, D3]] [~ [F3, B3, D3] [F3, B3, D3]]",
"[~ [F3, Bb3, D4] [F3, Bb3, D4]] [~ [F3, Bb3, C4] [F3, Bb3, C4]] [~ [F3, A3, C4] [F3, A3, C4]] [~ [F3, A3, C4] [F3, A3, C4]]",
"[~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, Bb3, D3] [F3, Bb3, D3]] [~ [F3, B3, D3] [F3, B3, D3]]",
"[~ [A3, C4, E4] [A3, C4, E4]] [~ [Ab3, C4, Eb4] [Ab3, C4, Eb4]] [~ [F3, Bb3, D3] [F3, Bb3, D3]] [~ [G3, C4, E4] [G3, C4, E4]]",
"[~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, Bb3, D3] [F3, Bb3, D3]] [~ [F3, B3, D3] [F3, B3, D3]]",
"[~ [F3, Bb3, D4] [F3, Bb3, D4]] [~ [F3, Bb3, C4] [F3, Bb3, C4]] [~ [F3, A3, C4] [F3, A3, C4]] [~ [F3, A3, C4] [F3, A3, C4]]",
"[~ [Bb3, D3, F4] [Bb3, D3, F4]] [~ [Bb3, D3, F4] [Bb3, D3, F4]] [~ [A3, C4, F4] [A3, C4, F4]] [~ [A3, C4, F4] [A3, C4, F4]]",
"[~ [Ab3, B3, F4] [Ab3, B3, F4]] [~ [Ab3, B3, F4] [Ab3, B3, F4]] [~ [G3, Bb3, F4] [G3, Bb3, F4]] [~ [G3, Bb3, E4] [G3, Bb3, E4]]",
"[~ [Bb3, D3, F4] [Bb3, D3, F4]] [~ [Bb3, D3, F4] [Bb3, D3, F4]] [~ [A3, C4, F4] [A3, C4, F4]] [~ [A3, C4, F4] [A3, C4, F4]]",
"[~ [Ab3, B3, F4] [Ab3, B3, F4]] [~ [Ab3, B3, F4] [Ab3, B3, F4]] [~ [G3, Bb3, F4] [G3, Bb3, F4]] [~ [G3, Bb3, E4] [G3, Bb3, E4]]",
"[~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, Bb3, D3] [F3, Bb3, D3]] [~ [F3, B3, D3] [F3, B3, D3]]",
"[~ [F3, Bb3, D4] [F3, Bb3, D4]] [~ [F3, Bb3, C4] [F3, Bb3, C4]] [~ [F3, A3, C4] [F3, A3, C4]] [~ [F3, A3, C4] [F3, A3, C4]]"
).s('Kalimba: Ethnic'),
n(
"[G3 G3 C3 E3]",
"[F2 D2 G2 C2]",
"[F2 D2 G2 C2]",
"[F2 A2 Bb2 B2]",
"[A2 Ab2 G2 C2]",
"[F2 A2 Bb2 B2]",
"[G2 C2 F2 F2]",
"[F2 A2 Bb2 B2]",
"[A2 Ab2 G2 C2]",
"[F2 A2 Bb2 B2]",
"[G2 C2 F2 F2]",
"[Bb2 Bb2 A2 A2]",
"[Ab2 Ab2 G2 [C2 D2 E2]]",
"[Bb2 Bb2 A2 A2]",
"[Ab2 Ab2 G2 [C2 D2 E2]]",
"[F2 A2 Bb2 B2]",
"[G2 C2 F2 F2]"
).s('Acoustic Bass: Bass')
).slow(51)
`;
export const outroMusic = `samples({
export const outroMusic = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// by Felix Roos
samples({
bd: ['bd/BT0AADA.wav','bd/BT0AAD0.wav','bd/BT0A0DA.wav','bd/BT0A0D3.wav','bd/BT0A0D0.wav','bd/BT0A0A7.wav'],
sd: ['sd/rytm-01-classic.wav','sd/rytm-00-hard.wav'],
hh: ['hh27/000_hh27closedhh.wav','hh/000_hh3closedhh.wav'],
@@ -789,7 +551,9 @@ export const outroMusic = `samples({
//.pianoroll({autorange:1,vertical:1,fold:0})
`;
export const bassFuge = `samples({ flbass: ['00_c2_finger_long_neck.wav','01_c2_finger_short_neck.wav','02_c2_finger_long_bridge.wav','03_c2_finger_short_bridge.wav','04_c2_pick_long.wav','05_c2_pick_short.wav','06_c2_palm_mute.wav'] },
export const bassFuge = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// by Felix Roos
samples({ flbass: ['00_c2_finger_long_neck.wav','01_c2_finger_short_neck.wav','02_c2_finger_long_bridge.wav','03_c2_finger_short_bridge.wav','04_c2_pick_long.wav','05_c2_pick_short.wav','06_c2_palm_mute.wav'] },
'github:cleary/samples-flbass/main/')
samples({
bd: ['bd/BT0AADA.wav','bd/BT0AAD0.wav','bd/BT0A0DA.wav','bd/BT0A0D3.wav','bd/BT0A0D0.wav','bd/BT0A0A7.wav'],
@@ -813,18 +577,9 @@ x=>x.add(7).color('steelblue')
.stack(s("bd:1*2,~ sd:0,[~ hh:0]*2"))
.pianoroll({vertical:1})`;
export const bossaRandom = `const chords = "<Am7 Am7 Dm7 E7>"
const roots = chords.rootNotes(2)
stack(
chords.voicings(['F4', 'A5']).struct(
\` x@2 ~ x ~ ~ ~ x |
x? ~ ~ x@3 ~ x |
x? ~ ~ x ~ x@3\`),
roots.struct("x [~ x?0.2] x [~ x?] | x!4 | x@2 ~ ~ ~ x x x").transpose("0 7")
).slow(2).pianoroll().note().piano()`;
export const chop = `samples({ p: 'https://cdn.freesound.org/previews/648/648433_11943129-lq.mp3' })
export const chop = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// by Felix Roos
samples({ p: 'https://cdn.freesound.org/previews/648/648433_11943129-lq.mp3' })
s("p")
.loopAt(32,1)
@@ -835,14 +590,18 @@ s("p")
.sustain(.6)
`;
export const delay = `stack(
export const delay = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// by Felix Roos
stack(
s("bd <sd cp>")
.delay("<0 .5>")
.delaytime(".16 | .33")
.delayfeedback(".6 | .8")
).sometimes(x=>x.speed("-1"))`;
export const orbit = `stack(
export const orbit = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// by Felix Roos
stack(
s("bd <sd cp>")
.delay(.5)
.delaytime(.33)
@@ -854,7 +613,9 @@ export const orbit = `stack(
.orbit(2)
).sometimes(x=>x.speed("-1"))`;
export const belldub = `samples({ bell: {b4:'https://cdn.freesound.org/previews/339/339809_5121236-lq.mp3'}})
export const belldub = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// by Felix Roos
samples({ bell: {b4:'https://cdn.freesound.org/previews/339/339809_5121236-lq.mp3'}})
// "Hand Bells, B, Single.wav" by InspectorJ (www.jshaw.co.uk) of Freesound.org
stack(
// bass
@@ -885,7 +646,9 @@ stack(
.mask("<1 0>/8")
).slow(5)`;
export const dinofunk = `samples({bass:'https://cdn.freesound.org/previews/614/614637_2434927-hq.mp3',
export const dinofunk = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// by Felix Roos
samples({bass:'https://cdn.freesound.org/previews/614/614637_2434927-hq.mp3',
dino:{b4:'https://cdn.freesound.org/previews/316/316403_5123851-hq.mp3'}})
stack(
@@ -903,7 +666,9 @@ note("Abm7".voicings(['c3','a4']).struct("x(3,8,1)".slow(2))),
note("<b4 eb4>").s('dino').delay(.8).slow(8).room(.5)
)`;
export const sampleDemo = `stack(
export const sampleDemo = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// by Felix Roos
stack(
// percussion
s("[woodblock:1 woodblock:2*2] snare_rim:0,gong/8,brakedrum:1(3,8),~@3 cowbell:3")
.sometimes(x=>x.speed(2)),
@@ -917,7 +682,9 @@ export const sampleDemo = `stack(
.release(.1).room(.5)
)`;
export const holyflute = `"c3 eb3(3,8) c4/2 g3*2"
export const holyflute = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// by Felix Roos
"c3 eb3(3,8) c4/2 g3*2"
.superimpose(
x=>x.slow(2).add(12),
x=>x.slow(4).sub(5)
@@ -928,7 +695,9 @@ export const holyflute = `"c3 eb3(3,8) c4/2 g3*2"
.pianoroll({fold:0,autorange:0,vertical:0,cycles:12,smear:0,minMidi:40})
`;
export const flatrave = `stack(
export const flatrave = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// by Felix Roos
stack(
s("bd*2,~ [cp,sd]").bank('RolandTR909'),
s("hh:1*4").sometimes(fast("2"))
@@ -949,7 +718,9 @@ export const flatrave = `stack(
.decay(.05).sustain(0).delay(.2).degradeBy(.5).mask("<0 1>/16")
)`;
export const amensister = `await samples('github:tidalcycles/Dirt-Samples/master')
export const amensister = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// by Felix Roos
await samples('github:tidalcycles/Dirt-Samples/master')
stack(
// amen
@@ -981,7 +752,9 @@ stack(
n("0 1").s("east").delay(.5).degradeBy(.8).speed(rand.range(.5,1.5))
).reset("<x@7 x(5,8)>")`;
export const juxUndTollerei = `note("c3 eb3 g3 bb3").palindrome()
export const juxUndTollerei = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// by Felix Roos
note("c3 eb3 g3 bb3").palindrome()
.s('sawtooth')
.jux(x=>x.rev().color('green').s('sawtooth'))
.off(1/4, x=>x.add(note("<7 12>/2")).slow(2).late(.005).s('triangle'))
@@ -991,3 +764,75 @@ export const juxUndTollerei = `note("c3 eb3 g3 bb3").palindrome()
.room(.6)
.delay(.5).delaytime(.1).delayfeedback(.4)
.pianoroll()`;
export const csoundDemo = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// by Felix Roos
await csound\`
instr CoolSynth
iduration = p3
ifreq = p4
igain = p5
ioct = octcps(ifreq)
kpwm = oscili(.05, 8)
asig = vco2(igain, ifreq, 4, .5 + kpwm)
asig += vco2(igain, ifreq * 2)
idepth = 2
acut = transegr:a(0, .005, 0, idepth, .06, -4.2, 0.001, .01, -4.2, 0) ; filter envelope
asig = zdf_2pole(asig, cpsoct(ioct + acut + 2), 0.5)
iattack = .01
isustain = .5
idecay = .1
irelease = .1
asig *= linsegr:a(0, iattack, 1, idecay, isustain, iduration, isustain, irelease, 0)
out(asig, asig)
endin\`
"<0 2 [4 6](3,4,1) 3*2>"
.off(1/4, add(2))
.off(1/2, add(6))
.scale('D minor')
.note()
//.pianoroll()
.csound('CoolSynth')`;
export const loungeSponge = `
// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// by Felix Roos
// livecode.orc by Steven Yi
await loadOrc('github:kunstmusik/csound-live-code/master/livecode.orc')
stack(
note("<C^7 A7 Dm7 Fm7>/2".voicings())
.cutoff(sine.range(500,2000).round().slow(16))
.euclidLegato(3,8).csound('FM1')
,
note("<C2 A1 D2 F2>/2").ply(8).csound('Bass').gain("1 4 1 4")
,
note("0 7 [4 3] 2".fast(2/3).off(".25 .125",add("<2 4 -3 -1>"))
.slow(2).scale('A4 minor'))
.legato(.25).csound('SynHarp')
,
s("bd*2,[~ hh]*2,~ cp").bank('RolandTR909')
)`;
export const arpoon = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// "Arpoon" by Felix Roos
await samples('github:tidalcycles/Dirt-Samples/master')
"<<Am7 C^7> C7 F^7 [Fm7 E7b9]>".voicings()
.arp("[0,3] 2 [1,3] 2".fast(3)).legato(2)
.add(perlin.range(0,0.2)).sub("<0 -12>/8")
.note().cutoff(perlin.range(500,4000)).resonance(12)
.gain("<.5 .8>*16")
.decay(.16).sustain(0.5)
.delay(.2)
.room(.5).pan(sine.range(.3,.6))
.s('piano').clip(1)
.stack("<<A1 C2>!2 F2 [F2 E2]>".add.out("0 -5".fast(2)).add("0,.12").note().s('sawtooth').clip(1).cutoff(300))
.slow(4)
.stack(s("bd*4, [~ [hh hh? hh?]]*2,~ [sd ~ [sd:2? bd?]]").arp("0|1").bank('RolandTR909').gain(.5).slow(2))
`;
+1 -1
View File
@@ -18,7 +18,7 @@ function renderAsMDX(name) {
}
return `### ${item.longname}
${item.description.replaceAll(/\{\@link ([a-zA-Z]+)?\#?([a-zA-Z]*)\}/g, (_, a, b) => {
${item.description.replaceAll(/\{@link ([a-zA-Z]+)?#?([a-zA-Z]*)\}/g, (_, a, b) => {
// console.log(_, 'a', a, 'b', b);
return `<a href="#${a}${b ? `-${b}` : ''}">${a}${b ? `#${b}` : ''}</a>`;
})}
@@ -232,23 +232,6 @@ exports[`runs examples > example "amp" example index 0 1`] = `
]
`;
exports[`runs examples > example "apply" example index 0 1`] = `
[
"0/1 -> 1/1: {\\"note\\":\\"C3\\"}",
"0/1 -> 1/1: {\\"note\\":\\"Eb3\\"}",
"0/1 -> 1/1: {\\"note\\":\\"G3\\"}",
"1/1 -> 2/1: {\\"note\\":\\"Eb3\\"}",
"1/1 -> 2/1: {\\"note\\":\\"G3\\"}",
"1/1 -> 2/1: {\\"note\\":\\"Bb3\\"}",
"2/1 -> 3/1: {\\"note\\":\\"G3\\"}",
"2/1 -> 3/1: {\\"note\\":\\"Bb3\\"}",
"2/1 -> 3/1: {\\"note\\":\\"D4\\"}",
"3/1 -> 4/1: {\\"note\\":\\"C3\\"}",
"3/1 -> 4/1: {\\"note\\":\\"Eb3\\"}",
"3/1 -> 4/1: {\\"note\\":\\"G3\\"}",
]
`;
exports[`runs examples > example "bandf" example index 0 1`] = `
[
"0/1 -> 1/2: {\\"s\\":\\"bd\\",\\"bandf\\":1000}",
@@ -782,27 +765,6 @@ exports[`runs examples > example "dry" example index 0 1`] = `
]
`;
exports[`runs examples > example "each" example index 0 1`] = `
[
"0/1 -> 1/4: {\\"note\\":\\"c3\\"}",
"1/4 -> 1/2: {\\"note\\":\\"d3\\"}",
"1/2 -> 3/4: {\\"note\\":\\"e3\\"}",
"3/4 -> 1/1: {\\"note\\":\\"g3\\"}",
"1/1 -> 5/4: {\\"note\\":\\"c3\\"}",
"5/4 -> 3/2: {\\"note\\":\\"d3\\"}",
"3/2 -> 7/4: {\\"note\\":\\"e3\\"}",
"7/4 -> 2/1: {\\"note\\":\\"g3\\"}",
"2/1 -> 9/4: {\\"note\\":\\"c3\\"}",
"9/4 -> 5/2: {\\"note\\":\\"d3\\"}",
"5/2 -> 11/4: {\\"note\\":\\"e3\\"}",
"11/4 -> 3/1: {\\"note\\":\\"g3\\"}",
"15/4 -> 4/1: {\\"note\\":\\"c3\\"}",
"7/2 -> 15/4: {\\"note\\":\\"d3\\"}",
"13/4 -> 7/2: {\\"note\\":\\"e3\\"}",
"3/1 -> 13/4: {\\"note\\":\\"g3\\"}",
]
`;
exports[`runs examples > example "early" example index 0 1`] = `
[
"0/1 -> 1/2: {\\"s\\":\\"bd\\"}",
@@ -1547,27 +1509,6 @@ exports[`runs examples > example "every" example index 0 1`] = `
]
`;
exports[`runs examples > example "every" example index 0 2`] = `
[
"3/4 -> 1/1: {\\"note\\":\\"c3\\"}",
"1/2 -> 3/4: {\\"note\\":\\"d3\\"}",
"1/4 -> 1/2: {\\"note\\":\\"e3\\"}",
"0/1 -> 1/4: {\\"note\\":\\"g3\\"}",
"1/1 -> 5/4: {\\"note\\":\\"c3\\"}",
"5/4 -> 3/2: {\\"note\\":\\"d3\\"}",
"3/2 -> 7/4: {\\"note\\":\\"e3\\"}",
"7/4 -> 2/1: {\\"note\\":\\"g3\\"}",
"2/1 -> 9/4: {\\"note\\":\\"c3\\"}",
"9/4 -> 5/2: {\\"note\\":\\"d3\\"}",
"5/2 -> 11/4: {\\"note\\":\\"e3\\"}",
"11/4 -> 3/1: {\\"note\\":\\"g3\\"}",
"3/1 -> 13/4: {\\"note\\":\\"c3\\"}",
"13/4 -> 7/2: {\\"note\\":\\"d3\\"}",
"7/2 -> 15/4: {\\"note\\":\\"e3\\"}",
"15/4 -> 4/1: {\\"note\\":\\"g3\\"}",
]
`;
exports[`runs examples > example "fast" example index 0 1`] = `
[
"0/1 -> 1/4: {\\"s\\":\\"bd\\"}",