mirror of
https://github.com/eliasstepanik/strudel-docker.git
synced 2026-01-11 13:48:34 +00:00
Merge branch 'main' into patterns-tab
This commit is contained in:
commit
80601451b6
@ -83,7 +83,7 @@ Please report any problems you've had with the setup instructions!
|
||||
|
||||
To make sure the code changes only where it should, we are using prettier to unify the code style.
|
||||
|
||||
- You can format all files at once by running `pnpm prettier` from the project root
|
||||
- You can format all files at once by running `pnpm codeformat` from the project root
|
||||
- Run `pnpm format-check` from the project root to check if all files are well formatted
|
||||
|
||||
If you use VSCode, you can
|
||||
|
||||
@ -47,7 +47,7 @@ If you want to automatically deploy your site on push, go to `deploy.yml` and ch
|
||||
## running locally
|
||||
|
||||
- install dependencies with `npm run setup`
|
||||
- run dev server with `npm run repl` and open `http://localhost:3000/strudel/swatch/`
|
||||
- run dev server with `npm run repl` and open `http://localhost:4321/strudel/swatch/`
|
||||
|
||||
## tests fail?
|
||||
|
||||
|
||||
@ -111,6 +111,15 @@ export const sliderPlugin = ViewPlugin.fromClass(
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* Displays a slider widget to allow the user manipulate a value
|
||||
*
|
||||
* @name slider
|
||||
* @param {number} value Initial value
|
||||
* @param {number} min Minimum value - optional, defaults to 0
|
||||
* @param {number} max Maximum value - optional, defaults to 1
|
||||
* @param {number} step Step size - optional
|
||||
*/
|
||||
export let slider = (value) => {
|
||||
console.warn('slider will only work when the transpiler is used... passing value as is');
|
||||
return pure(value);
|
||||
|
||||
@ -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'],
|
||||
@ -1296,6 +1355,17 @@ generic_params.forEach(([names, ...aliases]) => {
|
||||
controls.createParams = (...names) =>
|
||||
names.reduce((acc, name) => Object.assign(acc, { [name]: controls.createParam(name) }), {});
|
||||
|
||||
/**
|
||||
* ADSR envelope: Combination of Attack, Decay, Sustain, and Release.
|
||||
*
|
||||
* @name adsr
|
||||
* @param {number | Pattern} time attack time in seconds
|
||||
* @param {number | Pattern} time decay time in seconds
|
||||
* @param {number | Pattern} gain sustain level (0 to 1)
|
||||
* @param {number | Pattern} time release time in seconds
|
||||
* @example
|
||||
* note("<c3 bb2 f3 eb3>").sound("sawtooth").lpf(600).adsr(".1:.1:.5:.2")
|
||||
*/
|
||||
controls.adsr = register('adsr', (adsr, pat) => {
|
||||
adsr = !Array.isArray(adsr) ? [adsr] : adsr;
|
||||
const [attack, decay, sustain, release] = adsr;
|
||||
|
||||
@ -145,6 +145,8 @@ export const { euclidrot, euclidRot } = register(['euclidrot', 'euclidRot'], fun
|
||||
* so there will be no gaps.
|
||||
* @name euclidLegato
|
||||
* @memberof Pattern
|
||||
* @param {number} pulses the number of onsets / beats
|
||||
* @param {number} steps the number of steps to fill
|
||||
* @example
|
||||
* n("g2").decay(.1).sustain(.3).euclidLegato(3,8)
|
||||
*/
|
||||
@ -166,6 +168,18 @@ export const euclidLegato = register(['euclidLegato'], function (pulses, steps,
|
||||
return _euclidLegato(pulses, steps, 0, pat);
|
||||
});
|
||||
|
||||
/**
|
||||
* Similar to `euclid`, but each pulse is held until the next pulse,
|
||||
* so there will be no gaps, and has an additional parameter for 'rotating'
|
||||
* the resulting sequence
|
||||
* @name euclidLegatoRot
|
||||
* @memberof Pattern
|
||||
* @param {number} pulses the number of onsets / beats
|
||||
* @param {number} steps the number of steps to fill
|
||||
* @param {number} rotation offset in steps
|
||||
* @example
|
||||
* note("c3").euclidLegatoRot(3,5,2)
|
||||
*/
|
||||
export const euclidLegatoRot = register(['euclidLegatoRot'], function (pulses, steps, rotation, pat) {
|
||||
return _euclidLegato(pulses, steps, rotation, pat);
|
||||
});
|
||||
|
||||
@ -47,10 +47,5 @@ export const evaluate = async (code, transpiler) => {
|
||||
// if no transpiler is given, we expect a single instruction (!wrapExpression)
|
||||
const options = { wrapExpression: !!transpiler };
|
||||
let evaluated = await safeEval(code, options);
|
||||
if (!isPattern(evaluated)) {
|
||||
console.log('evaluated', evaluated);
|
||||
const message = `got "${typeof evaluated}" instead of pattern`;
|
||||
throw new Error(message + (typeof evaluated === 'function' ? ', did you forget to call a function?' : '.'));
|
||||
}
|
||||
return { mode: 'javascript', pattern: evaluated, meta };
|
||||
};
|
||||
|
||||
@ -1178,7 +1178,7 @@ export function reify(thing) {
|
||||
* @return {Pattern}
|
||||
* @synonyms polyrhythm, pr
|
||||
* @example
|
||||
* stack(g3, b3, [e4, d4]).note() // "g3,b3,[e4,d4]".note()
|
||||
* stack("g3", "b3", ["e4", "d4"]).note() // "g3,b3,[e4,d4]".note()
|
||||
*/
|
||||
export function stack(...pats) {
|
||||
// Array test here is to avoid infinite recursions..
|
||||
@ -1193,7 +1193,7 @@ export function stack(...pats) {
|
||||
*
|
||||
* @return {Pattern}
|
||||
* @example
|
||||
* slowcat(e5, b4, [d5, c5])
|
||||
* slowcat("e5", "b4", ["d5", "c5"])
|
||||
*
|
||||
*/
|
||||
export function slowcat(...pats) {
|
||||
@ -1237,7 +1237,7 @@ export function slowcatPrime(...pats) {
|
||||
* @synonyms slowcat
|
||||
* @return {Pattern}
|
||||
* @example
|
||||
* cat(e5, b4, [d5, c5]).note() // "<e5 b4 [d5 c5]>".note()
|
||||
* cat("e5", "b4", ["d5", "c5"]).note() // "<e5 b4 [d5 c5]>".note()
|
||||
*
|
||||
*/
|
||||
export function cat(...pats) {
|
||||
@ -1247,7 +1247,7 @@ export function cat(...pats) {
|
||||
/** Like {@link Pattern.seq}, but each step has a length, relative to the whole.
|
||||
* @return {Pattern}
|
||||
* @example
|
||||
* timeCat([3,e3],[1, g3]).note() // "e3@3 g3".note()
|
||||
* timeCat([3,"e3"],[1, "g3"]).note() // "e3@3 g3".note()
|
||||
*/
|
||||
export function timeCat(...timepats) {
|
||||
const total = timepats.map((a) => a[0]).reduce((a, b) => a.add(b), Fraction(0));
|
||||
@ -1287,7 +1287,7 @@ export function sequence(...pats) {
|
||||
/** Like **cat**, but the items are crammed into one cycle.
|
||||
* @synonyms fastcat, sequence
|
||||
* @example
|
||||
* seq(e5, b4, [d5, c5]).note() // "e5 b4 [d5 c5]".note()
|
||||
* seq("e5", "b4", ["d5", "c5"]).note() // "e5 b4 [d5 c5]".note()
|
||||
*
|
||||
*/
|
||||
export function seq(...pats) {
|
||||
@ -1975,9 +1975,9 @@ export const press = register('press', function (pat) {
|
||||
* s("hh*3")
|
||||
* )
|
||||
*/
|
||||
export const hush = register('hush', function (pat) {
|
||||
Pattern.prototype.hush = function () {
|
||||
return silence;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Applies `rev` to a pattern every other cycle, so that the pattern alternates between forwards and backwards.
|
||||
@ -2100,23 +2100,43 @@ export const { iterBack, iterback } = register(['iterBack', 'iterback'], functio
|
||||
return _iter(times, pat, true);
|
||||
});
|
||||
|
||||
/**
|
||||
* Repeats each cycle the given number of times.
|
||||
* @name repeatCycles
|
||||
* @memberof Pattern
|
||||
* @returns Pattern
|
||||
* @example
|
||||
* note(irand(12).add(34)).segment(4).repeatCycles(2).s("gm_acoustic_guitar_nylon")
|
||||
*/
|
||||
const _repeatCycles = function (n, pat) {
|
||||
return slowcat(...Array(n).fill(pat));
|
||||
};
|
||||
|
||||
const { repeatCycles } = register('repeatCycles', _repeatCycles);
|
||||
|
||||
/**
|
||||
* Divides a pattern into a given number of parts, then cycles through those parts in turn, applying the given function to each part in turn (one part per cycle).
|
||||
* @name chunk
|
||||
* @synonyms slowChunk, slowchunk
|
||||
* @memberof Pattern
|
||||
* @returns Pattern
|
||||
* @example
|
||||
* "0 1 2 3".chunk(4, x=>x.add(7)).scale('A minor').note()
|
||||
*/
|
||||
const _chunk = function (n, func, pat, back = false) {
|
||||
const _chunk = function (n, func, pat, back = false, fast = false) {
|
||||
const binary = Array(n - 1).fill(false);
|
||||
binary.unshift(true);
|
||||
const binary_pat = _iter(n, sequence(...binary), back);
|
||||
// Invert the 'back' because we want to shift the pattern forwards,
|
||||
// and so time backwards
|
||||
const binary_pat = _iter(n, sequence(...binary), !back);
|
||||
if (!fast) {
|
||||
pat = pat.repeatCycles(n);
|
||||
}
|
||||
return pat.when(binary_pat, func);
|
||||
};
|
||||
|
||||
export const chunk = register('chunk', function (n, func, pat) {
|
||||
return _chunk(n, func, pat, false);
|
||||
const { chunk, slowchunk, slowChunk } = register(['chunk', 'slowchunk', 'slowChunk'], function (n, func, pat) {
|
||||
return _chunk(n, func, pat, false, false);
|
||||
});
|
||||
|
||||
/**
|
||||
@ -2132,6 +2152,21 @@ export const { chunkBack, chunkback } = register(['chunkBack', 'chunkback'], fun
|
||||
return _chunk(n, func, pat, true);
|
||||
});
|
||||
|
||||
/**
|
||||
* Like `chunk`, but the cycles of the source pattern aren't repeated
|
||||
* for each set of chunks.
|
||||
* @name fastChunk
|
||||
* @synonyms fastchunk
|
||||
* @memberof Pattern
|
||||
* @returns Pattern
|
||||
* @example
|
||||
* "<0 8> 1 2 3 4 5 6 7".fastChunk(4, x => x.color('red')).slow(4).scale("C2:major").note()
|
||||
.s("folkharp")
|
||||
*/
|
||||
const { fastchunk, fastChunk } = register(['fastchunk', 'fastChunk'], function (n, func, pat) {
|
||||
return _chunk(n, func, pat, false, true);
|
||||
});
|
||||
|
||||
// TODO - redefine elsewhere in terms of mask
|
||||
export const bypass = register('bypass', function (on, pat) {
|
||||
on = Boolean(parseInt(on));
|
||||
@ -2156,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) {
|
||||
@ -2357,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);
|
||||
};
|
||||
|
||||
@ -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,
|
||||
@ -228,6 +262,12 @@ Pattern.prototype.punchcard = function (options) {
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Displays a vertical pianoroll with event labels.
|
||||
* Supports all the same options as pianoroll.
|
||||
*
|
||||
* @name wordfall
|
||||
*/
|
||||
Pattern.prototype.wordfall = function (options) {
|
||||
return this.punchcard({ vertical: 1, labels: 1, stroke: 0, fillActive: 1, active: 'white', ...options });
|
||||
};
|
||||
|
||||
@ -3,7 +3,7 @@ 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';
|
||||
import { register, Pattern, isPattern, silence, stack } from './pattern.mjs';
|
||||
|
||||
export function repl({
|
||||
interval,
|
||||
@ -24,22 +24,37 @@ export function repl({
|
||||
getTime,
|
||||
onToggle,
|
||||
});
|
||||
let playPatterns = [];
|
||||
let pPatterns = {};
|
||||
let allTransform;
|
||||
|
||||
const hush = function () {
|
||||
pPatterns = {};
|
||||
allTransform = undefined;
|
||||
return silence;
|
||||
};
|
||||
|
||||
const setPattern = (pattern, autostart = true) => {
|
||||
pattern = editPattern?.(pattern) || pattern;
|
||||
scheduler.setPattern(pattern, autostart);
|
||||
};
|
||||
setTime(() => scheduler.now()); // TODO: refactor?
|
||||
const evaluate = async (code, autostart = true) => {
|
||||
const evaluate = async (code, autostart = true, shouldHush = true) => {
|
||||
if (!code) {
|
||||
throw new Error('no code to evaluate');
|
||||
}
|
||||
try {
|
||||
await beforeEval?.({ code });
|
||||
playPatterns = [];
|
||||
shouldHush && hush();
|
||||
let { pattern, meta } = await _evaluate(code, transpiler);
|
||||
if (playPatterns.length) {
|
||||
pattern = pattern.stack(...playPatterns);
|
||||
if (Object.keys(pPatterns).length) {
|
||||
pattern = stack(...Object.values(pPatterns));
|
||||
}
|
||||
if (allTransform) {
|
||||
pattern = allTransform(pattern);
|
||||
}
|
||||
if (!isPattern(pattern)) {
|
||||
const message = `got "${typeof evaluated}" instead of pattern`;
|
||||
throw new Error(message + (typeof evaluated === 'function' ? ', did you forget to call a function?' : '.'));
|
||||
}
|
||||
logger(`[eval] code updated`);
|
||||
setPattern(pattern, autostart);
|
||||
@ -62,10 +77,32 @@ export function repl({
|
||||
return pat.loopAtCps(cycles, scheduler.cps);
|
||||
});
|
||||
|
||||
const play = register('play', (pat) => {
|
||||
playPatterns.push(pat);
|
||||
return pat;
|
||||
});
|
||||
Pattern.prototype.p = function (id) {
|
||||
pPatterns[id] = this;
|
||||
return this;
|
||||
};
|
||||
Pattern.prototype.q = function (id) {
|
||||
return silence;
|
||||
};
|
||||
|
||||
const all = function (transform) {
|
||||
allTransform = transform;
|
||||
return silence;
|
||||
};
|
||||
|
||||
for (let i = 1; i < 10; ++i) {
|
||||
Object.defineProperty(Pattern.prototype, `d${i}`, {
|
||||
get() {
|
||||
return this.p(i);
|
||||
},
|
||||
});
|
||||
Object.defineProperty(Pattern.prototype, `p${i}`, {
|
||||
get() {
|
||||
return this.p(i);
|
||||
},
|
||||
});
|
||||
Pattern.prototype[`q${i}`] = silence;
|
||||
}
|
||||
|
||||
const fit = register('fit', (pat) =>
|
||||
pat.withHap((hap) =>
|
||||
@ -80,7 +117,8 @@ export function repl({
|
||||
evalScope({
|
||||
loopAt,
|
||||
fit,
|
||||
play,
|
||||
all,
|
||||
hush,
|
||||
setCps,
|
||||
setcps: setCps,
|
||||
setCpm,
|
||||
|
||||
@ -7,7 +7,7 @@ This program is free software: you can redistribute it and/or modify it under th
|
||||
import { Hap } from './hap.mjs';
|
||||
import { Pattern, fastcat, reify, silence, stack, register } from './pattern.mjs';
|
||||
import Fraction from './fraction.mjs';
|
||||
import { id } from './util.mjs';
|
||||
import { id, _mod, clamp } from './util.mjs';
|
||||
|
||||
export function steady(value) {
|
||||
// A continuous value
|
||||
@ -155,6 +155,52 @@ export const _irand = (i) => rand.fmap((x) => Math.trunc(x * i));
|
||||
*/
|
||||
export const irand = (ipat) => reify(ipat).fmap(_irand).innerJoin();
|
||||
|
||||
/**
|
||||
* pick from the list of values (or patterns of values) via the index using the given
|
||||
* pattern of integers
|
||||
* @param {Pattern} pat
|
||||
* @param {*} xs
|
||||
* @returns {Pattern}
|
||||
* @example
|
||||
* note(pick("<0 1 [2!2] 3>", ["g a", "e f", "f g f g" , "g a c d"]))
|
||||
*/
|
||||
|
||||
export const pick = (pat, xs) => {
|
||||
xs = xs.map(reify);
|
||||
if (xs.length == 0) {
|
||||
return silence;
|
||||
}
|
||||
return pat
|
||||
.fmap((i) => {
|
||||
const key = clamp(Math.round(i), 0, xs.length - 1);
|
||||
return xs[key];
|
||||
})
|
||||
.innerJoin();
|
||||
};
|
||||
|
||||
/**
|
||||
* pick from the list of values (or patterns of values) via the index using the given
|
||||
* pattern of integers. The selected pattern will be compressed to fit the duration of the selecting event
|
||||
* @param {Pattern} pat
|
||||
* @param {*} xs
|
||||
* @returns {Pattern}
|
||||
* @example
|
||||
* note(squeeze("<0@2 [1!2] 2>", ["g a", "f g f g" , "g a c d"]))
|
||||
*/
|
||||
|
||||
export const squeeze = (pat, xs) => {
|
||||
xs = xs.map(reify);
|
||||
if (xs.length == 0) {
|
||||
return silence;
|
||||
}
|
||||
return pat
|
||||
.fmap((i) => {
|
||||
const key = _mod(Math.round(i), xs.length);
|
||||
return xs[key];
|
||||
})
|
||||
.squeezeJoin();
|
||||
};
|
||||
|
||||
export const __chooseWith = (pat, xs) => {
|
||||
xs = xs.map(reify);
|
||||
if (xs.length == 0) {
|
||||
|
||||
@ -1003,4 +1003,23 @@ describe('Pattern', () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('chunk', () => {
|
||||
it('Processes each cycle of the source pattern multiple times, once for each chunk', () => {
|
||||
expect(sequence(0, 1, 2, 3).slow(2).chunk(2, add(10)).fast(4).firstCycleValues).toStrictEqual([
|
||||
10, 1, 0, 11, 12, 3, 2, 13,
|
||||
]);
|
||||
});
|
||||
});
|
||||
describe('fastChunk', () => {
|
||||
it('Unlike chunk, cycles of the source pattern proceed cycle-by-cycle', () => {
|
||||
expect(sequence(0, 1, 2, 3).slow(2).fastChunk(2, add(10)).fast(4).firstCycleValues).toStrictEqual([
|
||||
10, 1, 2, 13, 10, 1, 2, 13,
|
||||
]);
|
||||
});
|
||||
});
|
||||
describe('repeatCycles', () => {
|
||||
it('Repeats each cycle of the source pattern the given number of times', () => {
|
||||
expect(slowcat(0, 1).repeatCycles(2).fast(6).firstCycleValues).toStrictEqual([0, 0, 1, 1, 0, 0]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -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) => {
|
||||
|
||||
@ -33,12 +33,17 @@
|
||||
"homepage": "https://github.com/tidalcycles/strudel#readme",
|
||||
"dependencies": {
|
||||
"@codemirror/autocomplete": "^6.6.0",
|
||||
"@codemirror/commands": "^6.0.0",
|
||||
"@codemirror/lang-javascript": "^6.1.7",
|
||||
"@codemirror/language": "^6.0.0",
|
||||
"@codemirror/lint": "^6.0.0",
|
||||
"@codemirror/search": "^6.0.0",
|
||||
"@codemirror/state": "^6.2.0",
|
||||
"@codemirror/view": "^6.10.0",
|
||||
"@lezer/highlight": "^1.1.4",
|
||||
"@replit/codemirror-emacs": "^6.0.1",
|
||||
"@replit/codemirror-vim": "^6.0.14",
|
||||
"@replit/codemirror-vscode-keymap": "^6.0.2",
|
||||
"@strudel.cycles/core": "workspace:*",
|
||||
"@strudel.cycles/transpiler": "workspace:*",
|
||||
"@strudel.cycles/webaudio": "workspace:*",
|
||||
|
||||
@ -26,7 +26,6 @@ export function Autocomplete({ doc }) {
|
||||
<pre
|
||||
className="cursor-pointer"
|
||||
onMouseDown={(e) => {
|
||||
console.log('ola!');
|
||||
navigator.clipboard.writeText(example);
|
||||
e.stopPropagation();
|
||||
}}
|
||||
|
||||
@ -1,12 +1,15 @@
|
||||
import { autocompletion } from '@codemirror/autocomplete';
|
||||
import { Prec } from '@codemirror/state';
|
||||
import { javascript, javascriptLanguage } from '@codemirror/lang-javascript';
|
||||
import { EditorView } from '@codemirror/view';
|
||||
import { ViewPlugin, EditorView, keymap } from '@codemirror/view';
|
||||
import { emacs } from '@replit/codemirror-emacs';
|
||||
import { vim } from '@replit/codemirror-vim';
|
||||
import { vscodeKeymap } from '@replit/codemirror-vscode-keymap';
|
||||
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,
|
||||
@ -30,7 +33,9 @@ export default function CodeMirror({
|
||||
theme,
|
||||
keybindings,
|
||||
isLineNumbersDisplayed,
|
||||
isActiveLineHighlighted,
|
||||
isAutoCompletionEnabled,
|
||||
isTooltipEnabled,
|
||||
isLineWrappingEnabled,
|
||||
fontSize = 18,
|
||||
fontFamily = 'monospace',
|
||||
@ -61,11 +66,25 @@ export default function CodeMirror({
|
||||
[onSelectionChange],
|
||||
);
|
||||
|
||||
const vscodePlugin = ViewPlugin.fromClass(
|
||||
class {
|
||||
constructor(view) {}
|
||||
},
|
||||
{
|
||||
provide: (plugin) => {
|
||||
return Prec.highest(keymap.of([...vscodeKeymap]));
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
const vscodeExtension = (options) => [vscodePlugin].concat(options ?? []);
|
||||
|
||||
const extensions = useMemo(() => {
|
||||
let _extensions = [...staticExtensions];
|
||||
let bindings = {
|
||||
vim,
|
||||
emacs,
|
||||
vscode: vscodeExtension,
|
||||
};
|
||||
|
||||
if (bindings[keybindings]) {
|
||||
@ -78,14 +97,26 @@ export default function CodeMirror({
|
||||
_extensions.push(autocompletion({ override: [] }));
|
||||
}
|
||||
|
||||
if (isTooltipEnabled) {
|
||||
_extensions.push(strudelTooltip);
|
||||
}
|
||||
|
||||
_extensions.push([keymap.of({})]);
|
||||
|
||||
if (isLineWrappingEnabled) {
|
||||
_extensions.push(EditorView.lineWrapping);
|
||||
}
|
||||
|
||||
return _extensions;
|
||||
}, [keybindings, isAutoCompletionEnabled, isLineWrappingEnabled]);
|
||||
}, [keybindings, isAutoCompletionEnabled, isTooltipEnabled, isLineWrappingEnabled]);
|
||||
|
||||
const basicSetup = useMemo(() => ({ lineNumbers: isLineNumbersDisplayed }), [isLineNumbersDisplayed]);
|
||||
const basicSetup = useMemo(
|
||||
() => ({
|
||||
lineNumbers: isLineNumbersDisplayed,
|
||||
highlightActiveLine: isActiveLineHighlighted,
|
||||
}),
|
||||
[isLineNumbersDisplayed, isActiveLineHighlighted],
|
||||
);
|
||||
|
||||
return (
|
||||
<div style={{ fontSize, fontFamily }} className="w-full">
|
||||
|
||||
@ -30,6 +30,7 @@ export function MiniRepl({
|
||||
theme,
|
||||
keybindings,
|
||||
isLineNumbersDisplayed,
|
||||
isActiveLineHighlighted,
|
||||
}) {
|
||||
drawTime = drawTime || (punchcard ? [0, 4] : undefined);
|
||||
const evalOnMount = !!drawTime;
|
||||
@ -164,6 +165,7 @@ export function MiniRepl({
|
||||
fontSize={fontSize}
|
||||
keybindings={keybindings}
|
||||
isLineNumbersDisplayed={isLineNumbersDisplayed}
|
||||
isActiveLineHighlighted={isActiveLineHighlighted}
|
||||
/>
|
||||
)}
|
||||
{error && <div className="text-right p-1 text-md text-red-200">{error.message}</div>}
|
||||
|
||||
69
packages/react/src/components/Tooltip.jsx
Normal file
69
packages/react/src/components/Tooltip.jsx
Normal file
@ -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(<Autocomplete doc={entry} />);
|
||||
return { dom };
|
||||
},
|
||||
};
|
||||
},
|
||||
{ hoverTime: 10 },
|
||||
);
|
||||
@ -28,3 +28,7 @@
|
||||
footer {
|
||||
z-index: 0 !important;
|
||||
}
|
||||
|
||||
.strudel-tooltip {
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
@ -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 });
|
||||
|
||||
@ -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
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "superdough",
|
||||
"version": "0.9.10",
|
||||
"version": "0.9.11",
|
||||
"description": "simple web audio synth and sampler intended for live coding. inspired by superdirt and webdirt.",
|
||||
"main": "index.mjs",
|
||||
"type": "module",
|
||||
|
||||
@ -58,7 +58,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;
|
||||
};
|
||||
@ -163,9 +162,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:')) {
|
||||
@ -233,6 +240,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) {
|
||||
@ -248,6 +257,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');
|
||||
@ -279,6 +301,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();
|
||||
|
||||
@ -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,
|
||||
@ -261,6 +309,7 @@ export const superdough = async (value, deadline, hapDuration) => {
|
||||
if (bank && s) {
|
||||
s = `${bank}_${s}`;
|
||||
}
|
||||
|
||||
// get source AudioNode
|
||||
let sourceNode;
|
||||
if (source) {
|
||||
@ -378,6 +427,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);
|
||||
|
||||
@ -17,9 +17,6 @@ describe('transpiler', () => {
|
||||
it('wraps backtick string with mini and adds location', () => {
|
||||
expect(transpiler('`c3`', simple).output).toEqual("m('c3', 0);");
|
||||
});
|
||||
it('replaces note variables with note strings', () => {
|
||||
expect(transpiler('seq(c3, d3)', simple).output).toEqual("seq('c3', 'd3');");
|
||||
});
|
||||
it('keeps tagged template literal as is', () => {
|
||||
expect(transpiler('xxx`c3`', simple).output).toEqual('xxx`c3`;');
|
||||
});
|
||||
|
||||
@ -47,11 +47,6 @@ export function transpiler(input, options = {}) {
|
||||
});
|
||||
return this.replace(widgetWithLocation(node));
|
||||
}
|
||||
// TODO: remove pseudo note variables?
|
||||
if (node.type === 'Identifier' && isNoteWithOctave(node.name)) {
|
||||
this.skip();
|
||||
return this.replace({ type: 'Literal', value: node.name });
|
||||
}
|
||||
},
|
||||
leave(node, parent, prop, index) {},
|
||||
});
|
||||
|
||||
@ -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);
|
||||
|
||||
2692
pnpm-lock.yaml
generated
2692
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
91
src-tauri/Cargo.lock
generated
91
src-tauri/Cargo.lock
generated
@ -1727,6 +1727,17 @@ dependencies = [
|
||||
"objc_exception",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc-foundation"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9"
|
||||
dependencies = [
|
||||
"block",
|
||||
"objc",
|
||||
"objc_id",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc_exception"
|
||||
version = "0.1.2"
|
||||
@ -2190,6 +2201,30 @@ version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78"
|
||||
|
||||
[[package]]
|
||||
name = "rfd"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0149778bd99b6959285b0933288206090c50e2327f47a9c463bfdbf45c8823ea"
|
||||
dependencies = [
|
||||
"block",
|
||||
"dispatch",
|
||||
"glib-sys",
|
||||
"gobject-sys",
|
||||
"gtk-sys",
|
||||
"js-sys",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"objc",
|
||||
"objc-foundation",
|
||||
"objc_id",
|
||||
"raw-window-handle",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
"windows 0.37.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rosc"
|
||||
version = "0.10.1"
|
||||
@ -2696,6 +2731,7 @@ dependencies = [
|
||||
"percent-encoding",
|
||||
"rand 0.8.5",
|
||||
"raw-window-handle",
|
||||
"rfd",
|
||||
"semver",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@ -3251,6 +3287,18 @@ dependencies = [
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-futures"
|
||||
version = "0.4.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.87"
|
||||
@ -3406,6 +3454,19 @@ version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows"
|
||||
version = "0.37.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57b543186b344cc61c85b5aab0d2e3adf4e0f99bc076eff9aa5927bcc0b8a647"
|
||||
dependencies = [
|
||||
"windows_aarch64_msvc 0.37.0",
|
||||
"windows_i686_gnu 0.37.0",
|
||||
"windows_i686_msvc 0.37.0",
|
||||
"windows_x86_64_gnu 0.37.0",
|
||||
"windows_x86_64_msvc 0.37.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows"
|
||||
version = "0.39.0"
|
||||
@ -3512,6 +3573,12 @@ version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.37.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2623277cb2d1c216ba3b578c0f3cf9cdebeddb6e66b1b218bb33596ea7769c3a"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.39.0"
|
||||
@ -3530,6 +3597,12 @@ version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.37.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3925fd0b0b804730d44d4b6278c50f9699703ec49bcd628020f46f4ba07d9e1"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.39.0"
|
||||
@ -3548,6 +3621,12 @@ version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.37.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce907ac74fe331b524c1298683efbf598bb031bc84d5e274db2083696d07c57c"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.39.0"
|
||||
@ -3566,6 +3645,12 @@ version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.37.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2babfba0828f2e6b32457d5341427dcbb577ceef556273229959ac23a10af33d"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.39.0"
|
||||
@ -3596,6 +3681,12 @@ version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.37.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4dd6dc7df2d84cf7b33822ed5b86318fb1781948e9663bacd047fc9dd52259d"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.39.0"
|
||||
|
||||
@ -17,7 +17,7 @@ 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"] }
|
||||
tauri = { version = "1.4.0", features = [ "dialog-all", "clipboard-write-text", "fs-all"] }
|
||||
midir = "0.9.1"
|
||||
tokio = { version = "1.29.0", features = ["full"] }
|
||||
rosc = "0.10.1"
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
"build": {
|
||||
"beforeBuildCommand": "npm run build",
|
||||
"beforeDevCommand": "npm run dev",
|
||||
"devPath": "http://localhost:3000",
|
||||
"devPath": "http://localhost:4321",
|
||||
"distDir": "../website/dist",
|
||||
"withGlobalTauri": true
|
||||
},
|
||||
@ -13,6 +13,12 @@
|
||||
},
|
||||
"tauri": {
|
||||
"allowlist": {
|
||||
"dialog": {
|
||||
"all": true
|
||||
},
|
||||
"clipboard": {
|
||||
"writeText": true
|
||||
},
|
||||
"all": false,
|
||||
"fs": {
|
||||
"all": true,
|
||||
|
||||
@ -633,6 +633,15 @@ exports[`runs examples > example "addVoicings" example index 0 1`] = `
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`runs examples > example "adsr" example index 0 1`] = `
|
||||
[
|
||||
"[ 0/1 → 1/1 | note:c3 s:sawtooth cutoff:600 ]",
|
||||
"[ 1/1 → 2/1 | note:bb2 s:sawtooth cutoff:600 ]",
|
||||
"[ 2/1 → 3/1 | note:f3 s:sawtooth cutoff:600 ]",
|
||||
"[ 3/1 → 4/1 | note:eb3 s:sawtooth cutoff:600 ]",
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`runs examples > example "almostAlways" example index 0 1`] = `
|
||||
[
|
||||
"[ 0/1 → 1/8 | s:hh speed:0.5 ]",
|
||||
@ -1106,27 +1115,6 @@ exports[`runs examples > example "chop" example index 0 1`] = `
|
||||
`;
|
||||
|
||||
exports[`runs examples > example "chunk" example index 0 1`] = `
|
||||
[
|
||||
"[ 0/1 → 1/4 | note:A4 ]",
|
||||
"[ 1/4 → 1/2 | note:B3 ]",
|
||||
"[ 1/2 → 3/4 | note:C4 ]",
|
||||
"[ 3/4 → 1/1 | note:D4 ]",
|
||||
"[ 1/1 → 5/4 | note:A3 ]",
|
||||
"[ 5/4 → 3/2 | note:B3 ]",
|
||||
"[ 3/2 → 7/4 | note:C4 ]",
|
||||
"[ 7/4 → 2/1 | note:D5 ]",
|
||||
"[ 2/1 → 9/4 | note:A3 ]",
|
||||
"[ 9/4 → 5/2 | note:B3 ]",
|
||||
"[ 5/2 → 11/4 | note:C5 ]",
|
||||
"[ 11/4 → 3/1 | note:D4 ]",
|
||||
"[ 3/1 → 13/4 | note:A3 ]",
|
||||
"[ 13/4 → 7/2 | note:B4 ]",
|
||||
"[ 7/2 → 15/4 | note:C4 ]",
|
||||
"[ 15/4 → 4/1 | note:D4 ]",
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`runs examples > example "chunkBack" example index 0 1`] = `
|
||||
[
|
||||
"[ 0/1 → 1/4 | note:A4 ]",
|
||||
"[ 1/4 → 1/2 | note:B3 ]",
|
||||
@ -1147,6 +1135,27 @@ exports[`runs examples > example "chunkBack" example index 0 1`] = `
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`runs examples > example "chunkBack" example index 0 1`] = `
|
||||
[
|
||||
"[ 0/1 → 1/4 | note:A4 ]",
|
||||
"[ 1/4 → 1/2 | note:B3 ]",
|
||||
"[ 1/2 → 3/4 | note:C4 ]",
|
||||
"[ 3/4 → 1/1 | note:D4 ]",
|
||||
"[ 1/1 → 5/4 | note:A3 ]",
|
||||
"[ 5/4 → 3/2 | note:B3 ]",
|
||||
"[ 3/2 → 7/4 | note:C4 ]",
|
||||
"[ 7/4 → 2/1 | note:D5 ]",
|
||||
"[ 2/1 → 9/4 | note:A3 ]",
|
||||
"[ 9/4 → 5/2 | note:B3 ]",
|
||||
"[ 5/2 → 11/4 | note:C5 ]",
|
||||
"[ 11/4 → 3/1 | note:D4 ]",
|
||||
"[ 3/1 → 13/4 | note:A3 ]",
|
||||
"[ 13/4 → 7/2 | note:B4 ]",
|
||||
"[ 7/2 → 15/4 | note:C4 ]",
|
||||
"[ 15/4 → 4/1 | note:D4 ]",
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`runs examples > example "clip" example index 0 1`] = `
|
||||
[
|
||||
"[ 0/1 → 1/4 | note:c s:piano clip:0.5 ]",
|
||||
@ -1789,6 +1798,23 @@ exports[`runs examples > example "euclidLegato" example index 0 1`] = `
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`runs examples > example "euclidLegatoRot" example index 0 1`] = `
|
||||
[
|
||||
"[ 0/1 → 1/4 | note:c3 ]",
|
||||
"[ 1/4 → 3/4 | note:c3 ]",
|
||||
"[ 3/4 → 1/1 | note:c3 ]",
|
||||
"[ 1/1 → 5/4 | note:c3 ]",
|
||||
"[ 5/4 → 7/4 | note:c3 ]",
|
||||
"[ 7/4 → 2/1 | note:c3 ]",
|
||||
"[ 2/1 → 9/4 | note:c3 ]",
|
||||
"[ 9/4 → 11/4 | note:c3 ]",
|
||||
"[ 11/4 → 3/1 | note:c3 ]",
|
||||
"[ 3/1 → 13/4 | note:c3 ]",
|
||||
"[ 13/4 → 15/4 | note:c3 ]",
|
||||
"[ 15/4 → 4/1 | note:c3 ]",
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`runs examples > example "euclidRot" example index 0 1`] = `
|
||||
[
|
||||
"[ 3/16 → 1/4 | note:c3 ]",
|
||||
@ -1848,6 +1874,19 @@ exports[`runs examples > example "fast" example index 0 1`] = `
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`runs examples > example "fastChunk" example index 0 1`] = `
|
||||
[
|
||||
"[ 0/1 → 1/2 | note:C2 s:folkharp ]",
|
||||
"[ 1/2 → 1/1 | note:D2 s:folkharp ]",
|
||||
"[ 1/1 → 3/2 | note:E2 s:folkharp ]",
|
||||
"[ 3/2 → 2/1 | note:F2 s:folkharp ]",
|
||||
"[ 2/1 → 5/2 | note:G2 s:folkharp ]",
|
||||
"[ 5/2 → 3/1 | note:A2 s:folkharp ]",
|
||||
"[ 3/1 → 7/2 | note:B2 s:folkharp ]",
|
||||
"[ 7/2 → 4/1 | note:C3 s:folkharp ]",
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`runs examples > example "fastGap" example index 0 1`] = `
|
||||
[
|
||||
"[ 0/1 → 1/4 | s:bd ]",
|
||||
@ -2121,6 +2160,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 ]",
|
||||
@ -2408,6 +2456,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 ]",
|
||||
@ -3275,6 +3336,204 @@ 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 ]",
|
||||
"[ 1/2 → 1/1 | note:a ]",
|
||||
"[ 1/1 → 3/2 | note:e ]",
|
||||
"[ 3/2 → 2/1 | note:f ]",
|
||||
"[ 2/1 → 9/4 | note:f ]",
|
||||
"[ 9/4 → 5/2 | note:g ]",
|
||||
"[ 5/2 → 11/4 | note:f ]",
|
||||
"[ 11/4 → 3/1 | note:g ]",
|
||||
"[ 3/1 → 13/4 | note:g ]",
|
||||
"[ 13/4 → 7/2 | note:a ]",
|
||||
"[ 7/2 → 15/4 | note:c ]",
|
||||
"[ 15/4 → 4/1 | note:d ]",
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`runs examples > example "ply" example index 0 1`] = `
|
||||
[
|
||||
"[ 0/1 → 1/4 | s:bd ]",
|
||||
@ -3620,6 +3879,27 @@ exports[`runs examples > example "release" example index 0 1`] = `
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`runs examples > example "repeatCycles" example index 0 1`] = `
|
||||
[
|
||||
"[ 0/1 → 1/4 | note:42 s:gm_acoustic_guitar_nylon ]",
|
||||
"[ 1/4 → 1/2 | note:38 s:gm_acoustic_guitar_nylon ]",
|
||||
"[ 1/2 → 3/4 | note:35 s:gm_acoustic_guitar_nylon ]",
|
||||
"[ 3/4 → 1/1 | note:38 s:gm_acoustic_guitar_nylon ]",
|
||||
"[ 1/1 → 5/4 | note:42 s:gm_acoustic_guitar_nylon ]",
|
||||
"[ 5/4 → 3/2 | note:38 s:gm_acoustic_guitar_nylon ]",
|
||||
"[ 3/2 → 7/4 | note:35 s:gm_acoustic_guitar_nylon ]",
|
||||
"[ 7/4 → 2/1 | note:38 s:gm_acoustic_guitar_nylon ]",
|
||||
"[ 2/1 → 9/4 | note:42 s:gm_acoustic_guitar_nylon ]",
|
||||
"[ 9/4 → 5/2 | note:36 s:gm_acoustic_guitar_nylon ]",
|
||||
"[ 5/2 → 11/4 | note:39 s:gm_acoustic_guitar_nylon ]",
|
||||
"[ 11/4 → 3/1 | note:41 s:gm_acoustic_guitar_nylon ]",
|
||||
"[ 3/1 → 13/4 | note:42 s:gm_acoustic_guitar_nylon ]",
|
||||
"[ 13/4 → 7/2 | note:36 s:gm_acoustic_guitar_nylon ]",
|
||||
"[ 7/2 → 15/4 | note:39 s:gm_acoustic_guitar_nylon ]",
|
||||
"[ 15/4 → 4/1 | note:41 s:gm_acoustic_guitar_nylon ]",
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`runs examples > example "reset" example index 0 1`] = `
|
||||
[
|
||||
"[ 0/1 → 1/4 | s:hh ]",
|
||||
@ -4175,6 +4455,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 ]",
|
||||
@ -4612,6 +4901,25 @@ exports[`runs examples > example "square" example index 0 1`] = `
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`runs examples > example "squeeze" example index 0 1`] = `
|
||||
[
|
||||
"[ 0/1 → 1/1 | note:g ]",
|
||||
"[ 1/1 → 2/1 | note:a ]",
|
||||
"[ 2/1 → 17/8 | note:f ]",
|
||||
"[ 17/8 → 9/4 | note:g ]",
|
||||
"[ 9/4 → 19/8 | note:f ]",
|
||||
"[ 19/8 → 5/2 | note:g ]",
|
||||
"[ 5/2 → 21/8 | note:f ]",
|
||||
"[ 21/8 → 11/4 | note:g ]",
|
||||
"[ 11/4 → 23/8 | note:f ]",
|
||||
"[ 23/8 → 3/1 | note:g ]",
|
||||
"[ 3/1 → 13/4 | note:g ]",
|
||||
"[ 13/4 → 7/2 | note:a ]",
|
||||
"[ 7/2 → 15/4 | note:c ]",
|
||||
"[ 15/4 → 4/1 | note:d ]",
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`runs examples > example "squiz" example index 0 1`] = `
|
||||
[
|
||||
"[ 0/1 → 1/4 | squiz:2 s:bd ]",
|
||||
@ -5156,6 +5464,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 ]",
|
||||
|
||||
@ -56,7 +56,7 @@ All commands are run from the root of the project, from a terminal:
|
||||
| Command | Action |
|
||||
| :--------------------- | :----------------------------------------------- |
|
||||
| `npm install` | Installs dependencies |
|
||||
| `npm run dev` | Starts local dev server at `localhost:3000` |
|
||||
| `npm run dev` | Starts local dev server at `localhost:4321` |
|
||||
| `npm run build` | Build your production site to `./dist/` |
|
||||
| `npm run preview` | Preview your build locally, before deploying |
|
||||
| `npm run astro ...` | Run CLI commands like `astro add`, `astro check` |
|
||||
|
||||
@ -50,6 +50,7 @@ export default defineConfig({
|
||||
mdx(options),
|
||||
tailwind(),
|
||||
AstroPWA({
|
||||
experimental: { directoryAndTrailingSlashHandler: true },
|
||||
registerType: 'autoUpdate',
|
||||
injectRegister: 'auto',
|
||||
workbox: {
|
||||
|
||||
@ -13,9 +13,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@algolia/client-search": "^4.17.0",
|
||||
"@astrojs/mdx": "^0.19.0",
|
||||
"@astrojs/react": "^2.1.1",
|
||||
"@astrojs/tailwind": "^3.1.1",
|
||||
"@astrojs/mdx": "^1.1.3",
|
||||
"@astrojs/react": "^3.0.4",
|
||||
"@astrojs/tailwind": "^5.0.2",
|
||||
"@docsearch/css": "^3.3.4",
|
||||
"@docsearch/react": "^3.3.4",
|
||||
"@headlessui/react": "^1.7.14",
|
||||
@ -45,7 +45,7 @@
|
||||
"@types/react": "^18.2.0",
|
||||
"@types/react-dom": "^18.2.1",
|
||||
"@uiw/codemirror-themes-all": "^4.19.16",
|
||||
"astro": "^2.3.2",
|
||||
"astro": "^3.4.2",
|
||||
"canvas": "^2.11.2",
|
||||
"claviature": "^0.1.0",
|
||||
"fraction.js": "^4.2.0",
|
||||
@ -60,7 +60,7 @@
|
||||
"tailwindcss": "^3.3.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vite-pwa/astro": "file:vite-pwa-astro-0.1.3.tgz",
|
||||
"@vite-pwa/astro": "^0.1.4",
|
||||
"html-escaper": "^3.0.3",
|
||||
"vite-plugin-pwa": "^0.16.5",
|
||||
"workbox-window": "^7.0.0"
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -41,7 +41,7 @@ export function MiniRepl({
|
||||
claviatureLabels,
|
||||
}) {
|
||||
const [Repl, setRepl] = useState();
|
||||
const { theme, keybindings, fontSize, fontFamily, isLineNumbersDisplayed } = useSettings();
|
||||
const { theme, keybindings, fontSize, fontFamily, isLineNumbersDisplayed, isActiveLineHighlighted } = useSettings();
|
||||
const [activeNotes, setActiveNotes] = useState([]);
|
||||
useEffect(() => {
|
||||
// we have to load this package on the client
|
||||
@ -51,7 +51,7 @@ export function MiniRepl({
|
||||
.catch((err) => console.error(err));
|
||||
}, []);
|
||||
return Repl ? (
|
||||
<div className="mb-4">
|
||||
<div className="mb-4 mini-repl">
|
||||
<Repl
|
||||
tune={tune}
|
||||
hideOutsideView={true}
|
||||
@ -66,6 +66,7 @@ export function MiniRepl({
|
||||
fontFamily={fontFamily}
|
||||
fontSize={fontSize}
|
||||
isLineNumbersDisplayed={isLineNumbersDisplayed}
|
||||
isActiveLineHighlighted={isActiveLineHighlighted}
|
||||
onPaint={
|
||||
claviature
|
||||
? (ctx, time, haps, drawTime) => {
|
||||
|
||||
@ -25,7 +25,7 @@ import Box from '@components/Box.astro';
|
||||
|
||||
lpf = **l**ow **p**ass **f**ilter
|
||||
|
||||
- Ändere `lpf` in 200. Hörst du wie der Bass dumpfer klingt? Es klingt so ähnlich als würde die Musik hinter einer geschlossenen Tür laufen 🚪
|
||||
- Ändere `lpf` in 200. Hörst du, wie der Bass dumpfer klingt? Es klingt so, als würde die Musik hinter einer geschlossenen Tür spielen 🚪
|
||||
- Lass uns nun die Tür öffnen: Ändere `lpf` in 5000. Der Klang wird dadurch viel heller und schärfer ✨🪩
|
||||
|
||||
</Box>
|
||||
@ -42,9 +42,9 @@ lpf = **l**ow **p**ass **f**ilter
|
||||
<Box>
|
||||
|
||||
- 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.
|
||||
|
||||
</Box>
|
||||
|
||||
@ -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)
|
||||
|
||||
</Box>
|
||||
@ -99,13 +99,13 @@ Lass uns die obigen Beispiele kombinieren:
|
||||
|
||||
<Box>
|
||||
|
||||
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.
|
||||
|
||||
</Box>
|
||||
|
||||
**Den Sound formen mit ADSR Hüllkurve**
|
||||
**Den Sound formen mit ADSR-Hüllkurve**
|
||||
|
||||
<MiniRepl
|
||||
hideHeader
|
||||
@ -120,14 +120,14 @@ Die 3 Teile (Drums, Bass, Akkorde) sind genau wie vorher, nur in einem `stack`,
|
||||
|
||||
<Box>
|
||||
|
||||
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?
|
||||
|
||||
</Box>
|
||||
|
||||
@ -142,7 +142,7 @@ Kannst du erraten was die einzelnen Werte machen?
|
||||
|
||||
</QA>
|
||||
|
||||
**adsr Kurznotation**
|
||||
**adsr-Kurznotation**
|
||||
|
||||
<MiniRepl
|
||||
hideHeader
|
||||
@ -169,9 +169,9 @@ Kannst du erraten was die einzelnen Werte machen?
|
||||
|
||||
Probier verschiedene `delay` Werte zwischen 0 und 1. Übrigens: `.5` ist kurz für `0.5`.
|
||||
|
||||
Was passiert wenn du `.delay(".8:.125")` schreibst? Kannst du erraten was die zweite Zahl macht?
|
||||
Was passiert, wenn du `.delay(".8:.125")` schreibst? Kannst du erraten, was die zweite Zahl macht?
|
||||
|
||||
Was passiert wenn du `.delay(".8:.06:.8")` schreibst? Kannst du erraten was die dritte Zahl macht?
|
||||
Was passiert, wenn du `.delay(".8:.06:.8")` schreibst? Kannst du erraten, was die dritte Zahl macht?
|
||||
|
||||
</Box>
|
||||
|
||||
@ -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)
|
||||
|
||||
</QA>
|
||||
|
||||
@ -203,7 +203,7 @@ Füg auch ein Delay hinzu!
|
||||
|
||||
</Box>
|
||||
|
||||
**kleiner dub tune**
|
||||
**kleiner Dub-Tune**
|
||||
|
||||
<MiniRepl
|
||||
hideHeader
|
||||
@ -238,7 +238,7 @@ Für echten Dub fehlt noch der Bass:
|
||||
|
||||
<Box>
|
||||
|
||||
Füg `.hush()` ans ende eines Patterns im stack...
|
||||
Füg `.hush()` ans Ende eines Patterns im stack...
|
||||
|
||||
</Box>
|
||||
|
||||
@ -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:
|
||||
|
||||
<MiniRepl hideHeader client:visible tune={`sound("bd*2,~ rim").slow(2)`} />
|
||||
|
||||
<Box>
|
||||
|
||||
Ä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]>")` ?
|
||||
|
||||
</Box>
|
||||
|
||||
Übrigens, innerhalb der Mini-Notation, `fast` ist `*` und `slow` ist `/`.
|
||||
Übrigens, innerhalb der Mini-Notation: `fast` ist `*` und `slow` ist `/`.
|
||||
|
||||
<MiniRepl hideHeader client:visible tune={`sound("[bd*2,~ rim]*<1 [2 4]>")`} />
|
||||
|
||||
## 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:
|
||||
|
||||
<MiniRepl hideHeader client:visible tune={`sound("hh*16").gain(sine)`} punchcard punchcardLabels={false} />
|
||||
|
||||
@ -296,7 +296,7 @@ Signale bewegen sich standardmäßig zwischen 0 und 1. Wir können das mit `rang
|
||||
|
||||
<MiniRepl hideHeader client:visible tune={`sound("hh*8").lpf(saw.range(500, 2000))`} />
|
||||
|
||||
`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`)
|
||||
|
||||
<Box>
|
||||
|
||||
@ -322,7 +322,7 @@ Die ganze Automation braucht nun 8 cycle bis sie sich wiederholt.
|
||||
|
||||
## Rückblick
|
||||
|
||||
| name | example |
|
||||
| Name | Beispiel |
|
||||
| ----- | -------------------------------------------------------------------------------------------------- |
|
||||
| lpf | <MiniRepl hideHeader client:visible tune={`note("c2 c3").s("sawtooth").lpf("<400 2000>")`} /> |
|
||||
| vowel | <MiniRepl hideHeader client:visible tune={`note("c3 eb3 g3").s("sawtooth").vowel("<a e i o>")`} /> |
|
||||
@ -333,4 +333,4 @@ Die ganze Automation braucht nun 8 cycle bis sie sich wiederholt.
|
||||
| speed | <MiniRepl hideHeader client:visible tune={`s("bd rim").speed("<1 2 -1 -2>")`} /> |
|
||||
| range | <MiniRepl hideHeader client:visible tune={`s("hh*16").lpf(saw.range(200,4000))`} /> |
|
||||
|
||||
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).
|
||||
|
||||
@ -277,7 +277,7 @@ Das haben wir bisher gelernt:
|
||||
| Schneller | \* | <MiniRepl hideHeader client:visible tune={`sound("bd sd*2 cp*3")`} /> |
|
||||
| Parallel | , | <MiniRepl hideHeader client:visible tune={`sound("bd*2, hh*2 [hh oh]")`} /> |
|
||||
|
||||
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 |
|
||||
|
||||
@ -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
|
||||
|
||||
<MiniRepl hideHeader client:visible tune={`n("0 1 [4 3] 2").sound("jazz").jux(rev)`} />
|
||||
|
||||
So würde man das ohne jux schreiben:
|
||||
So würde man das ohne `jux` schreiben:
|
||||
|
||||
<MiniRepl
|
||||
hideHeader
|
||||
@ -32,7 +32,7 @@ So würde man das ohne jux schreiben:
|
||||
)`}
|
||||
/>
|
||||
|
||||
Lass uns visualisieren was hier passiert:
|
||||
Lass uns visualisieren, was hier passiert:
|
||||
|
||||
<MiniRepl
|
||||
hideHeader
|
||||
@ -54,7 +54,7 @@ Schreibe `//` vor eine der beiden Zeilen im `stack`!
|
||||
|
||||
<MiniRepl hideHeader client:visible tune={`note("c2, eb3 g3 [bb3 c4]").sound("piano").slow("1,2,3")`} />
|
||||
|
||||
Das hat den gleichen Effekt wie:
|
||||
Das hat den gleichen Effekt, wie:
|
||||
|
||||
<MiniRepl
|
||||
hideHeader
|
||||
@ -161,11 +161,11 @@ Probier `ply` mit einem pattern zu automatisieren, z.b. `"<1 2 1 3>"`
|
||||
|
||||
<Box>
|
||||
|
||||
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.
|
||||
|
||||
</Box>
|
||||
|
||||
`off` ist auch nützlich für sounds:
|
||||
`off` ist auch nützlich für Sounds:
|
||||
|
||||
<MiniRepl
|
||||
hideHeader
|
||||
@ -174,10 +174,10 @@ In der notation `x=>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 | <MiniRepl hideHeader client:visible tune={`n("0 2 4 6").scale("C:minor").rev()`} /> |
|
||||
| jux | ein stereo-kanal modifizieren | <MiniRepl hideHeader client:visible tune={`n("0 2 4 6").scale("C:minor").jux(rev)`} /> |
|
||||
| add | addiert zahlen oder noten | <MiniRepl hideHeader client:visible tune={`n("0 2 4 6".add("<0 1 2 1>")).scale("C:minor")`} /> |
|
||||
| ply | multipliziert jedes element x mal | <MiniRepl hideHeader client:visible tune={`s("bd sd").ply("<1 2 3>")`} /> |
|
||||
| off | verzögert eine modifizierte kopie | <MiniRepl hideHeader client:visible tune={`s("bd sd, hh*4").off(1/8, x=>x.speed(2))`} /> |
|
||||
| jux | einen Stereo-Kanal modifizieren | <MiniRepl hideHeader client:visible tune={`n("0 2 4 6").scale("C:minor").jux(rev)`} /> |
|
||||
| add | addiert Zahlen oder Noten | <MiniRepl hideHeader client:visible tune={`n("0 2 4 6".add("<0 1 2 1>")).scale("C:minor")`} /> |
|
||||
| ply | multipliziert jedes Element x mal | <MiniRepl hideHeader client:visible tune={`s("bd sd").ply("<1 2 3>")`} /> |
|
||||
| off | verzögert eine modifizierte Kopie | <MiniRepl hideHeader client:visible tune={`s("bd sd, hh*4").off(1/8, x=>x.speed(2))`} /> |
|
||||
|
||||
@ -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 | <MiniRepl hideHeader client:visible tune={`sound("bd bd sn hh")`} /> |
|
||||
| Sample Nummer | :x | <MiniRepl hideHeader client:visible tune={`sound("hh:0 hh:1 hh:2 hh:3")`} /> |
|
||||
| Sequenz | space | <MiniRepl hideHeader client:visible tune={`sound("bd bd sn hh")`} /> |
|
||||
| Sample-Nummer | :x | <MiniRepl hideHeader client:visible tune={`sound("hh:0 hh:1 hh:2 hh:3")`} /> |
|
||||
| Pausen | ~ | <MiniRepl hideHeader client:visible tune={`sound("metal ~ jazz jazz:1")`} /> |
|
||||
| Unter-Sequences | \[\] | <MiniRepl hideHeader client:visible tune={`sound("bd wind [metal jazz] hh")`} /> |
|
||||
| Unter-Unter-Sequences | \[\[\]\] | <MiniRepl hideHeader client:visible tune={`sound("bd [metal [jazz sn]]")`} /> |
|
||||
| Unter-Sequenzen | \[\] | <MiniRepl hideHeader client:visible tune={`sound("bd wind [metal jazz] hh")`} /> |
|
||||
| Unter-Unter-Sequenzen | \[\[\]\] | <MiniRepl hideHeader client:visible tune={`sound("bd [metal [jazz sn]]")`} /> |
|
||||
| Schneller | \* | <MiniRepl hideHeader client:visible tune={`sound("bd sn*2 cp*3")`} /> |
|
||||
| Slow down | \/ | <MiniRepl hideHeader client:visible tune={`note("[c a f e]/2")`} /> |
|
||||
| Verlangsamen | \/ | <MiniRepl hideHeader client:visible tune={`note("[c a f e]/2")`} /> |
|
||||
| Parallel | , | <MiniRepl hideHeader client:visible tune={`sound("bd*2, hh*2 [hh oh]")`} /> |
|
||||
| Alternieren | \<\> | <MiniRepl hideHeader client:visible tune={`note("c <e g>")`} /> |
|
||||
| Verlängern | @ | <MiniRepl hideHeader client:visible tune={`note("c@3 e")`} /> |
|
||||
@ -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 | <MiniRepl hideHeader client:visible tune={`sound("bd sd")`} /> |
|
||||
| bank | wählt die soundbank | <MiniRepl hideHeader client:visible tune={`sound("bd sd").bank("RolandTR909")`} /> |
|
||||
| n | wählt sample mit nummer | <MiniRepl hideHeader client:visible tune={`n("0 1 4 2").sound("jazz")`} /> |
|
||||
| sound | spielt den Sound mit Namen | <MiniRepl hideHeader client:visible tune={`sound("bd sd")`} /> |
|
||||
| bank | wählt die Soundbank | <MiniRepl hideHeader client:visible tune={`sound("bd sd").bank("RolandTR909")`} /> |
|
||||
| n | wählt Sample mit Nummer | <MiniRepl hideHeader client:visible tune={`n("0 1 4 2").sound("jazz")`} /> |
|
||||
|
||||
## Notes
|
||||
## Noten
|
||||
|
||||
| Name | Description | Example |
|
||||
| Name | Beschreibung | Beispiel |
|
||||
| --------- | ---------------------------------- | -------------------------------------------------------------------------------------------- |
|
||||
| note | wählt note per zahl oder buchstabe | <MiniRepl hideHeader client:visible tune={`note("b g e c").sound("piano")`} /> |
|
||||
| n + scale | wählt note n in skala | <MiniRepl hideHeader client:visible tune={`n("6 4 2 0").scale("C:minor").sound("piano")`} /> |
|
||||
| stack | spielt mehrere patterns parallel | <MiniRepl hideHeader client:visible tune={`stack(s("bd sd"),note("c eb g"))`} /> |
|
||||
| note | wählt Note per Zahl oder Buchstabe | <MiniRepl hideHeader client:visible tune={`note("b g e c").sound("piano")`} /> |
|
||||
| n + scale | wählt Note n in Skala | <MiniRepl hideHeader client:visible tune={`n("6 4 2 0").scale("C:minor").sound("piano")`} /> |
|
||||
| stack | spielt mehrere Patterns parallel | <MiniRepl hideHeader client:visible tune={`stack(s("bd sd"),note("c eb g"))`} /> |
|
||||
|
||||
## Audio Effekte
|
||||
## Audio-Effekte
|
||||
|
||||
| name | example |
|
||||
| Name | Beispiele |
|
||||
| ----- | -------------------------------------------------------------------------------------------------- |
|
||||
| lpf | <MiniRepl hideHeader client:visible tune={`note("c2 c3").s("sawtooth").lpf("<400 2000>")`} /> |
|
||||
| vowel | <MiniRepl hideHeader client:visible tune={`note("c3 eb3 g3").s("sawtooth").vowel("<a e i o>")`} /> |
|
||||
@ -54,15 +54,15 @@ Diese Seite ist eine Auflistung aller im Workshop enthaltenen Funktionen.
|
||||
| speed | <MiniRepl hideHeader client:visible tune={`s("bd rim").speed("<1 2 -1 -2>")`} /> |
|
||||
| range | <MiniRepl hideHeader client:visible tune={`s("hh*16").lpf(saw.range(200,4000))`} /> |
|
||||
|
||||
## Pattern Effects
|
||||
## Pattern-Effekte
|
||||
|
||||
| name | description | example |
|
||||
| Name | Beschreibung | Beispiel |
|
||||
| ---- | --------------------------------- | ---------------------------------------------------------------------------------------------- |
|
||||
| cpm | tempo in cycles pro minute | <MiniRepl hideHeader client:visible tune={`sound("bd sd").cpm(90)`} /> |
|
||||
| cpm | Tempo in Cycles pro Minute | <MiniRepl hideHeader client:visible tune={`sound("bd sd").cpm(90)`} /> |
|
||||
| fast | schneller | <MiniRepl hideHeader client:visible tune={`sound("bd sd").fast(2)`} /> |
|
||||
| slow | langsamer | <MiniRepl hideHeader client:visible tune={`sound("bd sd").slow(2)`} /> |
|
||||
| rev | rückwärts | <MiniRepl hideHeader client:visible tune={`n("0 2 4 6").scale("C:minor").rev()`} /> |
|
||||
| jux | ein stereo-kanal modifizieren | <MiniRepl hideHeader client:visible tune={`n("0 2 4 6").scale("C:minor").jux(rev)`} /> |
|
||||
| add | addiert zahlen oder noten | <MiniRepl hideHeader client:visible tune={`n("0 2 4 6".add("<0 1 2 1>")).scale("C:minor")`} /> |
|
||||
| ply | jedes element schneller machen | <MiniRepl hideHeader client:visible tune={`s("bd sd").ply("<1 2 3>")`} /> |
|
||||
| off | verzögert eine modifizierte kopie | <MiniRepl hideHeader client:visible tune={`s("bd sd, hh*4").off(1/8, x=>x.speed(2))`} /> |
|
||||
| jux | einen Stereo-Kanal modifizieren | <MiniRepl hideHeader client:visible tune={`n("0 2 4 6").scale("C:minor").jux(rev)`} /> |
|
||||
| add | addiert Zahlen oder Noten | <MiniRepl hideHeader client:visible tune={`n("0 2 4 6".add("<0 1 2 1>")).scale("C:minor")`} /> |
|
||||
| ply | jedes Element schneller machen | <MiniRepl hideHeader client:visible tune={`s("bd sd").ply("<1 2 3>")`} /> |
|
||||
| off | verzögert eine modifizierte Kopie | <MiniRepl hideHeader client:visible tune={`s("bd sd, hh*4").off(1/8, x=>x.speed(2))`} /> |
|
||||
|
||||
@ -60,4 +60,12 @@ import { JsDoc } from '../../docs/JsDoc';
|
||||
|
||||
<JsDoc client:idle name="invert" h={0} />
|
||||
|
||||
## pick
|
||||
|
||||
<JsDoc client:idle name="pick" h={0} />
|
||||
|
||||
## squeeze
|
||||
|
||||
<JsDoc client:idle name="squeeze" h={0} />
|
||||
|
||||
After Conditional Modifiers, let's see what [Accumulation Modifiers](/learn/accumulation) have to offer.
|
||||
|
||||
@ -82,6 +82,10 @@ Strudel uses ADSR envelopes, which are probably the most common way to describe
|
||||
|
||||
<JsDoc client:idle name="release" h={0} />
|
||||
|
||||
## adsr
|
||||
|
||||
<JsDoc client:idle name="adsr" h={0} />
|
||||
|
||||
# Filter Envelope
|
||||
|
||||
Each filter can receive an additional filter envelope controlling the cutoff value dynamically. It uses an ADSR envelope similar to the one used for amplitude. There is an additional parameter to control the depth of the filter modulation: `lpenv`|`hpenv`|`bpenv`. This allows you to play subtle or huge filter modulations just the same by only increasing or decreasing the depth.
|
||||
@ -152,6 +156,10 @@ There is one filter envelope for each filter type and thus one set of envelope f
|
||||
|
||||
<JsDoc client:idle name="postgain" h={0} />
|
||||
|
||||
## xfade
|
||||
|
||||
<JsDoc client:idle name="xfade" h={0} />
|
||||
|
||||
# Panning
|
||||
|
||||
## jux
|
||||
@ -232,3 +240,21 @@ global effects use the same chain for all events of the same orbit:
|
||||
<JsDoc client:idle name="iresponse" h={0} />
|
||||
|
||||
Next, we'll look at strudel's support for [Csound](/learn/csound).
|
||||
|
||||
## Phaser
|
||||
|
||||
### phaser
|
||||
|
||||
<JsDoc client:idle name="phaser" h={0} />
|
||||
|
||||
### phaserdepth
|
||||
|
||||
<JsDoc client:idle name="phaserdepth" h={0} />
|
||||
|
||||
### phasercenter
|
||||
|
||||
<JsDoc client:idle name="phasercenter" h={0} />
|
||||
|
||||
### phasersweep
|
||||
|
||||
<JsDoc client:idle name="phasersweep" h={0} />
|
||||
|
||||
@ -13,7 +13,7 @@ Just like [Tidal Cycles](https://tidalcycles.org/), Strudel uses a so called "Mi
|
||||
## Note
|
||||
|
||||
This page just explains the entirety of the Mini-Notation syntax.
|
||||
If you are just getting started with Strudel, you can learn the basics of the Mini-Notation in a more practical manner in the [workshop](http://localhost:3000/workshop/first-sounds).
|
||||
If you are just getting started with Strudel, you can learn the basics of the Mini-Notation in a more practical manner in the [workshop](/workshop/first-sounds).
|
||||
After that, you can come back here if you want to understand every little detail.
|
||||
|
||||
## Example
|
||||
|
||||
@ -106,7 +106,7 @@ You can find a [list of available effects here](./learn/effects).
|
||||
|
||||
### Sampler
|
||||
|
||||
Strudel's sampler supports [a subset](http://127.0.0.1:3000/learn/samples) of Superdirt's sampler.
|
||||
Strudel's sampler supports [a subset](/learn/samples) of Superdirt's sampler.
|
||||
Also, samples are always loaded from a URL rather than from the disk, although [that might be possible in the future](https://github.com/tidalcycles/strudel/issues/118).
|
||||
|
||||
## Evaluation
|
||||
|
||||
@ -9,7 +9,7 @@ The docs page is built ontop of astro's [docs site](https://github.com/withastro
|
||||
|
||||
## Adding a new Docs Page
|
||||
|
||||
1. add a `.mdx` file in a path under `website/src/pages/`, e.g. [website/src/pages/learn/code.mdx](https://raw.githubusercontent.com/tidalcycles/strudel/main/website/src/pages/learn/code.mdx) will be available under https://strudel.cc/learn/code (or locally under `http://localhost:3000/learn/code`)
|
||||
1. add a `.mdx` file in a path under `website/src/pages/`, e.g. [website/src/pages/learn/code.mdx](https://raw.githubusercontent.com/tidalcycles/strudel/main/website/src/pages/learn/code.mdx) will be available under https://strudel.cc/learn/code (or locally under `http://localhost:4321/learn/code`)
|
||||
2. make sure to copy the top part of another existing docs page. Adjust the title accordingly
|
||||
3. To add a link to the sidebar, add a new entry to `SIDEBAR` to [`config.ts`](https://github.com/tidalcycles/strudel/blob/main/website/src/config.ts)
|
||||
|
||||
|
||||
@ -57,3 +57,7 @@
|
||||
#code .cm-foldGutter {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
#code .cm-focused {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
@ -23,6 +23,7 @@ import { settingPatterns } from '../settings.mjs';
|
||||
import { code2hash, hash2code } from './helpers.mjs';
|
||||
import { isTauri } from '../tauri.mjs';
|
||||
import { useWidgets } from '@strudel.cycles/react/src/hooks/useWidgets.mjs';
|
||||
import { writeText } from '@tauri-apps/api/clipboard';
|
||||
|
||||
const { latestCode } = settingsMap.get();
|
||||
|
||||
@ -124,7 +125,9 @@ export function Repl({ embedded = false }) {
|
||||
fontSize,
|
||||
fontFamily,
|
||||
isLineNumbersDisplayed,
|
||||
isActiveLineHighlighted,
|
||||
isAutoCompletionEnabled,
|
||||
isTooltipEnabled,
|
||||
isLineWrappingEnabled,
|
||||
panelPosition,
|
||||
isZen,
|
||||
@ -272,7 +275,11 @@ export function Repl({ embedded = false }) {
|
||||
if (!error) {
|
||||
setLastShared(activeCode || code);
|
||||
// copy shareUrl to clipboard
|
||||
await navigator.clipboard.writeText(shareUrl);
|
||||
if (isTauri()) {
|
||||
await writeText(shareUrl);
|
||||
} else {
|
||||
await navigator.clipboard.writeText(shareUrl);
|
||||
}
|
||||
const message = `Link copied to clipboard: ${shareUrl}`;
|
||||
alert(message);
|
||||
// alert(message);
|
||||
@ -331,7 +338,9 @@ export function Repl({ embedded = false }) {
|
||||
value={code}
|
||||
keybindings={keybindings}
|
||||
isLineNumbersDisplayed={isLineNumbersDisplayed}
|
||||
isActiveLineHighlighted={isActiveLineHighlighted}
|
||||
isAutoCompletionEnabled={isAutoCompletionEnabled}
|
||||
isTooltipEnabled={isTooltipEnabled}
|
||||
isLineWrappingEnabled={isLineWrappingEnabled}
|
||||
fontSize={fontSize}
|
||||
fontFamily={fontFamily}
|
||||
|
||||
@ -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 (
|
||||
<div className="flex h-full w-full pt-2 text-foreground overflow-hidden">
|
||||
<div className="w-42 flex-none h-full overflow-y-auto overflow-x-hidden pr-4">
|
||||
{visibleFunctions.map((entry, i) => (
|
||||
<a key={i} className="cursor-pointer block hover:bg-lineHighlight py-1 px-4" href={`#doc-${i}`}>
|
||||
<a
|
||||
key={i}
|
||||
className="cursor-pointer block hover:bg-lineHighlight py-1 px-4"
|
||||
onClick={() => {
|
||||
const el = document.getElementById(`doc-${i}`);
|
||||
const container = document.getElementById('reference-container');
|
||||
container.scrollTo(0, el.offsetTop);
|
||||
}}
|
||||
>
|
||||
{entry.name} {/* <span className="text-gray-600">{entry.meta.filename}</span> */}
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
<div className="break-normal w-full h-full overflow-auto pl-4 flex relative">
|
||||
<div className="break-normal w-full h-full overflow-auto pl-4 flex relative" id="reference-container">
|
||||
<div className="prose dark:prose-invert max-w-full pr-4">
|
||||
<h2>API Reference</h2>
|
||||
<p>
|
||||
@ -24,8 +38,14 @@ export function Reference() {
|
||||
<section key={i}>
|
||||
<h3 id={`doc-${i}`}>{entry.name}</h3>
|
||||
{/* <small>{entry.meta.filename}</small> */}
|
||||
|
||||
<p dangerouslySetInnerHTML={{ __html: entry.description }}></p>
|
||||
<ul>
|
||||
{entry.params?.map(({ name, type, description }, i) => (
|
||||
<li key={i}>
|
||||
{name} : {type.names?.join(' | ')} {description ? <> - {getInnerText(description)}</> : ''}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
{entry.examples?.map((example, j) => (
|
||||
<pre key={j}>{example}</pre>
|
||||
))}
|
||||
|
||||
@ -78,7 +78,9 @@ export function SettingsTab() {
|
||||
theme,
|
||||
keybindings,
|
||||
isLineNumbersDisplayed,
|
||||
isActiveLineHighlighted,
|
||||
isAutoCompletionEnabled,
|
||||
isTooltipEnabled,
|
||||
isLineWrappingEnabled,
|
||||
fontSize,
|
||||
fontFamily,
|
||||
@ -130,7 +132,7 @@ export function SettingsTab() {
|
||||
<ButtonGroup
|
||||
value={keybindings}
|
||||
onChange={(keybindings) => settingsMap.setKey('keybindings', keybindings)}
|
||||
items={{ codemirror: 'Codemirror', vim: 'Vim', emacs: 'Emacs' }}
|
||||
items={{ codemirror: 'Codemirror', vim: 'Vim', emacs: 'Emacs', vscode: 'VSCode' }}
|
||||
></ButtonGroup>
|
||||
</FormItem>
|
||||
<FormItem label="Panel Position">
|
||||
@ -146,11 +148,26 @@ export function SettingsTab() {
|
||||
onChange={(cbEvent) => settingsMap.setKey('isLineNumbersDisplayed', cbEvent.target.checked)}
|
||||
value={isLineNumbersDisplayed}
|
||||
/>
|
||||
<Checkbox
|
||||
label="Highlight active line"
|
||||
onChange={(cbEvent) => settingsMap.setKey('isActiveLineHighlighted', cbEvent.target.checked)}
|
||||
value={isActiveLineHighlighted}
|
||||
/>
|
||||
<Checkbox
|
||||
label="Highlight active line"
|
||||
onChange={(cbEvent) => settingsMap.setKey('isActiveLineHighlighted', cbEvent.target.checked)}
|
||||
value={isActiveLineHighlighted}
|
||||
/>
|
||||
<Checkbox
|
||||
label="Enable auto-completion"
|
||||
onChange={(cbEvent) => settingsMap.setKey('isAutoCompletionEnabled', cbEvent.target.checked)}
|
||||
value={isAutoCompletionEnabled}
|
||||
/>
|
||||
<Checkbox
|
||||
label="Enable tooltips on Ctrl and hover"
|
||||
onChange={(cbEvent) => settingsMap.setKey('isTooltipEnabled', cbEvent.target.checked)}
|
||||
value={isTooltipEnabled}
|
||||
/>
|
||||
<Checkbox
|
||||
label="Enable line wrapping"
|
||||
onChange={(cbEvent) => settingsMap.setKey('isLineWrappingEnabled', cbEvent.target.checked)}
|
||||
|
||||
@ -7,7 +7,9 @@ export const defaultSettings = {
|
||||
activeFooter: 'intro',
|
||||
keybindings: 'codemirror',
|
||||
isLineNumbersDisplayed: true,
|
||||
isActiveLineHighlighted: true,
|
||||
isAutoCompletionEnabled: false,
|
||||
isTooltipEnabled: false,
|
||||
isLineWrappingEnabled: false,
|
||||
theme: 'strudelTheme',
|
||||
fontFamily: 'monospace',
|
||||
@ -28,7 +30,9 @@ export function useSettings() {
|
||||
...state,
|
||||
isZen: [true, 'true'].includes(state.isZen) ? true : false,
|
||||
isLineNumbersDisplayed: [true, 'true'].includes(state.isLineNumbersDisplayed) ? true : false,
|
||||
isActiveLineHighlighted: [true, 'true'].includes(state.isActiveLineHighlighted) ? 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,
|
||||
fontSize: Number(state.fontSize),
|
||||
panelPosition: state.activeFooter !== '' ? state.panelPosition : 'bottom',
|
||||
|
||||
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user