Compare commits

..

3 Commits

Author SHA1 Message Date
Felix Roos a2f3b85f38 remove notes 2023-06-11 11:20:28 +02:00
Felix Roos 8e6846a3aa add workshop file 2023-06-10 12:14:15 +02:00
Felix Roos 34ee2081d3 fix: typo 2023-06-09 23:02:48 +02:00
86 changed files with 3428 additions and 7929 deletions
-62
View File
@@ -1,62 +0,0 @@
name: Tauri Builder
on:
push:
tags:
- "v*"
workflow_dispatch:
jobs:
release:
strategy:
fail-fast: false
matrix:
platform: [macos-latest, ubuntu-latest, windows-latest]
include:
- os: ubuntu-latest
rust_target: x86_64-unknown-linux-gnu
- os: macos-latest
rust_target: x86_64-apple-darwin
- os: macos-latest
rust_target: aarch64-apple-darwin
- os: windows-latest
rust_target: x86_64-pc-windows-msvc
runs-on: ${{ matrix.platform }}
steps:
- name: Checkout repository
uses: actions/checkout@v3
- uses: pnpm/action-setup@v2
with:
version: 8.6.2
- name: Node.js setup
uses: actions/setup-node@v3
with:
node-version: latest
# node-version-file: '.nvmrc'
- name: Install Rust (Stable)
run:
curl https://sh.rustup.rs -sSf | sh -s -- -y
- name: Install dependencies (ubuntu only)
if: matrix.platform == 'ubuntu-latest'
run: |
sudo apt-get update
sudo apt-get install -y libgtk-3-dev webkit2gtk-4.0 libappindicator3-dev librsvg2-dev patchelf
- name: Install app dependencies from lockfile and build web
run: pnpm install
- name: Build the app
uses: tauri-apps/tauri-action@v0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
# tauri-action replaces \_\_VERSION\_\_ with the app version
tagName: ${{ github.ref_name }}
releaseName: "Strudel v__VERSION__"
releaseBody: |
See the assets to download this version and install.
releaseDraft: true
prerelease: false
-1
View File
@@ -43,4 +43,3 @@ dev-dist
Dirt-Samples Dirt-Samples
tidal-drum-machines tidal-drum-machines
webaudiofontdata webaudiofontdata
src-tauri/target
+1 -1
View File
@@ -31,7 +31,7 @@ Use one of the Communication Channels listed above.
## Improve the Docs ## Improve the Docs
If you find some weak spots in the [docs](https://strudel.tidalcycles.org/workshop/getting-started/), If you find some weak spots in the [docs](https://strudel.tidalcycles.org/learn/getting-started),
you can edit each file directly on github via the "Edit this page" link located in the right sidebar. you can edit each file directly on github via the "Edit this page" link located in the right sidebar.
## Propose a Feature ## Propose a Feature
+3 -4
View File
@@ -52,10 +52,10 @@
"@strudel.cycles/webaudio": "workspace:*", "@strudel.cycles/webaudio": "workspace:*",
"@strudel.cycles/xen": "workspace:*", "@strudel.cycles/xen": "workspace:*",
"acorn": "^8.8.1", "acorn": "^8.8.1",
"dependency-tree": "^9.0.0" "dependency-tree": "^9.0.0",
"vitest": "^0.28.0"
}, },
"devDependencies": { "devDependencies": {
"@tauri-apps/cli": "^1.4.0",
"@vitest/ui": "^0.28.0", "@vitest/ui": "^0.28.0",
"canvas": "^2.11.2", "canvas": "^2.11.2",
"eslint": "^8.39.0", "eslint": "^8.39.0",
@@ -66,7 +66,6 @@
"jsdoc-to-markdown": "^8.0.0", "jsdoc-to-markdown": "^8.0.0",
"lerna": "^6.6.1", "lerna": "^6.6.1",
"prettier": "^2.8.8", "prettier": "^2.8.8",
"rollup-plugin-visualizer": "^5.8.1", "rollup-plugin-visualizer": "^5.8.1"
"vitest": "^0.28.0"
} }
} }
+1 -1
View File
@@ -133,7 +133,7 @@ export class StrudelMirror {
this.code = initialCode; this.code = initialCode;
this.drawer = new Drawer((haps, time) => { this.drawer = new Drawer((haps, time) => {
const currentFrame = haps.filter((hap) => time >= hap.whole.begin && time <= hap.endClipped); const currentFrame = haps.filter((hap) => time >= hap.whole.begin && time <= hap.whole.end);
this.highlight(currentFrame); this.highlight(currentFrame);
onDraw?.(haps, time, currentFrame); onDraw?.(haps, time, currentFrame);
}, drawTime); }, drawTime);
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@strudel/codemirror", "name": "@strudel/codemirror",
"version": "0.8.4", "version": "0.8.3",
"description": "Codemirror Extensions for Strudel", "description": "Codemirror Extensions for Strudel",
"main": "codemirror.mjs", "main": "codemirror.mjs",
"publishConfig": { "publishConfig": {
+4 -6
View File
@@ -222,7 +222,6 @@ const generic_params = [
* *
* @name legato * @name legato
* @param {number | Pattern} duration between 0 and 1, where 1 is the length of the whole hap time * @param {number | Pattern} duration between 0 and 1, where 1 is the length of the whole hap time
* @noAutocomplete
* @example * @example
* "c4 eb4 g4 bb4".legato("<0.125 .25 .5 .75 1 2 4>") * "c4 eb4 g4 bb4".legato("<0.125 .25 .5 .75 1 2 4>")
* *
@@ -750,14 +749,13 @@ const generic_params = [
['val'], ['val'],
['cps'], ['cps'],
/** /**
* Multiplies the duration with the given number. Also cuts samples off at the end if they exceed the duration. * If set to 1, samples will be cut to the duration of their event.
* In tidal, this would be done with legato, [which has a complicated history in strudel](https://github.com/tidalcycles/strudel/issues/111). * In tidal, this would be done with legato, which [is about to land in strudel too](https://github.com/tidalcycles/strudel/issues/111)
* For now, if you're coming from tidal, just think clip = legato.
* *
* @name clip * @name clip
* @param {number | Pattern} factor >= 0 * @param {number | Pattern} active 1 or 0
* @example * @example
* note("c a f e").s("piano").clip("<.5 1 2>") * note("c a f e ~").s("piano").clip(1)
* *
*/ */
['clip'], ['clip'],
+1 -5
View File
@@ -32,11 +32,7 @@ export class Hap {
} }
get duration() { get duration() {
return this.whole.end.sub(this.whole.begin).mul(typeof this.value?.clip === 'number' ? this.value?.clip : 1); return this.whole.end.sub(this.whole.begin);
}
get endClipped() {
return this.whole.begin.add(this.duration);
} }
wholeOrPart() { wholeOrPart() {
-1
View File
@@ -24,7 +24,6 @@ export * from './time.mjs';
export * from './draw.mjs'; export * from './draw.mjs';
export * from './animate.mjs'; export * from './animate.mjs';
export * from './pianoroll.mjs'; export * from './pianoroll.mjs';
export * from './spiral.mjs';
export * from './ui.mjs'; export * from './ui.mjs';
export { default as drawLine } from './drawLine.mjs'; export { default as drawLine } from './drawLine.mjs';
export { default as gist } from './gist.js'; export { default as gist } from './gist.js';
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@strudel.cycles/core", "name": "@strudel.cycles/core",
"version": "0.8.2", "version": "0.8.1",
"description": "Port of Tidal Cycles to JavaScript", "description": "Port of Tidal Cycles to JavaScript",
"main": "index.mjs", "main": "index.mjs",
"type": "module", "type": "module",
+5 -33
View File
@@ -1582,24 +1582,6 @@ export const range2 = register('range2', function (min, max, pat) {
return pat.fromBipolar()._range(min, max); return pat.fromBipolar()._range(min, max);
}); });
/**
* Allows dividing numbers via list notation using ":".
* Returns a new pattern with just numbers.
* @name ratio
* @memberof Pattern
* @returns Pattern
* @example
* ratio("1, 5:4, 3:2").mul(110).freq().s("piano").slow(2)
*/
export const ratio = register('ratio', (pat) =>
pat.fmap((v) => {
if (!Array.isArray(v)) {
return v;
}
return v.slice(1).reduce((acc, n) => acc / n, v[0]);
}),
);
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// Structural and temporal transformations // Structural and temporal transformations
@@ -1695,9 +1677,6 @@ export const ply = register('ply', function (factor, pat) {
* s("<bd sd> hh").fast(2) // s("[<bd sd> hh]*2") * s("<bd sd> hh").fast(2) // s("[<bd sd> hh]*2")
*/ */
export const { fast, density } = register(['fast', 'density'], function (factor, pat) { export const { fast, density } = register(['fast', 'density'], function (factor, pat) {
if (factor === 0) {
return silence;
}
factor = Fraction(factor); factor = Fraction(factor);
const fastQuery = pat.withQueryTime((t) => t.mul(factor)); const fastQuery = pat.withQueryTime((t) => t.mul(factor));
return fastQuery.withHapTime((t) => t.div(factor)); return fastQuery.withHapTime((t) => t.div(factor));
@@ -1724,9 +1703,6 @@ export const hurry = register('hurry', function (r, pat) {
* s("<bd sd> hh").slow(2) // s("[<bd sd> hh]/2") * s("<bd sd> hh").slow(2) // s("[<bd sd> hh]/2")
*/ */
export const { slow, sparsity } = register(['slow', 'sparsity'], function (factor, pat) { export const { slow, sparsity } = register(['slow', 'sparsity'], function (factor, pat) {
if (factor === 0) {
return silence;
}
return pat._fast(Fraction(1).div(factor)); return pat._fast(Fraction(1).div(factor));
}); });
@@ -2053,7 +2029,7 @@ export const jux = register('jux', function (func, pat) {
* @example * @example
* "<0 [2 4]>" * "<0 [2 4]>"
* .echoWith(4, 1/8, (p,n) => p.add(n*2)) * .echoWith(4, 1/8, (p,n) => p.add(n*2))
* .scale('C minor').note().clip(.2) * .scale('C minor').note().legato(.2)
*/ */
export const { echoWith, echowith, stutWith, stutwith } = register( export const { echoWith, echowith, stutWith, stutwith } = register(
['echoWith', 'echowith', 'stutWith', 'stutwith'], ['echoWith', 'echowith', 'stutWith', 'stutwith'],
@@ -2203,7 +2179,6 @@ export const velocity = register('velocity', function (velocity, pat) {
/** /**
* *
* Multiplies the hap duration with the given factor. * Multiplies the hap duration with the given factor.
* With samples, `clip` might be a better function to use ([more info](https://github.com/tidalcycles/strudel/pull/598))
* @name legato * @name legato
* @memberof Pattern * @memberof Pattern
* @example * @example
@@ -2276,7 +2251,7 @@ const _loopAt = function (factor, pat, cps = 1) {
* s("breaks165").slice(8, "0 1 <2 2*2> 3 [4 0] 5 6 7".every(3, rev)).slow(1.5) * s("breaks165").slice(8, "0 1 <2 2*2> 3 [4 0] 5 6 7".every(3, rev)).slow(1.5)
*/ */
export const slice = register( const slice = register(
'slice', 'slice',
function (npat, ipat, opat) { function (npat, ipat, opat) {
return npat.innerBind((n) => return npat.innerBind((n) =>
@@ -2304,7 +2279,7 @@ export const slice = register(
* s("breaks165").splice(8, "0 1 [2 3 0]@2 3 0@2 7").hurry(0.65) * s("breaks165").splice(8, "0 1 [2 3 0]@2 3 0@2 7").hurry(0.65)
*/ */
export const splice = register( const splice = register(
'splice', 'splice',
function (npat, ipat, opat) { function (npat, ipat, opat) {
const sliced = slice(npat, ipat, opat); const sliced = slice(npat, ipat, opat);
@@ -2321,10 +2296,7 @@ export const splice = register(
false, // turns off auto-patternification false, // turns off auto-patternification
); );
// this function will be redefined in repl.mjs to use the correct cps value. const { loopAt, loopat } = register(['loopAt', 'loopat'], function (factor, pat) {
// It is still here to work in cases where repl.mjs is not used
export const { loopAt, loopat } = register(['loopAt', 'loopat'], function (factor, pat) {
return _loopAt(factor, pat, 1); return _loopAt(factor, pat, 1);
}); });
@@ -2341,6 +2313,6 @@ export const { loopAt, loopat } = register(['loopAt', 'loopat'], function (facto
* s("rhodes").loopAtCps(4,1.5).cps(1.5) * s("rhodes").loopAtCps(4,1.5).cps(1.5)
*/ */
// TODO - global cps clock // TODO - global cps clock
export const { loopAtCps, loopatcps } = register(['loopAtCps', 'loopatcps'], function (factor, cps, pat) { const { loopAtCps, loopatcps } = register(['loopAtCps', 'loopatcps'], function (factor, cps, pat) {
return _loopAt(factor, pat, cps); return _loopAt(factor, pat, cps);
}); });
+2 -2
View File
@@ -83,9 +83,9 @@ Pattern.prototype.pianoroll = function ({
ctx.fillRect(0, 0, w, h); ctx.fillRect(0, 0, w, h);
} }
const inFrame = (event) => const inFrame = (event) =>
(!hideNegative || event.whole.begin >= 0) && event.whole.begin <= t + to && event.endClipped >= t + from; (!hideNegative || event.whole.begin >= 0) && event.whole.begin <= t + to && event.whole.end >= t + from;
events.filter(inFrame).forEach((event) => { events.filter(inFrame).forEach((event) => {
const isActive = event.whole.begin <= t && event.endClipped > t; const isActive = event.whole.begin <= t && event.whole.end > t;
ctx.fillStyle = event.context?.color || inactive; ctx.fillStyle = event.context?.color || inactive;
ctx.strokeStyle = event.context?.color || active; ctx.strokeStyle = event.context?.color || active;
ctx.globalAlpha = event.context.velocity ?? event.value?.gain ?? 1; ctx.globalAlpha = event.context.velocity ?? event.value?.gain ?? 1;
-23
View File
@@ -3,7 +3,6 @@ import { evaluate as _evaluate } from './evaluate.mjs';
import { logger } from './logger.mjs'; import { logger } from './logger.mjs';
import { setTime } from './time.mjs'; import { setTime } from './time.mjs';
import { evalScope } from './evaluate.mjs'; import { evalScope } from './evaluate.mjs';
import { register } from './pattern.mjs';
export function repl({ export function repl({
interval, interval,
@@ -51,32 +50,10 @@ export function repl({
const start = () => scheduler.start(); const start = () => scheduler.start();
const pause = () => scheduler.pause(); const pause = () => scheduler.pause();
const setCps = (cps) => scheduler.setCps(cps); const setCps = (cps) => scheduler.setCps(cps);
const setCpm = (cpm) => scheduler.setCps(cpm / 60);
// the following functions use the cps value, which is why they are defined here..
const loopAt = register('loopAt', (cycles, pat) => {
return pat.loopAtCps(cycles, scheduler.cps);
});
const fit = register('fit', (pat) =>
pat.withHap((hap) =>
hap.withValue((v) => ({
...v,
speed: scheduler.cps / hap.whole.duration, // overwrite speed completely?
unit: 'c',
})),
),
);
evalScope({ evalScope({
loopAt,
fit,
setCps, setCps,
setcps: setCps, setcps: setCps,
setCpm,
setcpm: setCpm,
}); });
return { scheduler, evaluate, start, stop, pause, setCps, setPattern }; return { scheduler, evaluate, start, stop, pause, setCps, setPattern };
} }
+1 -1
View File
@@ -27,7 +27,7 @@ export const isaw2 = isaw.toBipolar();
* *
* @return {Pattern} * @return {Pattern}
* @example * @example
* "c3 [eb3,g3] g2 [g3,bb3]".note().clip(saw.slow(4)) * "c3 [eb3,g3] g2 [g3,bb3]".legato(saw.slow(4)).note()
* @example * @example
* saw.range(0,8).segment(8).scale('C major').slow(4).note() * saw.range(0,8).segment(8).scale('C major').slow(4).note()
* *
-117
View File
@@ -1,117 +0,0 @@
import { Pattern } from './index.mjs';
// polar coords -> xy
function fromPolar(angle, radius, cx, cy) {
const radians = ((angle - 90) * Math.PI) / 180;
return [cx + Math.cos(radians) * radius, cy + Math.sin(radians) * radius];
}
const xyOnSpiral = (angle, margin, cx, cy, rotate = 0) => fromPolar((angle + rotate) * 360, margin * angle, cx, cy); // TODO: logSpiral
// draw spiral / segment of spiral
function spiralSegment(options) {
let {
ctx,
from = 0,
to = 3,
margin = 50,
cx = 100,
cy = 100,
rotate = 0,
thickness = margin / 2,
color = '#0000ff30',
cap = 'round',
stretch = 1,
fromOpacity = 1,
toOpacity = 1,
} = options;
from *= stretch;
to *= stretch;
rotate *= stretch;
ctx.lineWidth = thickness;
ctx.lineCap = cap;
ctx.strokeStyle = color;
ctx.globalAlpha = fromOpacity;
ctx.beginPath();
let [sx, sy] = xyOnSpiral(from, margin, cx, cy, rotate);
ctx.moveTo(sx, sy);
const increment = 1 / 60;
let angle = from;
while (angle <= to) {
const [x, y] = xyOnSpiral(angle, margin, cx, cy, rotate);
//ctx.lineWidth = angle*thickness;
ctx.globalAlpha = ((angle - from) / (to - from)) * toOpacity;
ctx.lineTo(x, y);
angle += increment;
}
ctx.stroke();
}
Pattern.prototype.spiral = function (options = {}) {
const {
stretch = 1,
size = 80,
thickness = size / 2,
cap = 'butt', // round butt squar,
inset = 3, // start angl,
playheadColor = '#ffffff90',
playheadLength = 0.02,
playheadThickness = thickness,
padding = 0,
steady = 1,
inactiveColor = '#ffffff20',
colorizeInactive = 0,
fade = true,
// logSpiral = true,
} = options;
function spiral({ ctx, time, haps, drawTime }) {
ctx.clearRect(0, 0, ctx.canvas.clientWidth, ctx.canvas.clientHeight);
const [cx, cy] = [ctx.canvas.width / 2, ctx.canvas.height / 2];
const settings = {
margin: size / stretch,
cx,
cy,
stretch,
cap,
thickness,
};
const playhead = {
...settings,
thickness: playheadThickness,
from: inset - playheadLength,
to: inset,
color: playheadColor,
};
const [min] = drawTime;
const rotate = steady * time;
haps.forEach((hap) => {
const isActive = hap.whole.begin <= time && hap.endClipped > time;
const from = hap.whole.begin - time + inset;
const to = hap.endClipped - time + inset - padding;
const { color } = hap.context;
const opacity = fade ? 1 - Math.abs((hap.whole.begin - time) / min) : 1;
spiralSegment({
ctx,
...settings,
from,
to,
rotate,
color: colorizeInactive || isActive ? color : inactiveColor,
fromOpacity: opacity,
toOpacity: opacity,
});
});
spiralSegment({
ctx,
...playhead,
rotate,
});
}
return this.onPaint((ctx, time, haps, drawTime) => spiral({ ctx, time, haps, drawTime }));
};
-40
View File
@@ -1,40 +0,0 @@
/*test for issue 302 support alternative solmization types */
import { sol2note } from '../util.mjs';
import { test } from 'vitest';
import assert from 'assert';
test('solmization - letters', () => {
const result = sol2note(60, 'letters');
const expected = 'C4';
assert.equal(result, expected);
});
test('solmization - solfeggio', () => {
const result = sol2note(60, 'solfeggio');
const expected = 'Do4';
assert.equal(result, expected);
});
test('solmization - indian', () => {
const result = sol2note(60, 'indian');
const expected = 'Sa4';
assert.equal(result, expected);
});
test('solmization - german', () => {
const result = sol2note(60, 'german');
const expected = 'C4';
assert.equal(result, expected);
});
test('solmization - byzantine', () => {
const result = sol2note(60, 'byzantine');
const expected = 'Ni4';
assert.equal(result, expected);
});
test('solmization - japanese', () => {
const result = sol2note(60, 'japanese');
const expected = 'I4';
assert.equal(result, expected);
});
+4 -60
View File
@@ -6,12 +6,12 @@ This program is free software: you can redistribute it and/or modify it under th
// returns true if the given string is a note // returns true if the given string is a note
export const isNoteWithOctave = (name) => /^[a-gA-G][#bs]*[0-9]$/.test(name); export const isNoteWithOctave = (name) => /^[a-gA-G][#bs]*[0-9]$/.test(name);
export const isNote = (name) => /^[a-gA-G][#bsf]*[0-9]?$/.test(name); export const isNote = (name) => /^[a-gA-G][#bs]*[0-9]?$/.test(name);
export const tokenizeNote = (note) => { export const tokenizeNote = (note) => {
if (typeof note !== 'string') { if (typeof note !== 'string') {
return []; return [];
} }
const [pc, acc = '', oct] = note.match(/^([a-gA-G])([#bsf]*)([0-9])?$/)?.slice(1) || []; const [pc, acc = '', oct] = note.match(/^([a-gA-G])([#bs]*)([0-9])?$/)?.slice(1) || [];
if (!pc) { if (!pc) {
return []; return [];
} }
@@ -25,7 +25,7 @@ export const noteToMidi = (note) => {
throw new Error('not a note: "' + note + '"'); throw new Error('not a note: "' + note + '"');
} }
const chroma = { c: 0, d: 2, e: 4, f: 5, g: 7, a: 9, b: 11 }[pc.toLowerCase()]; const chroma = { c: 0, d: 2, e: 4, f: 5, g: 7, a: 9, b: 11 }[pc.toLowerCase()];
const offset = acc?.split('').reduce((o, char) => o + { '#': 1, b: -1, s: 1, f: -1 }[char], 0) || 0; const offset = acc?.split('').reduce((o, char) => o + { '#': 1, b: -1, s: 1 }[char], 0) || 0;
return (Number(oct) + 1) * 12 + chroma + offset; return (Number(oct) + 1) * 12 + chroma + offset;
}; };
export const midiToFreq = (n) => { export const midiToFreq = (n) => {
@@ -69,7 +69,7 @@ export const getFreq = (noteOrMidi) => {
const pcs = ['C', 'Db', 'D', 'Eb', 'E', 'F', 'Gb', 'G', 'Ab', 'A', 'Bb', 'B']; const pcs = ['C', 'Db', 'D', 'Eb', 'E', 'F', 'Gb', 'G', 'Ab', 'A', 'Bb', 'B'];
/** /**
* @deprecated only used in workshop (first-notes) * @deprecated does not appear to be referenced or invoked anywhere in the codebase
* @noAutocomplete * @noAutocomplete
*/ */
export const midi2note = (n) => { export const midi2note = (n) => {
@@ -215,59 +215,3 @@ export const splitAt = function (index, value) {
export const zipWith = (f, xs, ys) => xs.map((n, i) => f(n, ys[i])); export const zipWith = (f, xs, ys) => xs.map((n, i) => f(n, ys[i]));
export const clamp = (num, min, max) => Math.min(Math.max(num, min), max); export const clamp = (num, min, max) => Math.min(Math.max(num, min), max);
/* solmization, not used yet */
const solfeggio = ['Do', 'Reb', 'Re', 'Mib', 'Mi', 'Fa', 'Solb', 'Sol', 'Lab', 'La', 'Sib', 'Si']; /*solffegio notes*/
const indian = [
'Sa',
'Re',
'Ga',
'Ma',
'Pa',
'Dha',
'Ni',
]; /*indian musical notes, seems like they do not use flats or sharps*/
const german = ['C', 'Db', 'D', 'Eb', 'E', 'F', 'Gb', 'G', 'Ab', 'A', 'Hb', 'H']; /*german & dutch musical notes*/
const byzantine = [
'Ni',
'Pab',
'Pa',
'Voub',
'Vou',
'Ga',
'Dib',
'Di',
'Keb',
'Ke',
'Zob',
'Zo',
]; /*byzantine musical notes*/
const japanese = [
'I',
'Ro',
'Ha',
'Ni',
'Ho',
'He',
'To',
]; /*traditional japanese musical notes, seems like they do not use falts or sharps*/
const english = ['C', 'Db', 'D', 'Eb', 'E', 'F', 'Gb', 'G', 'Ab', 'A', 'Bb', 'B'];
export const sol2note = (n, notation = 'letters') => {
const pc =
notation === 'solfeggio'
? solfeggio /*check if its is any of the following*/
: notation === 'indian'
? indian
: notation === 'german'
? german
: notation === 'byzantine'
? byzantine
: notation === 'japanese'
? japanese
: english; /*if not use standard version*/
const note = pc[n % 12]; /*calculating the midi value to the note*/
const oct = Math.floor(n / 12) - 1;
return note + oct;
};
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@strudel.cycles/csound", "name": "@strudel.cycles/csound",
"version": "0.8.0", "version": "0.7.1",
"description": "csound bindings for strudel", "description": "csound bindings for strudel",
"main": "index.mjs", "main": "index.mjs",
"publishConfig": { "publishConfig": {
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@strudel.cycles/eval", "name": "@strudel.cycles/eval",
"version": "0.8.0", "version": "0.7.1",
"description": "Code evaluator for strudel", "description": "Code evaluator for strudel",
"main": "index.mjs", "main": "index.mjs",
"publishConfig": { "publishConfig": {
+1 -1
View File
@@ -105,7 +105,7 @@ Pattern.prototype.midi = function (output) {
hap.ensureObjectValue(); hap.ensureObjectValue();
// calculate time // calculate time
const timingOffset = WebMidi.time - getAudioContext().getOutputTimestamp().contextTime * 1000; const timingOffset = WebMidi.time - getAudioContext().currentTime * 1000;
time = time * 1000 + timingOffset; time = time * 1000 + timingOffset;
// destructure value // destructure value
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@strudel.cycles/midi", "name": "@strudel.cycles/midi",
"version": "0.8.0", "version": "0.7.1",
"description": "Midi API for strudel", "description": "Midi API for strudel",
"main": "index.mjs", "main": "index.mjs",
"publishConfig": { "publishConfig": {
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@strudel.cycles/mini", "name": "@strudel.cycles/mini",
"version": "0.8.2", "version": "0.8.1",
"description": "Mini notation for strudel", "description": "Mini notation for strudel",
"main": "index.mjs", "main": "index.mjs",
"type": "module", "type": "module",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@strudel.cycles/osc", "name": "@strudel.cycles/osc",
"version": "0.8.0", "version": "0.7.1",
"description": "OSC messaging for strudel", "description": "OSC messaging for strudel",
"main": "osc.mjs", "main": "osc.mjs",
"publishConfig": { "publishConfig": {
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@strudel.cycles/react", "name": "@strudel.cycles/react",
"version": "0.8.0", "version": "0.7.1",
"description": "React components for strudel", "description": "React components for strudel",
"main": "src/index.js", "main": "src/index.js",
"publishConfig": { "publishConfig": {
+13 -25
View File
@@ -2,12 +2,12 @@ import React, { useMemo } from 'react';
import _CodeMirror from '@uiw/react-codemirror'; import _CodeMirror from '@uiw/react-codemirror';
import { EditorView, Decoration } from '@codemirror/view'; import { EditorView, Decoration } from '@codemirror/view';
import { StateField, StateEffect } from '@codemirror/state'; import { StateField, StateEffect } from '@codemirror/state';
import { javascript, javascriptLanguage } from '@codemirror/lang-javascript'; import { javascript } from '@codemirror/lang-javascript';
import strudelTheme from '../themes/strudel-theme'; import strudelTheme from '../themes/strudel-theme';
import './style.css'; import './style.css';
import { useCallback } from 'react'; import { useCallback } from 'react';
import { autocompletion } from '@codemirror/autocomplete'; import { autocompletion } from '@codemirror/autocomplete';
import { strudelAutocomplete } from './Autocomplete'; //import { strudelAutocomplete } from './Autocomplete';
import { vim } from '@replit/codemirror-vim'; import { vim } from '@replit/codemirror-vim';
import { emacs } from '@replit/codemirror-emacs'; import { emacs } from '@replit/codemirror-emacs';
@@ -88,7 +88,14 @@ const highlightField = StateField.define({
provide: (f) => EditorView.decorations.from(f), provide: (f) => EditorView.decorations.from(f),
}); });
const staticExtensions = [javascript(), highlightField, flashField]; const staticExtensions = [
javascript(),
highlightField,
flashField,
// javascriptLanguage.data.of({ autocomplete: strudelAutocomplete }),
// autocompletion({ override: [strudelAutocomplete] }),
autocompletion({ override: [] }), // wait for https://github.com/uiwjs/react-codemirror/pull/458
];
export default function CodeMirror({ export default function CodeMirror({
value, value,
@@ -98,8 +105,6 @@ export default function CodeMirror({
theme, theme,
keybindings, keybindings,
isLineNumbersDisplayed, isLineNumbersDisplayed,
isAutoCompletionEnabled,
isLineWrappingEnabled,
fontSize = 18, fontSize = 18,
fontFamily = 'monospace', fontFamily = 'monospace',
options, options,
@@ -111,14 +116,12 @@ export default function CodeMirror({
}, },
[onChange], [onChange],
); );
const handleOnCreateEditor = useCallback( const handleOnCreateEditor = useCallback(
(view) => { (view) => {
onViewChanged?.(view); onViewChanged?.(view);
}, },
[onViewChanged], [onViewChanged],
); );
const handleOnUpdate = useCallback( const handleOnUpdate = useCallback(
(viewUpdate) => { (viewUpdate) => {
if (viewUpdate.selectionSet && onSelectionChange) { if (viewUpdate.selectionSet && onSelectionChange) {
@@ -127,31 +130,16 @@ export default function CodeMirror({
}, },
[onSelectionChange], [onSelectionChange],
); );
const extensions = useMemo(() => { const extensions = useMemo(() => {
let _extensions = [...staticExtensions];
let bindings = { let bindings = {
vim, vim,
emacs, emacs,
}; };
if (bindings[keybindings]) { if (bindings[keybindings]) {
_extensions.push(bindings[keybindings]()); return [...staticExtensions, bindings[keybindings]()];
} }
return staticExtensions;
if (isAutoCompletionEnabled) { }, [keybindings]);
_extensions.push(javascriptLanguage.data.of({ autocomplete: strudelAutocomplete }));
} else {
_extensions.push(autocompletion({ override: [] }));
}
if (isLineWrappingEnabled) {
_extensions.push(EditorView.lineWrapping);
}
return _extensions;
}, [keybindings, isAutoCompletionEnabled, isLineWrappingEnabled]);
return ( return (
<div style={{ fontSize, fontFamily }} className="w-full"> <div style={{ fontSize, fontFamily }} className="w-full">
<_CodeMirror <_CodeMirror
-4
View File
@@ -24,7 +24,3 @@
.cm-theme-light { .cm-theme-light {
width: 100%; width: 100%;
} }
footer {
z-index: 0 !important;
}
+1 -1
View File
@@ -17,7 +17,7 @@ function useHighlighting({ view, pattern, active, getTime }) {
const begin = Math.max(lastEnd.current ?? audioTime, audioTime - 1 / 10, -0.01); // negative time seems buggy const begin = Math.max(lastEnd.current ?? audioTime, audioTime - 1 / 10, -0.01); // negative time seems buggy
const span = [round(begin), round(audioTime + 1 / 60)]; const span = [round(begin), round(audioTime + 1 / 60)];
lastEnd.current = span[1]; lastEnd.current = span[1];
highlights.current = highlights.current.filter((hap) => hap.endClipped > audioTime); // keep only highlights that are still active highlights.current = highlights.current.filter((hap) => hap.whole.end > audioTime); // keep only highlights that are still active
const haps = pattern.queryArc(...span).filter((hap) => hap.hasOnset()); const haps = pattern.queryArc(...span).filter((hap) => hap.hasOnset());
highlights.current = highlights.current.concat(haps); // add potential new onsets highlights.current = highlights.current.concat(haps); // add potential new onsets
view.dispatch({ effects: setHighlights.of({ haps: highlights.current }) }); // highlight all still active + new active haps view.dispatch({ effects: setHighlights.of({ haps: highlights.current }) }); // highlight all still active + new active haps
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@strudel.cycles/serial", "name": "@strudel.cycles/serial",
"version": "0.8.0", "version": "0.7.1",
"description": "Webserial API for strudel", "description": "Webserial API for strudel",
"main": "serial.mjs", "main": "serial.mjs",
"publishConfig": { "publishConfig": {
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@strudel.cycles/soundfonts", "name": "@strudel.cycles/soundfonts",
"version": "0.8.2", "version": "0.8.1",
"description": "Soundsfont support for strudel", "description": "Soundsfont support for strudel",
"main": "index.mjs", "main": "index.mjs",
"publishConfig": { "publishConfig": {
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@strudel.cycles/tonal", "name": "@strudel.cycles/tonal",
"version": "0.8.2", "version": "0.8.1",
"description": "Tonal functions for strudel", "description": "Tonal functions for strudel",
"main": "index.mjs", "main": "index.mjs",
"publishConfig": { "publishConfig": {
+1 -1
View File
@@ -145,7 +145,7 @@ export const scaleTranspose = register('scaleTranspose', function (offset /* : n
export const scale = register('scale', function (scale, pat) { export const scale = register('scale', function (scale, pat) {
// Supports ':' list syntax in mininotation // Supports ':' list syntax in mininotation
if (Array.isArray(scale)) { if (Array.isArray(scale)) {
scale = scale.flat().join(' '); scale = scale.join(' ');
} }
return pat.withHap((hap) => { return pat.withHap((hap) => {
const isObject = typeof hap.value === 'object'; const isObject = typeof hap.value === 'object';
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@strudel.cycles/tone", "name": "@strudel.cycles/tone",
"version": "0.8.0", "version": "0.7.1",
"description": "Tone.js API for strudel", "description": "Tone.js API for strudel",
"main": "index.mjs", "main": "index.mjs",
"type": "module", "type": "module",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@strudel.cycles/transpiler", "name": "@strudel.cycles/transpiler",
"version": "0.8.2", "version": "0.8.1",
"description": "Transpiler for strudel user code. Converts syntactically correct but semantically meaningless JS into evaluatable strudel code.", "description": "Transpiler for strudel user code. Converts syntactically correct but semantically meaningless JS into evaluatable strudel code.",
"main": "index.mjs", "main": "index.mjs",
"publishConfig": { "publishConfig": {
+3 -3
View File
@@ -1,6 +1,6 @@
{ {
"name": "@strudel/web", "name": "@strudel/web",
"version": "0.8.3", "version": "0.8.2",
"description": "Easy to setup, opiniated bundle of Strudel for the browser.", "description": "Easy to setup, opiniated bundle of Strudel for the browser.",
"main": "web.mjs", "main": "web.mjs",
"publishConfig": { "publishConfig": {
@@ -34,10 +34,10 @@
"homepage": "https://github.com/tidalcycles/strudel#readme", "homepage": "https://github.com/tidalcycles/strudel#readme",
"dependencies": { "dependencies": {
"@strudel.cycles/core": "workspace:*", "@strudel.cycles/core": "workspace:*",
"@strudel.cycles/webaudio": "workspace:*",
"@strudel.cycles/mini": "workspace:*", "@strudel.cycles/mini": "workspace:*",
"@strudel.cycles/tonal": "workspace:*", "@strudel.cycles/tonal": "workspace:*",
"@strudel.cycles/transpiler": "workspace:*", "@strudel.cycles/transpiler": "workspace:*"
"@strudel.cycles/webaudio": "workspace:*"
}, },
"devDependencies": { "devDependencies": {
"vite": "^4.3.3" "vite": "^4.3.3"
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@strudel.cycles/webaudio", "name": "@strudel.cycles/webaudio",
"version": "0.8.2", "version": "0.8.1",
"description": "Web Audio helpers for Strudel", "description": "Web Audio helpers for Strudel",
"main": "index.mjs", "main": "index.mjs",
"type": "module", "type": "module",
+33 -65
View File
@@ -21,7 +21,7 @@ function humanFileSize(bytes, si) {
return bytes.toFixed(1) + ' ' + units[u]; return bytes.toFixed(1) + ' ' + units[u];
} }
export const getSampleBufferSource = async (s, n, note, speed, freq, bank, resolveUrl) => { export const getSampleBufferSource = async (s, n, note, speed, freq, bank) => {
let transpose = 0; let transpose = 0;
if (freq !== undefined && note !== undefined) { if (freq !== undefined && note !== undefined) {
logger('[sampler] hap has note and freq. ignoring note', 'warning'); logger('[sampler] hap has note and freq. ignoring note', 'warning');
@@ -45,9 +45,6 @@ export const getSampleBufferSource = async (s, n, note, speed, freq, bank, resol
transpose = -midiDiff(closest); // semitones to repitch transpose = -midiDiff(closest); // semitones to repitch
sampleUrl = bank[closest][n % bank[closest].length]; sampleUrl = bank[closest][n % bank[closest].length];
} }
if (resolveUrl) {
sampleUrl = await resolveUrl(sampleUrl);
}
let buffer = await loadBuffer(sampleUrl, ac, s, n); let buffer = await loadBuffer(sampleUrl, ac, s, n);
if (speed < 0) { if (speed < 0) {
// should this be cached? // should this be cached?
@@ -94,46 +91,6 @@ export const getLoadedBuffer = (url) => {
return bufferCache[url]; return bufferCache[url];
}; };
export const processSampleMap = (sampleMap, fn, baseUrl = sampleMap._base || '') => {
return Object.entries(sampleMap).forEach(([key, value]) => {
if (typeof value === 'string') {
value = [value];
}
if (typeof value !== 'object') {
throw new Error('wrong sample map format for ' + key);
}
baseUrl = value._base || baseUrl;
const replaceUrl = (v) => (baseUrl + v).replace('github:', 'https://raw.githubusercontent.com/');
if (Array.isArray(value)) {
//return [key, value.map(replaceUrl)];
value = value.map(replaceUrl);
} else {
// must be object
value = Object.fromEntries(
Object.entries(value).map(([note, samples]) => {
return [note, (typeof samples === 'string' ? [samples] : samples).map(replaceUrl)];
}),
);
}
fn(key, value);
});
};
// allows adding a custom url prefix handler
// for example, it is used by the desktop app to load samples starting with '~/music'
let resourcePrefixHandlers = {};
export function registerSamplesPrefix(prefix, resolve) {
resourcePrefixHandlers[prefix] = resolve;
}
// finds a prefix handler for the given url (if any)
function getSamplesPrefixHandler(url) {
const handler = Object.entries(resourcePrefixHandlers).find(([key]) => url.startsWith(key));
if (handler) {
return handler[1];
}
return;
}
/** /**
* Loads a collection of samples to use with `s` * Loads a collection of samples to use with `s`
* @example * @example
@@ -150,11 +107,6 @@ function getSamplesPrefixHandler(url) {
export const samples = async (sampleMap, baseUrl = sampleMap._base || '', options = {}) => { export const samples = async (sampleMap, baseUrl = sampleMap._base || '', options = {}) => {
if (typeof sampleMap === 'string') { if (typeof sampleMap === 'string') {
// check if custom prefix handler
const handler = getSamplesPrefixHandler(sampleMap);
if (handler) {
return handler(sampleMap);
}
if (sampleMap.startsWith('github:')) { if (sampleMap.startsWith('github:')) {
let [_, path] = sampleMap.split('github:'); let [_, path] = sampleMap.split('github:');
path = path.endsWith('/') ? path.slice(0, -1) : path; path = path.endsWith('/') ? path.slice(0, -1) : path;
@@ -178,23 +130,39 @@ export const samples = async (sampleMap, baseUrl = sampleMap._base || '', option
}); });
} }
const { prebake, tag } = options; const { prebake, tag } = options;
processSampleMap( Object.entries(sampleMap).forEach(([key, value]) => {
sampleMap, if (typeof value === 'string') {
(key, value) => value = [value];
registerSound(key, (t, hapValue, onended) => onTriggerSample(t, hapValue, onended, value), { }
type: 'sample', if (typeof value !== 'object') {
samples: value, throw new Error('wrong sample map format for ' + key);
baseUrl, }
prebake, baseUrl = value._base || baseUrl;
tag, const replaceUrl = (v) => (baseUrl + v).replace('github:', 'https://raw.githubusercontent.com/');
}), if (Array.isArray(value)) {
baseUrl, //return [key, value.map(replaceUrl)];
); value = value.map(replaceUrl);
} else {
// must be object
value = Object.fromEntries(
Object.entries(value).map(([note, samples]) => {
return [note, (typeof samples === 'string' ? [samples] : samples).map(replaceUrl)];
}),
);
}
registerSound(key, (t, hapValue, onended) => onTriggerSample(t, hapValue, onended, value), {
type: 'sample',
samples: value,
baseUrl,
prebake,
tag,
});
});
}; };
const cutGroups = []; const cutGroups = [];
export async function onTriggerSample(t, value, onended, bank, resolveUrl) { export async function onTriggerSample(t, value, onended, bank) {
const { const {
s, s,
freq, freq,
@@ -202,7 +170,7 @@ export async function onTriggerSample(t, value, onended, bank, resolveUrl) {
nudge = 0, // TODO: is this in seconds? nudge = 0, // TODO: is this in seconds?
cut, cut,
loop, loop,
clip = undefined, // if 1, samples will be cut off when the hap ends clip = 0, // if 1, samples will be cut off when the hap ends
n = 0, n = 0,
note, note,
speed = 1, // sample playback speed speed = 1, // sample playback speed
@@ -220,7 +188,7 @@ export async function onTriggerSample(t, value, onended, bank, resolveUrl) {
//const soundfont = getSoundfontKey(s); //const soundfont = getSoundfontKey(s);
const time = t + nudge; const time = t + nudge;
const bufferSource = await getSampleBufferSource(s, n, note, speed, freq, bank, resolveUrl); const bufferSource = await getSampleBufferSource(s, n, note, speed, freq, bank);
// asny stuff above took too long? // asny stuff above took too long?
if (ac.currentTime > t) { if (ac.currentTime > t) {
@@ -264,7 +232,7 @@ export async function onTriggerSample(t, value, onended, bank, resolveUrl) {
out.disconnect(); out.disconnect();
onended(); onended();
}; };
const stop = (endTime, playWholeBuffer = clip === undefined) => { const stop = (endTime, playWholeBuffer = !clip) => {
let releaseTime = endTime; let releaseTime = endTime;
if (playWholeBuffer) { if (playWholeBuffer) {
releaseTime = t + (end - begin) * bufferDuration; releaseTime = t + (end - begin) * bufferDuration;
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@strudel.cycles/webdirt", "name": "@strudel.cycles/webdirt",
"version": "0.8.0", "version": "0.7.1",
"description": "WebDirt integration for Strudel", "description": "WebDirt integration for Strudel",
"main": "index.mjs", "main": "index.mjs",
"type": "module", "type": "module",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@strudel.cycles/xen", "name": "@strudel.cycles/xen",
"version": "0.8.0", "version": "0.7.1",
"description": "Xenharmonic API for strudel", "description": "Xenharmonic API for strudel",
"main": "index.mjs", "main": "index.mjs",
"publishConfig": { "publishConfig": {
+25 -215
View File
@@ -28,10 +28,10 @@ importers:
dependency-tree: dependency-tree:
specifier: ^9.0.0 specifier: ^9.0.0
version: 9.0.0 version: 9.0.0
vitest:
specifier: ^0.28.0
version: 0.28.0(@vitest/ui@0.28.0)
devDependencies: devDependencies:
'@tauri-apps/cli':
specifier: ^1.4.0
version: 1.4.0
'@vitest/ui': '@vitest/ui':
specifier: ^0.28.0 specifier: ^0.28.0
version: 0.28.0 version: 0.28.0
@@ -65,9 +65,6 @@ importers:
rollup-plugin-visualizer: rollup-plugin-visualizer:
specifier: ^5.8.1 specifier: ^5.8.1
version: 5.9.0 version: 5.9.0
vitest:
specifier: ^0.28.0
version: 0.28.0(@vitest/ui@0.28.0)
packages/codemirror: packages/codemirror:
dependencies: dependencies:
@@ -95,7 +92,7 @@ importers:
devDependencies: devDependencies:
vite: vite:
specifier: ^4.3.3 specifier: ^4.3.3
version: 4.3.3(@types/node@18.16.3) version: 4.3.3(@types/node@18.11.18)
packages/core: packages/core:
dependencies: dependencies:
@@ -105,7 +102,7 @@ importers:
devDependencies: devDependencies:
vite: vite:
specifier: ^4.3.3 specifier: ^4.3.3
version: 4.3.3(@types/node@18.16.3) version: 4.3.3(@types/node@18.11.18)
vitest: vitest:
specifier: ^0.28.0 specifier: ^0.28.0
version: 0.28.0(@vitest/ui@0.28.0) version: 0.28.0(@vitest/ui@0.28.0)
@@ -130,7 +127,7 @@ importers:
devDependencies: devDependencies:
vite: vite:
specifier: ^4.3.3 specifier: ^4.3.3
version: 4.3.3(@types/node@18.16.3) version: 4.3.3(@types/node@18.11.18)
packages/core/examples/vite-vanilla-repl-cm6: packages/core/examples/vite-vanilla-repl-cm6:
dependencies: dependencies:
@@ -158,7 +155,7 @@ importers:
devDependencies: devDependencies:
vite: vite:
specifier: ^4.3.2 specifier: ^4.3.2
version: 4.3.3(@types/node@18.16.3) version: 4.3.3(@types/node@18.11.18)
packages/csound: packages/csound:
dependencies: dependencies:
@@ -174,7 +171,7 @@ importers:
devDependencies: devDependencies:
vite: vite:
specifier: ^4.3.3 specifier: ^4.3.3
version: 4.3.3(@types/node@18.16.3) version: 4.3.3(@types/node@18.11.18)
packages/embed: {} packages/embed: {}
@@ -207,7 +204,7 @@ importers:
version: link:../mini version: link:../mini
vite: vite:
specifier: ^4.3.3 specifier: ^4.3.3
version: 4.3.3(@types/node@18.16.3) version: 4.3.3(@types/node@18.11.18)
vitest: vitest:
specifier: ^0.28.0 specifier: ^0.28.0
version: 0.28.0(@vitest/ui@0.28.0) version: 0.28.0(@vitest/ui@0.28.0)
@@ -226,7 +223,7 @@ importers:
devDependencies: devDependencies:
vite: vite:
specifier: ^4.3.3 specifier: ^4.3.3
version: 4.3.3(@types/node@18.16.3) version: 4.3.3(@types/node@18.11.18)
packages/mini: packages/mini:
dependencies: dependencies:
@@ -239,7 +236,7 @@ importers:
version: 3.0.2 version: 3.0.2
vite: vite:
specifier: ^4.3.3 specifier: ^4.3.3
version: 4.3.3(@types/node@18.16.3) version: 4.3.3(@types/node@18.11.18)
vitest: vitest:
specifier: ^0.28.0 specifier: ^0.28.0
version: 0.28.0(@vitest/ui@0.28.0) version: 0.28.0(@vitest/ui@0.28.0)
@@ -258,7 +255,7 @@ importers:
version: 5.8.1 version: 5.8.1
vite: vite:
specifier: ^4.3.3 specifier: ^4.3.3
version: 4.3.3(@types/node@18.16.3) version: 4.3.3(@types/node@18.11.18)
packages/react: packages/react:
dependencies: dependencies:
@@ -328,7 +325,7 @@ importers:
version: 3.3.2 version: 3.3.2
vite: vite:
specifier: ^4.3.3 specifier: ^4.3.3
version: 4.3.3(@types/node@18.16.3) version: 4.3.3(@types/node@18.11.18)
packages/react/examples/nano-repl: packages/react/examples/nano-repl:
dependencies: dependencies:
@@ -383,7 +380,7 @@ importers:
version: 3.3.2 version: 3.3.2
vite: vite:
specifier: ^4.3.3 specifier: ^4.3.3
version: 4.3.3(@types/node@18.16.3) version: 4.3.3(@types/node@18.11.18)
packages/serial: packages/serial:
dependencies: dependencies:
@@ -393,7 +390,7 @@ importers:
devDependencies: devDependencies:
vite: vite:
specifier: ^4.3.3 specifier: ^4.3.3
version: 4.3.3(@types/node@18.16.3) version: 4.3.3(@types/node@18.11.18)
packages/soundfonts: packages/soundfonts:
dependencies: dependencies:
@@ -415,7 +412,7 @@ importers:
version: 3.3.1 version: 3.3.1
vite: vite:
specifier: ^4.3.3 specifier: ^4.3.3
version: 4.3.3(@types/node@18.16.3) version: 4.3.3(@types/node@18.11.18)
packages/tonal: packages/tonal:
dependencies: dependencies:
@@ -434,7 +431,7 @@ importers:
devDependencies: devDependencies:
vite: vite:
specifier: ^4.3.3 specifier: ^4.3.3
version: 4.3.3(@types/node@18.16.3) version: 4.3.3(@types/node@18.11.18)
vitest: vitest:
specifier: ^0.28.0 specifier: ^0.28.0
version: 0.28.0(@vitest/ui@0.28.0) version: 0.28.0(@vitest/ui@0.28.0)
@@ -450,7 +447,7 @@ importers:
devDependencies: devDependencies:
vite: vite:
specifier: ^4.3.3 specifier: ^4.3.3
version: 4.3.3(@types/node@18.16.3) version: 4.3.3(@types/node@18.11.18)
vitest: vitest:
specifier: ^0.28.0 specifier: ^0.28.0
version: 0.28.0(@vitest/ui@0.28.0) version: 0.28.0(@vitest/ui@0.28.0)
@@ -472,7 +469,7 @@ importers:
devDependencies: devDependencies:
vite: vite:
specifier: ^4.3.3 specifier: ^4.3.3
version: 4.3.3(@types/node@18.16.3) version: 4.3.3(@types/node@18.11.18)
vitest: vitest:
specifier: ^0.28.0 specifier: ^0.28.0
version: 0.28.0(@vitest/ui@0.28.0) version: 0.28.0(@vitest/ui@0.28.0)
@@ -497,7 +494,7 @@ importers:
devDependencies: devDependencies:
vite: vite:
specifier: ^4.3.3 specifier: ^4.3.3
version: 4.3.3(@types/node@18.16.3) version: 4.3.3(@types/node@18.11.18)
packages/web/examples/repl-example: packages/web/examples/repl-example:
dependencies: dependencies:
@@ -507,7 +504,7 @@ importers:
devDependencies: devDependencies:
vite: vite:
specifier: ^4.3.2 specifier: ^4.3.2
version: 4.3.3(@types/node@18.16.3) version: 4.3.3(@types/node@18.11.18)
packages/webaudio: packages/webaudio:
dependencies: dependencies:
@@ -520,7 +517,7 @@ importers:
devDependencies: devDependencies:
vite: vite:
specifier: ^4.3.3 specifier: ^4.3.3
version: 4.3.3(@types/node@18.16.3) version: 4.3.3(@types/node@18.11.18)
packages/webdirt: packages/webdirt:
dependencies: dependencies:
@@ -536,7 +533,7 @@ importers:
devDependencies: devDependencies:
vite: vite:
specifier: ^4.3.3 specifier: ^4.3.3
version: 4.3.3(@types/node@18.16.3) version: 4.3.3(@types/node@18.11.18)
vitest: vitest:
specifier: ^0.28.0 specifier: ^0.28.0
version: 0.28.0(@vitest/ui@0.28.0) version: 0.28.0(@vitest/ui@0.28.0)
@@ -549,7 +546,7 @@ importers:
devDependencies: devDependencies:
vite: vite:
specifier: ^4.3.3 specifier: ^4.3.3
version: 4.3.3(@types/node@18.16.3) version: 4.3.3(@types/node@18.11.18)
vitest: vitest:
specifier: ^0.28.0 specifier: ^0.28.0
version: 0.28.0(@vitest/ui@0.28.0) version: 0.28.0(@vitest/ui@0.28.0)
@@ -3540,7 +3537,6 @@ packages:
/@polka/url@1.0.0-next.21: /@polka/url@1.0.0-next.21:
resolution: {integrity: sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==} resolution: {integrity: sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==}
dev: true
/@proload/core@0.3.3: /@proload/core@0.3.3:
resolution: {integrity: sha512-7dAFWsIK84C90AMl24+N/ProHKm4iw0akcnoKjRvbfHifJZBLhaDsDus1QJmhG12lXj4e/uB/8mB/0aduCW+NQ==} resolution: {integrity: sha512-7dAFWsIK84C90AMl24+N/ProHKm4iw0akcnoKjRvbfHifJZBLhaDsDus1QJmhG12lXj4e/uB/8mB/0aduCW+NQ==}
@@ -3774,113 +3770,6 @@ packages:
tailwindcss: 3.3.2 tailwindcss: 3.3.2
dev: false dev: false
/@tauri-apps/cli-darwin-arm64@1.4.0:
resolution: {integrity: sha512-nA/ml0SfUt6/CYLVbHmT500Y+ijqsuv5+s9EBnVXYSLVg9kbPUZJJHluEYK+xKuOj6xzyuT/+rZFMRapmJD3jQ==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [darwin]
requiresBuild: true
dev: true
optional: true
/@tauri-apps/cli-darwin-x64@1.4.0:
resolution: {integrity: sha512-ov/F6Zr+dg9B0PtRu65stFo2G0ow2TUlneqYYrkj+vA3n+moWDHfVty0raDjMLQbQt3rv3uayFMXGPMgble9OA==}
engines: {node: '>= 10'}
cpu: [x64]
os: [darwin]
requiresBuild: true
dev: true
optional: true
/@tauri-apps/cli-linux-arm-gnueabihf@1.4.0:
resolution: {integrity: sha512-zwjbiMncycXDV7doovymyKD7sCg53ouAmfgpUqEBOTY3vgBi9TwijyPhJOqoG5vUVWhouNBC08akGmE4dja15g==}
engines: {node: '>= 10'}
cpu: [arm]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@tauri-apps/cli-linux-arm64-gnu@1.4.0:
resolution: {integrity: sha512-5MCBcziqXC72mMXnkZU68mutXIR6zavDxopArE2gQtK841IlE06bIgtLi0kUUhlFJk2nhPRgiDgdLbrPlyt7fw==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@tauri-apps/cli-linux-arm64-musl@1.4.0:
resolution: {integrity: sha512-7J3pRB6n6uNYgIfCeKt2Oz8J7oSaz2s8GGFRRH2HPxuTHrBNCinzVYm68UhVpJrL3bnGkU0ziVZLsW/iaOGfUg==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@tauri-apps/cli-linux-x64-gnu@1.4.0:
resolution: {integrity: sha512-Zh5gfAJxOv5AVWxcwuueaQ2vIAhlg0d6nZui6nMyfIJ8dbf3aZQ5ZzP38sYow5h/fbvgL+3GSQxZRBIa3c2E1w==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@tauri-apps/cli-linux-x64-musl@1.4.0:
resolution: {integrity: sha512-OLAYoICU3FaYiTdBsI+lQTKnDHeMmFMXIApN0M+xGiOkoIOQcV9CConMPjgmJQ867+NHRNgUGlvBEAh9CiJodQ==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@tauri-apps/cli-win32-arm64-msvc@1.4.0:
resolution: {integrity: sha512-gZ05GENFbI6CB5MlOUsLlU0kZ9UtHn9riYtSXKT6MYs8HSPRffPHaHSL0WxsJweWh9nR5Hgh/TUU8uW3sYCzCg==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [win32]
requiresBuild: true
dev: true
optional: true
/@tauri-apps/cli-win32-ia32-msvc@1.4.0:
resolution: {integrity: sha512-JsetT/lTx/Zq98eo8T5CiRyF1nKeX04RO8JlJrI3ZOYsZpp/A5RJvMd/szQ17iOzwiHdge+tx7k2jHysR6oBlQ==}
engines: {node: '>= 10'}
cpu: [ia32]
os: [win32]
requiresBuild: true
dev: true
optional: true
/@tauri-apps/cli-win32-x64-msvc@1.4.0:
resolution: {integrity: sha512-z8Olcnwp5aYhzqUAarFjqF+oELCjuYWnB2HAJHlfsYNfDCAORY5kct3Fklz8PSsubC3U2EugWn8n42DwnThurg==}
engines: {node: '>= 10'}
cpu: [x64]
os: [win32]
requiresBuild: true
dev: true
optional: true
/@tauri-apps/cli@1.4.0:
resolution: {integrity: sha512-VXYr2i2iVFl98etQSQsqLzXgX96bnWiNZd1YADgatqwy/qecbd6Kl5ZAPB5R4ynsgE8A1gU7Fbzh7dCEQYFfmA==}
engines: {node: '>= 10'}
hasBin: true
optionalDependencies:
'@tauri-apps/cli-darwin-arm64': 1.4.0
'@tauri-apps/cli-darwin-x64': 1.4.0
'@tauri-apps/cli-linux-arm-gnueabihf': 1.4.0
'@tauri-apps/cli-linux-arm64-gnu': 1.4.0
'@tauri-apps/cli-linux-arm64-musl': 1.4.0
'@tauri-apps/cli-linux-x64-gnu': 1.4.0
'@tauri-apps/cli-linux-x64-musl': 1.4.0
'@tauri-apps/cli-win32-arm64-msvc': 1.4.0
'@tauri-apps/cli-win32-ia32-msvc': 1.4.0
'@tauri-apps/cli-win32-x64-msvc': 1.4.0
dev: true
/@tonaljs/abc-notation@4.8.0: /@tonaljs/abc-notation@4.8.0:
resolution: {integrity: sha512-JggT/DW4rMxu+q1WkeACrg52is3acp9zaW4LJmCheFi3CmLa63sy7/6mgKnlScTOvcpAyTcSytu0VbQHRXyBDA==} resolution: {integrity: sha512-JggT/DW4rMxu+q1WkeACrg52is3acp9zaW4LJmCheFi3CmLa63sy7/6mgKnlScTOvcpAyTcSytu0VbQHRXyBDA==}
dependencies: dependencies:
@@ -4095,11 +3984,9 @@ packages:
resolution: {integrity: sha512-frBecisrNGz+F4T6bcc+NLeolfiojh5FxW2klu669+8BARtyQv2C/GkNW6FUodVe4BroGMP/wER/YDGc7rEllw==} resolution: {integrity: sha512-frBecisrNGz+F4T6bcc+NLeolfiojh5FxW2klu669+8BARtyQv2C/GkNW6FUodVe4BroGMP/wER/YDGc7rEllw==}
dependencies: dependencies:
'@types/chai': 4.3.4 '@types/chai': 4.3.4
dev: true
/@types/chai@4.3.4: /@types/chai@4.3.4:
resolution: {integrity: sha512-KnRanxnpfpjUTqTCXslZSEdLfXExwgNxYPdiO2WGUj8+HDjFi8R3k5RVKPeSCzLjCcshCAtVO2QBbVuAV4kTnw==} resolution: {integrity: sha512-KnRanxnpfpjUTqTCXslZSEdLfXExwgNxYPdiO2WGUj8+HDjFi8R3k5RVKPeSCzLjCcshCAtVO2QBbVuAV4kTnw==}
dev: true
/@types/debug@4.1.7: /@types/debug@4.1.7:
resolution: {integrity: sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==} resolution: {integrity: sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==}
@@ -4176,7 +4063,6 @@ packages:
/@types/node@18.11.18: /@types/node@18.11.18:
resolution: {integrity: sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==} resolution: {integrity: sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==}
dev: true
/@types/node@18.16.3: /@types/node@18.16.3:
resolution: {integrity: sha512-OPs5WnnT1xkCBiuQrZA4+YAV4HEJejmHneyraIaxsbev5yCEr6KMwINNFP9wQeFIw8FWcoTqF3vQsa5CDaI+8Q==} resolution: {integrity: sha512-OPs5WnnT1xkCBiuQrZA4+YAV4HEJejmHneyraIaxsbev5yCEr6KMwINNFP9wQeFIw8FWcoTqF3vQsa5CDaI+8Q==}
@@ -4619,7 +4505,7 @@ packages:
'@babel/plugin-transform-react-jsx-self': 7.21.0(@babel/core@7.21.5) '@babel/plugin-transform-react-jsx-self': 7.21.0(@babel/core@7.21.5)
'@babel/plugin-transform-react-jsx-source': 7.19.6(@babel/core@7.21.5) '@babel/plugin-transform-react-jsx-source': 7.19.6(@babel/core@7.21.5)
react-refresh: 0.14.0 react-refresh: 0.14.0
vite: 4.3.3 vite: 4.3.3(@types/node@18.11.18)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
dev: true dev: true
@@ -4630,7 +4516,6 @@ packages:
'@vitest/spy': 0.28.0 '@vitest/spy': 0.28.0
'@vitest/utils': 0.28.0 '@vitest/utils': 0.28.0
chai: 4.3.7 chai: 4.3.7
dev: true
/@vitest/runner@0.28.0: /@vitest/runner@0.28.0:
resolution: {integrity: sha512-SXQO9aubp7Hg4DV4D5DP70wJ/4o0krH1gAPrSt+rhEZQbQvMaBJAHWOxEibwzLkklgoHreaMEvETFILkGQWXww==} resolution: {integrity: sha512-SXQO9aubp7Hg4DV4D5DP70wJ/4o0krH1gAPrSt+rhEZQbQvMaBJAHWOxEibwzLkklgoHreaMEvETFILkGQWXww==}
@@ -4638,13 +4523,11 @@ packages:
'@vitest/utils': 0.28.0 '@vitest/utils': 0.28.0
p-limit: 4.0.0 p-limit: 4.0.0
pathe: 1.1.0 pathe: 1.1.0
dev: true
/@vitest/spy@0.28.0: /@vitest/spy@0.28.0:
resolution: {integrity: sha512-gYBDQIP0QDvxrscl2Id0BTbzLUbuAzFiFur3eHxH9Yt5cM6YCH/kxBrSHhmXTbu92UenLx53Gwq17u5N0zGNDQ==} resolution: {integrity: sha512-gYBDQIP0QDvxrscl2Id0BTbzLUbuAzFiFur3eHxH9Yt5cM6YCH/kxBrSHhmXTbu92UenLx53Gwq17u5N0zGNDQ==}
dependencies: dependencies:
tinyspy: 1.0.2 tinyspy: 1.0.2
dev: true
/@vitest/ui@0.28.0: /@vitest/ui@0.28.0:
resolution: {integrity: sha512-ihcVEx8t1gZXMboPGcIvoHk+PxiW5USxDMqnZOeUVIUm+XrRCtoJ96YDXdeR6MyPWeYLBPXfBWSxp5gMqoNSkw==} resolution: {integrity: sha512-ihcVEx8t1gZXMboPGcIvoHk+PxiW5USxDMqnZOeUVIUm+XrRCtoJ96YDXdeR6MyPWeYLBPXfBWSxp5gMqoNSkw==}
@@ -4654,7 +4537,6 @@ packages:
pathe: 1.1.0 pathe: 1.1.0
picocolors: 1.0.0 picocolors: 1.0.0
sirv: 2.0.2 sirv: 2.0.2
dev: true
/@vitest/utils@0.28.0: /@vitest/utils@0.28.0:
resolution: {integrity: sha512-Dt+jDZbwriZWzJ5Hi9nAUnz9IPgNb+ACE96tWiXPp/u9NmCYWIWcuNoUOYS8HQyGFz31GiNYGvaZ4ZEDjAgi1g==} resolution: {integrity: sha512-Dt+jDZbwriZWzJ5Hi9nAUnz9IPgNb+ACE96tWiXPp/u9NmCYWIWcuNoUOYS8HQyGFz31GiNYGvaZ4ZEDjAgi1g==}
@@ -4664,7 +4546,6 @@ packages:
loupe: 2.3.6 loupe: 2.3.6
picocolors: 1.0.0 picocolors: 1.0.0
pretty-format: 27.5.1 pretty-format: 27.5.1
dev: true
/@vscode/emmet-helper@2.8.6: /@vscode/emmet-helper@2.8.6:
resolution: {integrity: sha512-IIB8jbiKy37zN8bAIHx59YmnIelY78CGHtThnibD/d3tQOKRY83bYVi9blwmZVUZh6l9nfkYH3tvReaiNxY9EQ==} resolution: {integrity: sha512-IIB8jbiKy37zN8bAIHx59YmnIelY78CGHtThnibD/d3tQOKRY83bYVi9blwmZVUZh6l9nfkYH3tvReaiNxY9EQ==}
@@ -4730,7 +4611,6 @@ packages:
/acorn-walk@8.2.0: /acorn-walk@8.2.0:
resolution: {integrity: sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==} resolution: {integrity: sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==}
engines: {node: '>=0.4.0'} engines: {node: '>=0.4.0'}
dev: true
/acorn@8.8.2: /acorn@8.8.2:
resolution: {integrity: sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==} resolution: {integrity: sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==}
@@ -4855,7 +4735,6 @@ packages:
/ansi-styles@5.2.0: /ansi-styles@5.2.0:
resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==}
engines: {node: '>=10'} engines: {node: '>=10'}
dev: true
/ansi-styles@6.2.1: /ansi-styles@6.2.1:
resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==}
@@ -5005,7 +4884,6 @@ packages:
/assertion-error@1.1.0: /assertion-error@1.1.0:
resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==}
dev: true
/ast-module-types@3.0.0: /ast-module-types@3.0.0:
resolution: {integrity: sha512-CMxMCOCS+4D+DkOQfuZf+vLrSEmY/7xtORwdxs4wtcC1wVgvk2MqFFTwQCFhvWsI4KPU9lcWXPI8DgRiz+xetQ==} resolution: {integrity: sha512-CMxMCOCS+4D+DkOQfuZf+vLrSEmY/7xtORwdxs4wtcC1wVgvk2MqFFTwQCFhvWsI4KPU9lcWXPI8DgRiz+xetQ==}
@@ -5275,7 +5153,6 @@ packages:
/buffer-from@1.1.2: /buffer-from@1.1.2:
resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
dev: true
/buffer@5.7.1: /buffer@5.7.1:
resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==}
@@ -5326,7 +5203,6 @@ packages:
/cac@6.7.14: /cac@6.7.14:
resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
engines: {node: '>=8'} engines: {node: '>=8'}
dev: true
/cacache@16.1.3: /cacache@16.1.3:
resolution: {integrity: sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==} resolution: {integrity: sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==}
@@ -5456,7 +5332,6 @@ packages:
loupe: 2.3.6 loupe: 2.3.6
pathval: 1.1.1 pathval: 1.1.1
type-detect: 4.0.8 type-detect: 4.0.8
dev: true
/chalk@2.4.2: /chalk@2.4.2:
resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==}
@@ -5504,7 +5379,6 @@ packages:
/check-error@1.0.2: /check-error@1.0.2:
resolution: {integrity: sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==} resolution: {integrity: sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==}
dev: true
/chokidar@3.5.3: /chokidar@3.5.3:
resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==}
@@ -5583,7 +5457,6 @@ packages:
dependencies: dependencies:
slice-ansi: 5.0.0 slice-ansi: 5.0.0
string-width: 5.1.2 string-width: 5.1.2
dev: true
/cli-width@3.0.0: /cli-width@3.0.0:
resolution: {integrity: sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==} resolution: {integrity: sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==}
@@ -6063,7 +5936,6 @@ packages:
engines: {node: '>=6'} engines: {node: '>=6'}
dependencies: dependencies:
type-detect: 4.0.8 type-detect: 4.0.8
dev: true
/deep-extend@0.6.0: /deep-extend@0.6.0:
resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==}
@@ -7262,7 +7134,6 @@ packages:
/get-func-name@2.0.0: /get-func-name@2.0.0:
resolution: {integrity: sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==} resolution: {integrity: sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==}
dev: true
/get-intrinsic@1.2.0: /get-intrinsic@1.2.0:
resolution: {integrity: sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==} resolution: {integrity: sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==}
@@ -8094,7 +7965,6 @@ packages:
/is-fullwidth-code-point@4.0.0: /is-fullwidth-code-point@4.0.0:
resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==} resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==}
engines: {node: '>=12'} engines: {node: '>=12'}
dev: true
/is-glob@4.0.3: /is-glob@4.0.3:
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
@@ -8738,7 +8608,6 @@ packages:
/local-pkg@0.4.3: /local-pkg@0.4.3:
resolution: {integrity: sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==} resolution: {integrity: sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==}
engines: {node: '>=14'} engines: {node: '>=14'}
dev: true
/locate-path@2.0.0: /locate-path@2.0.0:
resolution: {integrity: sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==} resolution: {integrity: sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==}
@@ -8831,7 +8700,6 @@ packages:
resolution: {integrity: sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==} resolution: {integrity: sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==}
dependencies: dependencies:
get-func-name: 2.0.0 get-func-name: 2.0.0
dev: true
/lru-cache@5.1.1: /lru-cache@5.1.1:
resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
@@ -9726,7 +9594,6 @@ packages:
pathe: 1.1.0 pathe: 1.1.0
pkg-types: 1.0.2 pkg-types: 1.0.2
ufo: 1.1.1 ufo: 1.1.1
dev: true
/modify-values@1.0.1: /modify-values@1.0.1:
resolution: {integrity: sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==} resolution: {integrity: sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==}
@@ -9772,7 +9639,6 @@ packages:
/mrmime@1.0.1: /mrmime@1.0.1:
resolution: {integrity: sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==} resolution: {integrity: sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==}
engines: {node: '>=10'} engines: {node: '>=10'}
dev: true
/ms@2.0.0: /ms@2.0.0:
resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==}
@@ -10453,7 +10319,6 @@ packages:
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
dependencies: dependencies:
yocto-queue: 1.0.0 yocto-queue: 1.0.0
dev: true
/p-locate@2.0.0: /p-locate@2.0.0:
resolution: {integrity: sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==} resolution: {integrity: sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==}
@@ -10706,11 +10571,9 @@ packages:
/pathe@1.1.0: /pathe@1.1.0:
resolution: {integrity: sha512-ODbEPR0KKHqECXW1GoxdDb+AZvULmXjVPy4rt+pGo2+TnjJTIPJQSVS6N63n8T2Ip+syHhbn52OewKicV0373w==} resolution: {integrity: sha512-ODbEPR0KKHqECXW1GoxdDb+AZvULmXjVPy4rt+pGo2+TnjJTIPJQSVS6N63n8T2Ip+syHhbn52OewKicV0373w==}
dev: true
/pathval@1.1.1: /pathval@1.1.1:
resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==}
dev: true
/peggy@3.0.2: /peggy@3.0.2:
resolution: {integrity: sha512-n7chtCbEoGYRwZZ0i/O3t1cPr6o+d9Xx4Zwy2LYfzv0vjchMBU0tO+qYYyvZloBPcgRgzYvALzGWHe609JjEpg==} resolution: {integrity: sha512-n7chtCbEoGYRwZZ0i/O3t1cPr6o+d9Xx4Zwy2LYfzv0vjchMBU0tO+qYYyvZloBPcgRgzYvALzGWHe609JjEpg==}
@@ -10787,7 +10650,6 @@ packages:
jsonc-parser: 3.2.0 jsonc-parser: 3.2.0
mlly: 1.2.0 mlly: 1.2.0
pathe: 1.1.0 pathe: 1.1.0
dev: true
/pkg@5.8.1: /pkg@5.8.1:
resolution: {integrity: sha512-CjBWtFStCfIiT4Bde9QpJy0KeH19jCfwZRJqHFDFXfhUklCx8JoFmMj3wgnEYIwGmZVNkhsStPHEOnrtrQhEXA==} resolution: {integrity: sha512-CjBWtFStCfIiT4Bde9QpJy0KeH19jCfwZRJqHFDFXfhUklCx8JoFmMj3wgnEYIwGmZVNkhsStPHEOnrtrQhEXA==}
@@ -10989,7 +10851,6 @@ packages:
ansi-regex: 5.0.1 ansi-regex: 5.0.1
ansi-styles: 5.2.0 ansi-styles: 5.2.0
react-is: 17.0.2 react-is: 17.0.2
dev: true
/pretty-format@29.4.3: /pretty-format@29.4.3:
resolution: {integrity: sha512-cvpcHTc42lcsvOOAzd3XuNWTcvk1Jmnzqeu+WsOuiPmxUJTnkbAcFNsRKvEpBEUFVUgy/GTZLulZDcDEi+CIlA==} resolution: {integrity: sha512-cvpcHTc42lcsvOOAzd3XuNWTcvk1Jmnzqeu+WsOuiPmxUJTnkbAcFNsRKvEpBEUFVUgy/GTZLulZDcDEi+CIlA==}
@@ -11149,7 +11010,6 @@ packages:
/react-is@17.0.2: /react-is@17.0.2:
resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==}
dev: true
/react-is@18.2.0: /react-is@18.2.0:
resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==} resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==}
@@ -11903,7 +11763,6 @@ packages:
/siginfo@2.0.0: /siginfo@2.0.0:
resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==}
dev: true
/signal-exit@3.0.7: /signal-exit@3.0.7:
resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
@@ -11951,7 +11810,6 @@ packages:
'@polka/url': 1.0.0-next.21 '@polka/url': 1.0.0-next.21
mrmime: 1.0.1 mrmime: 1.0.1
totalist: 3.0.0 totalist: 3.0.0
dev: true
/sisteransi@1.0.5: /sisteransi@1.0.5:
resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==}
@@ -11970,7 +11828,6 @@ packages:
dependencies: dependencies:
ansi-styles: 6.2.1 ansi-styles: 6.2.1
is-fullwidth-code-point: 4.0.0 is-fullwidth-code-point: 4.0.0
dev: true
/smart-buffer@4.2.0: /smart-buffer@4.2.0:
resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==}
@@ -12029,7 +11886,6 @@ packages:
dependencies: dependencies:
buffer-from: 1.1.2 buffer-from: 1.1.2
source-map: 0.6.1 source-map: 0.6.1
dev: true
/source-map@0.5.7: /source-map@0.5.7:
resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==} resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==}
@@ -12112,7 +11968,6 @@ packages:
/stackback@0.0.2: /stackback@0.0.2:
resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==}
dev: true
/standardized-audio-context@25.3.37: /standardized-audio-context@25.3.37:
resolution: {integrity: sha512-lr0+RH/IJXYMts95oYKIJ+orTmstOZN3GXWVGmlkbMj8OLahREkRh7DhNGLYgBGDkBkhhc4ev5pYGSFN3gltHw==} resolution: {integrity: sha512-lr0+RH/IJXYMts95oYKIJ+orTmstOZN3GXWVGmlkbMj8OLahREkRh7DhNGLYgBGDkBkhhc4ev5pYGSFN3gltHw==}
@@ -12124,7 +11979,6 @@ packages:
/std-env@3.3.2: /std-env@3.3.2:
resolution: {integrity: sha512-uUZI65yrV2Qva5gqE0+A7uVAvO40iPo6jGhs7s8keRfHCmtg+uB2X6EiLGCI9IgL1J17xGhvoOqSz79lzICPTA==} resolution: {integrity: sha512-uUZI65yrV2Qva5gqE0+A7uVAvO40iPo6jGhs7s8keRfHCmtg+uB2X6EiLGCI9IgL1J17xGhvoOqSz79lzICPTA==}
dev: true
/stdopt@2.2.0: /stdopt@2.2.0:
resolution: {integrity: sha512-D/p41NgXOkcj1SeGhfXOwv9z1K6EV3sjAUY5aeepVbgEHv7DpKWLTjhjScyzMWAQCAgUQys1mjH0eArm4cjRGw==} resolution: {integrity: sha512-D/p41NgXOkcj1SeGhfXOwv9z1K6EV3sjAUY5aeepVbgEHv7DpKWLTjhjScyzMWAQCAgUQys1mjH0eArm4cjRGw==}
@@ -12295,7 +12149,6 @@ packages:
resolution: {integrity: sha512-QZTsipNpa2Ppr6v1AmJHESqJ3Uz247MUS0OjrnnZjFAvEoWqxuyFuXn2xLgMtRnijJShAa1HL0gtJyUs7u7n3Q==} resolution: {integrity: sha512-QZTsipNpa2Ppr6v1AmJHESqJ3Uz247MUS0OjrnnZjFAvEoWqxuyFuXn2xLgMtRnijJShAa1HL0gtJyUs7u7n3Q==}
dependencies: dependencies:
acorn: 8.8.2 acorn: 8.8.2
dev: true
/strong-log-transformer@2.1.0: /strong-log-transformer@2.1.0:
resolution: {integrity: sha512-B3Hgul+z0L9a236FAUC9iZsL+nVHgoCJnqCbN588DjYxvGXaXaaFbfmQ/JhvKjZwsOukuR72XbHv71Qkug0HxA==} resolution: {integrity: sha512-B3Hgul+z0L9a236FAUC9iZsL+nVHgoCJnqCbN588DjYxvGXaXaaFbfmQ/JhvKjZwsOukuR72XbHv71Qkug0HxA==}
@@ -12582,17 +12435,14 @@ packages:
/tinybench@2.5.0: /tinybench@2.5.0:
resolution: {integrity: sha512-kRwSG8Zx4tjF9ZiyH4bhaebu+EDz1BOx9hOigYHlUW4xxI/wKIUQUqo018UlU4ar6ATPBsaMrdbKZ+tmPdohFA==} resolution: {integrity: sha512-kRwSG8Zx4tjF9ZiyH4bhaebu+EDz1BOx9hOigYHlUW4xxI/wKIUQUqo018UlU4ar6ATPBsaMrdbKZ+tmPdohFA==}
dev: true
/tinypool@0.3.1: /tinypool@0.3.1:
resolution: {integrity: sha512-zLA1ZXlstbU2rlpA4CIeVaqvWq41MTWqLY3FfsAXgC8+f7Pk7zroaJQxDgxn1xNudKW6Kmj4808rPFShUlIRmQ==} resolution: {integrity: sha512-zLA1ZXlstbU2rlpA4CIeVaqvWq41MTWqLY3FfsAXgC8+f7Pk7zroaJQxDgxn1xNudKW6Kmj4808rPFShUlIRmQ==}
engines: {node: '>=14.0.0'} engines: {node: '>=14.0.0'}
dev: true
/tinyspy@1.0.2: /tinyspy@1.0.2:
resolution: {integrity: sha512-bSGlgwLBYf7PnUsQ6WOc6SJ3pGOcd+d8AA6EUnLDDM0kWEstC1JIlSZA3UNliDXhd9ABoS7hiRBDCu+XP/sf1Q==} resolution: {integrity: sha512-bSGlgwLBYf7PnUsQ6WOc6SJ3pGOcd+d8AA6EUnLDDM0kWEstC1JIlSZA3UNliDXhd9ABoS7hiRBDCu+XP/sf1Q==}
engines: {node: '>=14.0.0'} engines: {node: '>=14.0.0'}
dev: true
/tmp@0.0.33: /tmp@0.0.33:
resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==}
@@ -12628,7 +12478,6 @@ packages:
/totalist@3.0.0: /totalist@3.0.0:
resolution: {integrity: sha512-eM+pCBxXO/njtF7vdFsHuqb+ElbxqtI4r5EAvk6grfAFyJ6IvWlSkfZ5T9ozC6xWw3Fj1fGoSmrl0gUs46JVIw==} resolution: {integrity: sha512-eM+pCBxXO/njtF7vdFsHuqb+ElbxqtI4r5EAvk6grfAFyJ6IvWlSkfZ5T9ozC6xWw3Fj1fGoSmrl0gUs46JVIw==}
engines: {node: '>=6'} engines: {node: '>=6'}
dev: true
/tr46@0.0.3: /tr46@0.0.3:
resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
@@ -12735,7 +12584,6 @@ packages:
/type-detect@4.0.8: /type-detect@4.0.8:
resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==}
engines: {node: '>=4'} engines: {node: '>=4'}
dev: true
/type-fest@0.13.1: /type-fest@0.13.1:
resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==} resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==}
@@ -12836,7 +12684,6 @@ packages:
/ufo@1.1.1: /ufo@1.1.1:
resolution: {integrity: sha512-MvlCc4GHrmZdAllBc0iUDowff36Q9Ndw/UzqmEKyrfSzokTd9ZCy1i+IIk5hrYKkjoYVQyNbrw7/F8XJ2rEwTg==} resolution: {integrity: sha512-MvlCc4GHrmZdAllBc0iUDowff36Q9Ndw/UzqmEKyrfSzokTd9ZCy1i+IIk5hrYKkjoYVQyNbrw7/F8XJ2rEwTg==}
dev: true
/uglify-js@3.17.4: /uglify-js@3.17.4:
resolution: {integrity: sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==} resolution: {integrity: sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==}
@@ -13212,7 +13059,6 @@ packages:
- sugarss - sugarss
- supports-color - supports-color
- terser - terser
dev: true
/vite-plugin-pwa@0.14.7(vite@4.3.3)(workbox-build@6.5.4)(workbox-window@6.5.4): /vite-plugin-pwa@0.14.7(vite@4.3.3)(workbox-build@6.5.4)(workbox-window@6.5.4):
resolution: {integrity: sha512-dNJaf0fYOWncmjxv9HiSa2xrSjipjff7IkYE5oIUJ2x5HKu3cXgA8LRgzOwTc5MhwyFYRSU0xyN0Phbx3NsQYw==} resolution: {integrity: sha512-dNJaf0fYOWncmjxv9HiSa2xrSjipjff7IkYE5oIUJ2x5HKu3cXgA8LRgzOwTc5MhwyFYRSU0xyN0Phbx3NsQYw==}
@@ -13233,38 +13079,6 @@ packages:
- supports-color - supports-color
dev: true dev: true
/vite@4.3.3:
resolution: {integrity: sha512-MwFlLBO4udZXd+VBcezo3u8mC77YQk+ik+fbc0GZWGgzfbPP+8Kf0fldhARqvSYmtIWoAJ5BXPClUbMTlqFxrA==}
engines: {node: ^14.18.0 || >=16.0.0}
hasBin: true
peerDependencies:
'@types/node': '>= 14'
less: '*'
sass: '*'
stylus: '*'
sugarss: '*'
terser: ^5.4.0
peerDependenciesMeta:
'@types/node':
optional: true
less:
optional: true
sass:
optional: true
stylus:
optional: true
sugarss:
optional: true
terser:
optional: true
dependencies:
esbuild: 0.17.18
postcss: 8.4.23
rollup: 3.21.0
optionalDependencies:
fsevents: 2.3.2
dev: true
/vite@4.3.3(@types/node@18.11.18): /vite@4.3.3(@types/node@18.11.18):
resolution: {integrity: sha512-MwFlLBO4udZXd+VBcezo3u8mC77YQk+ik+fbc0GZWGgzfbPP+8Kf0fldhARqvSYmtIWoAJ5BXPClUbMTlqFxrA==} resolution: {integrity: sha512-MwFlLBO4udZXd+VBcezo3u8mC77YQk+ik+fbc0GZWGgzfbPP+8Kf0fldhARqvSYmtIWoAJ5BXPClUbMTlqFxrA==}
engines: {node: ^14.18.0 || >=16.0.0} engines: {node: ^14.18.0 || >=16.0.0}
@@ -13296,7 +13110,6 @@ packages:
rollup: 3.21.0 rollup: 3.21.0
optionalDependencies: optionalDependencies:
fsevents: 2.3.2 fsevents: 2.3.2
dev: true
/vite@4.3.3(@types/node@18.16.3): /vite@4.3.3(@types/node@18.16.3):
resolution: {integrity: sha512-MwFlLBO4udZXd+VBcezo3u8mC77YQk+ik+fbc0GZWGgzfbPP+8Kf0fldhARqvSYmtIWoAJ5BXPClUbMTlqFxrA==} resolution: {integrity: sha512-MwFlLBO4udZXd+VBcezo3u8mC77YQk+ik+fbc0GZWGgzfbPP+8Kf0fldhARqvSYmtIWoAJ5BXPClUbMTlqFxrA==}
@@ -13394,7 +13207,6 @@ packages:
- sugarss - sugarss
- supports-color - supports-color
- terser - terser
dev: true
/vscode-css-languageservice@6.2.3: /vscode-css-languageservice@6.2.3:
resolution: {integrity: sha512-EAyhyIVHpEaf+GjtI+tVe7SekdoANfG0aubnspsQwak3Qkimn/97FpAufNyXk636ngW05pjNKAR9zyTCzo6avQ==} resolution: {integrity: sha512-EAyhyIVHpEaf+GjtI+tVe7SekdoANfG0aubnspsQwak3Qkimn/97FpAufNyXk636ngW05pjNKAR9zyTCzo6avQ==}
@@ -13582,7 +13394,6 @@ packages:
dependencies: dependencies:
siginfo: 2.0.0 siginfo: 2.0.0
stackback: 0.0.2 stackback: 0.0.2
dev: true
/wide-align@1.1.5: /wide-align@1.1.5:
resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==} resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==}
@@ -13916,7 +13727,6 @@ packages:
/yocto-queue@1.0.0: /yocto-queue@1.0.0:
resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==} resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==}
engines: {node: '>=12.20'} engines: {node: '>=12.20'}
dev: true
/zod@3.21.4: /zod@3.21.4:
resolution: {integrity: sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==} resolution: {integrity: sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==}
-3
View File
@@ -1,3 +0,0 @@
# Generated by Cargo
# will have compiled files and executables
/target/
-3445
View File
File diff suppressed because it is too large Load Diff
-32
View File
@@ -1,32 +0,0 @@
[package]
name = "app"
version = "0.1.0"
description = "A Tauri App"
authors = ["you"]
license = ""
repository = ""
default-run = "app"
edition = "2021"
rust-version = "1.60"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[build-dependencies]
tauri-build = { version = "1.4.0", features = [] }
[dependencies]
serde_json = "1.0"
serde = { version = "1.0", features = ["derive"] }
tauri = { version = "1.4.0", features = ["fs-all"] }
[features]
# this feature is used for production builds or when `devPath` points to the filesystem and the built-in dev server is disabled.
# If you use cargo directly instead of tauri's cli you can use this feature flag to switch between tauri's `dev` and `build` modes.
# DO NOT REMOVE!!
custom-protocol = ["tauri/custom-protocol"]
[profile.release]
panic = "abort"
codegen-units = 1
lto = true
opt-level = "s"
-29
View File
@@ -1,29 +0,0 @@
# @strudel.cycles/tauri
Rust source files for building native desktop apps using Tauri
## Usage
Install [Rust](https://rustup.rs/) on your system.
From the project root:
- install Strudel dependencies
```js
pnpm i
```
- to run Strudel for development
```js
pnpm tauri dev
```
- to build the binary and installer/bundle
```js
pnpm tauri build
```
The binary and installer can be found in the 'src-tauri/target/release/bundle' directory
-3
View File
@@ -1,3 +0,0 @@
fn main() {
tauri_build::build()
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

-8
View File
@@ -1,8 +0,0 @@
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
fn main() {
tauri::Builder::default()
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
-71
View File
@@ -1,71 +0,0 @@
{
"$schema": "../node_modules/@tauri-apps/cli/schema.json",
"build": {
"beforeBuildCommand": "npm run build",
"beforeDevCommand": "npm run dev",
"devPath": "http://localhost:3000",
"distDir": "../website/dist",
"withGlobalTauri": true
},
"package": {
"productName": "Strudel",
"version": "0.1.0"
},
"tauri": {
"allowlist": {
"all": false,
"fs": {
"all": true,
"scope": ["$HOME/**", "$HOME", "$HOME/*"]
}
},
"bundle": {
"active": true,
"category": "DeveloperTool",
"copyright": "",
"deb": {
"depends": []
},
"externalBin": [],
"icon": [
"icons/32x32.png",
"icons/128x128.png",
"icons/128x128@2x.png",
"icons/icon.icns",
"icons/icon.ico"
],
"identifier": "com.strudel.dev",
"longDescription": "",
"macOS": {
"entitlements": null,
"exceptionDomain": "",
"frameworks": [],
"providerShortName": null,
"signingIdentity": null
},
"resources": [],
"shortDescription": "",
"targets": "all",
"windows": {
"certificateThumbprint": null,
"digestAlgorithm": "sha256",
"timestampUrl": ""
}
},
"security": {
"csp": null
},
"updater": {
"active": false
},
"windows": [
{
"fullscreen": false,
"height": 1200,
"resizable": true,
"title": "Strudel REPL",
"width": 1800
}
]
}
}
+76 -93
View File
@@ -1079,22 +1079,22 @@ exports[`runs examples > example "chunkBack" example index 0 1`] = `
exports[`runs examples > example "clip" example index 0 1`] = ` exports[`runs examples > example "clip" example index 0 1`] = `
[ [
"[ 0/1 → 1/4 | note:c s:piano clip:0.5 ]", "[ 0/1 → 1/5 | note:c s:piano clip:1 ]",
"[ 1/41/2 | note:a s:piano clip:0.5 ]", "[ 1/52/5 | note:a s:piano clip:1 ]",
"[ 1/2 → 3/4 | note:f s:piano clip:0.5 ]", "[ 2/5 → 3/5 | note:f s:piano clip:1 ]",
"[ 3/41/1 | note:e s:piano clip:0.5 ]", "[ 3/54/5 | note:e s:piano clip:1 ]",
"[ 1/1 → 5/4 | note:c s:piano clip:1 ]", "[ 1/1 → 6/5 | note:c s:piano clip:1 ]",
"[ 5/4 → 3/2 | note:a s:piano clip:1 ]", "[ 6/5 → 7/5 | note:a s:piano clip:1 ]",
"[ 3/2 → 7/4 | note:f s:piano clip:1 ]", "[ 7/5 → 8/5 | note:f s:piano clip:1 ]",
"[ 7/4 → 2/1 | note:e s:piano clip:1 ]", "[ 8/5 → 9/5 | note:e s:piano clip:1 ]",
"[ 2/1 → 9/4 | note:c s:piano clip:2 ]", "[ 2/1 → 11/5 | note:c s:piano clip:1 ]",
"[ 9/4 → 5/2 | note:a s:piano clip:2 ]", "[ 11/5 → 12/5 | note:a s:piano clip:1 ]",
"[ 5/2 → 11/4 | note:f s:piano clip:2 ]", "[ 12/5 → 13/5 | note:f s:piano clip:1 ]",
"[ 11/4 → 3/1 | note:e s:piano clip:2 ]", "[ 13/5 → 14/5 | note:e s:piano clip:1 ]",
"[ 3/1 → 13/4 | note:c s:piano clip:0.5 ]", "[ 3/1 → 16/5 | note:c s:piano clip:1 ]",
"[ 13/4 → 7/2 | note:a s:piano clip:0.5 ]", "[ 16/517/5 | note:a s:piano clip:1 ]",
"[ 7/2 → 15/4 | note:f s:piano clip:0.5 ]", "[ 17/5 → 18/5 | note:f s:piano clip:1 ]",
"[ 15/4 → 4/1 | note:e s:piano clip:0.5 ]", "[ 18/5 → 19/5 | note:e s:piano clip:1 ]",
] ]
`; `;
@@ -1588,42 +1588,42 @@ exports[`runs examples > example "echo" example index 0 1`] = `
exports[`runs examples > example "echoWith" example index 0 1`] = ` exports[`runs examples > example "echoWith" example index 0 1`] = `
[ [
"[ 0/1 → 1/1 | note:C3 clip:0.2 ]", "[ 0/1 → 1/5 | note:C3 ]",
"[ -3/8 ⇜ (0/1 → 1/8) | note:Bb3 clip:0.2 ]", "[ -3/8 ⇜ (0/1 → 1/40) ⇝ -11/40 | note:Bb3 ]",
"[ (1/8 → 1/1) ⇝ 9/8 | note:Eb3 clip:0.2 ]", "[ (1/8 → 3/10) ⇝ 13/40 | note:Eb3 ]",
"[ -1/4 ⇜ (0/1 → 1/4) | note:D4 clip:0.2 ]", "[ -1/4 ⇜ (0/1 → 1/20) ⇝ -3/20 | note:D4 ]",
"[ (1/4 → 1/1) ⇝ 5/4 | note:G3 clip:0.2 ]", "[ (1/4 → 2/5) ⇝ 9/20 | note:G3 ]",
"[ -1/8 ⇜ (0/1 → 3/8) | note:F4 clip:0.2 ]", "[ -1/8 ⇜ (0/1 → 3/40) ⇝ -1/40 | note:F4 ]",
"[ (3/8 → 1/1) ⇝ 11/8 | note:Bb3 clip:0.2 ]", "[ (3/8 → 1/2) ⇝ 23/40 | note:Bb3 ]",
"[ 1/1 → 3/2 | note:Eb3 clip:0.2 ]", "[ 1/1 → 11/10 | note:Eb3 ]",
"[ 3/2 → 2/1 | note:G3 clip:0.2 ]", "[ 3/2 → 8/5 | note:G3 ]",
"[ 1/8 ⇜ (1/1 → 9/8) | note:Eb3 clip:0.2 ]", "[ 1/8 ⇜ (1/1 → 41/40) ⇝ 13/40 | note:Eb3 ]",
"[ 9/8 → 13/8 | note:G3 clip:0.2 ]", "[ 9/8 → 49/40 | note:G3 ]",
"[ (13/8 → 2/1) ⇝ 17/8 | note:Bb3 clip:0.2 ]", "[ (13/8 → 17/10) ⇝ 69/40 | note:Bb3 ]",
"[ 1/4 ⇜ (1/1 → 5/4) | note:G3 clip:0.2 ]", "[ 1/4 ⇜ (1/1 → 21/20) ⇝ 9/20 | note:G3 ]",
"[ 5/4 → 7/4 | note:Bb3 clip:0.2 ]", "[ 5/4 → 27/20 | note:Bb3 ]",
"[ (7/4 → 2/1) ⇝ 9/4 | note:D4 clip:0.2 ]", "[ (7/4 → 9/5) ⇝ 37/20 | note:D4 ]",
"[ 3/8 ⇜ (1/1 → 11/8) | note:Bb3 clip:0.2 ]", "[ 3/8 ⇜ (1/1 → 43/40) ⇝ 23/40 | note:Bb3 ]",
"[ 11/8 → 15/8 | note:D4 clip:0.2 ]", "[ 11/8 → 59/40 | note:D4 ]",
"[ (15/8 → 2/1) ⇝ 19/8 | note:F4 clip:0.2 ]", "[ (15/8 → 19/10) ⇝ 79/40 | note:F4 ]",
"[ 2/1 → 3/1 | note:C3 clip:0.2 ]", "[ 2/1 → 11/5 | note:C3 ]",
"[ 13/8 ⇜ (2/1 → 17/8) | note:Bb3 clip:0.2 ]", "[ 13/8 ⇜ (2/1 → 81/40) ⇝ 69/40 | note:Bb3 ]",
"[ (17/8 → 3/1) ⇝ 25/8 | note:Eb3 clip:0.2 ]", "[ (17/8 → 23/10) ⇝ 93/40 | note:Eb3 ]",
"[ 7/4 ⇜ (2/1 → 9/4) | note:D4 clip:0.2 ]", "[ 7/4 ⇜ (2/1 → 41/20) ⇝ 37/20 | note:D4 ]",
"[ (9/4 → 3/1) ⇝ 13/4 | note:G3 clip:0.2 ]", "[ (9/4 → 12/5) ⇝ 49/20 | note:G3 ]",
"[ 15/8 ⇜ (2/1 → 19/8) | note:F4 clip:0.2 ]", "[ 15/8 ⇜ (2/1 → 83/40) ⇝ 79/40 | note:F4 ]",
"[ (19/8 → 3/1) ⇝ 27/8 | note:Bb3 clip:0.2 ]", "[ (19/8 → 5/2) ⇝ 103/40 | note:Bb3 ]",
"[ 3/1 → 7/2 | note:Eb3 clip:0.2 ]", "[ 3/1 → 31/10 | note:Eb3 ]",
"[ 7/2 → 4/1 | note:G3 clip:0.2 ]", "[ 7/2 → 18/5 | note:G3 ]",
"[ 17/8 ⇜ (3/1 → 25/8) | note:Eb3 clip:0.2 ]", "[ 17/8 ⇜ (3/1 → 121/40) ⇝ 93/40 | note:Eb3 ]",
"[ 25/8 → 29/8 | note:G3 clip:0.2 ]", "[ 25/8 → 129/40 | note:G3 ]",
"[ (29/8 → 4/1) ⇝ 33/8 | note:Bb3 clip:0.2 ]", "[ (29/8 → 37/10) ⇝ 149/40 | note:Bb3 ]",
"[ 9/4 ⇜ (3/1 → 13/4) | note:G3 clip:0.2 ]", "[ 9/4 ⇜ (3/1 → 61/20) ⇝ 49/20 | note:G3 ]",
"[ 13/4 → 15/4 | note:Bb3 clip:0.2 ]", "[ 13/4 → 67/20 | note:Bb3 ]",
"[ (15/4 → 4/1) ⇝ 17/4 | note:D4 clip:0.2 ]", "[ (15/4 → 19/5) ⇝ 77/20 | note:D4 ]",
"[ 19/8 ⇜ (3/1 → 27/8) | note:Bb3 clip:0.2 ]", "[ 19/8 ⇜ (3/1 → 123/40) ⇝ 103/40 | note:Bb3 ]",
"[ 27/8 → 31/8 | note:D4 clip:0.2 ]", "[ 27/8 → 139/40 | note:D4 ]",
"[ (31/8 → 4/1) ⇝ 35/8 | note:F4 clip:0.2 ]", "[ (31/8 → 39/10) ⇝ 159/40 | note:F4 ]",
] ]
`; `;
@@ -3193,23 +3193,6 @@ exports[`runs examples > example "rarely" example index 0 1`] = `
] ]
`; `;
exports[`runs examples > example "ratio" example index 0 1`] = `
[
"[ (0/1 → 1/1) ⇝ 2/1 | freq:110 s:piano ]",
"[ (0/1 → 1/1) ⇝ 2/1 | freq:137.5 s:piano ]",
"[ (0/1 → 1/1) ⇝ 2/1 | freq:165 s:piano ]",
"[ 0/1 ⇜ (1/1 → 2/1) | freq:110 s:piano ]",
"[ 0/1 ⇜ (1/1 → 2/1) | freq:137.5 s:piano ]",
"[ 0/1 ⇜ (1/1 → 2/1) | freq:165 s:piano ]",
"[ (2/1 → 3/1) ⇝ 4/1 | freq:110 s:piano ]",
"[ (2/1 → 3/1) ⇝ 4/1 | freq:137.5 s:piano ]",
"[ (2/1 → 3/1) ⇝ 4/1 | freq:165 s:piano ]",
"[ 2/1 ⇜ (3/1 → 4/1) | freq:110 s:piano ]",
"[ 2/1 ⇜ (3/1 → 4/1) | freq:137.5 s:piano ]",
"[ 2/1 ⇜ (3/1 → 4/1) | freq:165 s:piano ]",
]
`;
exports[`runs examples > example "release" example index 0 1`] = ` exports[`runs examples > example "release" example index 0 1`] = `
[ [
"[ 0/1 → 1/4 | note:c3 release:0 ]", "[ 0/1 → 1/4 | note:c3 release:0 ]",
@@ -3503,30 +3486,30 @@ exports[`runs examples > example "samples" example index 1 1`] = `
exports[`runs examples > example "saw" example index 0 1`] = ` exports[`runs examples > example "saw" example index 0 1`] = `
[ [
"[ 0/1 → 1/4 | note:c3 clip:0.03125 ]", "[ 0/1 → 1/32 | note:c3 ]",
"[ 1/4 → 1/2 | note:eb3 clip:0.09375 ]", "[ 1/4 → 9/32 | note:eb3 ]",
"[ 1/4 → 1/2 | note:g3 clip:0.09375 ]", "[ 1/4 → 9/32 | note:g3 ]",
"[ 1/2 → 3/4 | note:g2 clip:0.15625 ]", "[ 1/2 → 17/32 | note:g2 ]",
"[ 3/4 → 1/1 | note:g3 clip:0.21875 ]", "[ 3/4 → 25/32 | note:g3 ]",
"[ 3/4 → 1/1 | note:bb3 clip:0.21875 ]", "[ 3/4 → 25/32 | note:bb3 ]",
"[ 1/1 → 5/4 | note:c3 clip:0.28125 ]", "[ 1/1 → 35/32 | note:c3 ]",
"[ 5/4 → 3/2 | note:eb3 clip:0.34375 ]", "[ 5/4 → 43/32 | note:eb3 ]",
"[ 5/4 → 3/2 | note:g3 clip:0.34375 ]", "[ 5/4 → 43/32 | note:g3 ]",
"[ 3/2 → 7/4 | note:g2 clip:0.40625 ]", "[ 3/2 → 51/32 | note:g2 ]",
"[ 7/4 → 2/1 | note:g3 clip:0.46875 ]", "[ 7/4 → 59/32 | note:g3 ]",
"[ 7/4 → 2/1 | note:bb3 clip:0.46875 ]", "[ 7/4 → 59/32 | note:bb3 ]",
"[ 2/1 → 9/4 | note:c3 clip:0.53125 ]", "[ 2/1 → 69/32 | note:c3 ]",
"[ 9/4 → 5/2 | note:eb3 clip:0.59375 ]", "[ 9/4 → 77/32 | note:eb3 ]",
"[ 9/4 → 5/2 | note:g3 clip:0.59375 ]", "[ 9/4 → 77/32 | note:g3 ]",
"[ 5/2 → 11/4 | note:g2 clip:0.65625 ]", "[ 5/2 → 85/32 | note:g2 ]",
"[ 11/4 → 3/1 | note:g3 clip:0.71875 ]", "[ 11/4 → 93/32 | note:g3 ]",
"[ 11/4 → 3/1 | note:bb3 clip:0.71875 ]", "[ 11/4 → 93/32 | note:bb3 ]",
"[ 3/1 → 13/4 | note:c3 clip:0.78125 ]", "[ 3/1 → 103/32 | note:c3 ]",
"[ 13/4 → 7/2 | note:eb3 clip:0.84375 ]", "[ 13/4 → 111/32 | note:eb3 ]",
"[ 13/4 → 7/2 | note:g3 clip:0.84375 ]", "[ 13/4 → 111/32 | note:g3 ]",
"[ 7/2 → 15/4 | note:g2 clip:0.90625 ]", "[ 7/2 → 119/32 | note:g2 ]",
"[ 15/4 → 4/1 | note:g3 clip:0.96875 ]", "[ 15/4 → 127/32 | note:g3 ]",
"[ 15/4 → 4/1 | note:bb3 clip:0.96875 ]", "[ 15/4 → 127/32 | note:bb3 ]",
] ]
`; `;
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -221,7 +221,7 @@ export const testCycles = {
festivalOfFingers: 16, festivalOfFingers: 16,
festivalOfFingers2: 22, festivalOfFingers2: 22,
undergroundPlumber: 20, undergroundPlumber: 20,
bridgeIsOver: 8, bridgeIsOver: 16,
goodTimes: 16, goodTimes: 16,
echoPiano: 8, echoPiano: 8,
sml1: 48, sml1: 48,
+1 -1
View File
@@ -364,7 +364,7 @@ export const customTrigger = `// licensed with CC BY-NC-SA 4.0 https://creativec
// by Felix Roos // by Felix Roos
stack( 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("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)".clip(.18).mul("<1 3/4 2 2/3>")).gain(perlin.range(.2,.8)) freq("440(5,8)".legato(.18).mul("<1 3/4 2 2/3>")).gain(perlin.range(.2,.8))
).s("<sawtooth square>/2") ).s("<sawtooth square>/2")
.onTrigger((t,hap,ct)=>{ .onTrigger((t,hap,ct)=>{
const ac = Tone.getContext().rawContext; const ac = Tone.getContext().rawContext;
+1 -1
View File
@@ -87,7 +87,7 @@ export const SIDEBAR: Sidebar = {
{ text: 'Signals', link: 'learn/signals' }, { text: 'Signals', link: 'learn/signals' },
{ text: 'Conditional Modifiers', link: 'learn/conditional-modifiers' }, { text: 'Conditional Modifiers', link: 'learn/conditional-modifiers' },
{ text: 'Accumulation', link: 'learn/accumulation' }, { text: 'Accumulation', link: 'learn/accumulation' },
{ text: 'Tonal Functions', link: 'learn/tonal' }, { text: 'Tonal Modifiers', link: 'learn/tonal' },
], ],
Development: [ Development: [
{ text: 'REPL', link: 'technical-manual/repl' }, { text: 'REPL', link: 'technical-manual/repl' },
-8
View File
@@ -16,11 +16,3 @@
.cm-gutters { .cm-gutters {
display: none !important; display: none !important;
} }
.cm-cursorLayer {
animation-name: inherit !important;
}
.cm-cursor {
border-left: 2px solid currentcolor !important;
}
@@ -0,0 +1,162 @@
---
title: Strudel Live Coding Workshop
layout: ../../../layouts/MainLayout.astro
---
# Strudel: Live Coding Workshop
![workshop](https://toplap-ka.de/img/2023-06-10_strudel_workshop.jpeg)
Mit: Felix Roos
Veranstaltet von TOPLAP Karlsruhe, Digitale Kunstfabrik e.V. & Die Anstoß e.V.
# Was ist Live Coding
"In live coding performance, performers create time-based works by programming them while these same works are being executed."
Roberts & Wakefield, 2016
"In einer Live Coding Performance werden künstlerische Werke mit Code kreiert, während dieselben Werke ausgeführt werden"
- Sound & Musik
- Grafiken / Visuelles
- Tanz
- Webmuster
- ...
Dieser Workshop = Musik Live Coding
![live coding](https://www.thetimes.co.uk/imageserver/image/%2Fmethode%2Ftimes%2Fprod%2Fweb%2Fbin%2F2a5b60ca-718e-11e9-a116-49ac88679a93.jpg?crop=3291%2C1851%2C573%2C722)
## TOPLAP
- gegründet 2004, heute ein weltweites Netzwerk
- Temporary Organisation for the Promotion of Live Algorithm Programming
- https://toplap.org/
- toplap karlsruhe: https://toplap-ka.de/
![alex ka](https://trxprds3.s3.amazonaws.com/uploads/2020/03/photo-by-yecto.jpg)
## Live Coding is not Software Engineering
"Live Coders are much more interested in causing problems than solving them" - Alex McLean
## Viele verschiedene Programme / Tools
- meistens frei und open source
- supercollider, orca, foxdot, sonic pi, gibber, sardine, estuary, hydra, ... tidalcycles, strudel
<div class="grid grid-cols-3">
<img
alt="orca"
src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTlZAfu-tbPdn2yzwIGIqkqMmB2HpbtKR5MHA&usqp=CAU"
/>
<img
alt="hydra"
src="https://cdn.glitch.com/9c3a06ab-0731-42ca-a1a3-3a249825d08f%2FScreen%20Shot%202018-06-24%20at%204.47.49%20PM.png?1531889983803"
/>
<img
alt="gibber"
src="https://i.vimeocdn.com/video/456734745-c00bd0c9f6a11a966a4346335f9d55b128584323d237e6d9630ab559a607dfce-d"
/>
</div>
## TidalCycles & Strudel
- TidalCycles = Computersprache für algorithmische Muster, meist für Musik verwendet
- Strudel = Version von TidalCycles für den Browser
- Keine Installation notwendig
- frei & open source
<a target="_blank" href="https://strudel.tidalcycles.org/?MCc4-cDOwIdG">
strudel.tidalcycles.org
</a>
## Videos
**Algorave Generation**
<iframe
width="560"
height="315"
src="https://www.youtube.com/embed/S2EZqikCIfY"
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
allowfullscreen
></iframe>
**hellocatfood x yaxu**
<iframe
width="560"
height="315"
src="https://www.youtube.com/embed/Vomnc9R-7mw?start=261"
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
allowfullscreen
></iframe>
**Heavy Lifting x Graham Dunning**
<iframe
width="560"
height="315"
src="https://www.youtube.com/embed/ca3J1cztnrc?start=719"
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
allowfullscreen
></iframe>
**Andrew Sorensen - Five over Four**
<iframe
width="560"
height="315"
src="https://www.youtube.com/embed/FYWtlV4JV6o?start=226"
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
allowfullscreen
></iframe>
**boggo - Live Coding Metal Djents**
<iframe
width="560"
height="315"
src="https://www.youtube.com/embed/n0rhn9-PRwE?start=226"
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
allowfullscreen
></iframe>
**froos - Solstice Night 2022**
<iframe
width="560"
height="315"
src="https://www.youtube.com/embed/P1DDsOvcyco?start=414"
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
allowfullscreen
></iframe>
## Strudel Demos
- [yellow magic orchestra - firecracker](https://felixroos.github.io/strudel/#Ly9jb250aW51aW5nIHRoZSB0cmFuc2NyaXB0aW9uIG9mIG9uZSBvZiBteSBmYXZvcml0ZSB0cmFja3MgaW4gZWxlY3Ryb25pYyBtdXNpYyBoaXN0b3J5CgpsZXQgZHJ1bXMgPSBzdGFjaygKICBzKCJ%2BQDMgaGggfiBoaCB%2BIH4iKS5sYXRlKC4wMikuc3BlZWQoLjgpLmdhaW4oLjIpLnJvb20oLjQpLmhjdXRvZmYoNDAwMCksCiAgcygiYmQiKSwKICBzKCJ%2BIHNkIikucm9vbSgiPDAgLjY%2BIiksCiAgcygifiBwZXJjOjEqMiB%2BIHBlcmM6MSIpLnNwZWVkKCIyIDMiKS5yb29tKC4yKS5nYWluKC4yNSkKKS5iYW5rKCdSb2xhbmRDb21wdXJoeXRobTEwMDAnKQoKbGV0IHdoaXN0bGUgPSB4PT54Lm5vdGUoKS5zKCdzaW5lJykKICAuZGVjYXkoLjEpLnN1c3RhaW4oLjIpLmdhaW4oLjIpCiAgLnBhbiguMikucm9vbSguOCkKCmxldCBiYXNzID0geD0%2BeC5hZGQoIjAsMTIsMTEuOTIiKS5ub3RlKCkKICAucygic2F3dG9vdGgsc3F1YXJlIikuY3V0b2ZmKDgwMCkKICAuZGVjYXkoLjEpLnN1c3RhaW4oLjEpLmdhaW4oLjQpCgpsZXQgYmxpcHMgPSB4PT54Lm5vdGUoKS5qdXgocmV2KQogIC5zKCdzYXd0b290aCcpLmN1dG9mZig1MDApLmdhaW4oc2luZS5yYW5nZSguMiwuOCkuc2xvdyg0KSkKICAuZGVjYXkoLjA4KS5zdXN0YWluKDApCgpsZXQgZ3Jvb3ZlQSA9ICIyIH4gMyB%2BIDQgfiB%2BIC0xIH4gLTEgMCB%2BIC0xIH4gMCB%2BIi5sYXllcigKICB4PT54LnNjYWxlKCdlNyBtaW5vcicpLmxheWVyKHdoaXN0bGUpLAogIHg9Pnguc2NhbGUoJ2UxIG1pbm9yJykubGF5ZXIoYmFzcykKKS5zdGFjaygKICAiMioxNiIuZGVncmFkZUJ5KCIxIC4yQDciKS5zY2FsZSgnZTMgbWlub3InKS5sYXllcihibGlwcykKKS5zbG93KDIpCiAgLnN0YWNrKGRydW1zKQoKbGV0IG1lbG9keUEgPSBjYXQoCiAgIjYgWzcgNl0gNCAzIDIgMCAtMSAwIiwKICAiWzkgMTBdIFs5IDddIDYgNCAzIDQgNiA3Ii5zdWIoNyksCiAgIns2IDcgNiA0IDMgfn0lMTYiLnN1Yig3KS5yZXN0YXJ0KCJ4IiksCiAgIjMqMiA0KjIgNioyIDcqMiIuc3ViKDcpCikuc2xvdygyKS5hZGQoIjAiKS5zY2FsZSgnZTQgbWlub3InKS5ub3RlKCkKLmxheWVyKAogICAgeD0%2BeC5zKCJ4eWxvcGhvbmVfaGFyZF9mZiIpLmdhaW4oMS4yKSwKICAgIHg9Pngucygic2F3dG9vdGgiKS5nYWluKC40KS5kZWNheSguMSkuc3VzdGFpbigwLjIpLmFkZChub3RlKCIxMiwxMi4wNSIpKQogICkubXVsKGdhaW4oLjUpKQoKbGV0IG1lbG9keUIgPSAiWzBAMiB%2BIDBANCAxIDJAMiB%2BIDJANV0vNCIuc3ViKCIwLDMiKQogIC5zY2FsZSgnZzQgbWFqb3InKS5ub3RlKCkubGF5ZXIoCiAgICB4PT54LnMoInJlY29yZGVyX2FsdG9fc3VzIikuY2xpcCgxKS5zaGFwZSguOCkuZ2FpbiguNzUpLAogICAgeD0%2BeC5zKCJzcXVhcmUiKS5nYWluKC4xKS5hZGQobm90ZSgxMikpCiAgKQogIC5yb29tKC42KS5yZWxlYXNlKC4yKQoKCmZ1bmN0aW9uIGFycmFuZ2UoLi4uc2VjdGlvbnMpIHsKICBsZXQgdG90YWwgPSBzZWN0aW9ucy5yZWR1Y2UoKHN1bSwgW2N5Y2xlc10pID0%2BIHN1bSArIGN5Y2xlcywgMCkKICBzZWN0aW9ucyA9IHNlY3Rpb25zLm1hcCgoW2N5Y2xlcywgc2VjdGlvbl0pID0%2BIFtjeWNsZXMsIHNlY3Rpb24uZmFzdChjeWNsZXMpXSkKICByZXR1cm4gdGltZUNhdCguLi5zZWN0aW9ucykuc2xvdyh0b3RhbCkKfQoKZ3Jvb3ZlQS5zdGFjaygKICBhcnJhbmdlKFs4LCBzaWxlbmNlXSwgWzgsIG1lbG9keUFdLCBbNCwgbWVsb2R5Ql0sIFs4LCBtZWxvZHlBXSwgWzQsIG1lbG9keUJdKQopCg%3D%3D)
- [reliefpfeier](https://felixroos.github.io/strudel/#Ly8gdGl0bGU6IHJlbGllZnBmZWlsZXIKcygiPHBlcmMgbWlzYyByaW0oMyw4KSBvaD4iKS5iYW5rKCdZYW1haGFURzMzJykuZW5kKCI8MUAzIC4wMj4iKQoubigiPDAgMSAyIDM%2BIi5vdXRzaWRlKDQsIHBhbGluZHJvbWUpKQoub2ZmKCI8MSAyIDMgND4iLmRpdigiPDIgMyA0IDY%2BLzQiKSwgeD0%2BeC5zcGVlZCgiPDIgMyA0PiIpKQogIAouY2h1bmsoNCwgcGx5KCI8MiAzIDQ%2BIikpCi5sYXN0T2YoOCwgc2VnbWVudCgiPDMgNiA4PiIpKQogIAoubGF5ZXIoCiAgeD0%2BeC5jdXRvZmYocGVybGluLnJhbmdlKDEwMDAsMjAwMDApKSwKICB4PT54LmJhbmsoJycpLnNsb3coMikucygncGlhbm8nKS5nYWluKC42KS5kZWdyYWRlKCkubXVsKHNwZWVkKC0xKSkKICAgIC5iYW5kZihzaW5lLnJhbmdlKDIwMDAsMTAwMDApLnNsb3coNykpLnJlc29uYW5jZSgxMikuYXR0YWNrKC44KQogICAgLnBhbihyYW5kKSwKKQogIAoubGFzdE9mKDYsIHg9PnguY3J1c2goIjgiKSkKLmdhaW4oc2F3LnJhbmdlKC40LC45KSkKLm91dHNpZGUoNCwganV4QnkoLjUsIHJldikpCi5ub3RlKCIwIDUgNCBbMiw3XSIuc2NhbGUoJ0cxIG1pbm9yJykpCi5yb29tKC40KS5mYXN0KDIvMyk%3D)
- [insect schneckno](https://felixroos.github.io/strudel/#Ly8gYWxzbyBoYXZpbmcgYSBmdW4gdGltZSB3aXRoICNzaGFiZGEKLy90aXRsZTogaW5zZWN0IHNjaG5lY2tubwoKYXdhaXQgc2FtcGxlcygnaHR0cHM6Ly9zaGFiZGEubmRyZS5nci9iYXNzOjQsaGloYXQ6NCxyaW1zaG90OjIuanNvbj9zdHJ1ZGVsPTEnKQoKc3RhY2soCiAgbigiezEgMiAzfSUxMiIpLnNwZWVkKHNpbmUucmFuZ2UoMSwxLjIpKQogIC5zKCJoaWhhdCIpLmVuZChzYXcucmFuZ2V4KC4wNCwuMTUpLnNsb3coOCkubGF0ZSguMjUpKQogIC5nYWluKCIuNSAuOSIuZmFzdCgyKSkKICAuYnBmKHNpbmUucmFuZ2UoNDAwMCwxMDAwMCkuc2xvdyg0KSkKICAucm9vbSguOCkuZ2FpbiguNikucGFuKHNpbmUucmFuZ2UoLjMsLjYpLnNsb3coNykpCiAgLAogIG4oIjAgWzJAMyAxQDJdIDMqOCAxIikucygiYmFzcyIpLmN1dCgxKQogICwKICBzKCJiZCoyIikuc3BlZWQoLjYpLmJhbmsoJ1JvbGFuZFRSOTA5JykKICAsCiAgcygifiBbY3Ascmltc2hvdCo8MSAyPl0iKS5vZmYoMS84LHg9Pnguc3BlZWQoIjw0IC0yPiIpKS5zbG93KDIpCiAgLAogIG5vdGUoInswIDQgNSozIDIgMSAtMSoyIC0yfSUyIi5zY2FsZSgnZzIgZG9yaWFuJykpLmxhdGUoLjI4KQogIC5kZWxheSguNSkuZGVsYXl0aW1lKC4xNjYpLnJvb20oLjUpCiAgLnMoIlJoeXRobUFjZV9wZXJjOjEiKS5vZmYoMS8yNCwgeD0+eC5hZGQobm90ZSgxMikpKS5zbG93KDIpCiAgLmp1eEJ5KC43NSwgcmV2KS5scGYocGVybGluLnJhbmdlKDgwMCw4MDAwKSkubHBxKDExKQogIC5nYWluKHNpbmUucmFuZ2UoMCwuOCkuc2xvdygxMikpCikuZmFzdCgzLzQp)
- [hip hop with sampling](https://felixroos.github.io/strudel/#Ly8gYW5vdGhlciBzdHVtYmxpbmcgYmVhdCB3aXRoIHF1aW50dXBsZXQgc3dpbmcgYW5kIHNvbWUgc2xpY2VkIHN0cmluZyBpbnN0cnVtZW50cwphd2FpdCBzYW1wbGVzKCdnaXRodWI6ZmVsaXhyb29zL3NhbXBsZXMvbWFpbicpCmF3YWl0IHNhbXBsZXMoeyAKICBqel9ndHI6J2h0dHBzOi8vY2RuLmZyZWVzb3VuZC5vcmcvcHJldmlld3MvNTkvNTk1MDBfNTM4MzgzLWhxLm1wMycsIAogIGp6X2Jhc3M6J2h0dHBzOi8vY2RuLmZyZWVzb3VuZC5vcmcvcHJldmlld3MvMTYvMTYxNzFfMTg4MTEtaHEubXAzJ30KKQpQYXR0ZXJuLnByb3RvdHlwZS5zbGljZSA9IGZ1bmN0aW9uKHNsaWNlcywgY29udHJvbCkgewogIHJldHVybiBjb250cm9sLmZtYXAoaSA9PiB0aGlzLmJlZ2luKGkvc2xpY2VzKS5lbmQoKGkrMSkvc2xpY2VzKSkub3V0ZXJKb2luKCkKfQoKc3RhY2soCiAgLy8gZ3VpdGFyIHNsaWNlcwogIHMoJ2p6X2d0cicpLnNsaWNlKDgsICJbM0AzIDNAMl0qMiAyKlszIDZdIDEqNCAwKjIiKS5zcGVlZCgiMSAtMiIpLmxhdGUoLjAwOCkKICAuc2xvdyg0KS5jdXQoMSkucmVsZWFzZSguMikuYXR0YWNrKCIwLjA1IDAuMjUiKS5wYW4oc2luZS5yYW5nZSguMiwuOCkuc2xvdyg0KSkKICAubXVsKHNwZWVkKDQvMykpLmdhaW4ocmFuZC5yYW5nZSguMywuNikpCiAgLmxwZihzaW5lLnJhbmdlKDUwMCw1MDAwKS5zbG93KDgpKS5scHEoMTIpCiAgLCAvLyBiYXNzIHNsaWNlcwogIHMoJ2p6X2Jhc3MnKS5zbGljZSg4LCAiWzAgWzdAMyA3QDJdXSBbMSA2KjhdIDIgPDUgNj4qMiIpLmRlY2F5KC4yKS5zdXN0YWluKC41KQogIC5hZGQoYmVnaW4oLjAxMikuZW5kKC4wKSkubXVsKGJlZ2luKC44OCkuZW5kKC44OSkpLnJlbGVhc2UoLjEpCiAgLnNsb3coNCkuY3V0KDIpLm5vdGUoImQyIikKICAsIC8vIGtpY2sgCiAgcygiW2JkOjAoPDIgMT4sNSw8MyAwPiksfiA8fiBbfkAzIGJkQDJdPl0gfiIpLmJhbmsoJ1lhbWFoYVJYNScpCiAgLmdhaW4ocmFuZC5yYW5nZSguNSwuOSkpLm1hc2soIjwxQDYgMEAyPiIpCiAgLCAvLyBzbmFyZQogIHMoIn4gPHNkIHNkPiIpLmJhbmsoJ1lhbWFoYVJYNScpLmdhaW4oLjgpLnJvb20oIjwwIC4xPiIpLnNwZWVkKCI8LjkgMT4iKQogIC5lbmQoIjwuMSAuMj4iKS5yZWxlYXNlKC4xKQogICwgLy8gaGloYXQKICBzKCJoaEAzIGhoQDIiLmZhc3QoMikpLm4oMSkuYmFuaygnS29yZ00xJykuc3BlZWQoLjgpLmVuZCgwKS5yZWxlYXNlKC4wNSkuZ2FpbiguNSkKICAub2ZmKDEvNSwgeD0%2BeC5tdWwoc3BlZWQoMS4yKSkuZ2FpbiguMSkuZGVncmFkZSgpKQogICwgLy8geHlsb3Bob25lCiAgbm90ZSgiPFtlNEAzIGEzXSBkNCB%2BQDI%2BLzIiLmFkZCgyNCkpCiAgLnMoInh5bG8iKS5nYWluKC40KS5sYXRlKDQpLmNsaXAoMSkKICAuaHBmKDUwMCkuaHBxKDE2KQogIC5yb29tKDEpLmRlbGF5KC41KS5kZWxheXRpbWUoLjExKS5kZWxheWZlZWRiYWNrKC45KQogIC5tYXNrKCI8MCAxPi84IikKKS5lYXJseSgyKQouZmFzdCgyLzMp)
- [fuzzy planet](https://felixroos.github.io/strudel/#Ly8gc3BlZWRydW4gbm8gMywgdGhpcyB0aW1lIGEgbW9yZSBmdXp6eSB0eXBlIG9mIGdlbnJlCgphd2FpdCBzYW1wbGVzKCdnaXRodWI6ZmVsaXhyb29zL3NhbXBsZXMvbWFpbicpCmF3YWl0IHNhbXBsZXMoJ2dpdGh1Yjp0aWRhbGN5Y2xlcy9EaXJ0LVNhbXBsZXMvbWFzdGVyJykKCnNhbXBsZXMoeyBwbHVjazoge2U0OiAnaHR0cHM6Ly9jZG4uZnJlZXNvdW5kLm9yZy9wcmV2aWV3cy81OTIvNTkyNDQyXzEwODcwODgwLWxxLm1wMyd9IH0pCgphZGRWb2ljaW5ncygnY29va2llJywgewogIDc6IFsnM00gN20gOU0gMTJQIDE1UCcsICc3bSAxME0gMTNNIDE2TSAxOVAnXSwKICAnXjcnOiBbJzNNIDZNIDlNIDEyUCAxNE0nLCAnN00gMTBNIDEzTSAxNk0gMTlQJ10sCiAgbTc6IFsnOFAgMTFQIDE0bSAxN20gMTlQJywgJzVQIDhQIDExUCAxNG0gMTdtJ10sCiAgbTdiNTogWyczbSA1ZCA4UCAxMVAgMTRtJywgJzVkIDhQIDExUCAxNG0gMTdtJ10sCiAgbzc6IFsnM20gNk0gOU0gMTFBIDE1UCddLAogICc3YWx0JzogWyczTSA3bSAxMG0gMTNtIDE1UCddLAogICc3IzExJzogWyc3bSAxMG0gMTNtIDE1UCAxN20nXSwKfSwgWydDMycsICdDNiddKQoKc3RhY2soCiAgIjxDbTchMiBEbTdiNSBDIzcjMTE%2BLzQiLmxheWVyKAogICAgeD0%2BeC52b2ljaW5ncygnY29va2llJykubm90ZSgpLnMoJ3BsdWNrJykuY2xpcCgxKQogICAgICAuYXJwKCJbMyAyIDEgMEAyMV0gWzAgMSAyIDMgNEAyMV0iLmxlZ2F0byg0MCkuZmFzdCgyKSkuZWFybHkoMS80OCkKICAgICAgLmxwZihzaW5lLnJhbmdlKDQwMCw0MDAwKS5zbG93KDE2KSkuZ2FpbigxLjIpLnBhbiguMjUpLAogICAgeD0%2BeC5yb290Tm90ZXMoMikuYWRkLm91dCgiWzBAMyAwXSBbNyAxMiB%2BIDEyXSB%2BIH4iLnNsb3coMikpLm5vdGUoKQogICAgICAucygnamF6emJhc3MnKS5jbGlwKDEpLmdhaW4oLjgpLAogICAgeD0%2BeC52b2ljaW5ncygnY29va2llJykuYWRkKCItLjEsLjEiKS5ub3RlKCkKICAgICAgLnMoJ3NpbmUnKS5hdHRhY2soLjUpLmRlY2F5KC4yKS5zdXN0YWluKC41KS5nYWluKC4xKS5wYW4oLjc1KSwKICAgIHg9Pngudm9pY2luZ3MoJ2Nvb2tpZScpLmFkZCgwKS5hcnAoInsxIFsyIDNdIDAhM30lNCIpLm5vdGUoKQogICAgICAucygnc3F1YXJlJykubHBmKHNpbmUucmFuZ2UoNDAwLDIwMDApLnNsb3coMzYpKS5kZWdyYWRlKCkKICAgICAgLmRlY2F5KC4xKS5zdXN0YWluKDApLm9mZigxLzYsIGFkZChub3RlKDEyKSkpLnJvb20oLjgpLmdhaW4oLjYpCiAgKSwKICBzdGFjaygKICAgIHMoImJkIFt%2BIDx%2BIGJkPl0iKS5uKDIpLnNwZWVkKC41KS5iYW5rKCdSb2xhbmRUUjkwOScpLmdhaW4oIi44IC41IiksCiAgICBzKCJiZCoyIi5sYXRlKC4yNSkpLnNwZWVkKC41KS5iYW5rKCdVbml2b3hNaWNyb1JoeXRobWVyMTInKS5ocGYoMjAwMCkucm9vbSguMjUpLAogICAgcygifiBzZCIpLnNwZWVkKC4yNSkuYmFuaygnVW5pdm94TWljcm9SaHl0aG1lcjEyJykucm9vbSguNSkuZW5kKCI8LjA0QDMgLjg%2BIikKICApCikKLnNsb3coMikuY3BtKDkyKQ%3D%3D)
- [wutang](https://felixroos.github.io/strudel/#YXdhaXQgc2FtcGxlcygnZ2l0aHViOmZlbGl4cm9vcy9zYW1wbGVzL21haW4nKQphd2FpdCBzYW1wbGVzKCdnaXRodWI6eWF4dS9jbGVhbi1icmVha3MvbWFpbi8nKQoKY29uc3QgcnVuID0gKG4pID0%2BIHNhdy5yYW5nZSgwLG4pLmZsb29yKCkuc2VnbWVudChuKQoKc3RhY2soCiAgbihydW4oOCkuc2xvdygyKS5hZGQoMSkpLnMoInJlbmUiKQogIC5jbGlwKDEpLmxhc3RPZig0LHJldikKICAuc29tZXRpbWVzKHBseSgyKSkKICAubGFzdE9mKDgsIHg9Pnguc3BlZWQoMS41KSksCiAgcygiYWN0aW9uIikubG9vcEF0KDIpLmNob3AoOCkuZ2FpbiguNCkKICAubHBmKHNpbmUucmFuZ2UoMTUwMCw4MDAwKS5zbG93KDgpKS5scHEoMTIpCiAgLnJhcmVseSh4PT54LnNwZWVkKCIxLDQiKS5tdWwoZ2FpbiguNSkpKQogIC5hbG1vc3ROZXZlcih4PT54LnBseSgiNCIpKQopCiAgCg%3D%3D)
- [african groove](https://felixroos.github.io/strudel/#YXdhaXQgc2FtcGxlcygnZ2l0aHViOmZlbGl4cm9vcy9zYW1wbGVzL21haW4nKQoKc3RhY2soCiAgcygiYmQgc2QsaGgoPDMgNCAzIDU%2BLDgsPDAgMSAwIFswIDFdPiksPH5AMyBvaD4iKS5iYW5rKCdwcmVzaWRlbnQnKSwKICBzdGFjaygKICAgIG5vdGUoIntjIGViIDxnIGEgYmIgYT4gZWJ9JTMqPDFAMyAyPiIuYWRkKDEyKSkucygiZ21fZWxlY3RyaWNfZ3VpdGFyX211dGVkOjAiKQogICAgLmxwZihjb3NpbmUucmFuZ2UoMjAwLDgwMDApLnNsb3coMTYpKS5wYW4oc2luZS5zbG93KDgpKSwKICAgIG5vdGUoIn4gW1tjNCA8ZzMgYTMgYmIzIGEzPiBlYjNdIH5ANF0iLmFkZCgxMikpLnMoImdtX2VsZWN0cmljX2d1aXRhcl9jbGVhbjowIikucmVsZWFzZSguNSkuZ2FpbiguMzUpCiAgICAuYnBmKHBlcmxpbi5yYW5nZSgxMDAwLDUwMDApKS5zaGFwZSguNSksCiAgICBub3RlKCI8W3tjMioyIGcyIFtlYjIgZWIzXX0lMiB%2BXSBbZWIyIH5dKDMsOCk%2BIikucygiZ21fc2xhcF9iYXNzXzE6MSIpLm9mZiguMjUsIGFkZChub3RlKDEyKSkpLmxwZig4MDApLAogICAgbm90ZSgiYzUqOCIpLmxwZihzaW5lLnJhbmdlKDIwMCw4MDAwKS5zbG93KDE2KSkubHBxKDUpLnMoJ3h5bG8nKS5kZWdyYWRlKCkuanV4KHJldikuZ2FpbiguNCkKICApLnN1Yihub3RlKCI8NUAxNiA3QDg%2BIikpCikuZmFzdCg0LzUpLnJvb20oLjUp)
- [yaxu groove](https://felixroos.github.io/strudel/#c2V0Y3BzKDEuMSkKCnMoIntiZCB%2BIHJpbSB%2BLCB%2BIH4gaGh9IikuYmFuaygnUm9sYW5kVFI5MDknKQogIC5jaHVuayg0LCBmYXN0KDIpKQogIC5qdXgocmV2KQogIC5vZmYoLjI1LCBtdWwoc3BlZWQoLjgpKSkKICAuc3VwZXJpbXBvc2UoCiAgICB4PT54LnZvd2VsKCI8YSA8ZSBpPj4vNCIpLnJvb20oMikuc2xvdygyKS5sYXRlKC4yNSkuY29sb3IoIiMwMGZmMDA1MCIpCiAgKQogIC5sYXN0T2YoOCwgbXVsKHNwZWVkKC0yKSkpCiAgLmNvbG9yKCJbIzAwMDBmZjUwICNmZmZmMDAyMF0qMyIpCiAgLnB1bmNoY2FyZCgpCgo%3D)
- [dubby techno](https://felixroos.github.io/strudel/#Ly8gaHR0cHM6Ly9zdHJ1ZGVsLnRpZGFsY3ljbGVzLm9yZy8%2FTUNjNC1jRE93SWRHCi8vIGZyb29zIC0gY3J1bWJsaW5nIGR1bXBsaW5ncwoKbGV0IGNob3JkcyA9ICI8RG0hNyA8QSEzIDxGIEM%2BPj4iCgpzdGFjaygKICBzKCI8fiExNiBiZCoyITQwPix%2BIDx%2BITMyIHNkOjIhMjQ%2BLCA8fiEyOCBbfiBoaDoxXSoyITI4PiIpCiAgLmJhbmsoJ1JvbGFuZFRSOTA5JyksCiAgCiAgcygifiBoaCwgfiByaW0gfkAyIikKICAuYmFuaygnUm9sYW5kVFI5MDknKQogIC5qdXhCeSguNSwgcmV2KQogIC5zZXQubWl4KHNwZWVkKCIxIFs8MSAyPiA8LjkgPC43NSAuOD4%2BXSIpKQogIC5sYXN0T2YoOCwgZmFzdCgiMSBbPDMgND4gMl0iKSkuZ2FpbiguOCkKICAubHBmKHNpbmUucmFuZ2UoODAwLCA4MDAwKS5zbG93KDE1KS5sYXRlKDUpKQogIC5nYWluKC41KSwKICAKICBjaG9yZHMudm9pY2luZ3MoJ3RyaWFkcycpLm5vdGUoKQogIC5hcnAoIjAgMSAyIDEiKS5hZGQobm90ZSgiPDAgMTI%2BLzE2IikpCiAgLnJhcmVseSh4PT54LmFkZChub3RlKCIxMiIpKSkKICAucygncGlhbm8nKS5jbGlwKDEpCiAgLmRlY2F5KHBlcmxpbi5yYW5nZSguMSwuNSkpLnN1c3RhaW4oMCkKICAucm9vbShzaW5lLnJhbmdlKDAsIDQpLnNsb3coMTYpKQogIC5vZmYoMS84LCBhZGQobm90ZSgxMikpKQogIC5scGYoY29zaW5lLnJhbmdlKDIwMCwyMDAwKS5zbG93KDMyKSkKICAubHBxKDgpLmp1eChyZXYpLmdhaW4oLjQpLAogIAogIGNob3Jkcy52b2ljaW5ncygndHJpYWRzJykKICAubm90ZSgpLmF0dGFjaygiPC4wMSAuMDg%2BLzMyIikuc3VzdGFpbigwKS5zdHJ1Y3QoIlt%2BIHhdKjIiKQogIC5zKCJzcXVhcmUsdHJpYW5nbGUiKQogIC5scGYocGVybGluLnJhbmdlKDQwMCw4MDApLnNsb3coMS4yKSkKICAucmFyZWx5KG9mZigxLzgseD0%2BeC5hZGQobm90ZSgiMTIiKSkubHBmKDgwMCkpKQogIC5yb29tKC41KS5nYWluKC42KSwKICAKICBjaG9yZHMucm9vdE5vdGVzKDIpLmFkZCgiMCwuMSIpLm5vdGUoKS5zKCdzYXd0b290aCcpCiAgLmRlY2F5KC4xKS5zdXN0YWluKDApCiAgLmdhaW4oIlsuMyAxXSoyIikKICAucGx5KDgpLmxwZihzaW5lLnJhbmdlKDgwMCwyMDAwKS5zbG93KDgpKQogIC5scHEoMTApLm11bChnYWluKC44KSkKKQogIC5sYXRlKCJbMCAuMDJdKjQiKQogIC5jcG0oMTAwLzIp)
@@ -139,10 +139,6 @@ This group of functions allows to modify the value of events.
<JsDoc client:idle name="Pattern.range2" h={0} /> <JsDoc client:idle name="Pattern.range2" h={0} />
## ratio
<JsDoc client:idle name="Pattern.ratio" h={0} />
# Custom Parameters # Custom Parameters
You can also create your own parameters: You can also create your own parameters:
+1 -1
View File
@@ -32,4 +32,4 @@ import { JsDoc } from '../../docs/JsDoc';
<JsDoc client:idle name="stut" h={0} /> <JsDoc client:idle name="stut" h={0} />
There are also [Tonal Functions](/learn/tonal). There are also [Tonal Modifiers](/learn/tonal).
+1 -1
View File
@@ -1,3 +1,3 @@
<script is:inline> <script is:inline>
window.location.pathname = `/workshop/getting-started`; window.location.pathname = `/learn/getting-started`;
</script> </script>
@@ -38,10 +38,6 @@ Some of these have equivalent operators in the Mini Notation:
<JsDoc client:idle name="Pattern.legato" h={0} /> <JsDoc client:idle name="Pattern.legato" h={0} />
## clip
<JsDoc client:idle name="clip" h={0} />
## euclid ## euclid
<JsDoc client:idle name="Pattern.euclid" h={0} /> <JsDoc client:idle name="Pattern.euclid" h={0} />
+18 -18
View File
@@ -1,29 +1,14 @@
--- ---
title: Tonal Functions title: Tonal API
layout: ../../layouts/MainLayout.astro layout: ../../layouts/MainLayout.astro
--- ---
import { MiniRepl } from '../../docs/MiniRepl'; import { MiniRepl } from '../../docs/MiniRepl';
import { JsDoc } from '../../docs/JsDoc'; import { JsDoc } from '../../docs/JsDoc';
# Tonal Functions # Tonal API
These functions use [tonaljs](https://github.com/tonaljs/tonal) to provide helpers for musical operations. The Tonal API, uses [tonaljs](https://github.com/tonaljs/tonal) to provide helpers for musical operations.
### scale(name)
Turns numbers into notes in the scale (zero indexed). Also sets scale for other scale operations, like scaleTranspose.
<MiniRepl
client:idle
tune={`"0 2 4 6 4 2"
.scale("C2:major C2:minor").slow(2))
.note().s("piano")`}
/>
Note that the scale root is octaved here. You can also omit the octave, then index zero will default to octave 3.
All the available scale names can be found [here](https://github.com/tonaljs/tonal/blob/main/packages/scale-type/data.ts).
### transpose(semitones) ### transpose(semitones)
@@ -37,6 +22,21 @@ Instead of numbers, scientific interval notation can be used as well:
<MiniRepl client:only="react" tune={`"c2 c3".fast(2).transpose("<1P -2M 4P 3m>".slow(2)).note()`} /> <MiniRepl client:only="react" tune={`"c2 c3".fast(2).transpose("<1P -2M 4P 3m>".slow(2)).note()`} />
### scale(name)
Turns numbers into notes in the scale (zero indexed). Also sets scale for other scale operations, like scaleTranspose.
<MiniRepl
client:idle
tune={`"0 2 4 6 4 2"
.scale(seq('C2 major', 'C2 minor').slow(2))
.note()`}
/>
Note that the scale root is octaved here. You can also omit the octave, then index zero will default to octave 3.
All the available scale names can be found [here](https://github.com/tonaljs/tonal/blob/main/packages/scale-type/data.ts).
### scaleTranspose(steps) ### scaleTranspose(steps)
Transposes notes inside the scale by the number of steps: Transposes notes inside the scale by the number of steps:
+1 -1
View File
@@ -1,3 +1,3 @@
This section introduces you to Strudel in a technical sense. If you just want to _use_ Strudel, have a look at the [Tutorial](/workshop/getting-started). This section introduces you to Strudel in a technical sense. If you just want to _use_ Strudel, have a look at the [Tutorial](/learn/getting-started).
TODO TODO
@@ -7,7 +7,7 @@ import { MiniRepl } from '../../docs/MiniRepl';
# Strudel Packages # Strudel Packages
The [strudel repo](https://github.com/tidalcycles/strudel) is organized as a monorepo, containing multiple npm packages. The [strudel repo](github.com/tidalcycles/strudel) is organized as a monorepo, containing multiple npm packages.
The purpose of the multiple packages is to The purpose of the multiple packages is to
- organize the codebase into more modular, encapsulated pieces - organize the codebase into more modular, encapsulated pieces
+1 -1
View File
@@ -1,3 +1,3 @@
<script is:inline> <script is:inline>
window.location.pathname = `/workshop/getting-started`; window.location.pathname = `/learn/getting-started`;
</script> </script>
@@ -80,6 +80,7 @@ These letter combinations stand for different parts of a drum set:
- `bd` = **b**ass **d**rum - `bd` = **b**ass **d**rum
- `sd` = **s**nare **d**rum - `sd` = **s**nare **d**rum
- `sd` = **sd**are
- `rim` = **rim**shot - `rim` = **rim**shot
- `hh` = **h**i**h**at - `hh` = **h**i**h**at
- `oh` = **o**pen **h**ihat - `oh` = **o**pen **h**ihat
-75
View File
@@ -1,75 +0,0 @@
import { Fragment, useEffect } from 'react';
import React, { useMemo, useState } from 'react';
import { isAudioFile, readDir, dir, playFile } from './files.mjs';
export function FilesTab() {
const [path, setPath] = useState([]);
useEffect(() => {
let init = false;
readDir('', { dir, recursive: true })
.then((children) => setPath([{ name: '~/music', children }]))
.catch((err) => {
console.log('error loadin files', err);
});
return () => {
init = true;
};
}, []);
const current = useMemo(() => path[path.length - 1], [path]);
const subpath = useMemo(
() =>
path
.slice(1)
.map((p) => p.name)
.join('/'),
[path],
);
const folders = useMemo(() => current?.children.filter((e) => !!e.children), [current]);
const files = useMemo(() => current?.children.filter((e) => !e.children && isAudioFile(e.name)), [current]);
const select = (e) => setPath((p) => p.concat([e]));
return (
<div className="px-4 flex flex-col h-full">
<div className="flex justify-between font-mono pb-1">
<div>
<span>{`samples('`}</span>
{path?.map((p, i) => {
if (i < path.length - 1) {
return (
<Fragment key={i}>
<span className="cursor-pointer underline" onClick={() => setPath((p) => p.slice(0, i + 1))}>
{p.name}
</span>
<span>/</span>
</Fragment>
);
} else {
return (
<span className="cursor-pointer underline" key={i}>
{p.name}
</span>
);
}
})}
<span>{`')`}</span>
</div>
</div>
<div className="overflow-auto">
{!folders?.length && !files?.length && <span className="text-gray-500">Nothing here</span>}
{folders?.map((e, i) => (
<div className="cursor-pointer" key={i} onClick={() => select(e)}>
{e.name}
</div>
))}
{files?.map((e, i) => (
<div
className="text-gray-500 cursor-pointer select-none"
key={i}
onClick={async () => playFile(`${subpath}/${e.name}`)}
>
{e.name}
</div>
))}
</div>
</div>
);
}
+3 -27
View File
@@ -9,9 +9,6 @@ import { themes } from './themes.mjs';
import { useSettings, settingsMap, setActiveFooter, defaultSettings } from '../settings.mjs'; import { useSettings, settingsMap, setActiveFooter, defaultSettings } from '../settings.mjs';
import { getAudioContext, soundMap } from '@strudel.cycles/webaudio'; import { getAudioContext, soundMap } from '@strudel.cycles/webaudio';
import { useStore } from '@nanostores/react'; import { useStore } from '@nanostores/react';
import { FilesTab } from './FilesTab';
const TAURI = window.__TAURI__;
export function Footer({ context }) { export function Footer({ context }) {
const footerContent = useRef(); const footerContent = useRef();
@@ -80,7 +77,6 @@ export function Footer({ context }) {
<FooterTab name="console" /> <FooterTab name="console" />
<FooterTab name="reference" /> <FooterTab name="reference" />
<FooterTab name="settings" /> <FooterTab name="settings" />
{TAURI && <FooterTab name="files" />}
</div> </div>
{activeFooter !== '' && ( {activeFooter !== '' && (
<button onClick={() => setActiveFooter('')} className="text-foreground" aria-label="Close Panel"> <button onClick={() => setActiveFooter('')} className="text-foreground" aria-label="Close Panel">
@@ -95,7 +91,6 @@ export function Footer({ context }) {
{activeFooter === 'sounds' && <SoundsTab />} {activeFooter === 'sounds' && <SoundsTab />}
{activeFooter === 'reference' && <Reference />} {activeFooter === 'reference' && <Reference />}
{activeFooter === 'settings' && <SettingsTab scheduler={context.scheduler} />} {activeFooter === 'settings' && <SettingsTab scheduler={context.scheduler} />}
{activeFooter === 'files' && <FilesTab />}
</div> </div>
)} )}
</footer> </footer>
@@ -145,7 +140,7 @@ function WelcomeTab() {
</p> </p>
<p> <p>
To learn more about what this all means, check out the{' '} To learn more about what this all means, check out the{' '}
<a href="./workshop/getting-started" target="_blank"> <a href="./learn/getting-started" target="_blank">
interactive tutorial interactive tutorial
</a> </a>
. Also feel free to join the{' '} . Also feel free to join the{' '}
@@ -369,16 +364,7 @@ const fontFamilyOptions = {
}; };
function SettingsTab({ scheduler }) { function SettingsTab({ scheduler }) {
const { const { theme, keybindings, isLineNumbersDisplayed, fontSize, fontFamily } = useSettings();
theme,
keybindings,
isLineNumbersDisplayed,
isAutoCompletionEnabled,
isLineWrappingEnabled,
fontSize,
fontFamily,
} = useSettings();
return ( return (
<div className="text-foreground p-4 space-y-4"> <div className="text-foreground p-4 space-y-4">
{/* <FormItem label="Tempo"> {/* <FormItem label="Tempo">
@@ -420,7 +406,7 @@ function SettingsTab({ scheduler }) {
/> />
</FormItem> </FormItem>
</div> </div>
<div className="grid grid-cols-1 md:grid-cols-4 gap-4"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<FormItem label="Keybindings"> <FormItem label="Keybindings">
<ButtonGroup <ButtonGroup
value={keybindings} value={keybindings}
@@ -433,16 +419,6 @@ function SettingsTab({ scheduler }) {
onChange={(cbEvent) => settingsMap.setKey('isLineNumbersDisplayed', cbEvent.target.checked)} onChange={(cbEvent) => settingsMap.setKey('isLineNumbersDisplayed', cbEvent.target.checked)}
value={isLineNumbersDisplayed} value={isLineNumbersDisplayed}
/> />
<Checkbox
label="Enable auto-completion"
onChange={(cbEvent) => settingsMap.setKey('isAutoCompletionEnabled', cbEvent.target.checked)}
value={isAutoCompletionEnabled}
/>
<Checkbox
label="Enable line wrapping"
onChange={(cbEvent) => settingsMap.setKey('isLineWrappingEnabled', cbEvent.target.checked)}
value={isLineWrappingEnabled}
/>
</div> </div>
<FormItem label="Reset Settings"> <FormItem label="Reset Settings">
<button <button
-8
View File
@@ -45,11 +45,3 @@
#code .cm-theme-light { #code .cm-theme-light {
width: 100%; width: 100%;
} }
#code .cm-cursorLayer {
animation-name: inherit !important;
}
#code .cm-cursor {
border-left: 2px solid currentcolor !important;
}
+2 -14
View File
@@ -19,7 +19,6 @@ import PlayCircleIcon from '@heroicons/react/20/solid/PlayCircleIcon';
import { themes } from './themes.mjs'; import { themes } from './themes.mjs';
import { settingsMap, useSettings, setLatestCode } from '../settings.mjs'; import { settingsMap, useSettings, setLatestCode } from '../settings.mjs';
import Loader from './Loader'; import Loader from './Loader';
import { settingPatterns } from '../settings.mjs';
const { latestCode } = settingsMap.get(); const { latestCode } = settingsMap.get();
@@ -46,7 +45,6 @@ const modules = [
const modulesLoading = evalScope( const modulesLoading = evalScope(
controls, // sadly, this cannot be exported from core direclty controls, // sadly, this cannot be exported from core direclty
settingPatterns,
...modules, ...modules,
); );
@@ -107,15 +105,7 @@ export function Repl({ embedded = false }) {
const [lastShared, setLastShared] = useState(); const [lastShared, setLastShared] = useState();
const [pending, setPending] = useState(true); const [pending, setPending] = useState(true);
const { const { theme, keybindings, fontSize, fontFamily, isLineNumbersDisplayed } = useSettings();
theme,
keybindings,
fontSize,
fontFamily,
isLineNumbersDisplayed,
isAutoCompletionEnabled,
isLineWrappingEnabled,
} = useSettings();
const { code, setCode, scheduler, evaluate, activateCode, isDirty, activeCode, pattern, started, stop, error } = const { code, setCode, scheduler, evaluate, activateCode, isDirty, activeCode, pattern, started, stop, error } =
useStrudel({ useStrudel({
@@ -167,7 +157,7 @@ export function Repl({ embedded = false }) {
e.preventDefault(); e.preventDefault();
flash(view); flash(view);
await activateCode(); await activateCode();
} else if (e.key === '.' || e.code === 'Period') { } else if (e.key === '.' || e.keyCode === 'Period') {
stop(); stop();
e.preventDefault(); e.preventDefault();
} }
@@ -282,8 +272,6 @@ export function Repl({ embedded = false }) {
value={code} value={code}
keybindings={keybindings} keybindings={keybindings}
isLineNumbersDisplayed={isLineNumbersDisplayed} isLineNumbersDisplayed={isLineNumbersDisplayed}
isAutoCompletionEnabled={isAutoCompletionEnabled}
isLineWrappingEnabled={isLineWrappingEnabled}
fontSize={fontSize} fontSize={fontSize}
fontFamily={fontFamily} fontFamily={fontFamily}
onChange={handleChangeCode} onChange={handleChangeCode}
-107
View File
@@ -1,107 +0,0 @@
import {
processSampleMap,
registerSamplesPrefix,
registerSound,
onTriggerSample,
getAudioContext,
loadBuffer,
} from '@strudel.cycles/webaudio';
let TAURI;
if (typeof window !== 'undefined') {
TAURI = window?.__TAURI__;
}
export const { BaseDirectory, readDir, readBinaryFile, writeTextFile, readTextFile, exists } = TAURI?.fs || {};
export const dir = BaseDirectory?.Audio; // https://tauri.app/v1/api/js/path#audiodir
const prefix = '~/music/';
async function hasStrudelJson(subpath) {
return exists(subpath + '/strudel.json', { dir });
}
async function loadStrudelJson(subpath) {
const contents = await readTextFile(subpath + '/strudel.json', { dir });
const sampleMap = JSON.parse(contents);
processSampleMap(sampleMap, (key, value) => {
registerSound(key, (t, hapValue, onended) => onTriggerSample(t, hapValue, onended, value, fileResolver(subpath)), {
type: 'sample',
samples: value,
fileSystem: true,
tag: 'local',
});
});
}
async function writeStrudelJson(subpath) {
const children = await readDir(subpath, { dir, recursive: true });
const name = subpath.split('/').slice(-1)[0];
const tree = { name, children };
let samples = {};
let count = 0;
walkFileTree(tree, (entry, parent) => {
if (['wav', 'mp3'].includes(entry.name.split('.').slice(-1)[0])) {
samples[parent.name] = samples[parent.name] || [];
count += 1;
samples[parent.name].push(entry.subpath.slice(1).concat([entry.name]).join('/'));
}
});
const json = JSON.stringify(samples, null, 2);
const filepath = subpath + '/strudel.json';
await writeTextFile(filepath, json, { dir });
console.log(`wrote strudel.json with ${count} samples to ${subpath}!`);
}
registerSamplesPrefix(prefix, async (path) => {
const subpath = path.replace(prefix, '');
const hasJson = await hasStrudelJson(subpath);
if (!hasJson) {
await writeStrudelJson(subpath);
}
return loadStrudelJson(subpath);
});
export const walkFileTree = (node, fn) => {
if (!Array.isArray(node?.children)) {
return;
}
for (const entry of node.children) {
entry.subpath = (node.subpath || []).concat([node.name]);
fn(entry, node);
if (entry.children) {
walkFileTree(entry, fn);
}
}
};
export const isAudioFile = (filename) => ['wav', 'mp3'].includes(filename.split('.').slice(-1)[0]);
function uint8ArrayToDataURL(uint8Array) {
const blob = new Blob([uint8Array], { type: 'audio/*' });
const dataURL = URL.createObjectURL(blob);
return dataURL;
}
const loadCache = {}; // caches local urls to data urls
export async function resolveFileURL(url) {
if (loadCache[url]) {
return loadCache[url];
}
loadCache[url] = (async () => {
const contents = await readBinaryFile(url, { dir });
return uint8ArrayToDataURL(contents);
})();
return loadCache[url];
}
const fileResolver = (subpath) => (url) => resolveFileURL(subpath.endsWith('/') ? subpath + url : subpath + '/' + url);
export async function playFile(path) {
const url = await resolveFileURL(path);
const ac = getAudioContext();
const bufferSource = ac.createBufferSource();
bufferSource.buffer = await loadBuffer(url, ac);
bufferSource.connect(ac.destination);
bufferSource.start(ac.currentTime);
}
+1 -2
View File
@@ -1,7 +1,6 @@
import { Pattern, noteToMidi, valueToMidi } from '@strudel.cycles/core'; import { Pattern, noteToMidi, valueToMidi } from '@strudel.cycles/core';
import { registerSynthSounds, samples } from '@strudel.cycles/webaudio'; import { registerSynthSounds, samples } from '@strudel.cycles/webaudio';
import './piano.mjs'; import './piano.mjs';
import './files.mjs';
export async function prebake() { export async function prebake() {
// https://archive.org/details/SalamanderGrandPianoV3 // https://archive.org/details/SalamanderGrandPianoV3
@@ -119,7 +118,7 @@ const maxPan = noteToMidi('C8');
const panwidth = (pan, width) => pan * width + (1 - width) / 2; const panwidth = (pan, width) => pan * width + (1 - width) / 2;
Pattern.prototype.piano = function () { Pattern.prototype.piano = function () {
return this.fmap((v) => ({ ...v, clip: v.clip ?? 1 })) // set clip if not already set.. return this.clip(1)
.s('piano') .s('piano')
.release(0.1) .release(0.1)
.fmap((value) => { .fmap((value) => {
+102 -70
View File
@@ -205,24 +205,27 @@ samples({
} }
}, 'https://loophole-letters.vercel.app/') }, 'https://loophole-letters.vercel.app/')
const scales = cat('C major', 'C mixolydian', 'F lydian', ['F minor', cat('Db major','Db mixolydian')])
stack( stack(
s("<bd sn> <hh hh*2 hh*3>").color('#00B8D4'), s("<bd sn> <hh hh*2 hh*3>").color('#00B8D4'),
"<g4 c5 a4 [ab4 <eb5 f5>]>" "<g4 c5 a4 [ab4 <eb5 f5>]>"
.scale("<C:major C:mixolydian F:lydian [F:minor <Db:major Db:mixolydian>]>") .scale(scales)
.struct("x*8") .struct("x*8")
.scaleTranspose("0 [-5,-2] -7 [-9,-2]") .scaleTranspose("0 [-5,-2] -7 [-9,-2]")
.legato(.3)
.slow(2) .slow(2)
.note() .note()
.clip(.3)
.s('rhodes') .s('rhodes')
.clip(1)
.room(.5) .room(.5)
.delay(.3) .delay(.3)
.delayfeedback(.4) .delayfeedback(.4)
.delaytime(1/12).gain(.5).color('#7ED321'), .delaytime(1/12).gain(.5).color('#7ED321'),
"<c2 c3 f2 [[F2 C2] db2]>/2" "<c2 c3 f2 [[F2 C2] db2]>"
.add("0,.02") .legato("<1@3 [.3 1]>")
.slow(2).superimpose(x=>x.add(.02))
.note().gain(.3) .note().gain(.3)
.clip("<1@3 [.3 1]>/2")
.s('sawtooth').cutoff(600).color('#F8E71C'), .s('sawtooth').cutoff(600).color('#F8E71C'),
).fast(3/2) ).fast(3/2)
//.pianoroll({fold:1})`; //.pianoroll({fold:1})`;
@@ -234,7 +237,7 @@ export const wavyKalimba = `// "Wavy kalimba"
samples({ samples({
'kalimba': { c5:'https://freesound.org/data/previews/536/536549_11935698-lq.mp3' } 'kalimba': { c5:'https://freesound.org/data/previews/536/536549_11935698-lq.mp3' }
}) })
const scales = "<C:major C:mixolydian F:lydian [F:minor Db:major]>" const scales = cat('C major', 'C mixolydian', 'F lydian', ['F minor', 'Db major'])
stack( stack(
"[0 2 4 6 9 2 0 -2]*3" "[0 2 4 6 9 2 0 -2]*3"
@@ -251,11 +254,13 @@ stack(
.velocity(0.8) .velocity(0.8)
.slow(2) .slow(2)
) )
.legato("<.4 .8 1 1.2 1.4 1.6 1.8 2>/8")
.fast(1) .fast(1)
.note() .note()
.clip("<.4 .8 1 1.2 1.4 1.6 1.8 2>/8") .clip(1)
.s('kalimba') .s('kalimba')
.delay(.2)`; .delay(.2)
`;
export const festivalOfFingers = `// "Festival of fingers" export const festivalOfFingers = `// "Festival of fingers"
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ // @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
@@ -288,19 +293,19 @@ stack(
s("<<bd*2 bd> sn> hh").fast(2).gain(.7), s("<<bd*2 bd> sn> hh").fast(2).gain(.7),
"[c2 a1 bb1 ~] ~" "[c2 a1 bb1 ~] ~"
.echo(2, 1/16, 1) .echo(2, 1/16, 1)
.legato(.4)
.slow(2) .slow(2)
.layer(h) .layer(h)
.note().s('square') .note().s('square')
.clip(.4)
.cutoff(400).decay(.12).sustain(0) .cutoff(400).decay(.12).sustain(0)
, ,
"[g2,[c3 eb3]]".iter(4) "[g2,[c3 eb3]]".iter(4)
.echoWith(4, 1/8, (x,n)=>x.transpose(n*12).velocity(Math.pow(.4,n))) .echoWith(4, 1/8, (x,n)=>x.transpose(n*12).velocity(Math.pow(.4,n)))
.legato(.1)
.layer(h).note() .layer(h).note()
.clip(.1)
) )
.fast(2/3) .fast(2/3)
.pianoroll()`; .pianoroll({})`;
export const bridgeIsOver = `// "Bridge is over" export const bridgeIsOver = `// "Bridge is over"
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ // @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
@@ -309,16 +314,19 @@ export const bridgeIsOver = `// "Bridge is over"
samples({mad:'https://freesound.org/data/previews/22/22274_109943-lq.mp3'}) samples({mad:'https://freesound.org/data/previews/22/22274_109943-lq.mp3'})
stack( stack(
stack( stack(
note("c3*2 [[c3@1.4 bb2] ab2] gb2*2 <[[gb2@1.4 ab2] bb2] gb2>") "c3*2 [[c3@1.4 bb2] ab2] gb2*2 <[[gb2@1.4 ab2] bb2] gb2>".legato(".5 1".fast(2)).velocity(.8),
.gain(.8).clip("[.5 1]*2"), "0 ~".scale('c4 whole tone')
n("<0 1 2 3 4 3 2 1>") .euclidLegato(3,8).slow(2).mask("x ~")
.clip(.5) .stutWith(8, 1/16, (x,n)=>x.scaleTranspose(n).velocity(Math.pow(.7,n)))
.echoWith(8, 1/32, (x,i)=>x.add(n(i)).velocity(Math.pow(.7,i))) .scaleTranspose("<0 1 2 3 4 3 2 1>")
.scale('c4 whole tone') .fast(2)
.echo(3, 1/8, .5) .velocity(.7)
).piano(), .legato(.5)
.stut(3, .5, 1/8)
).transpose(-1).note().piano(),
s("mad").slow(2) s("mad").slow(2)
).cpm(78).slow(4) ).cpm(78).slow(4)
.pianoroll() .pianoroll()
`; `;
@@ -328,39 +336,63 @@ export const goodTimes = `// "Good times"
const scale = cat('C3 dorian','Bb2 major').slow(4); const scale = cat('C3 dorian','Bb2 major').slow(4);
stack( stack(
n("2*4".add(12)).off(1/8, add(2)) "2*4".add(12).scale(scale)
.off(1/8, scaleTranspose("2")).fast(2)
.scaleTranspose("<0 1 2 1>").hush(),
"<0 1 2 3>(3,8,2)"
.scale(scale) .scale(scale)
.fast(2) .off(1/4, scaleTranspose("2,4")),
.add("<0 1 2 1>").hush(), "<0 4>(5,8,-1)".scale(scale).transpose(-12)
"<0 1 2 3>(3,8,2)".off(1/4, add("2,4"))
.n().scale(scale),
n("<0 4>(5,8,-1)").scale(scale).sub(note(12))
) )
.velocity(".6 .7".fast(4)) .velocity(".6 .7".fast(4))
.add(note(4)) .legato("2")
.piano() .scaleTranspose("<0>".slow(4))
.clip(2) .transpose(5)
.note().piano()
.velocity(.8) .velocity(.8)
.slow(2) .slow(2)
.pianoroll()`; .pianoroll({maxMidi:100,minMidi:20})`;
/* // new style notation:
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(
n("2*4").add(12)
.off(1/8, add("2")).fast(2)
.add("<0 1 2 1>").hush(),
n("<0 1 2 3>(3,8,2)")
.off(1/4, add("2,4")),
n("<0 4>(5,8,-1)").sub(7)
)
.scale(scale)
.gain(".6 .7".fast(4))
.legato(2)
.add(note(5))
.piano()
.mul(gain(.8))
.slow(2)
.pianoroll({maxMidi:100,minMidi:20})`;
*/
export const echoPiano = `// "Echo piano" export const echoPiano = `// "Echo piano"
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ // @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// @by Felix Roos // @by Felix Roos
n("<0 2 [4 6](3,4,2) 3*2>").color('salmon') "<0 2 [4 6](3,4,2) 3*2>"
.off(1/4, x=>x.add(2).color('green'))
.off(1/2, x=>x.add(6).color('steelblue'))
.scale('D minor') .scale('D minor')
.color('salmon')
.off(1/4, x=>x.scaleTranspose(2).color('green'))
.off(1/2, x=>x.scaleTranspose(6).color('steelblue'))
.legato(.5)
.echo(4, 1/8, .5) .echo(4, 1/8, .5)
.clip(.5) .note().piano()
.piano()
.pianoroll()`; .pianoroll()`;
export const sml1 = `// Hirokazu Tanaka - World 1-1 export const sml1 = `// Hirokazu Tanaka - World 1-1
stack( stack(
// melody // melody
note(\`< \`<
[e5 ~] [[d5@2 c5] [~@2 e5]] ~ [~ [c5@2 d5]] [e5 e5] [d5 c5] [e5 f5] [g5 a5] [e5 ~] [[d5@2 c5] [~@2 e5]] ~ [~ [c5@2 d5]] [e5 e5] [d5 c5] [e5 f5] [g5 a5]
[~ c5] [c5 d5] [e5 [c5@2 c5]] [~ c5] [f5 e5] [c5 d5] [~ g6] [g6 ~] [~ c5] [c5 d5] [e5 [c5@2 c5]] [~ c5] [f5 e5] [c5 d5] [~ g6] [g6 ~]
[e5 ~] [[d5@2 c5] [~@2 e5]] ~ [~ [c5@2 d5]] [e5 e5] [d5 c5] [a5 g5] [c6 [e5@2 d5]] [e5 ~] [[d5@2 c5] [~@2 e5]] ~ [~ [c5@2 d5]] [e5 e5] [d5 c5] [a5 g5] [c6 [e5@2 d5]]
@@ -369,28 +401,28 @@ stack(
[f5 ~] [[g5@2 f5] ~] [[e5 ~] [f5 ~]] [[f#5 ~] [g5 ~]] [f5 ~] [[g5@2 f5] ~] [[e5 ~] [f5 ~]] [[f#5 ~] [g5 ~]]
[~ a5] [b5 c6] [b5@2 ~@2 g5] ~ [~ a5] [b5 c6] [b5@2 ~@2 g5] ~
[eb6 d6] [~ c6] ~!2 [eb6 d6] [~ c6] ~!2
>\`) >\`
.clip(.95), .legato(.95),
// sub melody // sub melody
note(\`< \`<
[~ g4]!2 [~ ab4]!2 [~ a4]!2 [~ bb4]!2 [~ g4]!2 [~ ab4]!2 [~ a4]!2 [~ bb4]!2
[~ a4]!2 [~ g4]!2 [d4 e4] [f4 gb4] ~!2 [~ a4]!2 [~ g4]!2 [d4 e4] [f4 gb4] ~!2
[~ g4]!2 [~ ab4]!2 [~ a4]!2 [~ bb4]!2 [~ g4]!2 [~ ab4]!2 [~ a4]!2 [~ bb4]!2
[~ a4]!2 [~ g4]!2 [d4 e4] [f4 gb4] ~!2 [~ a4]!2 [~ g4]!2 [d4 e4] [f4 gb4] ~!2
[~ c5]!4 [~ a4]!2 [[c4 ~] [d4 ~]] [[eb4 ~] [e4 ~]] [~ c5]!4 [~ a4]!2 [[c4 ~] [d4 ~]] [[eb4 ~] [e4 ~]]
[~ c5]!4 [~ eb5]!2 [g4*2 [f4 ~]] [[e4 ~] [d4 ~]] [~ c5]!4 [~ eb5]!2 [g4*2 [f4 ~]] [[e4 ~] [d4 ~]]
>\`), >\`,
// bass // bass
note(\`< \`<
c3!7 a3 f3!2 c3!7 a3 f3!2
e3!2 ~!4 e3!2 ~!4
c3!7 a3 f3!2 c3!7 a3 f3!2
e3!2 ~!4 e3!2 ~!4
f3!2 e3!2 d3!2 ~!2 f3!2 e3!2 d3!2 ~!2
f3!2 e3!2 ab3!2 ~!2 f3!2 e3!2 ab3!2 ~!2
>\`) >\`
.clip(.5) .legato(.5)
).fast(2)`; ).fast(2).note()`;
export const randomBells = `// "Random bells" export const randomBells = `// "Random bells"
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ // @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
@@ -406,14 +438,16 @@ stack(
"0".euclidLegato(3,8) "0".euclidLegato(3,8)
.echo(3, 1/16, .5) .echo(3, 1/16, .5)
.add(rand.range(0,12)) .add(rand.range(0,12))
.scale("D:minor:pentatonic").note()
.velocity(rand.range(.5,1)) .velocity(rand.range(.5,1))
.legato(rand.range(.4,3))
.scale(cat('D minor pentatonic')).note()
.s('bell').gain(.6).delay(.2).delaytime(1/3).delayfeedback(.8), .s('bell').gain(.6).delay(.2).delaytime(1/3).delayfeedback(.8),
// bass // bass
note("<D2 A2 G2 F2>").euclidLegatoRot(6,8,4).s('bass').clip(1).gain(.8) "<D2 A2 G2 F2>".euclidLegatoRot(6,8,4).note().s('bass').clip(1).gain(.8)
) )
.slow(6) .slow(6)
.pianoroll({vertical:1})`; .pianoroll({minMidi:20,maxMidi:120,background:'transparent'})
`;
export const waa2 = `// "Waa2" export const waa2 = `// "Waa2"
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ // @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
@@ -426,7 +460,7 @@ n(
.off(1/8,x=>x.add(12)) .off(1/8,x=>x.add(12))
) )
.slow(2) .slow(2)
.clip(sine.range(0.3, 2).slow(28)) .legato(sine.range(0.3, 2).slow(28))
.s("sawtooth square".fast(2)) .s("sawtooth square".fast(2))
.cutoff(cosine.range(500,4000).slow(16)) .cutoff(cosine.range(500,4000).slow(16))
.gain(.5) .gain(.5)
@@ -490,22 +524,20 @@ export const festivalOfFingers3 = `// "Festival of fingers 3"
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ // @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// @by Felix Roos // @by Felix Roos
n("[-7*3],0,2,6,[8 7]") "[-7*3],0,2,6,[8 7]"
.echoWith( .echoWith(4,1/4, (x,n)=>x
4, // echo 4 times .add(n*7)
1/4, // 1/4s between echos .velocity(1/(n+1))
(x,i)=>x .legato(1/(n+1)))
.add(n(i*7)) // add octaves .velocity(perlin.range(.5,.9).slow(8))
.gain(1/(i+1)) // reduce gain .stack("[22 25]*3"
.clip(1/(i+1)) .legato(sine.range(.5,2).slow(8))
) .velocity(sine.range(.4,.8).slow(5))
.velocity(perlin.range(.5,.9).slow(8)) .echo(4,1/12,.5))
.stack(n("[22 25]*3") .scale(cat('D dorian','G mixolydian','C dorian','F mixolydian'))
.clip(sine.range(.5,2).slow(8)) .legato(1)
.gain(sine.range(.4,.8).slow(5)) .slow(2)
.echo(4,1/12,.5)) .note().piano()
.scale("<D:dorian G:mixolydian C:dorian F:mixolydian>")
.slow(2).piano()
//.pianoroll({maxMidi:160})`; //.pianoroll({maxMidi:160})`;
export const meltingsubmarine = `// "Melting submarine" export const meltingsubmarine = `// "Melting submarine"
@@ -865,9 +897,9 @@ stack(
, ,
note("<C2 A1 D2 F2>/2").ply(8).csound('Bass').gain("1 4 1 4") note("<C2 A1 D2 F2>/2").ply(8).csound('Bass').gain("1 4 1 4")
, ,
n("0 7 [4 3] 2".fast(2/3).off(".25 .125", add("<2 4 -3 -1>")) note("0 7 [4 3] 2".fast(2/3).off(".25 .125",add("<2 4 -3 -1>"))
.slow(2).scale('A4 minor')) .slow(2).scale('A4 minor'))
.clip(.25).csound('SynHarp') .legato(.25).csound('SynHarp')
, ,
s("bd*2,[~ hh]*2,~ cp").bank('RolandTR909') s("bd*2,[~ hh]*2,~ cp").bank('RolandTR909')
)`; )`;
@@ -878,15 +910,15 @@ export const arpoon = `// "Arpoon"
await samples('github:tidalcycles/Dirt-Samples/master') await samples('github:tidalcycles/Dirt-Samples/master')
note("<<Am7 C^7> C7 F^7 [Fm7 E7b9]>".voicings('lefthand')) "<<Am7 C^7> C7 F^7 [Fm7 E7b9]>".voicings('lefthand')
.arp("[0,3] 2 [1,3] 2".fast(3).lastOf(4, fast(2))).clip(2) .arp("[0,3] 2 [1,3] 2".fast(3).lastOf(4, fast(2))).legato(2)
.add(perlin.range(0,0.2).add("<0 12>/8").note()) .add(perlin.range(0,0.2)).sub("<0 -12>/8")
.cutoff(perlin.range(500,4000)).resonance(12) .note().cutoff(perlin.range(500,4000)).resonance(12)
.gain("<.5 .8>*16") .gain("<.5 .8>*16")
.decay(.16).sustain(0.5) .decay(.16).sustain(0.5)
.delay(.2) .delay(.2)
.room(.5).pan(sine.range(.3,.6)) .room(.5).pan(sine.range(.3,.6))
.s('piano') .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)) .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) .slow(4)
.stack(s("bd*4, [~ [hh hh? hh?]]*2,~ [sd ~ [sd:2? bd?]]").bank('RolandTR909').gain(.5).slow(2)) .stack(s("bd*4, [~ [hh hh? hh?]]*2,~ [sd ~ [sd:2? bd?]]").bank('RolandTR909').gain(.5).slow(2))
-20
View File
@@ -1,13 +1,10 @@
import { persistentMap } from '@nanostores/persistent'; import { persistentMap } from '@nanostores/persistent';
import { useStore } from '@nanostores/react'; import { useStore } from '@nanostores/react';
import { register } from '@strudel.cycles/core';
export const defaultSettings = { export const defaultSettings = {
activeFooter: 'intro', activeFooter: 'intro',
keybindings: 'codemirror', keybindings: 'codemirror',
isLineNumbersDisplayed: true, isLineNumbersDisplayed: true,
isAutoCompletionEnabled: false,
isLineWrappingEnabled: false,
theme: 'strudelTheme', theme: 'strudelTheme',
fontFamily: 'monospace', fontFamily: 'monospace',
fontSize: 18, fontSize: 18,
@@ -24,8 +21,6 @@ export function useSettings() {
...state, ...state,
isZen: [true, 'true'].includes(state.isZen) ? true : false, isZen: [true, 'true'].includes(state.isZen) ? true : false,
isLineNumbersDisplayed: [true, 'true'].includes(state.isLineNumbersDisplayed) ? true : false, isLineNumbersDisplayed: [true, 'true'].includes(state.isLineNumbersDisplayed) ? true : false,
isAutoCompletionEnabled: [true, 'true'].includes(state.isAutoCompletionEnabled) ? true : false,
isLineWrappingEnabled: [true, 'true'].includes(state.isLineWrappingEnabled) ? true : false,
fontSize: Number(state.fontSize), fontSize: Number(state.fontSize),
}; };
} }
@@ -34,18 +29,3 @@ export const setActiveFooter = (tab) => settingsMap.setKey('activeFooter', tab);
export const setLatestCode = (code) => settingsMap.setKey('latestCode', code); export const setLatestCode = (code) => settingsMap.setKey('latestCode', code);
export const setIsZen = (active) => settingsMap.setKey('isZen', !!active); export const setIsZen = (active) => settingsMap.setKey('isZen', !!active);
const patternSetting = (key) =>
register(key, (value, pat) => {
value = Array.isArray(value) ? value.join(' ') : value;
if (value !== settingsMap.get()[key]) {
settingsMap.setKey(key, value);
}
return pat;
});
export const theme = patternSetting('theme');
export const fontFamily = patternSetting('fontFamily');
export const fontSize = patternSetting('fontSize');
export const settingPatterns = { theme, fontFamily, fontSize };