Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a2f3b85f38 | |||
| 8e6846a3aa | |||
| 34ee2081d3 |
@@ -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
|
||||
@@ -43,4 +43,3 @@ dev-dist
|
||||
Dirt-Samples
|
||||
tidal-drum-machines
|
||||
webaudiofontdata
|
||||
src-tauri/target
|
||||
@@ -31,7 +31,7 @@ Use one of the Communication Channels listed above.
|
||||
|
||||
## 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.
|
||||
|
||||
## Propose a Feature
|
||||
|
||||
@@ -52,10 +52,10 @@
|
||||
"@strudel.cycles/webaudio": "workspace:*",
|
||||
"@strudel.cycles/xen": "workspace:*",
|
||||
"acorn": "^8.8.1",
|
||||
"dependency-tree": "^9.0.0"
|
||||
"dependency-tree": "^9.0.0",
|
||||
"vitest": "^0.28.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tauri-apps/cli": "^1.4.0",
|
||||
"@vitest/ui": "^0.28.0",
|
||||
"canvas": "^2.11.2",
|
||||
"eslint": "^8.39.0",
|
||||
@@ -66,7 +66,6 @@
|
||||
"jsdoc-to-markdown": "^8.0.0",
|
||||
"lerna": "^6.6.1",
|
||||
"prettier": "^2.8.8",
|
||||
"rollup-plugin-visualizer": "^5.8.1",
|
||||
"vitest": "^0.28.0"
|
||||
"rollup-plugin-visualizer": "^5.8.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,7 +133,7 @@ export class StrudelMirror {
|
||||
this.code = initialCode;
|
||||
|
||||
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);
|
||||
onDraw?.(haps, time, currentFrame);
|
||||
}, drawTime);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@strudel/codemirror",
|
||||
"version": "0.8.4",
|
||||
"version": "0.8.3",
|
||||
"description": "Codemirror Extensions for Strudel",
|
||||
"main": "codemirror.mjs",
|
||||
"publishConfig": {
|
||||
|
||||
@@ -222,7 +222,6 @@ const generic_params = [
|
||||
*
|
||||
* @name legato
|
||||
* @param {number | Pattern} duration between 0 and 1, where 1 is the length of the whole hap time
|
||||
* @noAutocomplete
|
||||
* @example
|
||||
* "c4 eb4 g4 bb4".legato("<0.125 .25 .5 .75 1 2 4>")
|
||||
*
|
||||
@@ -750,14 +749,13 @@ const generic_params = [
|
||||
['val'],
|
||||
['cps'],
|
||||
/**
|
||||
* Multiplies the duration with the given number. Also cuts samples off at the end if they exceed the duration.
|
||||
* In tidal, this would be done with legato, [which has a complicated history in strudel](https://github.com/tidalcycles/strudel/issues/111).
|
||||
* For now, if you're coming from tidal, just think clip = legato.
|
||||
* If set to 1, samples will be cut to the duration of their event.
|
||||
* In tidal, this would be done with legato, which [is about to land in strudel too](https://github.com/tidalcycles/strudel/issues/111)
|
||||
*
|
||||
* @name clip
|
||||
* @param {number | Pattern} factor >= 0
|
||||
* @param {number | Pattern} active 1 or 0
|
||||
* @example
|
||||
* note("c a f e").s("piano").clip("<.5 1 2>")
|
||||
* note("c a f e ~").s("piano").clip(1)
|
||||
*
|
||||
*/
|
||||
['clip'],
|
||||
|
||||
@@ -32,11 +32,7 @@ export class Hap {
|
||||
}
|
||||
|
||||
get duration() {
|
||||
return this.whole.end.sub(this.whole.begin).mul(typeof this.value?.clip === 'number' ? this.value?.clip : 1);
|
||||
}
|
||||
|
||||
get endClipped() {
|
||||
return this.whole.begin.add(this.duration);
|
||||
return this.whole.end.sub(this.whole.begin);
|
||||
}
|
||||
|
||||
wholeOrPart() {
|
||||
|
||||
@@ -24,7 +24,6 @@ export * from './time.mjs';
|
||||
export * from './draw.mjs';
|
||||
export * from './animate.mjs';
|
||||
export * from './pianoroll.mjs';
|
||||
export * from './spiral.mjs';
|
||||
export * from './ui.mjs';
|
||||
export { default as drawLine } from './drawLine.mjs';
|
||||
export { default as gist } from './gist.js';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@strudel.cycles/core",
|
||||
"version": "0.8.2",
|
||||
"version": "0.8.1",
|
||||
"description": "Port of Tidal Cycles to JavaScript",
|
||||
"main": "index.mjs",
|
||||
"type": "module",
|
||||
|
||||
@@ -1582,24 +1582,6 @@ export const range2 = register('range2', function (min, max, pat) {
|
||||
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
|
||||
|
||||
@@ -1695,9 +1677,6 @@ export const ply = register('ply', function (factor, pat) {
|
||||
* s("<bd sd> hh").fast(2) // s("[<bd sd> hh]*2")
|
||||
*/
|
||||
export const { fast, density } = register(['fast', 'density'], function (factor, pat) {
|
||||
if (factor === 0) {
|
||||
return silence;
|
||||
}
|
||||
factor = Fraction(factor);
|
||||
const fastQuery = pat.withQueryTime((t) => t.mul(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")
|
||||
*/
|
||||
export const { slow, sparsity } = register(['slow', 'sparsity'], function (factor, pat) {
|
||||
if (factor === 0) {
|
||||
return silence;
|
||||
}
|
||||
return pat._fast(Fraction(1).div(factor));
|
||||
});
|
||||
|
||||
@@ -2053,7 +2029,7 @@ export const jux = register('jux', function (func, pat) {
|
||||
* @example
|
||||
* "<0 [2 4]>"
|
||||
* .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(
|
||||
['echoWith', 'echowith', 'stutWith', 'stutwith'],
|
||||
@@ -2203,7 +2179,6 @@ export const velocity = register('velocity', function (velocity, pat) {
|
||||
/**
|
||||
*
|
||||
* 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
|
||||
* @memberof Pattern
|
||||
* @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)
|
||||
*/
|
||||
|
||||
export const slice = register(
|
||||
const slice = register(
|
||||
'slice',
|
||||
function (npat, ipat, opat) {
|
||||
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)
|
||||
*/
|
||||
|
||||
export const splice = register(
|
||||
const splice = register(
|
||||
'splice',
|
||||
function (npat, ipat, opat) {
|
||||
const sliced = slice(npat, ipat, opat);
|
||||
@@ -2321,10 +2296,7 @@ export const splice = register(
|
||||
false, // turns off auto-patternification
|
||||
);
|
||||
|
||||
// this function will be redefined in repl.mjs to use the correct cps value.
|
||||
// It is still here to work in cases where repl.mjs is not used
|
||||
|
||||
export const { loopAt, loopat } = register(['loopAt', 'loopat'], function (factor, pat) {
|
||||
const { loopAt, loopat } = register(['loopAt', 'loopat'], function (factor, pat) {
|
||||
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)
|
||||
*/
|
||||
// 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);
|
||||
});
|
||||
|
||||
@@ -83,9 +83,9 @@ Pattern.prototype.pianoroll = function ({
|
||||
ctx.fillRect(0, 0, w, h);
|
||||
}
|
||||
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) => {
|
||||
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.strokeStyle = event.context?.color || active;
|
||||
ctx.globalAlpha = event.context.velocity ?? event.value?.gain ?? 1;
|
||||
|
||||
@@ -3,7 +3,6 @@ import { evaluate as _evaluate } from './evaluate.mjs';
|
||||
import { logger } from './logger.mjs';
|
||||
import { setTime } from './time.mjs';
|
||||
import { evalScope } from './evaluate.mjs';
|
||||
import { register } from './pattern.mjs';
|
||||
|
||||
export function repl({
|
||||
interval,
|
||||
@@ -51,32 +50,10 @@ export function repl({
|
||||
const start = () => scheduler.start();
|
||||
const pause = () => scheduler.pause();
|
||||
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({
|
||||
loopAt,
|
||||
fit,
|
||||
setCps,
|
||||
setcps: setCps,
|
||||
setCpm,
|
||||
setcpm: setCpm,
|
||||
});
|
||||
|
||||
return { scheduler, evaluate, start, stop, pause, setCps, setPattern };
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ export const isaw2 = isaw.toBipolar();
|
||||
*
|
||||
* @return {Pattern}
|
||||
* @example
|
||||
* "c3 [eb3,g3] g2 [g3,bb3]".note().clip(saw.slow(4))
|
||||
* "c3 [eb3,g3] g2 [g3,bb3]".legato(saw.slow(4)).note()
|
||||
* @example
|
||||
* saw.range(0,8).segment(8).scale('C major').slow(4).note()
|
||||
*
|
||||
|
||||
@@ -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 }));
|
||||
};
|
||||
@@ -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);
|
||||
});
|
||||
@@ -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
|
||||
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) => {
|
||||
if (typeof note !== 'string') {
|
||||
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) {
|
||||
return [];
|
||||
}
|
||||
@@ -25,7 +25,7 @@ export const noteToMidi = (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 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;
|
||||
};
|
||||
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'];
|
||||
/**
|
||||
* @deprecated only used in workshop (first-notes)
|
||||
* @deprecated does not appear to be referenced or invoked anywhere in the codebase
|
||||
* @noAutocomplete
|
||||
*/
|
||||
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 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,6 +1,6 @@
|
||||
{
|
||||
"name": "@strudel.cycles/csound",
|
||||
"version": "0.8.0",
|
||||
"version": "0.7.1",
|
||||
"description": "csound bindings for strudel",
|
||||
"main": "index.mjs",
|
||||
"publishConfig": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@strudel.cycles/eval",
|
||||
"version": "0.8.0",
|
||||
"version": "0.7.1",
|
||||
"description": "Code evaluator for strudel",
|
||||
"main": "index.mjs",
|
||||
"publishConfig": {
|
||||
|
||||
@@ -105,7 +105,7 @@ Pattern.prototype.midi = function (output) {
|
||||
hap.ensureObjectValue();
|
||||
|
||||
// calculate time
|
||||
const timingOffset = WebMidi.time - getAudioContext().getOutputTimestamp().contextTime * 1000;
|
||||
const timingOffset = WebMidi.time - getAudioContext().currentTime * 1000;
|
||||
time = time * 1000 + timingOffset;
|
||||
|
||||
// destructure value
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@strudel.cycles/midi",
|
||||
"version": "0.8.0",
|
||||
"version": "0.7.1",
|
||||
"description": "Midi API for strudel",
|
||||
"main": "index.mjs",
|
||||
"publishConfig": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@strudel.cycles/mini",
|
||||
"version": "0.8.2",
|
||||
"version": "0.8.1",
|
||||
"description": "Mini notation for strudel",
|
||||
"main": "index.mjs",
|
||||
"type": "module",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@strudel.cycles/osc",
|
||||
"version": "0.8.0",
|
||||
"version": "0.7.1",
|
||||
"description": "OSC messaging for strudel",
|
||||
"main": "osc.mjs",
|
||||
"publishConfig": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@strudel.cycles/react",
|
||||
"version": "0.8.0",
|
||||
"version": "0.7.1",
|
||||
"description": "React components for strudel",
|
||||
"main": "src/index.js",
|
||||
"publishConfig": {
|
||||
|
||||
@@ -2,12 +2,12 @@ import React, { useMemo } from 'react';
|
||||
import _CodeMirror from '@uiw/react-codemirror';
|
||||
import { EditorView, Decoration } from '@codemirror/view';
|
||||
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 './style.css';
|
||||
import { useCallback } from 'react';
|
||||
import { autocompletion } from '@codemirror/autocomplete';
|
||||
import { strudelAutocomplete } from './Autocomplete';
|
||||
//import { strudelAutocomplete } from './Autocomplete';
|
||||
import { vim } from '@replit/codemirror-vim';
|
||||
import { emacs } from '@replit/codemirror-emacs';
|
||||
|
||||
@@ -88,7 +88,14 @@ const highlightField = StateField.define({
|
||||
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({
|
||||
value,
|
||||
@@ -98,8 +105,6 @@ export default function CodeMirror({
|
||||
theme,
|
||||
keybindings,
|
||||
isLineNumbersDisplayed,
|
||||
isAutoCompletionEnabled,
|
||||
isLineWrappingEnabled,
|
||||
fontSize = 18,
|
||||
fontFamily = 'monospace',
|
||||
options,
|
||||
@@ -111,14 +116,12 @@ export default function CodeMirror({
|
||||
},
|
||||
[onChange],
|
||||
);
|
||||
|
||||
const handleOnCreateEditor = useCallback(
|
||||
(view) => {
|
||||
onViewChanged?.(view);
|
||||
},
|
||||
[onViewChanged],
|
||||
);
|
||||
|
||||
const handleOnUpdate = useCallback(
|
||||
(viewUpdate) => {
|
||||
if (viewUpdate.selectionSet && onSelectionChange) {
|
||||
@@ -127,31 +130,16 @@ export default function CodeMirror({
|
||||
},
|
||||
[onSelectionChange],
|
||||
);
|
||||
|
||||
const extensions = useMemo(() => {
|
||||
let _extensions = [...staticExtensions];
|
||||
let bindings = {
|
||||
vim,
|
||||
emacs,
|
||||
};
|
||||
|
||||
if (bindings[keybindings]) {
|
||||
_extensions.push(bindings[keybindings]());
|
||||
return [...staticExtensions, bindings[keybindings]()];
|
||||
}
|
||||
|
||||
if (isAutoCompletionEnabled) {
|
||||
_extensions.push(javascriptLanguage.data.of({ autocomplete: strudelAutocomplete }));
|
||||
} else {
|
||||
_extensions.push(autocompletion({ override: [] }));
|
||||
}
|
||||
|
||||
if (isLineWrappingEnabled) {
|
||||
_extensions.push(EditorView.lineWrapping);
|
||||
}
|
||||
|
||||
return _extensions;
|
||||
}, [keybindings, isAutoCompletionEnabled, isLineWrappingEnabled]);
|
||||
|
||||
return staticExtensions;
|
||||
}, [keybindings]);
|
||||
return (
|
||||
<div style={{ fontSize, fontFamily }} className="w-full">
|
||||
<_CodeMirror
|
||||
|
||||
@@ -24,7 +24,3 @@
|
||||
.cm-theme-light {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
footer {
|
||||
z-index: 0 !important;
|
||||
}
|
||||
|
||||
@@ -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 span = [round(begin), round(audioTime + 1 / 60)];
|
||||
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());
|
||||
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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@strudel.cycles/serial",
|
||||
"version": "0.8.0",
|
||||
"version": "0.7.1",
|
||||
"description": "Webserial API for strudel",
|
||||
"main": "serial.mjs",
|
||||
"publishConfig": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@strudel.cycles/soundfonts",
|
||||
"version": "0.8.2",
|
||||
"version": "0.8.1",
|
||||
"description": "Soundsfont support for strudel",
|
||||
"main": "index.mjs",
|
||||
"publishConfig": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@strudel.cycles/tonal",
|
||||
"version": "0.8.2",
|
||||
"version": "0.8.1",
|
||||
"description": "Tonal functions for strudel",
|
||||
"main": "index.mjs",
|
||||
"publishConfig": {
|
||||
|
||||
@@ -145,7 +145,7 @@ export const scaleTranspose = register('scaleTranspose', function (offset /* : n
|
||||
export const scale = register('scale', function (scale, pat) {
|
||||
// Supports ':' list syntax in mininotation
|
||||
if (Array.isArray(scale)) {
|
||||
scale = scale.flat().join(' ');
|
||||
scale = scale.join(' ');
|
||||
}
|
||||
return pat.withHap((hap) => {
|
||||
const isObject = typeof hap.value === 'object';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@strudel.cycles/tone",
|
||||
"version": "0.8.0",
|
||||
"version": "0.7.1",
|
||||
"description": "Tone.js API for strudel",
|
||||
"main": "index.mjs",
|
||||
"type": "module",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"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.",
|
||||
"main": "index.mjs",
|
||||
"publishConfig": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@strudel/web",
|
||||
"version": "0.8.3",
|
||||
"version": "0.8.2",
|
||||
"description": "Easy to setup, opiniated bundle of Strudel for the browser.",
|
||||
"main": "web.mjs",
|
||||
"publishConfig": {
|
||||
@@ -34,10 +34,10 @@
|
||||
"homepage": "https://github.com/tidalcycles/strudel#readme",
|
||||
"dependencies": {
|
||||
"@strudel.cycles/core": "workspace:*",
|
||||
"@strudel.cycles/webaudio": "workspace:*",
|
||||
"@strudel.cycles/mini": "workspace:*",
|
||||
"@strudel.cycles/tonal": "workspace:*",
|
||||
"@strudel.cycles/transpiler": "workspace:*",
|
||||
"@strudel.cycles/webaudio": "workspace:*"
|
||||
"@strudel.cycles/transpiler": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"vite": "^4.3.3"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@strudel.cycles/webaudio",
|
||||
"version": "0.8.2",
|
||||
"version": "0.8.1",
|
||||
"description": "Web Audio helpers for Strudel",
|
||||
"main": "index.mjs",
|
||||
"type": "module",
|
||||
|
||||
@@ -21,7 +21,7 @@ function humanFileSize(bytes, si) {
|
||||
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;
|
||||
if (freq !== undefined && note !== undefined) {
|
||||
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
|
||||
sampleUrl = bank[closest][n % bank[closest].length];
|
||||
}
|
||||
if (resolveUrl) {
|
||||
sampleUrl = await resolveUrl(sampleUrl);
|
||||
}
|
||||
let buffer = await loadBuffer(sampleUrl, ac, s, n);
|
||||
if (speed < 0) {
|
||||
// should this be cached?
|
||||
@@ -94,46 +91,6 @@ export const getLoadedBuffer = (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`
|
||||
* @example
|
||||
@@ -150,11 +107,6 @@ function getSamplesPrefixHandler(url) {
|
||||
|
||||
export const samples = async (sampleMap, baseUrl = sampleMap._base || '', options = {}) => {
|
||||
if (typeof sampleMap === 'string') {
|
||||
// check if custom prefix handler
|
||||
const handler = getSamplesPrefixHandler(sampleMap);
|
||||
if (handler) {
|
||||
return handler(sampleMap);
|
||||
}
|
||||
if (sampleMap.startsWith('github:')) {
|
||||
let [_, path] = sampleMap.split('github:');
|
||||
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;
|
||||
processSampleMap(
|
||||
sampleMap,
|
||||
(key, value) =>
|
||||
registerSound(key, (t, hapValue, onended) => onTriggerSample(t, hapValue, onended, value), {
|
||||
type: 'sample',
|
||||
samples: value,
|
||||
baseUrl,
|
||||
prebake,
|
||||
tag,
|
||||
}),
|
||||
baseUrl,
|
||||
);
|
||||
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)];
|
||||
}),
|
||||
);
|
||||
}
|
||||
registerSound(key, (t, hapValue, onended) => onTriggerSample(t, hapValue, onended, value), {
|
||||
type: 'sample',
|
||||
samples: value,
|
||||
baseUrl,
|
||||
prebake,
|
||||
tag,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const cutGroups = [];
|
||||
|
||||
export async function onTriggerSample(t, value, onended, bank, resolveUrl) {
|
||||
export async function onTriggerSample(t, value, onended, bank) {
|
||||
const {
|
||||
s,
|
||||
freq,
|
||||
@@ -202,7 +170,7 @@ export async function onTriggerSample(t, value, onended, bank, resolveUrl) {
|
||||
nudge = 0, // TODO: is this in seconds?
|
||||
cut,
|
||||
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,
|
||||
note,
|
||||
speed = 1, // sample playback speed
|
||||
@@ -220,7 +188,7 @@ export async function onTriggerSample(t, value, onended, bank, resolveUrl) {
|
||||
//const soundfont = getSoundfontKey(s);
|
||||
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?
|
||||
if (ac.currentTime > t) {
|
||||
@@ -264,7 +232,7 @@ export async function onTriggerSample(t, value, onended, bank, resolveUrl) {
|
||||
out.disconnect();
|
||||
onended();
|
||||
};
|
||||
const stop = (endTime, playWholeBuffer = clip === undefined) => {
|
||||
const stop = (endTime, playWholeBuffer = !clip) => {
|
||||
let releaseTime = endTime;
|
||||
if (playWholeBuffer) {
|
||||
releaseTime = t + (end - begin) * bufferDuration;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@strudel.cycles/webdirt",
|
||||
"version": "0.8.0",
|
||||
"version": "0.7.1",
|
||||
"description": "WebDirt integration for Strudel",
|
||||
"main": "index.mjs",
|
||||
"type": "module",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@strudel.cycles/xen",
|
||||
"version": "0.8.0",
|
||||
"version": "0.7.1",
|
||||
"description": "Xenharmonic API for strudel",
|
||||
"main": "index.mjs",
|
||||
"publishConfig": {
|
||||
|
||||
@@ -28,10 +28,10 @@ importers:
|
||||
dependency-tree:
|
||||
specifier: ^9.0.0
|
||||
version: 9.0.0
|
||||
vitest:
|
||||
specifier: ^0.28.0
|
||||
version: 0.28.0(@vitest/ui@0.28.0)
|
||||
devDependencies:
|
||||
'@tauri-apps/cli':
|
||||
specifier: ^1.4.0
|
||||
version: 1.4.0
|
||||
'@vitest/ui':
|
||||
specifier: ^0.28.0
|
||||
version: 0.28.0
|
||||
@@ -65,9 +65,6 @@ importers:
|
||||
rollup-plugin-visualizer:
|
||||
specifier: ^5.8.1
|
||||
version: 5.9.0
|
||||
vitest:
|
||||
specifier: ^0.28.0
|
||||
version: 0.28.0(@vitest/ui@0.28.0)
|
||||
|
||||
packages/codemirror:
|
||||
dependencies:
|
||||
@@ -95,7 +92,7 @@ importers:
|
||||
devDependencies:
|
||||
vite:
|
||||
specifier: ^4.3.3
|
||||
version: 4.3.3(@types/node@18.16.3)
|
||||
version: 4.3.3(@types/node@18.11.18)
|
||||
|
||||
packages/core:
|
||||
dependencies:
|
||||
@@ -105,7 +102,7 @@ importers:
|
||||
devDependencies:
|
||||
vite:
|
||||
specifier: ^4.3.3
|
||||
version: 4.3.3(@types/node@18.16.3)
|
||||
version: 4.3.3(@types/node@18.11.18)
|
||||
vitest:
|
||||
specifier: ^0.28.0
|
||||
version: 0.28.0(@vitest/ui@0.28.0)
|
||||
@@ -130,7 +127,7 @@ importers:
|
||||
devDependencies:
|
||||
vite:
|
||||
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:
|
||||
dependencies:
|
||||
@@ -158,7 +155,7 @@ importers:
|
||||
devDependencies:
|
||||
vite:
|
||||
specifier: ^4.3.2
|
||||
version: 4.3.3(@types/node@18.16.3)
|
||||
version: 4.3.3(@types/node@18.11.18)
|
||||
|
||||
packages/csound:
|
||||
dependencies:
|
||||
@@ -174,7 +171,7 @@ importers:
|
||||
devDependencies:
|
||||
vite:
|
||||
specifier: ^4.3.3
|
||||
version: 4.3.3(@types/node@18.16.3)
|
||||
version: 4.3.3(@types/node@18.11.18)
|
||||
|
||||
packages/embed: {}
|
||||
|
||||
@@ -207,7 +204,7 @@ importers:
|
||||
version: link:../mini
|
||||
vite:
|
||||
specifier: ^4.3.3
|
||||
version: 4.3.3(@types/node@18.16.3)
|
||||
version: 4.3.3(@types/node@18.11.18)
|
||||
vitest:
|
||||
specifier: ^0.28.0
|
||||
version: 0.28.0(@vitest/ui@0.28.0)
|
||||
@@ -226,7 +223,7 @@ importers:
|
||||
devDependencies:
|
||||
vite:
|
||||
specifier: ^4.3.3
|
||||
version: 4.3.3(@types/node@18.16.3)
|
||||
version: 4.3.3(@types/node@18.11.18)
|
||||
|
||||
packages/mini:
|
||||
dependencies:
|
||||
@@ -239,7 +236,7 @@ importers:
|
||||
version: 3.0.2
|
||||
vite:
|
||||
specifier: ^4.3.3
|
||||
version: 4.3.3(@types/node@18.16.3)
|
||||
version: 4.3.3(@types/node@18.11.18)
|
||||
vitest:
|
||||
specifier: ^0.28.0
|
||||
version: 0.28.0(@vitest/ui@0.28.0)
|
||||
@@ -258,7 +255,7 @@ importers:
|
||||
version: 5.8.1
|
||||
vite:
|
||||
specifier: ^4.3.3
|
||||
version: 4.3.3(@types/node@18.16.3)
|
||||
version: 4.3.3(@types/node@18.11.18)
|
||||
|
||||
packages/react:
|
||||
dependencies:
|
||||
@@ -328,7 +325,7 @@ importers:
|
||||
version: 3.3.2
|
||||
vite:
|
||||
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:
|
||||
dependencies:
|
||||
@@ -383,7 +380,7 @@ importers:
|
||||
version: 3.3.2
|
||||
vite:
|
||||
specifier: ^4.3.3
|
||||
version: 4.3.3(@types/node@18.16.3)
|
||||
version: 4.3.3(@types/node@18.11.18)
|
||||
|
||||
packages/serial:
|
||||
dependencies:
|
||||
@@ -393,7 +390,7 @@ importers:
|
||||
devDependencies:
|
||||
vite:
|
||||
specifier: ^4.3.3
|
||||
version: 4.3.3(@types/node@18.16.3)
|
||||
version: 4.3.3(@types/node@18.11.18)
|
||||
|
||||
packages/soundfonts:
|
||||
dependencies:
|
||||
@@ -415,7 +412,7 @@ importers:
|
||||
version: 3.3.1
|
||||
vite:
|
||||
specifier: ^4.3.3
|
||||
version: 4.3.3(@types/node@18.16.3)
|
||||
version: 4.3.3(@types/node@18.11.18)
|
||||
|
||||
packages/tonal:
|
||||
dependencies:
|
||||
@@ -434,7 +431,7 @@ importers:
|
||||
devDependencies:
|
||||
vite:
|
||||
specifier: ^4.3.3
|
||||
version: 4.3.3(@types/node@18.16.3)
|
||||
version: 4.3.3(@types/node@18.11.18)
|
||||
vitest:
|
||||
specifier: ^0.28.0
|
||||
version: 0.28.0(@vitest/ui@0.28.0)
|
||||
@@ -450,7 +447,7 @@ importers:
|
||||
devDependencies:
|
||||
vite:
|
||||
specifier: ^4.3.3
|
||||
version: 4.3.3(@types/node@18.16.3)
|
||||
version: 4.3.3(@types/node@18.11.18)
|
||||
vitest:
|
||||
specifier: ^0.28.0
|
||||
version: 0.28.0(@vitest/ui@0.28.0)
|
||||
@@ -472,7 +469,7 @@ importers:
|
||||
devDependencies:
|
||||
vite:
|
||||
specifier: ^4.3.3
|
||||
version: 4.3.3(@types/node@18.16.3)
|
||||
version: 4.3.3(@types/node@18.11.18)
|
||||
vitest:
|
||||
specifier: ^0.28.0
|
||||
version: 0.28.0(@vitest/ui@0.28.0)
|
||||
@@ -497,7 +494,7 @@ importers:
|
||||
devDependencies:
|
||||
vite:
|
||||
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:
|
||||
dependencies:
|
||||
@@ -507,7 +504,7 @@ importers:
|
||||
devDependencies:
|
||||
vite:
|
||||
specifier: ^4.3.2
|
||||
version: 4.3.3(@types/node@18.16.3)
|
||||
version: 4.3.3(@types/node@18.11.18)
|
||||
|
||||
packages/webaudio:
|
||||
dependencies:
|
||||
@@ -520,7 +517,7 @@ importers:
|
||||
devDependencies:
|
||||
vite:
|
||||
specifier: ^4.3.3
|
||||
version: 4.3.3(@types/node@18.16.3)
|
||||
version: 4.3.3(@types/node@18.11.18)
|
||||
|
||||
packages/webdirt:
|
||||
dependencies:
|
||||
@@ -536,7 +533,7 @@ importers:
|
||||
devDependencies:
|
||||
vite:
|
||||
specifier: ^4.3.3
|
||||
version: 4.3.3(@types/node@18.16.3)
|
||||
version: 4.3.3(@types/node@18.11.18)
|
||||
vitest:
|
||||
specifier: ^0.28.0
|
||||
version: 0.28.0(@vitest/ui@0.28.0)
|
||||
@@ -549,7 +546,7 @@ importers:
|
||||
devDependencies:
|
||||
vite:
|
||||
specifier: ^4.3.3
|
||||
version: 4.3.3(@types/node@18.16.3)
|
||||
version: 4.3.3(@types/node@18.11.18)
|
||||
vitest:
|
||||
specifier: ^0.28.0
|
||||
version: 0.28.0(@vitest/ui@0.28.0)
|
||||
@@ -3540,7 +3537,6 @@ packages:
|
||||
|
||||
/@polka/url@1.0.0-next.21:
|
||||
resolution: {integrity: sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==}
|
||||
dev: true
|
||||
|
||||
/@proload/core@0.3.3:
|
||||
resolution: {integrity: sha512-7dAFWsIK84C90AMl24+N/ProHKm4iw0akcnoKjRvbfHifJZBLhaDsDus1QJmhG12lXj4e/uB/8mB/0aduCW+NQ==}
|
||||
@@ -3774,113 +3770,6 @@ packages:
|
||||
tailwindcss: 3.3.2
|
||||
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:
|
||||
resolution: {integrity: sha512-JggT/DW4rMxu+q1WkeACrg52is3acp9zaW4LJmCheFi3CmLa63sy7/6mgKnlScTOvcpAyTcSytu0VbQHRXyBDA==}
|
||||
dependencies:
|
||||
@@ -4095,11 +3984,9 @@ packages:
|
||||
resolution: {integrity: sha512-frBecisrNGz+F4T6bcc+NLeolfiojh5FxW2klu669+8BARtyQv2C/GkNW6FUodVe4BroGMP/wER/YDGc7rEllw==}
|
||||
dependencies:
|
||||
'@types/chai': 4.3.4
|
||||
dev: true
|
||||
|
||||
/@types/chai@4.3.4:
|
||||
resolution: {integrity: sha512-KnRanxnpfpjUTqTCXslZSEdLfXExwgNxYPdiO2WGUj8+HDjFi8R3k5RVKPeSCzLjCcshCAtVO2QBbVuAV4kTnw==}
|
||||
dev: true
|
||||
|
||||
/@types/debug@4.1.7:
|
||||
resolution: {integrity: sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==}
|
||||
@@ -4176,7 +4063,6 @@ packages:
|
||||
|
||||
/@types/node@18.11.18:
|
||||
resolution: {integrity: sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==}
|
||||
dev: true
|
||||
|
||||
/@types/node@18.16.3:
|
||||
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-source': 7.19.6(@babel/core@7.21.5)
|
||||
react-refresh: 0.14.0
|
||||
vite: 4.3.3
|
||||
vite: 4.3.3(@types/node@18.11.18)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
@@ -4630,7 +4516,6 @@ packages:
|
||||
'@vitest/spy': 0.28.0
|
||||
'@vitest/utils': 0.28.0
|
||||
chai: 4.3.7
|
||||
dev: true
|
||||
|
||||
/@vitest/runner@0.28.0:
|
||||
resolution: {integrity: sha512-SXQO9aubp7Hg4DV4D5DP70wJ/4o0krH1gAPrSt+rhEZQbQvMaBJAHWOxEibwzLkklgoHreaMEvETFILkGQWXww==}
|
||||
@@ -4638,13 +4523,11 @@ packages:
|
||||
'@vitest/utils': 0.28.0
|
||||
p-limit: 4.0.0
|
||||
pathe: 1.1.0
|
||||
dev: true
|
||||
|
||||
/@vitest/spy@0.28.0:
|
||||
resolution: {integrity: sha512-gYBDQIP0QDvxrscl2Id0BTbzLUbuAzFiFur3eHxH9Yt5cM6YCH/kxBrSHhmXTbu92UenLx53Gwq17u5N0zGNDQ==}
|
||||
dependencies:
|
||||
tinyspy: 1.0.2
|
||||
dev: true
|
||||
|
||||
/@vitest/ui@0.28.0:
|
||||
resolution: {integrity: sha512-ihcVEx8t1gZXMboPGcIvoHk+PxiW5USxDMqnZOeUVIUm+XrRCtoJ96YDXdeR6MyPWeYLBPXfBWSxp5gMqoNSkw==}
|
||||
@@ -4654,7 +4537,6 @@ packages:
|
||||
pathe: 1.1.0
|
||||
picocolors: 1.0.0
|
||||
sirv: 2.0.2
|
||||
dev: true
|
||||
|
||||
/@vitest/utils@0.28.0:
|
||||
resolution: {integrity: sha512-Dt+jDZbwriZWzJ5Hi9nAUnz9IPgNb+ACE96tWiXPp/u9NmCYWIWcuNoUOYS8HQyGFz31GiNYGvaZ4ZEDjAgi1g==}
|
||||
@@ -4664,7 +4546,6 @@ packages:
|
||||
loupe: 2.3.6
|
||||
picocolors: 1.0.0
|
||||
pretty-format: 27.5.1
|
||||
dev: true
|
||||
|
||||
/@vscode/emmet-helper@2.8.6:
|
||||
resolution: {integrity: sha512-IIB8jbiKy37zN8bAIHx59YmnIelY78CGHtThnibD/d3tQOKRY83bYVi9blwmZVUZh6l9nfkYH3tvReaiNxY9EQ==}
|
||||
@@ -4730,7 +4611,6 @@ packages:
|
||||
/acorn-walk@8.2.0:
|
||||
resolution: {integrity: sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==}
|
||||
engines: {node: '>=0.4.0'}
|
||||
dev: true
|
||||
|
||||
/acorn@8.8.2:
|
||||
resolution: {integrity: sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==}
|
||||
@@ -4855,7 +4735,6 @@ packages:
|
||||
/ansi-styles@5.2.0:
|
||||
resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==}
|
||||
engines: {node: '>=10'}
|
||||
dev: true
|
||||
|
||||
/ansi-styles@6.2.1:
|
||||
resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==}
|
||||
@@ -5005,7 +4884,6 @@ packages:
|
||||
|
||||
/assertion-error@1.1.0:
|
||||
resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==}
|
||||
dev: true
|
||||
|
||||
/ast-module-types@3.0.0:
|
||||
resolution: {integrity: sha512-CMxMCOCS+4D+DkOQfuZf+vLrSEmY/7xtORwdxs4wtcC1wVgvk2MqFFTwQCFhvWsI4KPU9lcWXPI8DgRiz+xetQ==}
|
||||
@@ -5275,7 +5153,6 @@ packages:
|
||||
|
||||
/buffer-from@1.1.2:
|
||||
resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
|
||||
dev: true
|
||||
|
||||
/buffer@5.7.1:
|
||||
resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==}
|
||||
@@ -5326,7 +5203,6 @@ packages:
|
||||
/cac@6.7.14:
|
||||
resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
|
||||
engines: {node: '>=8'}
|
||||
dev: true
|
||||
|
||||
/cacache@16.1.3:
|
||||
resolution: {integrity: sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==}
|
||||
@@ -5456,7 +5332,6 @@ packages:
|
||||
loupe: 2.3.6
|
||||
pathval: 1.1.1
|
||||
type-detect: 4.0.8
|
||||
dev: true
|
||||
|
||||
/chalk@2.4.2:
|
||||
resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==}
|
||||
@@ -5504,7 +5379,6 @@ packages:
|
||||
|
||||
/check-error@1.0.2:
|
||||
resolution: {integrity: sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==}
|
||||
dev: true
|
||||
|
||||
/chokidar@3.5.3:
|
||||
resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==}
|
||||
@@ -5583,7 +5457,6 @@ packages:
|
||||
dependencies:
|
||||
slice-ansi: 5.0.0
|
||||
string-width: 5.1.2
|
||||
dev: true
|
||||
|
||||
/cli-width@3.0.0:
|
||||
resolution: {integrity: sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==}
|
||||
@@ -6063,7 +5936,6 @@ packages:
|
||||
engines: {node: '>=6'}
|
||||
dependencies:
|
||||
type-detect: 4.0.8
|
||||
dev: true
|
||||
|
||||
/deep-extend@0.6.0:
|
||||
resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==}
|
||||
@@ -7262,7 +7134,6 @@ packages:
|
||||
|
||||
/get-func-name@2.0.0:
|
||||
resolution: {integrity: sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==}
|
||||
dev: true
|
||||
|
||||
/get-intrinsic@1.2.0:
|
||||
resolution: {integrity: sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==}
|
||||
@@ -8094,7 +7965,6 @@ packages:
|
||||
/is-fullwidth-code-point@4.0.0:
|
||||
resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==}
|
||||
engines: {node: '>=12'}
|
||||
dev: true
|
||||
|
||||
/is-glob@4.0.3:
|
||||
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
|
||||
@@ -8738,7 +8608,6 @@ packages:
|
||||
/local-pkg@0.4.3:
|
||||
resolution: {integrity: sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==}
|
||||
engines: {node: '>=14'}
|
||||
dev: true
|
||||
|
||||
/locate-path@2.0.0:
|
||||
resolution: {integrity: sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==}
|
||||
@@ -8831,7 +8700,6 @@ packages:
|
||||
resolution: {integrity: sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==}
|
||||
dependencies:
|
||||
get-func-name: 2.0.0
|
||||
dev: true
|
||||
|
||||
/lru-cache@5.1.1:
|
||||
resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
|
||||
@@ -9726,7 +9594,6 @@ packages:
|
||||
pathe: 1.1.0
|
||||
pkg-types: 1.0.2
|
||||
ufo: 1.1.1
|
||||
dev: true
|
||||
|
||||
/modify-values@1.0.1:
|
||||
resolution: {integrity: sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==}
|
||||
@@ -9772,7 +9639,6 @@ packages:
|
||||
/mrmime@1.0.1:
|
||||
resolution: {integrity: sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==}
|
||||
engines: {node: '>=10'}
|
||||
dev: true
|
||||
|
||||
/ms@2.0.0:
|
||||
resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==}
|
||||
@@ -10453,7 +10319,6 @@ packages:
|
||||
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
||||
dependencies:
|
||||
yocto-queue: 1.0.0
|
||||
dev: true
|
||||
|
||||
/p-locate@2.0.0:
|
||||
resolution: {integrity: sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==}
|
||||
@@ -10706,11 +10571,9 @@ packages:
|
||||
|
||||
/pathe@1.1.0:
|
||||
resolution: {integrity: sha512-ODbEPR0KKHqECXW1GoxdDb+AZvULmXjVPy4rt+pGo2+TnjJTIPJQSVS6N63n8T2Ip+syHhbn52OewKicV0373w==}
|
||||
dev: true
|
||||
|
||||
/pathval@1.1.1:
|
||||
resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==}
|
||||
dev: true
|
||||
|
||||
/peggy@3.0.2:
|
||||
resolution: {integrity: sha512-n7chtCbEoGYRwZZ0i/O3t1cPr6o+d9Xx4Zwy2LYfzv0vjchMBU0tO+qYYyvZloBPcgRgzYvALzGWHe609JjEpg==}
|
||||
@@ -10787,7 +10650,6 @@ packages:
|
||||
jsonc-parser: 3.2.0
|
||||
mlly: 1.2.0
|
||||
pathe: 1.1.0
|
||||
dev: true
|
||||
|
||||
/pkg@5.8.1:
|
||||
resolution: {integrity: sha512-CjBWtFStCfIiT4Bde9QpJy0KeH19jCfwZRJqHFDFXfhUklCx8JoFmMj3wgnEYIwGmZVNkhsStPHEOnrtrQhEXA==}
|
||||
@@ -10989,7 +10851,6 @@ packages:
|
||||
ansi-regex: 5.0.1
|
||||
ansi-styles: 5.2.0
|
||||
react-is: 17.0.2
|
||||
dev: true
|
||||
|
||||
/pretty-format@29.4.3:
|
||||
resolution: {integrity: sha512-cvpcHTc42lcsvOOAzd3XuNWTcvk1Jmnzqeu+WsOuiPmxUJTnkbAcFNsRKvEpBEUFVUgy/GTZLulZDcDEi+CIlA==}
|
||||
@@ -11149,7 +11010,6 @@ packages:
|
||||
|
||||
/react-is@17.0.2:
|
||||
resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==}
|
||||
dev: true
|
||||
|
||||
/react-is@18.2.0:
|
||||
resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==}
|
||||
@@ -11903,7 +11763,6 @@ packages:
|
||||
|
||||
/siginfo@2.0.0:
|
||||
resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==}
|
||||
dev: true
|
||||
|
||||
/signal-exit@3.0.7:
|
||||
resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
|
||||
@@ -11951,7 +11810,6 @@ packages:
|
||||
'@polka/url': 1.0.0-next.21
|
||||
mrmime: 1.0.1
|
||||
totalist: 3.0.0
|
||||
dev: true
|
||||
|
||||
/sisteransi@1.0.5:
|
||||
resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==}
|
||||
@@ -11970,7 +11828,6 @@ packages:
|
||||
dependencies:
|
||||
ansi-styles: 6.2.1
|
||||
is-fullwidth-code-point: 4.0.0
|
||||
dev: true
|
||||
|
||||
/smart-buffer@4.2.0:
|
||||
resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==}
|
||||
@@ -12029,7 +11886,6 @@ packages:
|
||||
dependencies:
|
||||
buffer-from: 1.1.2
|
||||
source-map: 0.6.1
|
||||
dev: true
|
||||
|
||||
/source-map@0.5.7:
|
||||
resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==}
|
||||
@@ -12112,7 +11968,6 @@ packages:
|
||||
|
||||
/stackback@0.0.2:
|
||||
resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==}
|
||||
dev: true
|
||||
|
||||
/standardized-audio-context@25.3.37:
|
||||
resolution: {integrity: sha512-lr0+RH/IJXYMts95oYKIJ+orTmstOZN3GXWVGmlkbMj8OLahREkRh7DhNGLYgBGDkBkhhc4ev5pYGSFN3gltHw==}
|
||||
@@ -12124,7 +11979,6 @@ packages:
|
||||
|
||||
/std-env@3.3.2:
|
||||
resolution: {integrity: sha512-uUZI65yrV2Qva5gqE0+A7uVAvO40iPo6jGhs7s8keRfHCmtg+uB2X6EiLGCI9IgL1J17xGhvoOqSz79lzICPTA==}
|
||||
dev: true
|
||||
|
||||
/stdopt@2.2.0:
|
||||
resolution: {integrity: sha512-D/p41NgXOkcj1SeGhfXOwv9z1K6EV3sjAUY5aeepVbgEHv7DpKWLTjhjScyzMWAQCAgUQys1mjH0eArm4cjRGw==}
|
||||
@@ -12295,7 +12149,6 @@ packages:
|
||||
resolution: {integrity: sha512-QZTsipNpa2Ppr6v1AmJHESqJ3Uz247MUS0OjrnnZjFAvEoWqxuyFuXn2xLgMtRnijJShAa1HL0gtJyUs7u7n3Q==}
|
||||
dependencies:
|
||||
acorn: 8.8.2
|
||||
dev: true
|
||||
|
||||
/strong-log-transformer@2.1.0:
|
||||
resolution: {integrity: sha512-B3Hgul+z0L9a236FAUC9iZsL+nVHgoCJnqCbN588DjYxvGXaXaaFbfmQ/JhvKjZwsOukuR72XbHv71Qkug0HxA==}
|
||||
@@ -12582,17 +12435,14 @@ packages:
|
||||
|
||||
/tinybench@2.5.0:
|
||||
resolution: {integrity: sha512-kRwSG8Zx4tjF9ZiyH4bhaebu+EDz1BOx9hOigYHlUW4xxI/wKIUQUqo018UlU4ar6ATPBsaMrdbKZ+tmPdohFA==}
|
||||
dev: true
|
||||
|
||||
/tinypool@0.3.1:
|
||||
resolution: {integrity: sha512-zLA1ZXlstbU2rlpA4CIeVaqvWq41MTWqLY3FfsAXgC8+f7Pk7zroaJQxDgxn1xNudKW6Kmj4808rPFShUlIRmQ==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dev: true
|
||||
|
||||
/tinyspy@1.0.2:
|
||||
resolution: {integrity: sha512-bSGlgwLBYf7PnUsQ6WOc6SJ3pGOcd+d8AA6EUnLDDM0kWEstC1JIlSZA3UNliDXhd9ABoS7hiRBDCu+XP/sf1Q==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
dev: true
|
||||
|
||||
/tmp@0.0.33:
|
||||
resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==}
|
||||
@@ -12628,7 +12478,6 @@ packages:
|
||||
/totalist@3.0.0:
|
||||
resolution: {integrity: sha512-eM+pCBxXO/njtF7vdFsHuqb+ElbxqtI4r5EAvk6grfAFyJ6IvWlSkfZ5T9ozC6xWw3Fj1fGoSmrl0gUs46JVIw==}
|
||||
engines: {node: '>=6'}
|
||||
dev: true
|
||||
|
||||
/tr46@0.0.3:
|
||||
resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
|
||||
@@ -12735,7 +12584,6 @@ packages:
|
||||
/type-detect@4.0.8:
|
||||
resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==}
|
||||
engines: {node: '>=4'}
|
||||
dev: true
|
||||
|
||||
/type-fest@0.13.1:
|
||||
resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==}
|
||||
@@ -12836,7 +12684,6 @@ packages:
|
||||
|
||||
/ufo@1.1.1:
|
||||
resolution: {integrity: sha512-MvlCc4GHrmZdAllBc0iUDowff36Q9Ndw/UzqmEKyrfSzokTd9ZCy1i+IIk5hrYKkjoYVQyNbrw7/F8XJ2rEwTg==}
|
||||
dev: true
|
||||
|
||||
/uglify-js@3.17.4:
|
||||
resolution: {integrity: sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==}
|
||||
@@ -13212,7 +13059,6 @@ packages:
|
||||
- sugarss
|
||||
- supports-color
|
||||
- terser
|
||||
dev: true
|
||||
|
||||
/vite-plugin-pwa@0.14.7(vite@4.3.3)(workbox-build@6.5.4)(workbox-window@6.5.4):
|
||||
resolution: {integrity: sha512-dNJaf0fYOWncmjxv9HiSa2xrSjipjff7IkYE5oIUJ2x5HKu3cXgA8LRgzOwTc5MhwyFYRSU0xyN0Phbx3NsQYw==}
|
||||
@@ -13233,38 +13079,6 @@ packages:
|
||||
- supports-color
|
||||
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):
|
||||
resolution: {integrity: sha512-MwFlLBO4udZXd+VBcezo3u8mC77YQk+ik+fbc0GZWGgzfbPP+8Kf0fldhARqvSYmtIWoAJ5BXPClUbMTlqFxrA==}
|
||||
engines: {node: ^14.18.0 || >=16.0.0}
|
||||
@@ -13296,7 +13110,6 @@ packages:
|
||||
rollup: 3.21.0
|
||||
optionalDependencies:
|
||||
fsevents: 2.3.2
|
||||
dev: true
|
||||
|
||||
/vite@4.3.3(@types/node@18.16.3):
|
||||
resolution: {integrity: sha512-MwFlLBO4udZXd+VBcezo3u8mC77YQk+ik+fbc0GZWGgzfbPP+8Kf0fldhARqvSYmtIWoAJ5BXPClUbMTlqFxrA==}
|
||||
@@ -13394,7 +13207,6 @@ packages:
|
||||
- sugarss
|
||||
- supports-color
|
||||
- terser
|
||||
dev: true
|
||||
|
||||
/vscode-css-languageservice@6.2.3:
|
||||
resolution: {integrity: sha512-EAyhyIVHpEaf+GjtI+tVe7SekdoANfG0aubnspsQwak3Qkimn/97FpAufNyXk636ngW05pjNKAR9zyTCzo6avQ==}
|
||||
@@ -13582,7 +13394,6 @@ packages:
|
||||
dependencies:
|
||||
siginfo: 2.0.0
|
||||
stackback: 0.0.2
|
||||
dev: true
|
||||
|
||||
/wide-align@1.1.5:
|
||||
resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==}
|
||||
@@ -13916,7 +13727,6 @@ packages:
|
||||
/yocto-queue@1.0.0:
|
||||
resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==}
|
||||
engines: {node: '>=12.20'}
|
||||
dev: true
|
||||
|
||||
/zod@3.21.4:
|
||||
resolution: {integrity: sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==}
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
# Generated by Cargo
|
||||
# will have compiled files and executables
|
||||
/target/
|
||||
@@ -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"
|
||||
@@ -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
|
||||
@@ -1,3 +0,0 @@
|
||||
fn main() {
|
||||
tauri_build::build()
|
||||
}
|
||||
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 9.0 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 7.1 KiB |
|
Before Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 70 KiB |
@@ -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");
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1079,22 +1079,22 @@ exports[`runs examples > example "chunkBack" example index 0 1`] = `
|
||||
|
||||
exports[`runs examples > example "clip" example index 0 1`] = `
|
||||
[
|
||||
"[ 0/1 → 1/4 | note:c s:piano clip:0.5 ]",
|
||||
"[ 1/4 → 1/2 | note:a s:piano clip:0.5 ]",
|
||||
"[ 1/2 → 3/4 | note:f s:piano clip:0.5 ]",
|
||||
"[ 3/4 → 1/1 | note:e s:piano clip:0.5 ]",
|
||||
"[ 1/1 → 5/4 | note:c s:piano clip:1 ]",
|
||||
"[ 5/4 → 3/2 | note:a s:piano clip:1 ]",
|
||||
"[ 3/2 → 7/4 | note:f s:piano clip:1 ]",
|
||||
"[ 7/4 → 2/1 | note:e s:piano clip:1 ]",
|
||||
"[ 2/1 → 9/4 | note:c s:piano clip:2 ]",
|
||||
"[ 9/4 → 5/2 | note:a s:piano clip:2 ]",
|
||||
"[ 5/2 → 11/4 | note:f s:piano clip:2 ]",
|
||||
"[ 11/4 → 3/1 | note:e s:piano clip:2 ]",
|
||||
"[ 3/1 → 13/4 | note:c s:piano clip:0.5 ]",
|
||||
"[ 13/4 → 7/2 | note:a s:piano clip:0.5 ]",
|
||||
"[ 7/2 → 15/4 | note:f s:piano clip:0.5 ]",
|
||||
"[ 15/4 → 4/1 | note:e s:piano clip:0.5 ]",
|
||||
"[ 0/1 → 1/5 | note:c s:piano clip:1 ]",
|
||||
"[ 1/5 → 2/5 | note:a s:piano clip:1 ]",
|
||||
"[ 2/5 → 3/5 | note:f s:piano clip:1 ]",
|
||||
"[ 3/5 → 4/5 | note:e s:piano clip:1 ]",
|
||||
"[ 1/1 → 6/5 | note:c s:piano clip:1 ]",
|
||||
"[ 6/5 → 7/5 | note:a s:piano clip:1 ]",
|
||||
"[ 7/5 → 8/5 | note:f s:piano clip:1 ]",
|
||||
"[ 8/5 → 9/5 | note:e s:piano clip:1 ]",
|
||||
"[ 2/1 → 11/5 | note:c s:piano clip:1 ]",
|
||||
"[ 11/5 → 12/5 | note:a s:piano clip:1 ]",
|
||||
"[ 12/5 → 13/5 | note:f s:piano clip:1 ]",
|
||||
"[ 13/5 → 14/5 | note:e s:piano clip:1 ]",
|
||||
"[ 3/1 → 16/5 | note:c s:piano clip:1 ]",
|
||||
"[ 16/5 → 17/5 | note:a s:piano clip:1 ]",
|
||||
"[ 17/5 → 18/5 | note:f s:piano clip:1 ]",
|
||||
"[ 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`] = `
|
||||
[
|
||||
"[ 0/1 → 1/1 | note:C3 clip:0.2 ]",
|
||||
"[ -3/8 ⇜ (0/1 → 1/8) | note:Bb3 clip:0.2 ]",
|
||||
"[ (1/8 → 1/1) ⇝ 9/8 | note:Eb3 clip:0.2 ]",
|
||||
"[ -1/4 ⇜ (0/1 → 1/4) | note:D4 clip:0.2 ]",
|
||||
"[ (1/4 → 1/1) ⇝ 5/4 | note:G3 clip:0.2 ]",
|
||||
"[ -1/8 ⇜ (0/1 → 3/8) | note:F4 clip:0.2 ]",
|
||||
"[ (3/8 → 1/1) ⇝ 11/8 | note:Bb3 clip:0.2 ]",
|
||||
"[ 1/1 → 3/2 | note:Eb3 clip:0.2 ]",
|
||||
"[ 3/2 → 2/1 | note:G3 clip:0.2 ]",
|
||||
"[ 1/8 ⇜ (1/1 → 9/8) | note:Eb3 clip:0.2 ]",
|
||||
"[ 9/8 → 13/8 | note:G3 clip:0.2 ]",
|
||||
"[ (13/8 → 2/1) ⇝ 17/8 | note:Bb3 clip:0.2 ]",
|
||||
"[ 1/4 ⇜ (1/1 → 5/4) | note:G3 clip:0.2 ]",
|
||||
"[ 5/4 → 7/4 | note:Bb3 clip:0.2 ]",
|
||||
"[ (7/4 → 2/1) ⇝ 9/4 | note:D4 clip:0.2 ]",
|
||||
"[ 3/8 ⇜ (1/1 → 11/8) | note:Bb3 clip:0.2 ]",
|
||||
"[ 11/8 → 15/8 | note:D4 clip:0.2 ]",
|
||||
"[ (15/8 → 2/1) ⇝ 19/8 | note:F4 clip:0.2 ]",
|
||||
"[ 2/1 → 3/1 | note:C3 clip:0.2 ]",
|
||||
"[ 13/8 ⇜ (2/1 → 17/8) | note:Bb3 clip:0.2 ]",
|
||||
"[ (17/8 → 3/1) ⇝ 25/8 | note:Eb3 clip:0.2 ]",
|
||||
"[ 7/4 ⇜ (2/1 → 9/4) | note:D4 clip:0.2 ]",
|
||||
"[ (9/4 → 3/1) ⇝ 13/4 | note:G3 clip:0.2 ]",
|
||||
"[ 15/8 ⇜ (2/1 → 19/8) | note:F4 clip:0.2 ]",
|
||||
"[ (19/8 → 3/1) ⇝ 27/8 | note:Bb3 clip:0.2 ]",
|
||||
"[ 3/1 → 7/2 | note:Eb3 clip:0.2 ]",
|
||||
"[ 7/2 → 4/1 | note:G3 clip:0.2 ]",
|
||||
"[ 17/8 ⇜ (3/1 → 25/8) | note:Eb3 clip:0.2 ]",
|
||||
"[ 25/8 → 29/8 | note:G3 clip:0.2 ]",
|
||||
"[ (29/8 → 4/1) ⇝ 33/8 | note:Bb3 clip:0.2 ]",
|
||||
"[ 9/4 ⇜ (3/1 → 13/4) | note:G3 clip:0.2 ]",
|
||||
"[ 13/4 → 15/4 | note:Bb3 clip:0.2 ]",
|
||||
"[ (15/4 → 4/1) ⇝ 17/4 | note:D4 clip:0.2 ]",
|
||||
"[ 19/8 ⇜ (3/1 → 27/8) | note:Bb3 clip:0.2 ]",
|
||||
"[ 27/8 → 31/8 | note:D4 clip:0.2 ]",
|
||||
"[ (31/8 → 4/1) ⇝ 35/8 | note:F4 clip:0.2 ]",
|
||||
"[ 0/1 → 1/5 | note:C3 ]",
|
||||
"[ -3/8 ⇜ (0/1 → 1/40) ⇝ -11/40 | note:Bb3 ]",
|
||||
"[ (1/8 → 3/10) ⇝ 13/40 | note:Eb3 ]",
|
||||
"[ -1/4 ⇜ (0/1 → 1/20) ⇝ -3/20 | note:D4 ]",
|
||||
"[ (1/4 → 2/5) ⇝ 9/20 | note:G3 ]",
|
||||
"[ -1/8 ⇜ (0/1 → 3/40) ⇝ -1/40 | note:F4 ]",
|
||||
"[ (3/8 → 1/2) ⇝ 23/40 | note:Bb3 ]",
|
||||
"[ 1/1 → 11/10 | note:Eb3 ]",
|
||||
"[ 3/2 → 8/5 | note:G3 ]",
|
||||
"[ 1/8 ⇜ (1/1 → 41/40) ⇝ 13/40 | note:Eb3 ]",
|
||||
"[ 9/8 → 49/40 | note:G3 ]",
|
||||
"[ (13/8 → 17/10) ⇝ 69/40 | note:Bb3 ]",
|
||||
"[ 1/4 ⇜ (1/1 → 21/20) ⇝ 9/20 | note:G3 ]",
|
||||
"[ 5/4 → 27/20 | note:Bb3 ]",
|
||||
"[ (7/4 → 9/5) ⇝ 37/20 | note:D4 ]",
|
||||
"[ 3/8 ⇜ (1/1 → 43/40) ⇝ 23/40 | note:Bb3 ]",
|
||||
"[ 11/8 → 59/40 | note:D4 ]",
|
||||
"[ (15/8 → 19/10) ⇝ 79/40 | note:F4 ]",
|
||||
"[ 2/1 → 11/5 | note:C3 ]",
|
||||
"[ 13/8 ⇜ (2/1 → 81/40) ⇝ 69/40 | note:Bb3 ]",
|
||||
"[ (17/8 → 23/10) ⇝ 93/40 | note:Eb3 ]",
|
||||
"[ 7/4 ⇜ (2/1 → 41/20) ⇝ 37/20 | note:D4 ]",
|
||||
"[ (9/4 → 12/5) ⇝ 49/20 | note:G3 ]",
|
||||
"[ 15/8 ⇜ (2/1 → 83/40) ⇝ 79/40 | note:F4 ]",
|
||||
"[ (19/8 → 5/2) ⇝ 103/40 | note:Bb3 ]",
|
||||
"[ 3/1 → 31/10 | note:Eb3 ]",
|
||||
"[ 7/2 → 18/5 | note:G3 ]",
|
||||
"[ 17/8 ⇜ (3/1 → 121/40) ⇝ 93/40 | note:Eb3 ]",
|
||||
"[ 25/8 → 129/40 | note:G3 ]",
|
||||
"[ (29/8 → 37/10) ⇝ 149/40 | note:Bb3 ]",
|
||||
"[ 9/4 ⇜ (3/1 → 61/20) ⇝ 49/20 | note:G3 ]",
|
||||
"[ 13/4 → 67/20 | note:Bb3 ]",
|
||||
"[ (15/4 → 19/5) ⇝ 77/20 | note:D4 ]",
|
||||
"[ 19/8 ⇜ (3/1 → 123/40) ⇝ 103/40 | note:Bb3 ]",
|
||||
"[ 27/8 → 139/40 | note:D4 ]",
|
||||
"[ (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`] = `
|
||||
[
|
||||
"[ 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`] = `
|
||||
[
|
||||
"[ 0/1 → 1/4 | note:c3 clip:0.03125 ]",
|
||||
"[ 1/4 → 1/2 | note:eb3 clip:0.09375 ]",
|
||||
"[ 1/4 → 1/2 | note:g3 clip:0.09375 ]",
|
||||
"[ 1/2 → 3/4 | note:g2 clip:0.15625 ]",
|
||||
"[ 3/4 → 1/1 | note:g3 clip:0.21875 ]",
|
||||
"[ 3/4 → 1/1 | note:bb3 clip:0.21875 ]",
|
||||
"[ 1/1 → 5/4 | note:c3 clip:0.28125 ]",
|
||||
"[ 5/4 → 3/2 | note:eb3 clip:0.34375 ]",
|
||||
"[ 5/4 → 3/2 | note:g3 clip:0.34375 ]",
|
||||
"[ 3/2 → 7/4 | note:g2 clip:0.40625 ]",
|
||||
"[ 7/4 → 2/1 | note:g3 clip:0.46875 ]",
|
||||
"[ 7/4 → 2/1 | note:bb3 clip:0.46875 ]",
|
||||
"[ 2/1 → 9/4 | note:c3 clip:0.53125 ]",
|
||||
"[ 9/4 → 5/2 | note:eb3 clip:0.59375 ]",
|
||||
"[ 9/4 → 5/2 | note:g3 clip:0.59375 ]",
|
||||
"[ 5/2 → 11/4 | note:g2 clip:0.65625 ]",
|
||||
"[ 11/4 → 3/1 | note:g3 clip:0.71875 ]",
|
||||
"[ 11/4 → 3/1 | note:bb3 clip:0.71875 ]",
|
||||
"[ 3/1 → 13/4 | note:c3 clip:0.78125 ]",
|
||||
"[ 13/4 → 7/2 | note:eb3 clip:0.84375 ]",
|
||||
"[ 13/4 → 7/2 | note:g3 clip:0.84375 ]",
|
||||
"[ 7/2 → 15/4 | note:g2 clip:0.90625 ]",
|
||||
"[ 15/4 → 4/1 | note:g3 clip:0.96875 ]",
|
||||
"[ 15/4 → 4/1 | note:bb3 clip:0.96875 ]",
|
||||
"[ 0/1 → 1/32 | note:c3 ]",
|
||||
"[ 1/4 → 9/32 | note:eb3 ]",
|
||||
"[ 1/4 → 9/32 | note:g3 ]",
|
||||
"[ 1/2 → 17/32 | note:g2 ]",
|
||||
"[ 3/4 → 25/32 | note:g3 ]",
|
||||
"[ 3/4 → 25/32 | note:bb3 ]",
|
||||
"[ 1/1 → 35/32 | note:c3 ]",
|
||||
"[ 5/4 → 43/32 | note:eb3 ]",
|
||||
"[ 5/4 → 43/32 | note:g3 ]",
|
||||
"[ 3/2 → 51/32 | note:g2 ]",
|
||||
"[ 7/4 → 59/32 | note:g3 ]",
|
||||
"[ 7/4 → 59/32 | note:bb3 ]",
|
||||
"[ 2/1 → 69/32 | note:c3 ]",
|
||||
"[ 9/4 → 77/32 | note:eb3 ]",
|
||||
"[ 9/4 → 77/32 | note:g3 ]",
|
||||
"[ 5/2 → 85/32 | note:g2 ]",
|
||||
"[ 11/4 → 93/32 | note:g3 ]",
|
||||
"[ 11/4 → 93/32 | note:bb3 ]",
|
||||
"[ 3/1 → 103/32 | note:c3 ]",
|
||||
"[ 13/4 → 111/32 | note:eb3 ]",
|
||||
"[ 13/4 → 111/32 | note:g3 ]",
|
||||
"[ 7/2 → 119/32 | note:g2 ]",
|
||||
"[ 15/4 → 127/32 | note:g3 ]",
|
||||
"[ 15/4 → 127/32 | note:bb3 ]",
|
||||
]
|
||||
`;
|
||||
|
||||
|
||||
@@ -221,7 +221,7 @@ export const testCycles = {
|
||||
festivalOfFingers: 16,
|
||||
festivalOfFingers2: 22,
|
||||
undergroundPlumber: 20,
|
||||
bridgeIsOver: 8,
|
||||
bridgeIsOver: 16,
|
||||
goodTimes: 16,
|
||||
echoPiano: 8,
|
||||
sml1: 48,
|
||||
|
||||
@@ -364,7 +364,7 @@ export const customTrigger = `// licensed with CC BY-NC-SA 4.0 https://creativec
|
||||
// by Felix Roos
|
||||
stack(
|
||||
freq("55 [110,165] 110 [220,275]".mul("<1 <3/4 2/3>>").struct("x(3,8)").layer(x=>x.mul("1.006,.995"))),
|
||||
freq("440(5,8)".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")
|
||||
.onTrigger((t,hap,ct)=>{
|
||||
const ac = Tone.getContext().rawContext;
|
||||
|
||||
@@ -87,7 +87,7 @@ export const SIDEBAR: Sidebar = {
|
||||
{ text: 'Signals', link: 'learn/signals' },
|
||||
{ text: 'Conditional Modifiers', link: 'learn/conditional-modifiers' },
|
||||
{ text: 'Accumulation', link: 'learn/accumulation' },
|
||||
{ text: 'Tonal Functions', link: 'learn/tonal' },
|
||||
{ text: 'Tonal Modifiers', link: 'learn/tonal' },
|
||||
],
|
||||
Development: [
|
||||
{ text: 'REPL', link: 'technical-manual/repl' },
|
||||
|
||||
@@ -16,11 +16,3 @@
|
||||
.cm-gutters {
|
||||
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
|
||||
|
||||

|
||||
|
||||
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
|
||||
|
||||

|
||||
|
||||
## 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/
|
||||
|
||||

|
||||
|
||||
## 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} />
|
||||
|
||||
## ratio
|
||||
|
||||
<JsDoc client:idle name="Pattern.ratio" h={0} />
|
||||
|
||||
# Custom Parameters
|
||||
|
||||
You can also create your own parameters:
|
||||
|
||||
@@ -32,4 +32,4 @@ import { JsDoc } from '../../docs/JsDoc';
|
||||
|
||||
<JsDoc client:idle name="stut" h={0} />
|
||||
|
||||
There are also [Tonal Functions](/learn/tonal).
|
||||
There are also [Tonal Modifiers](/learn/tonal).
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
<script is:inline>
|
||||
window.location.pathname = `/workshop/getting-started`;
|
||||
window.location.pathname = `/learn/getting-started`;
|
||||
</script>
|
||||
|
||||
@@ -38,10 +38,6 @@ Some of these have equivalent operators in the Mini Notation:
|
||||
|
||||
<JsDoc client:idle name="Pattern.legato" h={0} />
|
||||
|
||||
## clip
|
||||
|
||||
<JsDoc client:idle name="clip" h={0} />
|
||||
|
||||
## euclid
|
||||
|
||||
<JsDoc client:idle name="Pattern.euclid" h={0} />
|
||||
|
||||
@@ -1,29 +1,14 @@
|
||||
---
|
||||
title: Tonal Functions
|
||||
title: Tonal API
|
||||
layout: ../../layouts/MainLayout.astro
|
||||
---
|
||||
|
||||
import { MiniRepl } from '../../docs/MiniRepl';
|
||||
import { JsDoc } from '../../docs/JsDoc';
|
||||
|
||||
# Tonal Functions
|
||||
# Tonal API
|
||||
|
||||
These functions use [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).
|
||||
The Tonal API, uses [tonaljs](https://github.com/tonaljs/tonal) to provide helpers for musical operations.
|
||||
|
||||
### 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()`} />
|
||||
|
||||
### 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)
|
||||
|
||||
Transposes notes inside the scale by the number of steps:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -7,7 +7,7 @@ import { MiniRepl } from '../../docs/MiniRepl';
|
||||
|
||||
# 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
|
||||
|
||||
- organize the codebase into more modular, encapsulated pieces
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
<script is:inline>
|
||||
window.location.pathname = `/workshop/getting-started`;
|
||||
window.location.pathname = `/learn/getting-started`;
|
||||
</script>
|
||||
|
||||
@@ -80,6 +80,7 @@ These letter combinations stand for different parts of a drum set:
|
||||
|
||||
- `bd` = **b**ass **d**rum
|
||||
- `sd` = **s**nare **d**rum
|
||||
- `sd` = **sd**are
|
||||
- `rim` = **rim**shot
|
||||
- `hh` = **h**i**h**at
|
||||
- `oh` = **o**pen **h**ihat
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
@@ -9,9 +9,6 @@ import { themes } from './themes.mjs';
|
||||
import { useSettings, settingsMap, setActiveFooter, defaultSettings } from '../settings.mjs';
|
||||
import { getAudioContext, soundMap } from '@strudel.cycles/webaudio';
|
||||
import { useStore } from '@nanostores/react';
|
||||
import { FilesTab } from './FilesTab';
|
||||
|
||||
const TAURI = window.__TAURI__;
|
||||
|
||||
export function Footer({ context }) {
|
||||
const footerContent = useRef();
|
||||
@@ -80,7 +77,6 @@ export function Footer({ context }) {
|
||||
<FooterTab name="console" />
|
||||
<FooterTab name="reference" />
|
||||
<FooterTab name="settings" />
|
||||
{TAURI && <FooterTab name="files" />}
|
||||
</div>
|
||||
{activeFooter !== '' && (
|
||||
<button onClick={() => setActiveFooter('')} className="text-foreground" aria-label="Close Panel">
|
||||
@@ -95,7 +91,6 @@ export function Footer({ context }) {
|
||||
{activeFooter === 'sounds' && <SoundsTab />}
|
||||
{activeFooter === 'reference' && <Reference />}
|
||||
{activeFooter === 'settings' && <SettingsTab scheduler={context.scheduler} />}
|
||||
{activeFooter === 'files' && <FilesTab />}
|
||||
</div>
|
||||
)}
|
||||
</footer>
|
||||
@@ -145,7 +140,7 @@ function WelcomeTab() {
|
||||
</p>
|
||||
<p>
|
||||
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
|
||||
</a>
|
||||
. Also feel free to join the{' '}
|
||||
@@ -369,16 +364,7 @@ const fontFamilyOptions = {
|
||||
};
|
||||
|
||||
function SettingsTab({ scheduler }) {
|
||||
const {
|
||||
theme,
|
||||
keybindings,
|
||||
isLineNumbersDisplayed,
|
||||
isAutoCompletionEnabled,
|
||||
isLineWrappingEnabled,
|
||||
fontSize,
|
||||
fontFamily,
|
||||
} = useSettings();
|
||||
|
||||
const { theme, keybindings, isLineNumbersDisplayed, fontSize, fontFamily } = useSettings();
|
||||
return (
|
||||
<div className="text-foreground p-4 space-y-4">
|
||||
{/* <FormItem label="Tempo">
|
||||
@@ -420,7 +406,7 @@ function SettingsTab({ scheduler }) {
|
||||
/>
|
||||
</FormItem>
|
||||
</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">
|
||||
<ButtonGroup
|
||||
value={keybindings}
|
||||
@@ -433,16 +419,6 @@ function SettingsTab({ scheduler }) {
|
||||
onChange={(cbEvent) => settingsMap.setKey('isLineNumbersDisplayed', cbEvent.target.checked)}
|
||||
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>
|
||||
<FormItem label="Reset Settings">
|
||||
<button
|
||||
|
||||
@@ -45,11 +45,3 @@
|
||||
#code .cm-theme-light {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#code .cm-cursorLayer {
|
||||
animation-name: inherit !important;
|
||||
}
|
||||
|
||||
#code .cm-cursor {
|
||||
border-left: 2px solid currentcolor !important;
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ import PlayCircleIcon from '@heroicons/react/20/solid/PlayCircleIcon';
|
||||
import { themes } from './themes.mjs';
|
||||
import { settingsMap, useSettings, setLatestCode } from '../settings.mjs';
|
||||
import Loader from './Loader';
|
||||
import { settingPatterns } from '../settings.mjs';
|
||||
|
||||
const { latestCode } = settingsMap.get();
|
||||
|
||||
@@ -46,7 +45,6 @@ const modules = [
|
||||
|
||||
const modulesLoading = evalScope(
|
||||
controls, // sadly, this cannot be exported from core direclty
|
||||
settingPatterns,
|
||||
...modules,
|
||||
);
|
||||
|
||||
@@ -107,15 +105,7 @@ export function Repl({ embedded = false }) {
|
||||
const [lastShared, setLastShared] = useState();
|
||||
const [pending, setPending] = useState(true);
|
||||
|
||||
const {
|
||||
theme,
|
||||
keybindings,
|
||||
fontSize,
|
||||
fontFamily,
|
||||
isLineNumbersDisplayed,
|
||||
isAutoCompletionEnabled,
|
||||
isLineWrappingEnabled,
|
||||
} = useSettings();
|
||||
const { theme, keybindings, fontSize, fontFamily, isLineNumbersDisplayed } = useSettings();
|
||||
|
||||
const { code, setCode, scheduler, evaluate, activateCode, isDirty, activeCode, pattern, started, stop, error } =
|
||||
useStrudel({
|
||||
@@ -167,7 +157,7 @@ export function Repl({ embedded = false }) {
|
||||
e.preventDefault();
|
||||
flash(view);
|
||||
await activateCode();
|
||||
} else if (e.key === '.' || e.code === 'Period') {
|
||||
} else if (e.key === '.' || e.keyCode === 'Period') {
|
||||
stop();
|
||||
e.preventDefault();
|
||||
}
|
||||
@@ -282,8 +272,6 @@ export function Repl({ embedded = false }) {
|
||||
value={code}
|
||||
keybindings={keybindings}
|
||||
isLineNumbersDisplayed={isLineNumbersDisplayed}
|
||||
isAutoCompletionEnabled={isAutoCompletionEnabled}
|
||||
isLineWrappingEnabled={isLineWrappingEnabled}
|
||||
fontSize={fontSize}
|
||||
fontFamily={fontFamily}
|
||||
onChange={handleChangeCode}
|
||||
|
||||
@@ -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,7 +1,6 @@
|
||||
import { Pattern, noteToMidi, valueToMidi } from '@strudel.cycles/core';
|
||||
import { registerSynthSounds, samples } from '@strudel.cycles/webaudio';
|
||||
import './piano.mjs';
|
||||
import './files.mjs';
|
||||
|
||||
export async function prebake() {
|
||||
// https://archive.org/details/SalamanderGrandPianoV3
|
||||
@@ -119,7 +118,7 @@ const maxPan = noteToMidi('C8');
|
||||
const panwidth = (pan, width) => pan * width + (1 - width) / 2;
|
||||
|
||||
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')
|
||||
.release(0.1)
|
||||
.fmap((value) => {
|
||||
|
||||
@@ -205,24 +205,27 @@ samples({
|
||||
}
|
||||
}, 'https://loophole-letters.vercel.app/')
|
||||
|
||||
const scales = cat('C major', 'C mixolydian', 'F lydian', ['F minor', cat('Db major','Db mixolydian')])
|
||||
|
||||
stack(
|
||||
s("<bd sn> <hh hh*2 hh*3>").color('#00B8D4'),
|
||||
"<g4 c5 a4 [ab4 <eb5 f5>]>"
|
||||
.scale("<C:major C:mixolydian F:lydian [F:minor <Db:major Db:mixolydian>]>")
|
||||
.scale(scales)
|
||||
.struct("x*8")
|
||||
.scaleTranspose("0 [-5,-2] -7 [-9,-2]")
|
||||
.legato(.3)
|
||||
.slow(2)
|
||||
.note()
|
||||
.clip(.3)
|
||||
.s('rhodes')
|
||||
.clip(1)
|
||||
.room(.5)
|
||||
.delay(.3)
|
||||
.delayfeedback(.4)
|
||||
.delaytime(1/12).gain(.5).color('#7ED321'),
|
||||
"<c2 c3 f2 [[F2 C2] db2]>/2"
|
||||
.add("0,.02")
|
||||
"<c2 c3 f2 [[F2 C2] db2]>"
|
||||
.legato("<1@3 [.3 1]>")
|
||||
.slow(2).superimpose(x=>x.add(.02))
|
||||
.note().gain(.3)
|
||||
.clip("<1@3 [.3 1]>/2")
|
||||
.s('sawtooth').cutoff(600).color('#F8E71C'),
|
||||
).fast(3/2)
|
||||
//.pianoroll({fold:1})`;
|
||||
@@ -234,7 +237,7 @@ export const wavyKalimba = `// "Wavy kalimba"
|
||||
samples({
|
||||
'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(
|
||||
"[0 2 4 6 9 2 0 -2]*3"
|
||||
@@ -251,11 +254,13 @@ stack(
|
||||
.velocity(0.8)
|
||||
.slow(2)
|
||||
)
|
||||
.legato("<.4 .8 1 1.2 1.4 1.6 1.8 2>/8")
|
||||
.fast(1)
|
||||
.note()
|
||||
.clip("<.4 .8 1 1.2 1.4 1.6 1.8 2>/8")
|
||||
.clip(1)
|
||||
.s('kalimba')
|
||||
.delay(.2)`;
|
||||
.delay(.2)
|
||||
`;
|
||||
|
||||
export const festivalOfFingers = `// "Festival of fingers"
|
||||
// @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),
|
||||
"[c2 a1 bb1 ~] ~"
|
||||
.echo(2, 1/16, 1)
|
||||
.legato(.4)
|
||||
.slow(2)
|
||||
.layer(h)
|
||||
.note().s('square')
|
||||
.clip(.4)
|
||||
.cutoff(400).decay(.12).sustain(0)
|
||||
,
|
||||
"[g2,[c3 eb3]]".iter(4)
|
||||
.echoWith(4, 1/8, (x,n)=>x.transpose(n*12).velocity(Math.pow(.4,n)))
|
||||
.legato(.1)
|
||||
.layer(h).note()
|
||||
.clip(.1)
|
||||
)
|
||||
.fast(2/3)
|
||||
.pianoroll()`;
|
||||
.pianoroll({})`;
|
||||
|
||||
export const bridgeIsOver = `// "Bridge is over"
|
||||
// @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'})
|
||||
stack(
|
||||
stack(
|
||||
note("c3*2 [[c3@1.4 bb2] ab2] gb2*2 <[[gb2@1.4 ab2] bb2] gb2>")
|
||||
.gain(.8).clip("[.5 1]*2"),
|
||||
n("<0 1 2 3 4 3 2 1>")
|
||||
.clip(.5)
|
||||
.echoWith(8, 1/32, (x,i)=>x.add(n(i)).velocity(Math.pow(.7,i)))
|
||||
.scale('c4 whole tone')
|
||||
.echo(3, 1/8, .5)
|
||||
).piano(),
|
||||
"c3*2 [[c3@1.4 bb2] ab2] gb2*2 <[[gb2@1.4 ab2] bb2] gb2>".legato(".5 1".fast(2)).velocity(.8),
|
||||
"0 ~".scale('c4 whole tone')
|
||||
.euclidLegato(3,8).slow(2).mask("x ~")
|
||||
.stutWith(8, 1/16, (x,n)=>x.scaleTranspose(n).velocity(Math.pow(.7,n)))
|
||||
.scaleTranspose("<0 1 2 3 4 3 2 1>")
|
||||
.fast(2)
|
||||
.velocity(.7)
|
||||
.legato(.5)
|
||||
.stut(3, .5, 1/8)
|
||||
).transpose(-1).note().piano(),
|
||||
s("mad").slow(2)
|
||||
).cpm(78).slow(4)
|
||||
|
||||
.pianoroll()
|
||||
`;
|
||||
|
||||
@@ -328,39 +336,63 @@ export const goodTimes = `// "Good times"
|
||||
|
||||
const scale = cat('C3 dorian','Bb2 major').slow(4);
|
||||
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)
|
||||
.fast(2)
|
||||
.add("<0 1 2 1>").hush(),
|
||||
"<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))
|
||||
.off(1/4, scaleTranspose("2,4")),
|
||||
"<0 4>(5,8,-1)".scale(scale).transpose(-12)
|
||||
)
|
||||
.velocity(".6 .7".fast(4))
|
||||
.add(note(4))
|
||||
.piano()
|
||||
.clip(2)
|
||||
.legato("2")
|
||||
.scaleTranspose("<0>".slow(4))
|
||||
.transpose(5)
|
||||
.note().piano()
|
||||
.velocity(.8)
|
||||
.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"
|
||||
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
// @by Felix Roos
|
||||
|
||||
n("<0 2 [4 6](3,4,2) 3*2>").color('salmon')
|
||||
.off(1/4, x=>x.add(2).color('green'))
|
||||
.off(1/2, x=>x.add(6).color('steelblue'))
|
||||
"<0 2 [4 6](3,4,2) 3*2>"
|
||||
.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)
|
||||
.clip(.5)
|
||||
.piano()
|
||||
.note().piano()
|
||||
.pianoroll()`;
|
||||
|
||||
export const sml1 = `// Hirokazu Tanaka - World 1-1
|
||||
stack(
|
||||
// melody
|
||||
note(\`<
|
||||
\`<
|
||||
[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 ~]
|
||||
[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 ~]]
|
||||
[~ a5] [b5 c6] [b5@2 ~@2 g5] ~
|
||||
[eb6 d6] [~ c6] ~!2
|
||||
>\`)
|
||||
.clip(.95),
|
||||
>\`
|
||||
.legato(.95),
|
||||
// sub melody
|
||||
note(\`<
|
||||
\`<
|
||||
[~ g4]!2 [~ ab4]!2 [~ a4]!2 [~ bb4]!2
|
||||
[~ a4]!2 [~ g4]!2 [d4 e4] [f4 gb4] ~!2
|
||||
[~ g4]!2 [~ ab4]!2 [~ a4]!2 [~ bb4]!2
|
||||
[~ a4]!2 [~ g4]!2 [d4 e4] [f4 gb4] ~!2
|
||||
[~ c5]!4 [~ a4]!2 [[c4 ~] [d4 ~]] [[eb4 ~] [e4 ~]]
|
||||
[~ c5]!4 [~ eb5]!2 [g4*2 [f4 ~]] [[e4 ~] [d4 ~]]
|
||||
>\`),
|
||||
>\`,
|
||||
// bass
|
||||
note(\`<
|
||||
\`<
|
||||
c3!7 a3 f3!2
|
||||
e3!2 ~!4
|
||||
c3!7 a3 f3!2
|
||||
e3!2 ~!4
|
||||
f3!2 e3!2 d3!2 ~!2
|
||||
f3!2 e3!2 ab3!2 ~!2
|
||||
>\`)
|
||||
.clip(.5)
|
||||
).fast(2)`;
|
||||
>\`
|
||||
.legato(.5)
|
||||
).fast(2).note()`;
|
||||
|
||||
export const randomBells = `// "Random bells"
|
||||
// @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)
|
||||
.echo(3, 1/16, .5)
|
||||
.add(rand.range(0,12))
|
||||
.scale("D:minor:pentatonic").note()
|
||||
.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),
|
||||
// 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)
|
||||
.pianoroll({vertical:1})`;
|
||||
.pianoroll({minMidi:20,maxMidi:120,background:'transparent'})
|
||||
`;
|
||||
|
||||
export const waa2 = `// "Waa2"
|
||||
// @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))
|
||||
)
|
||||
.slow(2)
|
||||
.clip(sine.range(0.3, 2).slow(28))
|
||||
.legato(sine.range(0.3, 2).slow(28))
|
||||
.s("sawtooth square".fast(2))
|
||||
.cutoff(cosine.range(500,4000).slow(16))
|
||||
.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/
|
||||
// @by Felix Roos
|
||||
|
||||
n("[-7*3],0,2,6,[8 7]")
|
||||
.echoWith(
|
||||
4, // echo 4 times
|
||||
1/4, // 1/4s between echos
|
||||
(x,i)=>x
|
||||
.add(n(i*7)) // add octaves
|
||||
.gain(1/(i+1)) // reduce gain
|
||||
.clip(1/(i+1))
|
||||
)
|
||||
.velocity(perlin.range(.5,.9).slow(8))
|
||||
.stack(n("[22 25]*3")
|
||||
.clip(sine.range(.5,2).slow(8))
|
||||
.gain(sine.range(.4,.8).slow(5))
|
||||
.echo(4,1/12,.5))
|
||||
.scale("<D:dorian G:mixolydian C:dorian F:mixolydian>")
|
||||
.slow(2).piano()
|
||||
"[-7*3],0,2,6,[8 7]"
|
||||
.echoWith(4,1/4, (x,n)=>x
|
||||
.add(n*7)
|
||||
.velocity(1/(n+1))
|
||||
.legato(1/(n+1)))
|
||||
.velocity(perlin.range(.5,.9).slow(8))
|
||||
.stack("[22 25]*3"
|
||||
.legato(sine.range(.5,2).slow(8))
|
||||
.velocity(sine.range(.4,.8).slow(5))
|
||||
.echo(4,1/12,.5))
|
||||
.scale(cat('D dorian','G mixolydian','C dorian','F mixolydian'))
|
||||
.legato(1)
|
||||
.slow(2)
|
||||
.note().piano()
|
||||
//.pianoroll({maxMidi:160})`;
|
||||
|
||||
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")
|
||||
,
|
||||
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'))
|
||||
.clip(.25).csound('SynHarp')
|
||||
.legato(.25).csound('SynHarp')
|
||||
,
|
||||
s("bd*2,[~ hh]*2,~ cp").bank('RolandTR909')
|
||||
)`;
|
||||
@@ -878,15 +910,15 @@ export const arpoon = `// "Arpoon"
|
||||
|
||||
await samples('github:tidalcycles/Dirt-Samples/master')
|
||||
|
||||
note("<<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)
|
||||
.add(perlin.range(0,0.2).add("<0 12>/8").note())
|
||||
.cutoff(perlin.range(500,4000)).resonance(12)
|
||||
"<<Am7 C^7> C7 F^7 [Fm7 E7b9]>".voicings('lefthand')
|
||||
.arp("[0,3] 2 [1,3] 2".fast(3).lastOf(4, fast(2))).legato(2)
|
||||
.add(perlin.range(0,0.2)).sub("<0 -12>/8")
|
||||
.note().cutoff(perlin.range(500,4000)).resonance(12)
|
||||
.gain("<.5 .8>*16")
|
||||
.decay(.16).sustain(0.5)
|
||||
.delay(.2)
|
||||
.room(.5).pan(sine.range(.3,.6))
|
||||
.s('piano')
|
||||
.s('piano').clip(1)
|
||||
.stack("<<A1 C2>!2 F2 [F2 E2]>".add.out("0 -5".fast(2)).add("0,.12").note().s('sawtooth').clip(1).cutoff(300))
|
||||
.slow(4)
|
||||
.stack(s("bd*4, [~ [hh hh? hh?]]*2,~ [sd ~ [sd:2? bd?]]").bank('RolandTR909').gain(.5).slow(2))
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
import { persistentMap } from '@nanostores/persistent';
|
||||
import { useStore } from '@nanostores/react';
|
||||
import { register } from '@strudel.cycles/core';
|
||||
|
||||
export const defaultSettings = {
|
||||
activeFooter: 'intro',
|
||||
keybindings: 'codemirror',
|
||||
isLineNumbersDisplayed: true,
|
||||
isAutoCompletionEnabled: false,
|
||||
isLineWrappingEnabled: false,
|
||||
theme: 'strudelTheme',
|
||||
fontFamily: 'monospace',
|
||||
fontSize: 18,
|
||||
@@ -24,8 +21,6 @@ export function useSettings() {
|
||||
...state,
|
||||
isZen: [true, 'true'].includes(state.isZen) ? 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),
|
||||
};
|
||||
}
|
||||
@@ -34,18 +29,3 @@ export const setActiveFooter = (tab) => settingsMap.setKey('activeFooter', tab);
|
||||
|
||||
export const setLatestCode = (code) => settingsMap.setKey('latestCode', code);
|
||||
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 };
|
||||
|
||||