diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs index 1ca49bb6a..a03658a8b 100644 --- a/packages/core/controls.mjs +++ b/packages/core/controls.mjs @@ -380,6 +380,62 @@ const generic_params = [ * */ ['coarse'], + + ['phaserrate', 'phasr'], // superdirt only + + /** + * Phaser audio effect that approximates popular guitar pedals. + * + * @name phaser + * @synonyms ph + * @param {number | Pattern} speed speed of modulation + * @example + * n(run(8)).scale("D:pentatonic").s("sawtooth").release(0.5) + * .phaser("<1 2 4 8>") + * + */ + [['phaser', 'phaserdepth', 'phasercenter', 'phasersweep'], 'ph'], + + /** + * The frequency sweep range of the lfo for the phaser effect. Defaults to 2000 + * + * @name phasersweep + * @synonyms phs + * @param {number | Pattern} phasersweep most useful values are between 0 and 4000 + * @example + * n(run(8)).scale("D:pentatonic").s("sawtooth").release(0.5) + * .phaser(2).phasersweep("<800 2000 4000>") + * + */ + ['phasersweep', 'phs'], + + /** + * The center frequency of the phaser in HZ. Defaults to 1000 + * + * @name phasercenter + * @synonyms phc + * @param {number | Pattern} centerfrequency in HZ + * @example + * n(run(8)).scale("D:pentatonic").s("sawtooth").release(0.5) + * .phaser(2).phasercenter("<800 2000 4000>") + * + */ + + ['phasercenter', 'phc'], + + /** + * The amount the signal is affected by the phaser effect. Defaults to 0.75 + * + * @name phaserdepth + * @synonyms phd + * @param {number | Pattern} depth number between 0 and 1 + * @example + * n(run(8)).scale("D:pentatonic").s("sawtooth").release(0.5) + * .phaser(2).phaserdepth("<0 .5 .75 1>") + * + */ + ['phaserdepth', 'phd', 'phasdp'], // also a superdirt control + /** * choose the channel the pattern is sent to in superdirt * @@ -867,7 +923,12 @@ const generic_params = [ * */ ['lsize'], - // label for pianoroll + /** + * Sets the displayed text for an event on the pianoroll + * + * @name label + * @param {string} label text to display + */ ['activeLabel'], [['label', 'activeLabel']], // ['lfo'], @@ -1031,7 +1092,8 @@ const generic_params = [ */ ['roomfade', 'rfade'], /** - * Sets the sample to use as an impulse response for the reverb. * * @name iresponse + * Sets the sample to use as an impulse response for the reverb. + * @name iresponse * @param {string | Pattern} sample to use as an impulse response * @synonyms ir * @example @@ -1169,9 +1231,6 @@ const generic_params = [ */ ['tremolodepth', 'tremdp'], ['tremolorate', 'tremr'], - // TODO: doesn't seem to do anything - ['phaserdepth', 'phasdp'], - ['phaserrate', 'phasr'], ['fshift'], ['fshiftnote'], diff --git a/packages/core/pattern.mjs b/packages/core/pattern.mjs index dcf5da1b5..f30d21c81 100644 --- a/packages/core/pattern.mjs +++ b/packages/core/pattern.mjs @@ -2191,6 +2191,9 @@ export const duration = register('duration', function (value, pat) { /** * Sets the color of the hap in visualizations like pianoroll or highlighting. + * @name color + * @synonyms colour + * @param {string} color Hexadecimal or CSS color name */ // TODO: move this to controls https://github.com/tidalcycles/strudel/issues/288 export const { color, colour } = register(['color', 'colour'], function (color, pat) { @@ -2392,3 +2395,29 @@ export const ref = (accessor) => pure(1) .withValue(() => reify(accessor())) .innerJoin(); + +let fadeGain = (p) => (p < 0.5 ? 1 : 1 - (p - 0.5) / 0.5); + +/** + * Cross-fades between left and right from 0 to 1: + * - 0 = (full left, no right) + * - .5 = (both equal) + * - 1 = (no left, full right) + * + * @name xfade + * @example + * xfade(s("bd*2"), "<0 .25 .5 .75 1>", s("hh*8")) + */ +export let xfade = (a, pos, b) => { + pos = reify(pos); + a = reify(a); + b = reify(b); + let gaina = pos.fmap((v) => ({ gain: fadeGain(v) })); + let gainb = pos.fmap((v) => ({ gain: fadeGain(1 - v) })); + return stack(a.mul(gaina), b.mul(gainb)); +}; + +// the prototype version is actually flipped so left/right makes sense +Pattern.prototype.xfade = function (pos, b) { + return xfade(this, pos, b); +}; diff --git a/packages/core/pianoroll.mjs b/packages/core/pianoroll.mjs index 96126b175..01561cb24 100644 --- a/packages/core/pianoroll.mjs +++ b/packages/core/pianoroll.mjs @@ -56,6 +56,40 @@ Pattern.prototype.pianoroll = function (options = {}) { // this function allows drawing a pianoroll without ties to Pattern.prototype // it will probably replace the above in the future + +/** + * Displays a midi-style piano roll + * + * @name pianoroll + * @param {Object} options Object containing all the optional following parameters as key value pairs: + * @param {integer} cycles number of cycles to be displayed at the same time - defaults to 4 + * @param {number} playhead location of the active notes on the time axis - 0 to 1, defaults to 0.5 + * @param {boolean} vertical displays the roll vertically - 0 by default + * @param {boolean} labels displays labels on individual notes (see the label function) - 0 by default + * @param {boolean} flipTime reverse the direction of the roll - 0 by default + * @param {boolean} flipValues reverse the relative location of notes on the value axis - 0 by default + * @param {number} overscan lookup X cycles outside of the cycles window to display notes in advance - 1 by default + * @param {boolean} hideNegative hide notes with negative time (before starting playing the pattern) - 0 by default + * @param {boolean} smear notes leave a solid trace - 0 by default + * @param {boolean} fold notes takes the full value axis width - 0 by default + * @param {string} active hexadecimal or CSS color of the active notes - defaults to #FFCA28 + * @param {string} inactive hexadecimal or CSS color of the inactive notes - defaults to #7491D2 + * @param {string} background hexadecimal or CSS color of the background - defaults to transparent + * @param {string} playheadColor hexadecimal or CSS color of the line representing the play head - defaults to white + * @param {boolean} fill notes are filled with color (otherwise only the label is displayed) - 0 by default + * @param {boolean} fillActive active notes are filled with color - 0 by default + * @param {boolean} stroke notes are shown with colored borders - 0 by default + * @param {boolean} strokeActive active notes are shown with colored borders - 0 by default + * @param {boolean} hideInactive only active notes are shown - 0 by default + * @param {boolean} colorizeInactive use note color for inactive notes - 1 by default + * @param {string} fontFamily define the font used by notes labels - defaults to 'monospace' + * @param {integer} minMidi minimum note value to display on the value axis - defaults to 10 + * @param {integer} maxMidi maximum note value to display on the value axis - defaults to 90 + * @param {boolean} autorange automatically calculate the minMidi and maxMidi parameters - 0 by default + * + * @example + * note("C2 A2 G2").euclid(5,8).s('piano').clip(1).color('salmon').pianoroll({vertical:1, labels:1}) + */ export function pianoroll({ time, haps, diff --git a/packages/csound/index.mjs b/packages/csound/index.mjs index 31ffa83a5..3063febc1 100644 --- a/packages/csound/index.mjs +++ b/packages/csound/index.mjs @@ -137,7 +137,7 @@ export async function loadOrc(url) { export const csoundm = register('csoundm', (instrument, pat) => { let p1 = instrument; if (typeof instrument === 'string') { - p1 = `"{instrument}"`; + p1 = `"${instrument}"`; } init(); // not async to support csound inside other patterns + to be able to call pattern methods after it return pat.onTrigger((tidal_time, hap) => { diff --git a/packages/react/src/components/Autocomplete.jsx b/packages/react/src/components/Autocomplete.jsx index 7ec81d2d1..677baa6e7 100644 --- a/packages/react/src/components/Autocomplete.jsx +++ b/packages/react/src/components/Autocomplete.jsx @@ -26,7 +26,6 @@ export function Autocomplete({ doc }) {
{
- console.log('ola!');
navigator.clipboard.writeText(example);
e.stopPropagation();
}}
diff --git a/packages/react/src/components/CodeMirror6.jsx b/packages/react/src/components/CodeMirror6.jsx
index 520d8b76a..ab59ab9b3 100644
--- a/packages/react/src/components/CodeMirror6.jsx
+++ b/packages/react/src/components/CodeMirror6.jsx
@@ -9,6 +9,7 @@ import _CodeMirror from '@uiw/react-codemirror';
import React, { useCallback, useMemo } from 'react';
import strudelTheme from '../themes/strudel-theme';
import { strudelAutocomplete } from './Autocomplete';
+import { strudelTooltip } from './Tooltip';
import {
highlightExtension,
flashField,
@@ -37,6 +38,7 @@ export default function CodeMirror({
keybindings,
isLineNumbersDisplayed,
isAutoCompletionEnabled,
+ isTooltipEnabled,
isLineWrappingEnabled,
fontSize = 18,
fontFamily = 'monospace',
@@ -97,6 +99,14 @@ export default function CodeMirror({
} else {
_extensions.push(autocompletion({ override: [] }));
}
+ if (isTooltipEnabled) {
+ _extensions.push(strudelTooltip);
+ }
+ //_extensions.push([keymap.of({})]);
+
+ if (isLineWrappingEnabled) {
+ _extensions.push(EditorView.lineWrapping);
+ }
_extensions.push(
keymap.of([
@@ -130,12 +140,17 @@ export default function CodeMirror({
]),
);
- if (isLineWrappingEnabled) {
- _extensions.push(EditorView.lineWrapping);
- }
-
return _extensions;
- }, [keybindings, isAutoCompletionEnabled, isLineWrappingEnabled, onEvaluate, onReEvaluate, onStop, onPanic]);
+ }, [
+ keybindings,
+ isAutoCompletionEnabled,
+ isTooltipEnabled,
+ isLineWrappingEnabled,
+ onEvaluate,
+ onReEvaluate,
+ onStop,
+ onPanic,
+ ]);
const basicSetup = useMemo(() => ({ lineNumbers: isLineNumbersDisplayed }), [isLineNumbersDisplayed]);
diff --git a/packages/react/src/components/Tooltip.jsx b/packages/react/src/components/Tooltip.jsx
new file mode 100644
index 000000000..a443c1231
--- /dev/null
+++ b/packages/react/src/components/Tooltip.jsx
@@ -0,0 +1,69 @@
+import { createRoot } from 'react-dom/client';
+import { hoverTooltip } from '@codemirror/view';
+import jsdoc from '../../../../doc.json';
+import { Autocomplete } from './Autocomplete';
+
+const getDocLabel = (doc) => doc.name || doc.longname;
+
+let ctrlDown = false;
+
+// Record Control key event to trigger or block the tooltip depending on the state
+window.addEventListener(
+ 'keyup',
+ function (e) {
+ if (e.key == 'Control') {
+ ctrlDown = false;
+ }
+ },
+ true,
+);
+
+window.addEventListener(
+ 'keydown',
+ function (e) {
+ if (e.key == 'Control') {
+ ctrlDown = true;
+ }
+ },
+ true,
+);
+
+export const strudelTooltip = hoverTooltip(
+ (view, pos, side) => {
+ // Word selection from CodeMirror Hover Tooltip example https://codemirror.net/examples/tooltip/#hover-tooltips
+ let { from, to, text } = view.state.doc.lineAt(pos);
+ let start = pos,
+ end = pos;
+ while (start > from && /\w/.test(text[start - from - 1])) {
+ start--;
+ }
+ while (end < to && /\w/.test(text[end - from])) {
+ end++;
+ }
+ if ((start == pos && side < 0) || (end == pos && side > 0)) {
+ return null;
+ }
+ let word = text.slice(start - from, end - from);
+ // Get entry from Strudel documentation
+ let entry = jsdoc.docs.filter((doc) => getDocLabel(doc) === word)[0];
+ if (!entry) {
+ return null;
+ }
+ if (!ctrlDown) {
+ return null;
+ }
+ return {
+ pos: start,
+ end,
+ above: false,
+ arrow: true,
+ create(view) {
+ let dom = document.createElement('div');
+ dom.className = 'strudel-tooltip';
+ createRoot(dom).render( );
+ return { dom };
+ },
+ };
+ },
+ { hoverTime: 10 },
+);
diff --git a/packages/react/src/components/style.css b/packages/react/src/components/style.css
index d61c66190..6336bba32 100644
--- a/packages/react/src/components/style.css
+++ b/packages/react/src/components/style.css
@@ -28,3 +28,7 @@
footer {
z-index: 0 !important;
}
+
+.strudel-tooltip {
+ padding: 5px;
+}
diff --git a/packages/serial/serial.mjs b/packages/serial/serial.mjs
index c4e52d4d2..652b60546 100644
--- a/packages/serial/serial.mjs
+++ b/packages/serial/serial.mjs
@@ -6,23 +6,23 @@ This program is free software: you can redistribute it and/or modify it under th
import { Pattern, isPattern } from '@strudel.cycles/core';
-var writeMessage;
+var writeMessagers = {};
var choosing = false;
-export async function getWriter(br = 38400) {
+export async function getWriter(name, br) {
if (choosing) {
return;
}
choosing = true;
- if (writeMessage) {
- return writeMessage;
+ if (name in writeMessagers) {
+ return writeMessagers[name];
}
if ('serial' in navigator) {
const port = await navigator.serial.requestPort();
await port.open({ baudRate: br });
const encoder = new TextEncoder();
const writer = port.writable.getWriter();
- writeMessage = function (message, chk) {
+ writeMessagers[name] = function (message, chk) {
const encoded = encoder.encode(message);
if (!chk) {
writer.write(encoded);
@@ -63,10 +63,10 @@ function crc16(data) {
return crc & 0xffff;
}
-Pattern.prototype.serial = function (br = 38400, sendcrc = false, singlecharids = false) {
+Pattern.prototype.serial = function (br = 115200, sendcrc = false, singlecharids = false, name = 'default') {
return this.withHap((hap) => {
- if (!writeMessage) {
- getWriter(br);
+ if (!(name in writeMessagers)) {
+ getWriter(name, br);
}
const onTrigger = (time, hap, currentTime) => {
var message = '';
@@ -108,7 +108,7 @@ Pattern.prototype.serial = function (br = 38400, sendcrc = false, singlecharids
const offset = (time - currentTime + latency) * 1000;
window.setTimeout(function () {
- writeMessage(message, chk);
+ writeMessagers[name](message, chk);
}, offset);
};
return hap.setContext({ ...hap.context, onTrigger, dominantTrigger: true });
diff --git a/packages/superdough/README.md b/packages/superdough/README.md
index c5950dbfa..f32aa32d4 100644
--- a/packages/superdough/README.md
+++ b/packages/superdough/README.md
@@ -67,6 +67,10 @@ superdough({ s: 'bd', delay: 0.5 }, 0, 1);
- `crush`: amplitude bit crusher using given number of bits
- `shape`: distortion effect from 0 (none) to 1 (full). might get loud!
- `pan`: stereo panning from 0 (left) to 1 (right)
+ - `phaser`: sets the speed of the modulation
+ - `phaserdepth`: the amount the signal is affected by the phaser effect.
+ - `phasersweep`: the frequency sweep range of the lfo for the phaser effect.
+ - `phasercenter`: the amount the signal is affected by the phaser effect.
- `vowel`: vowel filter. possible values: "a", "e", "i", "o", "u"
- `delay`: delay mix
- `delayfeedback`: delay feedback
diff --git a/packages/superdough/sampler.mjs b/packages/superdough/sampler.mjs
index d0733b148..b8f10d5da 100644
--- a/packages/superdough/sampler.mjs
+++ b/packages/superdough/sampler.mjs
@@ -57,7 +57,6 @@ export const getSampleBufferSource = async (s, n, note, speed, freq, bank, resol
const bufferSource = ac.createBufferSource();
bufferSource.buffer = buffer;
const playbackRate = 1.0 * Math.pow(2, transpose / 12);
- // bufferSource.playbackRate.value = Math.pow(2, transpose / 12);
bufferSource.playbackRate.value = playbackRate;
return bufferSource;
};
@@ -162,9 +161,17 @@ export const samples = async (sampleMap, baseUrl = sampleMap._base || '', option
if (handler) {
return handler(sampleMap);
}
+ if (sampleMap.startsWith('bubo:')) {
+ const [_, repo] = sampleMap.split(':');
+ sampleMap = `github:Bubobubobubobubo/dough-${repo}`;
+ }
if (sampleMap.startsWith('github:')) {
let [_, path] = sampleMap.split('github:');
path = path.endsWith('/') ? path.slice(0, -1) : path;
+ if (path.split('/').length === 2) {
+ // assume main as default branch if none set
+ path += '/main';
+ }
sampleMap = `https://raw.githubusercontent.com/${path}/strudel.json`;
}
if (sampleMap.startsWith('shabda:')) {
@@ -232,6 +239,8 @@ export async function onTriggerSample(t, value, onended, bank, resolveUrl) {
begin = 0,
loopEnd = 1,
end = 1,
+ vib,
+ vibmod = 0.5,
} = value;
// load sample
if (speed === 0) {
@@ -247,6 +256,19 @@ export async function onTriggerSample(t, value, onended, bank, resolveUrl) {
const bufferSource = await getSampleBufferSource(s, n, note, speed, freq, bank, resolveUrl);
+ // vibrato
+ let vibratoOscillator;
+ if (vib > 0) {
+ vibratoOscillator = getAudioContext().createOscillator();
+ vibratoOscillator.frequency.value = vib;
+ const gain = getAudioContext().createGain();
+ // Vibmod is the amount of vibrato, in semitones
+ gain.gain.value = vibmod * 100;
+ vibratoOscillator.connect(gain);
+ gain.connect(bufferSource.detune);
+ vibratoOscillator.start(0);
+ }
+
// asny stuff above took too long?
if (ac.currentTime > t) {
logger(`[sampler] still loading sound "${s}:${n}"`, 'highlight');
@@ -278,6 +300,7 @@ export async function onTriggerSample(t, value, onended, bank, resolveUrl) {
envelope.connect(out);
bufferSource.onended = function () {
bufferSource.disconnect();
+ vibratoOscillator?.stop();
envelope.disconnect();
out.disconnect();
onended();
diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs
index e3033afe1..00e2f42ca 100644
--- a/packages/superdough/superdough.mjs
+++ b/packages/superdough/superdough.mjs
@@ -112,6 +112,48 @@ function getDelay(orbit, delaytime, delayfeedback, t) {
return delays[orbit];
}
+// each orbit will have its own lfo
+const phaserLFOs = {};
+function getPhaser(orbit, t, speed = 1, depth = 0.5, centerFrequency = 1000, sweep = 2000) {
+ //gain
+ const ac = getAudioContext();
+ const lfoGain = ac.createGain();
+ lfoGain.gain.value = sweep;
+
+ //LFO
+ if (phaserLFOs[orbit] == null) {
+ phaserLFOs[orbit] = ac.createOscillator();
+ phaserLFOs[orbit].frequency.value = speed;
+ phaserLFOs[orbit].type = 'sine';
+ phaserLFOs[orbit].start();
+ }
+
+ phaserLFOs[orbit].connect(lfoGain);
+ if (phaserLFOs[orbit].frequency.value != speed) {
+ phaserLFOs[orbit].frequency.setValueAtTime(speed, t);
+ }
+
+ //filters
+ const numStages = 2; //num of filters in series
+ let fOffset = 0;
+ const filterChain = [];
+ for (let i = 0; i < numStages; i++) {
+ const filter = ac.createBiquadFilter();
+ filter.type = 'notch';
+ filter.gain.value = 1;
+ filter.frequency.value = centerFrequency + fOffset;
+ filter.Q.value = 2 - Math.min(Math.max(depth * 2, 0), 1.9);
+
+ lfoGain.connect(filter.detune);
+ fOffset += 282;
+ if (i > 0) {
+ filterChain[i - 1].connect(filter);
+ }
+ filterChain.push(filter);
+ }
+ return filterChain[filterChain.length - 1];
+}
+
let reverbs = {};
let hasChanged = (now, before) => now !== undefined && now !== before;
@@ -226,6 +268,12 @@ export const superdough = async (value, deadline, hapDuration) => {
bpsustain = 1,
bprelease = 0.01,
bandq = 1,
+
+ //phaser
+ phaser,
+ phaserdepth = 0.75,
+ phasersweep,
+ phasercenter,
//
coarse,
crush,
@@ -260,6 +308,7 @@ export const superdough = async (value, deadline, hapDuration) => {
if (bank && s) {
s = `${bank}_${s}`;
}
+
// get source AudioNode
let sourceNode;
if (source) {
@@ -377,6 +426,11 @@ export const superdough = async (value, deadline, hapDuration) => {
panner.pan.value = 2 * pan - 1;
chain.push(panner);
}
+ // phaser
+ if (phaser !== undefined && phaserdepth > 0) {
+ const phaserFX = getPhaser(orbit, t, phaser, phaserdepth, phasercenter, phasersweep);
+ chain.push(phaserFX);
+ }
// last gain
const post = gainNode(postgain);
diff --git a/packages/webaudio/scope.mjs b/packages/webaudio/scope.mjs
index 9f052e8ee..1affd2624 100644
--- a/packages/webaudio/scope.mjs
+++ b/packages/webaudio/scope.mjs
@@ -3,7 +3,7 @@ import { analyser, getAnalyzerData } from 'superdough';
export function drawTimeScope(
analyser,
- { align = true, color = 'white', thickness = 3, scale = 0.25, pos = 0.75, next = 1, trigger = 0 } = {},
+ { align = true, color = 'white', thickness = 3, scale = 0.25, pos = 0.75, trigger = 0 } = {},
) {
const ctx = getDrawContext();
const dataArray = getAnalyzerData('time');
@@ -22,10 +22,9 @@ export function drawTimeScope(
const sliceWidth = (canvas.width * 1.0) / bufferSize;
let x = 0;
-
for (let i = triggerIndex; i < bufferSize; i++) {
const v = dataArray[i] + 1;
- const y = (1 - (scale * (v - 1) + pos)) * canvas.height;
+ const y = (pos - scale * (v - 1)) * canvas.height;
if (i === 0) {
ctx.moveTo(x, y);
@@ -71,6 +70,18 @@ function clearScreen(smear = 0, smearRGB = `0,0,0`) {
}
}
+/**
+ * Renders an oscilloscope for the frequency domain of the audio signal.
+ * @name fscope
+ * @param {string} color line color as hex or color name. defaults to white.
+ * @param {number} scale scales the y-axis. Defaults to 0.25
+ * @param {number} pos y-position relative to screen height. 0 = top, 1 = bottom of screen
+ * @param {number} lean y-axis alignment where 0 = top and 1 = bottom
+ * @param {number} min min value
+ * @param {number} max max value
+ * @example
+ * s("sawtooth").fscope()
+ */
Pattern.prototype.fscope = function (config = {}) {
return this.analyze(1).draw(() => {
clearScreen(config.smear);
@@ -78,6 +89,20 @@ Pattern.prototype.fscope = function (config = {}) {
});
};
+/**
+ * Renders an oscilloscope for the time domain of the audio signal.
+ * @name scope
+ * @synonyms tscope
+ * @param {object} config optional config with options:
+ * @param {boolean} align if 1, the scope will be aligned to the first zero crossing. defaults to 1
+ * @param {string} color line color as hex or color name. defaults to white.
+ * @param {number} thickness line thickness. defaults to 3
+ * @param {number} scale scales the y-axis. Defaults to 0.25
+ * @param {number} pos y-position relative to screen height. 0 = top, 1 = bottom of screen
+ * @param {number} trigger amplitude value that is used to align the scope. defaults to 0.
+ * @example
+ * s("sawtooth").scope()
+ */
Pattern.prototype.tscope = function (config = {}) {
return this.analyze(1).draw(() => {
clearScreen(config.smear);
diff --git a/test/__snapshots__/examples.test.mjs.snap b/test/__snapshots__/examples.test.mjs.snap
index 0963638f8..a12fcb655 100644
--- a/test/__snapshots__/examples.test.mjs.snap
+++ b/test/__snapshots__/examples.test.mjs.snap
@@ -2143,6 +2143,15 @@ exports[`runs examples > example "freq" example index 1 1`] = `
]
`;
+exports[`runs examples > example "fscope" example index 0 1`] = `
+[
+ "[ 0/1 → 1/1 | s:sawtooth analyze:1 ]",
+ "[ 1/1 → 2/1 | s:sawtooth analyze:1 ]",
+ "[ 2/1 → 3/1 | s:sawtooth analyze:1 ]",
+ "[ 3/1 → 4/1 | s:sawtooth analyze:1 ]",
+]
+`;
+
exports[`runs examples > example "ftype" example index 0 1`] = `
[
"[ 0/1 → 1/1 | note:c2 s:sawtooth cutoff:500 bpenv:4 ftype:12db ]",
@@ -2430,6 +2439,19 @@ exports[`runs examples > example "irand" example index 0 1`] = `
]
`;
+exports[`runs examples > example "iresponse" example index 0 1`] = `
+[
+ "[ 0/1 → 1/2 | s:bd room:0.8 ir:shaker_large i:0 ]",
+ "[ 1/2 → 1/1 | s:sd room:0.8 ir:shaker_large i:0 ]",
+ "[ 1/1 → 3/2 | s:bd room:0.8 ir:shaker_large i:2 ]",
+ "[ 3/2 → 2/1 | s:sd room:0.8 ir:shaker_large i:2 ]",
+ "[ 2/1 → 5/2 | s:bd room:0.8 ir:shaker_large i:0 ]",
+ "[ 5/2 → 3/1 | s:sd room:0.8 ir:shaker_large i:0 ]",
+ "[ 3/1 → 7/2 | s:bd room:0.8 ir:shaker_large i:2 ]",
+ "[ 7/2 → 4/1 | s:sd room:0.8 ir:shaker_large i:2 ]",
+]
+`;
+
exports[`runs examples > example "iter" example index 0 1`] = `
[
"[ 0/1 → 1/4 | note:A3 ]",
@@ -3297,6 +3319,187 @@ exports[`runs examples > example "perlin" example index 0 1`] = `
]
`;
+exports[`runs examples > example "phaser" example index 0 1`] = `
+[
+ "[ 0/1 → 1/8 | note:D3 s:sawtooth release:0.5 phaser:1 ]",
+ "[ 1/8 → 1/4 | note:E3 s:sawtooth release:0.5 phaser:1 ]",
+ "[ 1/4 → 3/8 | note:F#3 s:sawtooth release:0.5 phaser:1 ]",
+ "[ 3/8 → 1/2 | note:A3 s:sawtooth release:0.5 phaser:1 ]",
+ "[ 1/2 → 5/8 | note:B3 s:sawtooth release:0.5 phaser:1 ]",
+ "[ 5/8 → 3/4 | note:D4 s:sawtooth release:0.5 phaser:1 ]",
+ "[ 3/4 → 7/8 | note:E4 s:sawtooth release:0.5 phaser:1 ]",
+ "[ 7/8 → 1/1 | note:F#4 s:sawtooth release:0.5 phaser:1 ]",
+ "[ 1/1 → 9/8 | note:D3 s:sawtooth release:0.5 phaser:2 ]",
+ "[ 9/8 → 5/4 | note:E3 s:sawtooth release:0.5 phaser:2 ]",
+ "[ 5/4 → 11/8 | note:F#3 s:sawtooth release:0.5 phaser:2 ]",
+ "[ 11/8 → 3/2 | note:A3 s:sawtooth release:0.5 phaser:2 ]",
+ "[ 3/2 → 13/8 | note:B3 s:sawtooth release:0.5 phaser:2 ]",
+ "[ 13/8 → 7/4 | note:D4 s:sawtooth release:0.5 phaser:2 ]",
+ "[ 7/4 → 15/8 | note:E4 s:sawtooth release:0.5 phaser:2 ]",
+ "[ 15/8 → 2/1 | note:F#4 s:sawtooth release:0.5 phaser:2 ]",
+ "[ 2/1 → 17/8 | note:D3 s:sawtooth release:0.5 phaser:4 ]",
+ "[ 17/8 → 9/4 | note:E3 s:sawtooth release:0.5 phaser:4 ]",
+ "[ 9/4 → 19/8 | note:F#3 s:sawtooth release:0.5 phaser:4 ]",
+ "[ 19/8 → 5/2 | note:A3 s:sawtooth release:0.5 phaser:4 ]",
+ "[ 5/2 → 21/8 | note:B3 s:sawtooth release:0.5 phaser:4 ]",
+ "[ 21/8 → 11/4 | note:D4 s:sawtooth release:0.5 phaser:4 ]",
+ "[ 11/4 → 23/8 | note:E4 s:sawtooth release:0.5 phaser:4 ]",
+ "[ 23/8 → 3/1 | note:F#4 s:sawtooth release:0.5 phaser:4 ]",
+ "[ 3/1 → 25/8 | note:D3 s:sawtooth release:0.5 phaser:8 ]",
+ "[ 25/8 → 13/4 | note:E3 s:sawtooth release:0.5 phaser:8 ]",
+ "[ 13/4 → 27/8 | note:F#3 s:sawtooth release:0.5 phaser:8 ]",
+ "[ 27/8 → 7/2 | note:A3 s:sawtooth release:0.5 phaser:8 ]",
+ "[ 7/2 → 29/8 | note:B3 s:sawtooth release:0.5 phaser:8 ]",
+ "[ 29/8 → 15/4 | note:D4 s:sawtooth release:0.5 phaser:8 ]",
+ "[ 15/4 → 31/8 | note:E4 s:sawtooth release:0.5 phaser:8 ]",
+ "[ 31/8 → 4/1 | note:F#4 s:sawtooth release:0.5 phaser:8 ]",
+]
+`;
+
+exports[`runs examples > example "phasercenter" example index 0 1`] = `
+[
+ "[ 0/1 → 1/8 | note:D3 s:sawtooth release:0.5 phaser:2 phasercenter:800 ]",
+ "[ 1/8 → 1/4 | note:E3 s:sawtooth release:0.5 phaser:2 phasercenter:800 ]",
+ "[ 1/4 → 3/8 | note:F#3 s:sawtooth release:0.5 phaser:2 phasercenter:800 ]",
+ "[ 3/8 → 1/2 | note:A3 s:sawtooth release:0.5 phaser:2 phasercenter:800 ]",
+ "[ 1/2 → 5/8 | note:B3 s:sawtooth release:0.5 phaser:2 phasercenter:800 ]",
+ "[ 5/8 → 3/4 | note:D4 s:sawtooth release:0.5 phaser:2 phasercenter:800 ]",
+ "[ 3/4 → 7/8 | note:E4 s:sawtooth release:0.5 phaser:2 phasercenter:800 ]",
+ "[ 7/8 → 1/1 | note:F#4 s:sawtooth release:0.5 phaser:2 phasercenter:800 ]",
+ "[ 1/1 → 9/8 | note:D3 s:sawtooth release:0.5 phaser:2 phasercenter:2000 ]",
+ "[ 9/8 → 5/4 | note:E3 s:sawtooth release:0.5 phaser:2 phasercenter:2000 ]",
+ "[ 5/4 → 11/8 | note:F#3 s:sawtooth release:0.5 phaser:2 phasercenter:2000 ]",
+ "[ 11/8 → 3/2 | note:A3 s:sawtooth release:0.5 phaser:2 phasercenter:2000 ]",
+ "[ 3/2 → 13/8 | note:B3 s:sawtooth release:0.5 phaser:2 phasercenter:2000 ]",
+ "[ 13/8 → 7/4 | note:D4 s:sawtooth release:0.5 phaser:2 phasercenter:2000 ]",
+ "[ 7/4 → 15/8 | note:E4 s:sawtooth release:0.5 phaser:2 phasercenter:2000 ]",
+ "[ 15/8 → 2/1 | note:F#4 s:sawtooth release:0.5 phaser:2 phasercenter:2000 ]",
+ "[ 2/1 → 17/8 | note:D3 s:sawtooth release:0.5 phaser:2 phasercenter:4000 ]",
+ "[ 17/8 → 9/4 | note:E3 s:sawtooth release:0.5 phaser:2 phasercenter:4000 ]",
+ "[ 9/4 → 19/8 | note:F#3 s:sawtooth release:0.5 phaser:2 phasercenter:4000 ]",
+ "[ 19/8 → 5/2 | note:A3 s:sawtooth release:0.5 phaser:2 phasercenter:4000 ]",
+ "[ 5/2 → 21/8 | note:B3 s:sawtooth release:0.5 phaser:2 phasercenter:4000 ]",
+ "[ 21/8 → 11/4 | note:D4 s:sawtooth release:0.5 phaser:2 phasercenter:4000 ]",
+ "[ 11/4 → 23/8 | note:E4 s:sawtooth release:0.5 phaser:2 phasercenter:4000 ]",
+ "[ 23/8 → 3/1 | note:F#4 s:sawtooth release:0.5 phaser:2 phasercenter:4000 ]",
+ "[ 3/1 → 25/8 | note:D3 s:sawtooth release:0.5 phaser:2 phasercenter:800 ]",
+ "[ 25/8 → 13/4 | note:E3 s:sawtooth release:0.5 phaser:2 phasercenter:800 ]",
+ "[ 13/4 → 27/8 | note:F#3 s:sawtooth release:0.5 phaser:2 phasercenter:800 ]",
+ "[ 27/8 → 7/2 | note:A3 s:sawtooth release:0.5 phaser:2 phasercenter:800 ]",
+ "[ 7/2 → 29/8 | note:B3 s:sawtooth release:0.5 phaser:2 phasercenter:800 ]",
+ "[ 29/8 → 15/4 | note:D4 s:sawtooth release:0.5 phaser:2 phasercenter:800 ]",
+ "[ 15/4 → 31/8 | note:E4 s:sawtooth release:0.5 phaser:2 phasercenter:800 ]",
+ "[ 31/8 → 4/1 | note:F#4 s:sawtooth release:0.5 phaser:2 phasercenter:800 ]",
+]
+`;
+
+exports[`runs examples > example "phaserdepth" example index 0 1`] = `
+[
+ "[ 0/1 → 1/8 | note:D3 s:sawtooth release:0.5 phaser:2 phaserdepth:0 ]",
+ "[ 1/8 → 1/4 | note:E3 s:sawtooth release:0.5 phaser:2 phaserdepth:0 ]",
+ "[ 1/4 → 3/8 | note:F#3 s:sawtooth release:0.5 phaser:2 phaserdepth:0 ]",
+ "[ 3/8 → 1/2 | note:A3 s:sawtooth release:0.5 phaser:2 phaserdepth:0 ]",
+ "[ 1/2 → 5/8 | note:B3 s:sawtooth release:0.5 phaser:2 phaserdepth:0 ]",
+ "[ 5/8 → 3/4 | note:D4 s:sawtooth release:0.5 phaser:2 phaserdepth:0 ]",
+ "[ 3/4 → 7/8 | note:E4 s:sawtooth release:0.5 phaser:2 phaserdepth:0 ]",
+ "[ 7/8 → 1/1 | note:F#4 s:sawtooth release:0.5 phaser:2 phaserdepth:0 ]",
+ "[ 1/1 → 9/8 | note:D3 s:sawtooth release:0.5 phaser:2 phaserdepth:0.5 ]",
+ "[ 9/8 → 5/4 | note:E3 s:sawtooth release:0.5 phaser:2 phaserdepth:0.5 ]",
+ "[ 5/4 → 11/8 | note:F#3 s:sawtooth release:0.5 phaser:2 phaserdepth:0.5 ]",
+ "[ 11/8 → 3/2 | note:A3 s:sawtooth release:0.5 phaser:2 phaserdepth:0.5 ]",
+ "[ 3/2 → 13/8 | note:B3 s:sawtooth release:0.5 phaser:2 phaserdepth:0.5 ]",
+ "[ 13/8 → 7/4 | note:D4 s:sawtooth release:0.5 phaser:2 phaserdepth:0.5 ]",
+ "[ 7/4 → 15/8 | note:E4 s:sawtooth release:0.5 phaser:2 phaserdepth:0.5 ]",
+ "[ 15/8 → 2/1 | note:F#4 s:sawtooth release:0.5 phaser:2 phaserdepth:0.5 ]",
+ "[ 2/1 → 17/8 | note:D3 s:sawtooth release:0.5 phaser:2 phaserdepth:0.75 ]",
+ "[ 17/8 → 9/4 | note:E3 s:sawtooth release:0.5 phaser:2 phaserdepth:0.75 ]",
+ "[ 9/4 → 19/8 | note:F#3 s:sawtooth release:0.5 phaser:2 phaserdepth:0.75 ]",
+ "[ 19/8 → 5/2 | note:A3 s:sawtooth release:0.5 phaser:2 phaserdepth:0.75 ]",
+ "[ 5/2 → 21/8 | note:B3 s:sawtooth release:0.5 phaser:2 phaserdepth:0.75 ]",
+ "[ 21/8 → 11/4 | note:D4 s:sawtooth release:0.5 phaser:2 phaserdepth:0.75 ]",
+ "[ 11/4 → 23/8 | note:E4 s:sawtooth release:0.5 phaser:2 phaserdepth:0.75 ]",
+ "[ 23/8 → 3/1 | note:F#4 s:sawtooth release:0.5 phaser:2 phaserdepth:0.75 ]",
+ "[ 3/1 → 25/8 | note:D3 s:sawtooth release:0.5 phaser:2 phaserdepth:1 ]",
+ "[ 25/8 → 13/4 | note:E3 s:sawtooth release:0.5 phaser:2 phaserdepth:1 ]",
+ "[ 13/4 → 27/8 | note:F#3 s:sawtooth release:0.5 phaser:2 phaserdepth:1 ]",
+ "[ 27/8 → 7/2 | note:A3 s:sawtooth release:0.5 phaser:2 phaserdepth:1 ]",
+ "[ 7/2 → 29/8 | note:B3 s:sawtooth release:0.5 phaser:2 phaserdepth:1 ]",
+ "[ 29/8 → 15/4 | note:D4 s:sawtooth release:0.5 phaser:2 phaserdepth:1 ]",
+ "[ 15/4 → 31/8 | note:E4 s:sawtooth release:0.5 phaser:2 phaserdepth:1 ]",
+ "[ 31/8 → 4/1 | note:F#4 s:sawtooth release:0.5 phaser:2 phaserdepth:1 ]",
+]
+`;
+
+exports[`runs examples > example "phasersweep" example index 0 1`] = `
+[
+ "[ 0/1 → 1/8 | note:D3 s:sawtooth release:0.5 phaser:2 phasersweep:800 ]",
+ "[ 1/8 → 1/4 | note:E3 s:sawtooth release:0.5 phaser:2 phasersweep:800 ]",
+ "[ 1/4 → 3/8 | note:F#3 s:sawtooth release:0.5 phaser:2 phasersweep:800 ]",
+ "[ 3/8 → 1/2 | note:A3 s:sawtooth release:0.5 phaser:2 phasersweep:800 ]",
+ "[ 1/2 → 5/8 | note:B3 s:sawtooth release:0.5 phaser:2 phasersweep:800 ]",
+ "[ 5/8 → 3/4 | note:D4 s:sawtooth release:0.5 phaser:2 phasersweep:800 ]",
+ "[ 3/4 → 7/8 | note:E4 s:sawtooth release:0.5 phaser:2 phasersweep:800 ]",
+ "[ 7/8 → 1/1 | note:F#4 s:sawtooth release:0.5 phaser:2 phasersweep:800 ]",
+ "[ 1/1 → 9/8 | note:D3 s:sawtooth release:0.5 phaser:2 phasersweep:2000 ]",
+ "[ 9/8 → 5/4 | note:E3 s:sawtooth release:0.5 phaser:2 phasersweep:2000 ]",
+ "[ 5/4 → 11/8 | note:F#3 s:sawtooth release:0.5 phaser:2 phasersweep:2000 ]",
+ "[ 11/8 → 3/2 | note:A3 s:sawtooth release:0.5 phaser:2 phasersweep:2000 ]",
+ "[ 3/2 → 13/8 | note:B3 s:sawtooth release:0.5 phaser:2 phasersweep:2000 ]",
+ "[ 13/8 → 7/4 | note:D4 s:sawtooth release:0.5 phaser:2 phasersweep:2000 ]",
+ "[ 7/4 → 15/8 | note:E4 s:sawtooth release:0.5 phaser:2 phasersweep:2000 ]",
+ "[ 15/8 → 2/1 | note:F#4 s:sawtooth release:0.5 phaser:2 phasersweep:2000 ]",
+ "[ 2/1 → 17/8 | note:D3 s:sawtooth release:0.5 phaser:2 phasersweep:4000 ]",
+ "[ 17/8 → 9/4 | note:E3 s:sawtooth release:0.5 phaser:2 phasersweep:4000 ]",
+ "[ 9/4 → 19/8 | note:F#3 s:sawtooth release:0.5 phaser:2 phasersweep:4000 ]",
+ "[ 19/8 → 5/2 | note:A3 s:sawtooth release:0.5 phaser:2 phasersweep:4000 ]",
+ "[ 5/2 → 21/8 | note:B3 s:sawtooth release:0.5 phaser:2 phasersweep:4000 ]",
+ "[ 21/8 → 11/4 | note:D4 s:sawtooth release:0.5 phaser:2 phasersweep:4000 ]",
+ "[ 11/4 → 23/8 | note:E4 s:sawtooth release:0.5 phaser:2 phasersweep:4000 ]",
+ "[ 23/8 → 3/1 | note:F#4 s:sawtooth release:0.5 phaser:2 phasersweep:4000 ]",
+ "[ 3/1 → 25/8 | note:D3 s:sawtooth release:0.5 phaser:2 phasersweep:800 ]",
+ "[ 25/8 → 13/4 | note:E3 s:sawtooth release:0.5 phaser:2 phasersweep:800 ]",
+ "[ 13/4 → 27/8 | note:F#3 s:sawtooth release:0.5 phaser:2 phasersweep:800 ]",
+ "[ 27/8 → 7/2 | note:A3 s:sawtooth release:0.5 phaser:2 phasersweep:800 ]",
+ "[ 7/2 → 29/8 | note:B3 s:sawtooth release:0.5 phaser:2 phasersweep:800 ]",
+ "[ 29/8 → 15/4 | note:D4 s:sawtooth release:0.5 phaser:2 phasersweep:800 ]",
+ "[ 15/4 → 31/8 | note:E4 s:sawtooth release:0.5 phaser:2 phasersweep:800 ]",
+ "[ 31/8 → 4/1 | note:F#4 s:sawtooth release:0.5 phaser:2 phasersweep:800 ]",
+]
+`;
+
+exports[`runs examples > example "pianoroll" example index 0 1`] = `
+[
+ "[ 0/1 → 1/8 | note:C2 s:piano clip:1 ]",
+ "[ (1/4 → 1/3) ⇝ 3/8 | note:C2 s:piano clip:1 ]",
+ "[ 1/4 ⇜ (1/3 → 3/8) | note:A2 s:piano clip:1 ]",
+ "[ 3/8 → 1/2 | note:A2 s:piano clip:1 ]",
+ "[ (5/8 → 2/3) ⇝ 3/4 | note:A2 s:piano clip:1 ]",
+ "[ 5/8 ⇜ (2/3 → 3/4) | note:G2 s:piano clip:1 ]",
+ "[ 3/4 → 7/8 | note:G2 s:piano clip:1 ]",
+ "[ 1/1 → 9/8 | note:C2 s:piano clip:1 ]",
+ "[ (5/4 → 4/3) ⇝ 11/8 | note:C2 s:piano clip:1 ]",
+ "[ 5/4 ⇜ (4/3 → 11/8) | note:A2 s:piano clip:1 ]",
+ "[ 11/8 → 3/2 | note:A2 s:piano clip:1 ]",
+ "[ (13/8 → 5/3) ⇝ 7/4 | note:A2 s:piano clip:1 ]",
+ "[ 13/8 ⇜ (5/3 → 7/4) | note:G2 s:piano clip:1 ]",
+ "[ 7/4 → 15/8 | note:G2 s:piano clip:1 ]",
+ "[ 2/1 → 17/8 | note:C2 s:piano clip:1 ]",
+ "[ (9/4 → 7/3) ⇝ 19/8 | note:C2 s:piano clip:1 ]",
+ "[ 9/4 ⇜ (7/3 → 19/8) | note:A2 s:piano clip:1 ]",
+ "[ 19/8 → 5/2 | note:A2 s:piano clip:1 ]",
+ "[ (21/8 → 8/3) ⇝ 11/4 | note:A2 s:piano clip:1 ]",
+ "[ 21/8 ⇜ (8/3 → 11/4) | note:G2 s:piano clip:1 ]",
+ "[ 11/4 → 23/8 | note:G2 s:piano clip:1 ]",
+ "[ 3/1 → 25/8 | note:C2 s:piano clip:1 ]",
+ "[ (13/4 → 10/3) ⇝ 27/8 | note:C2 s:piano clip:1 ]",
+ "[ 13/4 ⇜ (10/3 → 27/8) | note:A2 s:piano clip:1 ]",
+ "[ 27/8 → 7/2 | note:A2 s:piano clip:1 ]",
+ "[ (29/8 → 11/3) ⇝ 15/4 | note:A2 s:piano clip:1 ]",
+ "[ 29/8 ⇜ (11/3 → 15/4) | note:G2 s:piano clip:1 ]",
+ "[ 15/4 → 31/8 | note:G2 s:piano clip:1 ]",
+]
+`;
+
exports[`runs examples > example "pick" example index 0 1`] = `
[
"[ 0/1 → 1/2 | note:g ]",
@@ -4235,6 +4438,15 @@ exports[`runs examples > example "scaleTranspose" example index 0 1`] = `
]
`;
+exports[`runs examples > example "scope" example index 0 1`] = `
+[
+ "[ 0/1 → 1/1 | s:sawtooth analyze:1 ]",
+ "[ 1/1 → 2/1 | s:sawtooth analyze:1 ]",
+ "[ 2/1 → 3/1 | s:sawtooth analyze:1 ]",
+ "[ 3/1 → 4/1 | s:sawtooth analyze:1 ]",
+]
+`;
+
exports[`runs examples > example "segment" example index 0 1`] = `
[
"[ 0/1 → 1/24 | note:40.25 ]",
@@ -5235,6 +5447,51 @@ exports[`runs examples > example "withValue" example index 0 1`] = `
]
`;
+exports[`runs examples > example "xfade" example index 0 1`] = `
+[
+ "[ 0/1 → 1/8 | s:hh gain:0 ]",
+ "[ 0/1 → 1/2 | s:bd gain:1 ]",
+ "[ 1/8 → 1/4 | s:hh gain:0 ]",
+ "[ 1/4 → 3/8 | s:hh gain:0 ]",
+ "[ 3/8 → 1/2 | s:hh gain:0 ]",
+ "[ 1/2 → 5/8 | s:hh gain:0 ]",
+ "[ 1/2 → 1/1 | s:bd gain:1 ]",
+ "[ 5/8 → 3/4 | s:hh gain:0 ]",
+ "[ 3/4 → 7/8 | s:hh gain:0 ]",
+ "[ 7/8 → 1/1 | s:hh gain:0 ]",
+ "[ 1/1 → 9/8 | s:hh gain:0.5 ]",
+ "[ 1/1 → 3/2 | s:bd gain:1 ]",
+ "[ 9/8 → 5/4 | s:hh gain:0.5 ]",
+ "[ 5/4 → 11/8 | s:hh gain:0.5 ]",
+ "[ 11/8 → 3/2 | s:hh gain:0.5 ]",
+ "[ 3/2 → 13/8 | s:hh gain:0.5 ]",
+ "[ 3/2 → 2/1 | s:bd gain:1 ]",
+ "[ 13/8 → 7/4 | s:hh gain:0.5 ]",
+ "[ 7/4 → 15/8 | s:hh gain:0.5 ]",
+ "[ 15/8 → 2/1 | s:hh gain:0.5 ]",
+ "[ 2/1 → 17/8 | s:hh gain:1 ]",
+ "[ 2/1 → 5/2 | s:bd gain:1 ]",
+ "[ 17/8 → 9/4 | s:hh gain:1 ]",
+ "[ 9/4 → 19/8 | s:hh gain:1 ]",
+ "[ 19/8 → 5/2 | s:hh gain:1 ]",
+ "[ 5/2 → 21/8 | s:hh gain:1 ]",
+ "[ 5/2 → 3/1 | s:bd gain:1 ]",
+ "[ 21/8 → 11/4 | s:hh gain:1 ]",
+ "[ 11/4 → 23/8 | s:hh gain:1 ]",
+ "[ 23/8 → 3/1 | s:hh gain:1 ]",
+ "[ 3/1 → 25/8 | s:hh gain:1 ]",
+ "[ 3/1 → 7/2 | s:bd gain:0.5 ]",
+ "[ 25/8 → 13/4 | s:hh gain:1 ]",
+ "[ 13/4 → 27/8 | s:hh gain:1 ]",
+ "[ 27/8 → 7/2 | s:hh gain:1 ]",
+ "[ 7/2 → 29/8 | s:hh gain:1 ]",
+ "[ 7/2 → 4/1 | s:bd gain:0.5 ]",
+ "[ 29/8 → 15/4 | s:hh gain:1 ]",
+ "[ 15/4 → 31/8 | s:hh gain:1 ]",
+ "[ 31/8 → 4/1 | s:hh gain:1 ]",
+]
+`;
+
exports[`runs examples > example "zoom" example index 0 1`] = `
[
"[ 0/1 → 1/6 | s:hh ]",
diff --git a/website/src/docs/MiniRepl.css b/website/src/docs/MiniRepl.css
index 84927a883..c46110b79 100644
--- a/website/src/docs/MiniRepl.css
+++ b/website/src/docs/MiniRepl.css
@@ -1,26 +1,26 @@
-.cm-activeLine,
-.cm-activeLineGutter {
+.mini-repl .cm-activeLine,
+.mini-repl .cm-activeLineGutter {
background-color: transparent !important;
}
-.cm-theme {
+.mini-repl .cm-theme {
background-color: var(--background);
border: 1px solid var(--lineHighlight);
padding: 2px;
}
-.cm-scroller {
+.mini-repl .cm-scroller {
font-family: inherit !important;
}
-.cm-gutters {
+.mini-repl .cm-gutters {
display: none !important;
}
-.cm-cursorLayer {
+.mini-repl .cm-cursorLayer {
animation-name: inherit !important;
}
-.cm-cursor {
+.mini-repl .cm-cursor {
border-left: 2px solid currentcolor !important;
}
diff --git a/website/src/docs/MiniRepl.jsx b/website/src/docs/MiniRepl.jsx
index 552e1027e..10af1d514 100644
--- a/website/src/docs/MiniRepl.jsx
+++ b/website/src/docs/MiniRepl.jsx
@@ -33,7 +33,7 @@ export function MiniRepl({
.catch((err) => console.error(err));
}, []);
return Repl ? (
-
+
@@ -42,9 +42,9 @@ lpf = **l**ow **p**ass **f**ilter
- Füg noch mehr `lpf` Werte hinzu
-- Das pattern in `lpf` ändert nicht den Rhythmus der Bassline
+- Das Pattern in `lpf` ändert nicht den Rhythmus der Basslinie
-Später sehen wir wie man mit Wellenformen Dinge automatisieren kann.
+Später sehen wir, wie man mit Wellenformen Dinge automatisieren kann.
@@ -73,7 +73,7 @@ Später sehen wir wie man mit Wellenformen Dinge automatisieren kann.
Bei Rhythmen ist die Dynamik (= Veränderungen der Lautstärke) sehr wichtig.
-- Entferne `.gain(...)` und achte darauf wie es viel flacher klingt.
+- Entferne `.gain(...)` und achte darauf, wie es viel flacher klingt.
- Mach es rückgängig (strg+z dann strg+enter)
@@ -99,13 +99,13 @@ Lass uns die obigen Beispiele kombinieren:
-Versuche die einzelnen Teile innerhalb `stack` zu erkennen, schau dir an wie die Kommas gesetzt sind.
+Versuche die einzelnen Teile innerhalb von `stack` zu erkennen. Schau dir an wie die Kommas gesetzt sind.
-Die 3 Teile (Drums, Bass, Akkorde) sind genau wie vorher, nur in einem `stack`, getrennt durch Kommas
+Die 3 Teile (Drums, Bass, Akkorde) sind genau wie vorher, nur in einem `stack`, getrennt durch Kommas.
-**Den Sound formen mit ADSR Hüllkurve**
+**Den Sound formen mit ADSR-Hüllkurve**
-Versuche herauszufinden was die Zahlen machen. Probier folgendes:
+Versuche herauszufinden, was die Zahlen machen. Probier folgendes:
- attack: `.5` vs `0`
- decay: `.5` vs `0`
- sustain: `1` vs `.25` vs `0`
- release: `0` vs `.5` vs `1`
-Kannst du erraten was die einzelnen Werte machen?
+Kannst du erraten, was die einzelnen Werte machen?
@@ -142,7 +142,7 @@ Kannst du erraten was die einzelnen Werte machen?
-**adsr Kurznotation**
+**adsr-Kurznotation**
@@ -181,7 +181,7 @@ Was passiert wenn du `.delay(".8:.06:.8")` schreibst? Kannst du erraten was die
- a: Lautstärke des Delays
- b: Verzögerungszeit
-- c: Feedback (je kleiner desto schneller verschwindet das Delay)
+- c: Feedback (je kleiner, desto schneller verschwindet das Delay)
@@ -203,7 +203,7 @@ Füg auch ein Delay hinzu!
-**kleiner dub tune**
+**kleiner Dub-Tune**
-Füg `.hush()` ans ende eines Patterns im stack...
+Füg `.hush()` ans Ende eines Patterns im stack...
@@ -258,25 +258,25 @@ Füg `.hush()` ans ende eines Patterns im stack...
**fast and slow = schnell und langsam**
-Mit `fast` und `slow` kann man das tempo eines patterns außerhalb der Mini-Notation ändern:
+Mit `fast` und `slow` kann man das Tempo eines Patterns außerhalb der Mini-Notation ändern:
-Ändere den `slow` Wert. Tausche `slow` durch `fast`.
+Ändere den `slow`-Wert. Ersetze `slow` durch `fast`.
-Was passiert wenn du den Wert automatisierst? z.b. `.fast("<1 [2 4]>")` ?
+Was passiert, wenn du den Wert automatisierst? z.b. `.fast("<1 [2 4]>")` ?
-Übrigens, innerhalb der Mini-Notation, `fast` ist `*` und `slow` ist `/`.
+Übrigens, innerhalb der Mini-Notation: `fast` ist `*` und `slow` ist `/`.
")`} />
## Automation mit Signalen
-Anstatt Werte schrittweise zu automatisieren können wir auch sogenannte Signale benutzen:
+Anstatt Werte schrittweise zu automatisieren, können wir auch sogenannte Signale benutzen:
@@ -296,7 +296,7 @@ Signale bewegen sich standardmäßig zwischen 0 und 1. Wir können das mit `rang
-`range` ist nützlich wenn wir Funktionen mit einem anderen Wertebereich als 0 und 1 automatisieren wollen (z.b. lpf)
+`range` ist nützlich wenn wir Funktionen mit einem anderen Wertebereich als 0 und 1 automatisieren wollen (z.b. `lpf`)
@@ -322,7 +322,7 @@ Die ganze Automation braucht nun 8 cycle bis sie sich wiederholt.
## Rückblick
-| name | example |
+| Name | Beispiel |
| ----- | -------------------------------------------------------------------------------------------------- |
| lpf | ")`} /> |
| vowel | ")`} /> |
@@ -333,4 +333,4 @@ Die ganze Automation braucht nun 8 cycle bis sie sich wiederholt.
| speed | ")`} /> |
| range | |
-Lass uns nun die für Tidal typischen [Pattern Effekte anschauen](/de/workshop/pattern-effects).
+Lass uns nun die für Tidal typischen [Pattern-Effekte anschauen](/de/workshop/pattern-effects).
diff --git a/website/src/pages/de/workshop/first-sounds.mdx b/website/src/pages/de/workshop/first-sounds.mdx
index fea64cbd4..a689add80 100644
--- a/website/src/pages/de/workshop/first-sounds.mdx
+++ b/website/src/pages/de/workshop/first-sounds.mdx
@@ -277,7 +277,7 @@ Das haben wir bisher gelernt:
| Schneller | \* | |
| Parallel | , | |
-Die mit Apostrophen umgebene Mini-Notation benutzt man normalerweise in eine sogenannten Funktion.
+Die mit Apostrophen umgebene Mini-Notation benutzt man normalerweise in einer sogenannten Funktion.
Die folgenden Funktionen haben wir bereits gesehen:
| Name | Description | Example |
diff --git a/website/src/pages/de/workshop/pattern-effects.mdx b/website/src/pages/de/workshop/pattern-effects.mdx
index b701958a8..703358819 100644
--- a/website/src/pages/de/workshop/pattern-effects.mdx
+++ b/website/src/pages/de/workshop/pattern-effects.mdx
@@ -1,5 +1,5 @@
---
-title: Pattern Effekte
+title: Pattern-Effekte
layout: ../../../layouts/MainLayout.astro
---
@@ -7,11 +7,11 @@ import { MiniRepl } from '@src/docs/MiniRepl';
import Box from '@components/Box.astro';
import QA from '@components/QA';
-# Pattern Effekte
+# Pattern-Effekte
-Bis jetzt sind die meisten Funktionen die wir kennengelernt haben ähnlich wie Funktionen in anderen Musik Programmen: Sequencing von Sounds, Noten und Effekten.
+Bis jetzt sind die meisten Funktionen, die wir kennengelernt haben, ähnlich wie Funktionen in anderen Musik Programmen: Sequencing von Sounds, Noten und Effekten.
-In diesem Kapitel beschäftigen wir uns mit Funktionen die weniger herkömmlich oder auch enzigartig sind.
+In diesem Kapitel beschäftigen wir uns mit Funktionen die weniger herkömmlich oder auch einzigartig sind.
**rev = rückwärts abspielen**
@@ -21,7 +21,7 @@ In diesem Kapitel beschäftigen wir uns mit Funktionen die weniger herkömmlich
-So würde man das ohne jux schreiben:
+So würde man das ohne `jux` schreiben:
-Lass uns visualisieren was hier passiert:
+Lass uns visualisieren, was hier passiert:
-Das hat den gleichen Effekt wie:
+Das hat den gleichen Effekt, wie:
"`
-In der notation `x=>x.`, das `x` ist das Pattern das wir bearbeiten.
+In der Notation `x=>x.`, ist `x` das Pattern, das wir bearbeiten.
-`off` ist auch nützlich für sounds:
+`off` ist auch nützlich für Sounds:
x.`, das `x` ist das Pattern das wir bearbeiten.
.off(1/8, x=>x.speed(1.5).gain(.25))`}
/>
-| name | description | example |
+| Name | Beschreibung | Beispiel |
| ---- | --------------------------------- | ---------------------------------------------------------------------------------------------- |
| rev | rückwärts | |
-| jux | ein stereo-kanal modifizieren | |
-| add | addiert zahlen oder noten | ")).scale("C:minor")`} /> |
-| ply | multipliziert jedes element x mal | ")`} /> |
-| off | verzögert eine modifizierte kopie | x.speed(2))`} /> |
+| jux | einen Stereo-Kanal modifizieren | |
+| add | addiert Zahlen oder Noten | ")).scale("C:minor")`} /> |
+| ply | multipliziert jedes Element x mal | ")`} /> |
+| off | verzögert eine modifizierte Kopie | x.speed(2))`} /> |
diff --git a/website/src/pages/de/workshop/recap.mdx b/website/src/pages/de/workshop/recap.mdx
index db392b8b0..c0d577d16 100644
--- a/website/src/pages/de/workshop/recap.mdx
+++ b/website/src/pages/de/workshop/recap.mdx
@@ -7,19 +7,19 @@ import { MiniRepl } from '../../../docs/MiniRepl';
# Workshop Rückblick
-Diese Seite ist eine Auflistung aller im Workshop enthaltenen Funktionen.
+Diese Seite ist eine Auflistung aller im Workshop vorgestellten Funktionen.
## Mini Notation
-| Concept | Syntax | Example |
+| Konzept | Syntax | Beispiel |
| --------------------- | -------- | -------------------------------------------------------------------------------- |
-| Sequence | space | |
-| Sample Nummer | :x | |
+| Sequenz | space | |
+| Sample-Nummer | :x | |
| Pausen | ~ | |
-| Unter-Sequences | \[\] | |
-| Unter-Unter-Sequences | \[\[\]\] | |
+| Unter-Sequenzen | \[\] | |
+| Unter-Unter-Sequenzen | \[\[\]\] | |
| Schneller | \* | |
-| Slow down | \/ | |
+| Verlangsamen | \/ | |
| Parallel | , | |
| Alternieren | \<\> | ")`} /> |
| Verlängern | @ | |
@@ -27,23 +27,23 @@ Diese Seite ist eine Auflistung aller im Workshop enthaltenen Funktionen.
## Sounds
-| Name | Description | Example |
+| Name | Beschreibung | Beispiel |
| ----- | -------------------------- | ---------------------------------------------------------------------------------- |
-| sound | spielt den sound mit namen | |
-| bank | wählt die soundbank | |
-| n | wählt sample mit nummer | |
+| sound | spielt den Sound mit Namen | |
+| bank | wählt die Soundbank | |
+| n | wählt Sample mit Nummer | |
-## Notes
+## Noten
-| Name | Description | Example |
+| Name | Beschreibung | Beispiel |
| --------- | ---------------------------------- | -------------------------------------------------------------------------------------------- |
-| note | wählt note per zahl oder buchstabe | |
-| n + scale | wählt note n in skala | |
-| stack | spielt mehrere patterns parallel | |
+| note | wählt Note per Zahl oder Buchstabe | |
+| n + scale | wählt Note n in Skala | |
+| stack | spielt mehrere Patterns parallel | |
-## Audio Effekte
+## Audio-Effekte
-| name | example |
+| Name | Beispiele |
| ----- | -------------------------------------------------------------------------------------------------- |
| lpf | ")`} /> |
| vowel | ")`} /> |
@@ -54,15 +54,15 @@ Diese Seite ist eine Auflistung aller im Workshop enthaltenen Funktionen.
| speed | ")`} /> |
| range | |
-## Pattern Effects
+## Pattern-Effekte
-| name | description | example |
+| Name | Beschreibung | Beispiel |
| ---- | --------------------------------- | ---------------------------------------------------------------------------------------------- |
-| cpm | tempo in cycles pro minute | |
+| cpm | Tempo in Cycles pro Minute | |
| fast | schneller | |
| slow | langsamer | |
| rev | rückwärts | |
-| jux | ein stereo-kanal modifizieren | |
-| add | addiert zahlen oder noten | ")).scale("C:minor")`} /> |
-| ply | jedes element schneller machen | ")`} /> |
-| off | verzögert eine modifizierte kopie | x.speed(2))`} /> |
+| jux | einen Stereo-Kanal modifizieren | |
+| add | addiert Zahlen oder Noten | ")).scale("C:minor")`} /> |
+| ply | jedes Element schneller machen | ")`} /> |
+| off | verzögert eine modifizierte Kopie | x.speed(2))`} /> |
diff --git a/website/src/pages/learn/effects.mdx b/website/src/pages/learn/effects.mdx
index 308042409..a3ae91d79 100644
--- a/website/src/pages/learn/effects.mdx
+++ b/website/src/pages/learn/effects.mdx
@@ -156,6 +156,10 @@ There is one filter envelope for each filter type and thus one set of envelope f
+## xfade
+
+
+
# Panning
## jux
@@ -236,3 +240,21 @@ global effects use the same chain for all events of the same orbit:
Next, we'll look at strudel's support for [Csound](/learn/csound).
+
+## Phaser
+
+### phaser
+
+
+
+### phaserdepth
+
+
+
+### phasercenter
+
+
+
+### phasersweep
+
+
diff --git a/website/src/repl/Footer.jsx b/website/src/repl/Footer.jsx
index 8423315fe..bea5af25a 100644
--- a/website/src/repl/Footer.jsx
+++ b/website/src/repl/Footer.jsx
@@ -387,6 +387,7 @@ function SettingsTab({ scheduler }) {
isAutoCompletionEnabled,
isFlashEnabled,
isPatternHighlightingEnabled,
+ isTooltipEnabled,
isLineWrappingEnabled,
fontSize,
fontFamily,
@@ -459,6 +460,11 @@ function SettingsTab({ scheduler }) {
onChange={(cbEvent) => settingsMap.setKey('isAutoCompletionEnabled', cbEvent.target.checked)}
value={isAutoCompletionEnabled}
/>
+ settingsMap.setKey('isTooltipEnabled', cbEvent.target.checked)}
+ value={isTooltipEnabled}
+ />
settingsMap.setKey('isLineWrappingEnabled', cbEvent.target.checked)}
diff --git a/website/src/repl/Reference.jsx b/website/src/repl/Reference.jsx
index de52982e9..cf6fd5b12 100644
--- a/website/src/repl/Reference.jsx
+++ b/website/src/repl/Reference.jsx
@@ -3,17 +3,31 @@ const visibleFunctions = jsdocJson.docs
.filter(({ name, description }) => name && !name.startsWith('_') && !!description)
.sort((a, b) => /* a.meta.filename.localeCompare(b.meta.filename) + */ a.name.localeCompare(b.name));
+const getInnerText = (html) => {
+ var div = document.createElement('div');
+ div.innerHTML = html;
+ return div.textContent || div.innerText || '';
+};
+
export function Reference() {
return (
{visibleFunctions.map((entry, i) => (
-
+ {
+ const el = document.getElementById(`doc-${i}`);
+ const container = document.getElementById('reference-container');
+ container.scrollTo(0, el.offsetTop);
+ }}
+ >
{entry.name} {/* {entry.meta.filename} */}
))}
-
+
API Reference
@@ -24,8 +38,14 @@ export function Reference() {
{entry.name}
{/* {entry.meta.filename} */}
-
+
+ {entry.params?.map(({ name, type, description }, i) => (
+ -
+ {name} : {type.names?.join(' | ')} {description ? <> - {getInnerText(description)}> : ''}
+
+ ))}
+
{entry.examples?.map((example, j) => (
{example}
))}
diff --git a/website/src/repl/Repl.jsx b/website/src/repl/Repl.jsx
index 02245e183..e43c2aa01 100644
--- a/website/src/repl/Repl.jsx
+++ b/website/src/repl/Repl.jsx
@@ -91,6 +91,7 @@ export function Repl({ embedded = false }) {
fontFamily,
isLineNumbersDisplayed,
isAutoCompletionEnabled,
+ isTooltipEnabled,
isLineWrappingEnabled,
panelPosition,
isZen,
@@ -287,6 +288,7 @@ export function Repl({ embedded = false }) {
keybindings={keybindings}
isLineNumbersDisplayed={isLineNumbersDisplayed}
isAutoCompletionEnabled={isAutoCompletionEnabled}
+ isTooltipEnabled={isTooltipEnabled}
isLineWrappingEnabled={isLineWrappingEnabled}
fontSize={fontSize}
fontFamily={fontFamily}
diff --git a/website/src/settings.mjs b/website/src/settings.mjs
index 2de6e4d79..c1872ec81 100644
--- a/website/src/settings.mjs
+++ b/website/src/settings.mjs
@@ -9,6 +9,7 @@ export const defaultSettings = {
isAutoCompletionEnabled: false,
isPatternHighlightingEnabled: true,
isFlashEnabled: true,
+ isTooltipEnabled: false,
isLineWrappingEnabled: false,
theme: 'strudelTheme',
fontFamily: 'monospace',
@@ -28,6 +29,7 @@ export function useSettings() {
isZen: [true, 'true'].includes(state.isZen) ? true : false,
isLineNumbersDisplayed: [true, 'true'].includes(state.isLineNumbersDisplayed) ? true : false,
isAutoCompletionEnabled: [true, 'true'].includes(state.isAutoCompletionEnabled) ? true : false,
+ isTooltipEnabled: [true, 'true'].includes(state.isTooltipEnabled) ? true : false,
isLineWrappingEnabled: [true, 'true'].includes(state.isLineWrappingEnabled) ? true : false,
isPatternHighlightingEnabled: [true, 'true'].includes(state.isPatternHighlightingEnabled) ? true : false,
isFlashEnabled: [true, 'true'].includes(state.isFlashEnabled) ? true : false,