diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs
index 6cac6e54..76a278a5 100644
--- a/packages/core/controls.mjs
+++ b/packages/core/controls.mjs
@@ -4,1220 +4,1231 @@ Copyright (C) 2022 Strudel contributors - see .
*/
-import { Pattern, register, sequence } from './pattern.mjs';
-import { zipWith } from './util.mjs';
+import {Pattern, register, sequence} from './pattern.mjs';
+import {zipWith} from './util.mjs';
const controls = {};
const generic_params = [
- /**
- * Select a sound / sample by name. When using mininotation, you can also optionally supply 'n' and 'gain' parameters
- * separated by ':'.
- *
- * @name s
- * @param {string | Pattern} sound The sound / pattern of sounds to pick
- * @synonyms sound
- * @example
- * s("bd hh")
- * @example
- * s("bd:0 bd:1 bd:0:0.3 bd:1:1.4")
- *
- */
- [['s', 'n', 'gain'], 'sound'],
- /**
- * Define a custom webaudio node to use as a sound source.
- *
- * @name source
- * @param {function} getSource
- * @synonyms src
- *
- */
- ['source', 'src'],
- /**
- * Selects the given index from the sample map.
- * Numbers too high will wrap around.
- * `n` can also be used to play midi numbers, but it is recommended to use `note` instead.
- *
- * @name n
- * @param {number | Pattern} value sample index starting from 0
- * @example
- * s("bd sd,hh*3").n("<0 1>")
- */
- // also see https://github.com/tidalcycles/strudel/pull/63
- ['n'],
- /**
- * Plays the given note name or midi number. A note name consists of
- *
- * - a letter (a-g or A-G)
- * - optional accidentals (b or #)
- * - optional octave number (0-9). Defaults to 3
- *
- * Examples of valid note names: `c`, `bb`, `Bb`, `f#`, `c3`, `A4`, `Eb2`, `c#5`
- *
- * You can also use midi numbers instead of note names, where 69 is mapped to A4 440Hz in 12EDO.
- *
- * @name note
- * @example
- * note("c a f e")
- * @example
- * note("c4 a4 f4 e4")
- * @example
- * note("60 69 65 64")
- */
- [['note', 'n']],
+ /**
+ * Select a sound / sample by name. When using mininotation, you can also optionally supply 'n' and 'gain' parameters
+ * separated by ':'.
+ *
+ * @name s
+ * @param {string | Pattern} sound The sound / pattern of sounds to pick
+ * @synonyms sound
+ * @example
+ * s("bd hh")
+ * @example
+ * s("bd:0 bd:1 bd:0:0.3 bd:1:1.4")
+ *
+ */
+ [['s', 'n', 'gain'], 'sound'],
+ /**
+ * Define a custom webaudio node to use as a sound source.
+ *
+ * @name source
+ * @param {function} getSource
+ * @synonyms src
+ *
+ */
+ ['source', 'src'],
+ /**
+ * Selects the given index from the sample map.
+ * Numbers too high will wrap around.
+ * `n` can also be used to play midi numbers, but it is recommended to use `note` instead.
+ *
+ * @name n
+ * @param {number | Pattern} value sample index starting from 0
+ * @example
+ * s("bd sd,hh*3").n("<0 1>")
+ */
+ // also see https://github.com/tidalcycles/strudel/pull/63
+ ['n'],
+ /**
+ * Plays the given note name or midi number. A note name consists of
+ *
+ * - a letter (a-g or A-G)
+ * - optional accidentals (b or #)
+ * - optional octave number (0-9). Defaults to 3
+ *
+ * Examples of valid note names: `c`, `bb`, `Bb`, `f#`, `c3`, `A4`, `Eb2`, `c#5`
+ *
+ * You can also use midi numbers instead of note names, where 69 is mapped to A4 440Hz in 12EDO.
+ *
+ * @name note
+ * @example
+ * note("c a f e")
+ * @example
+ * note("c4 a4 f4 e4")
+ * @example
+ * note("60 69 65 64")
+ */
+ [['note', 'n']],
- /**
- * A pattern of numbers that speed up (or slow down) samples while they play. Currently only supported by osc / superdirt.
- *
- * @name accelerate
- * @param {number | Pattern} amount acceleration.
- * @superdirtOnly
- * @example
- * s("sax").accelerate("<0 1 2 4 8 16>").slow(2).osc()
- *
- */
- ['accelerate'],
- /**
- * Controls the gain by an exponential amount.
- *
- * @name gain
- * @param {number | Pattern} amount gain.
- * @example
- * s("hh*8").gain(".4!2 1 .4!2 1 .4 1")
- *
- */
- ['gain'],
- /**
- * Like {@link gain}, but linear.
- *
- * @name amp
- * @param {number | Pattern} amount gain.
- * @superdirtOnly
- * @example
- * s("bd*8").amp(".1*2 .5 .1*2 .5 .1 .5").osc()
- *
- */
- ['amp'],
- /**
- * Amplitude envelope attack time: Specifies how long it takes for the sound to reach its peak value, relative to the onset.
- *
- * @name attack
- * @param {number | Pattern} attack time in seconds.
- * @synonyms att
- * @example
- * note("c3 e3").attack("<0 .1 .5>")
- *
- */
- ['attack', 'att'],
+ /**
+ * A pattern of numbers that speed up (or slow down) samples while they play. Currently only supported by osc / superdirt.
+ *
+ * @name accelerate
+ * @param {number | Pattern} amount acceleration.
+ * @superdirtOnly
+ * @example
+ * s("sax").accelerate("<0 1 2 4 8 16>").slow(2).osc()
+ *
+ */
+ ['accelerate'],
+ /**
+ * Controls the gain by an exponential amount.
+ *
+ * @name gain
+ * @param {number | Pattern} amount gain.
+ * @example
+ * s("hh*8").gain(".4!2 1 .4!2 1 .4 1")
+ *
+ */
+ ['gain'],
+ /**
+ * Like {@link gain}, but linear.
+ *
+ * @name amp
+ * @param {number | Pattern} amount gain.
+ * @superdirtOnly
+ * @example
+ * s("bd*8").amp(".1*2 .5 .1*2 .5 .1 .5").osc()
+ *
+ */
+ ['amp'],
+ /**
+ * Amplitude envelope attack time: Specifies how long it takes for the sound to reach its peak value, relative to the onset.
+ *
+ * @name attack
+ * @param {number | Pattern} attack time in seconds.
+ * @synonyms att
+ * @example
+ * note("c3 e3").attack("<0 .1 .5>")
+ *
+ */
+ ['attack', 'att'],
- /**
- * Sets the Frequency Modulation Harmonicity Ratio.
- * Controls the timbre of the sound.
- * Whole numbers and simple ratios sound more natural,
- * while decimal numbers and complex ratios sound metallic.
- *
- * @name fmh
- * @param {number | Pattern} harmonicity
- * @example
- * note("c e g b")
- * .fm(4)
- * .fmh("<1 2 1.5 1.61>")
- * .scope()
- *
- */
- [['fmh', 'fmi'], 'fmh'],
- /**
- * Sets the Frequency Modulation of the synth.
- * Controls the modulation index, which defines the brightness of the sound.
- *
- * @name fm
- * @param {number | Pattern} brightness modulation index
- * @synonyms fmi
- * @example
- * note("c e g b")
- * .fm("<0 1 2 8 32>")
- * .scope()
- *
- */
- [['fmi', 'fmh'], 'fm'],
- // fm envelope
- /**
- * Ramp type of fm envelope. Exp might be a bit broken..
- *
- * @name fmenv
- * @param {number | Pattern} type lin | exp
- * @example
- * note("c e g b")
- * .fm(4)
- * .fmdecay(.2)
- * .fmsustain(0)
- * .fmenv("")
- * .scope()
- *
- */
- ['fmenv'],
- /**
- * Attack time for the FM envelope: time it takes to reach maximum modulation
- *
- * @name fmattack
- * @param {number | Pattern} time attack time
- * @example
- * note("c e g b")
- * .fm(4)
- * .fmattack("<0 .05 .1 .2>")
- * .scope()
- *
- */
- ['fmattack'],
- /**
- * Decay time for the FM envelope: seconds until the sustain level is reached after the attack phase.
- *
- * @name fmdecay
- * @param {number | Pattern} time decay time
- * @example
- * note("c e g b")
- * .fm(4)
- * .fmdecay("<.01 .05 .1 .2>")
- * .fmsustain(.4)
- * .scope()
- *
- */
- ['fmdecay'],
- /**
- * Sustain level for the FM envelope: how much modulation is applied after the decay phase
- *
- * @name fmsustain
- * @param {number | Pattern} level sustain level
- * @example
- * note("c e g b")
- * .fm(4)
- * .fmdecay(.1)
- * .fmsustain("<1 .75 .5 0>")
- * .scope()
- *
- */
- ['fmsustain'],
- // these are not really useful... skipping for now
- ['fmrelease'],
- ['fmvelocity'],
+ /**
+ * Sets the Frequency Modulation Harmonicity Ratio.
+ * Controls the timbre of the sound.
+ * Whole numbers and simple ratios sound more natural,
+ * while decimal numbers and complex ratios sound metallic.
+ *
+ * @name fmh
+ * @param {number | Pattern} harmonicity
+ * @example
+ * note("c e g b")
+ * .fm(4)
+ * .fmh("<1 2 1.5 1.61>")
+ * .scope()
+ *
+ */
+ [['fmh', 'fmi'], 'fmh'],
+ /**
+ * Sets the Frequency Modulation of the synth.
+ * Controls the modulation index, which defines the brightness of the sound.
+ *
+ * @name fm
+ * @param {number | Pattern} brightness modulation index
+ * @synonyms fmi
+ * @example
+ * note("c e g b")
+ * .fm("<0 1 2 8 32>")
+ * .scope()
+ *
+ */
+ [['fmi', 'fmh'], 'fm'],
+ // fm envelope
+ /**
+ * Ramp type of fm envelope. Exp might be a bit broken..
+ *
+ * @name fmenv
+ * @param {number | Pattern} type lin | exp
+ * @example
+ * note("c e g b")
+ * .fm(4)
+ * .fmdecay(.2)
+ * .fmsustain(0)
+ * .fmenv("")
+ * .scope()
+ *
+ */
+ ['fmenv'],
+ /**
+ * Attack time for the FM envelope: time it takes to reach maximum modulation
+ *
+ * @name fmattack
+ * @param {number | Pattern} time attack time
+ * @example
+ * note("c e g b")
+ * .fm(4)
+ * .fmattack("<0 .05 .1 .2>")
+ * .scope()
+ *
+ */
+ ['fmattack'],
+ /**
+ * Decay time for the FM envelope: seconds until the sustain level is reached after the attack phase.
+ *
+ * @name fmdecay
+ * @param {number | Pattern} time decay time
+ * @example
+ * note("c e g b")
+ * .fm(4)
+ * .fmdecay("<.01 .05 .1 .2>")
+ * .fmsustain(.4)
+ * .scope()
+ *
+ */
+ ['fmdecay'],
+ /**
+ * Sustain level for the FM envelope: how much modulation is applied after the decay phase
+ *
+ * @name fmsustain
+ * @param {number | Pattern} level sustain level
+ * @example
+ * note("c e g b")
+ * .fm(4)
+ * .fmdecay(.1)
+ * .fmsustain("<1 .75 .5 0>")
+ * .scope()
+ *
+ */
+ ['fmsustain'],
+ // these are not really useful... skipping for now
+ ['fmrelease'],
+ ['fmvelocity'],
- /**
- * Select the sound bank to use. To be used together with `s`. The bank name (+ "_") will be prepended to the value of `s`.
- *
- * @name bank
- * @param {string | Pattern} bank the name of the bank
- * @example
- * s("bd sd").bank('RolandTR909') // = s("RolandTR909_bd RolandTR909_sd")
- *
- */
- ['bank'],
+ /**
+ * Select the sound bank to use. To be used together with `s`. The bank name (+ "_") will be prepended to the value of `s`.
+ *
+ * @name bank
+ * @param {string | Pattern} bank the name of the bank
+ * @example
+ * s("bd sd").bank('RolandTR909') // = s("RolandTR909_bd RolandTR909_sd")
+ *
+ */
+ ['bank'],
- ['analyze'], // analyser node send amount 0 - 1 (used by scope)
- ['fft'], // fftSize of analyser
+ ['analyze'], // analyser node send amount 0 - 1 (used by scope)
+ ['fft'], // fftSize of analyser
- /**
- * Amplitude envelope decay time: the time it takes after the attack time to reach the sustain level.
- * Note that the decay is only audible if the sustain value is lower than 1.
- *
- * @name decay
- * @param {number | Pattern} time decay time in seconds
- * @example
- * note("c3 e3").decay("<.1 .2 .3 .4>").sustain(0)
- *
- */
- ['decay'],
- /**
- * Amplitude envelope sustain level: The level which is reached after attack / decay, being sustained until the offset.
- *
- * @name sustain
- * @param {number | Pattern} gain sustain level between 0 and 1
- * @synonyms sus
- * @example
- * note("c3 e3").decay(.2).sustain("<0 .1 .4 .6 1>")
- *
- */
- ['sustain', 'sus'],
- /**
- * Amplitude envelope release time: The time it takes after the offset to go from sustain level to zero.
- *
- * @name release
- * @param {number | Pattern} time release time in seconds
- * @synonyms rel
- * @example
- * note("c3 e3 g3 c4").release("<0 .1 .4 .6 1>/2")
- *
- */
- ['release', 'rel'],
- ['hold'],
- // TODO: in tidal, it seems to be normalized
- /**
- * Sets the center frequency of the **b**and-**p**ass **f**ilter. When using mininotation, you
- * can also optionally supply the 'bpq' parameter separated by ':'.
- *
- * @name bpf
- * @param {number | Pattern} frequency center frequency
- * @synonyms bandf, bp
- * @example
- * s("bd sd,hh*3").bpf("<1000 2000 4000 8000>")
- *
- */
- [['bandf', 'bandq'], 'bpf', 'bp'],
- // TODO: in tidal, it seems to be normalized
- /**
- * Sets the **b**and-**p**ass **q**-factor (resonance).
- *
- * @name bpq
- * @param {number | Pattern} q q factor
- * @synonyms bandq
- * @example
- * s("bd sd").bpf(500).bpq("<0 1 2 3>")
- *
- */
- // currently an alias of 'bandq' https://github.com/tidalcycles/strudel/issues/496
- // ['bpq'],
- ['bandq', 'bpq'],
- /**
- * a pattern of numbers from 0 to 1. Skips the beginning of each sample, e.g. `0.25` to cut off the first quarter from each sample.
- *
- * @memberof Pattern
- * @name begin
- * @param {number | Pattern} amount between 0 and 1, where 1 is the length of the sample
- * @example
- * samples({ rave: 'rave/AREUREADY.wav' }, 'github:tidalcycles/Dirt-Samples/master/')
- * s("rave").begin("<0 .25 .5 .75>")
- *
- */
- ['begin'],
- /**
- * The same as .begin, but cuts off the end off each sample.
- *
- * @memberof Pattern
- * @name end
- * @param {number | Pattern} length 1 = whole sample, .5 = half sample, .25 = quarter sample etc..
- * @example
- * s("bd*2,oh*4").end("<.1 .2 .5 1>")
- *
- */
- ['end'],
- /**
- * Loops the sample.
- * Note that the tempo of the loop is not synced with the cycle tempo.
- * To change the loop region, use loopBegin / loopEnd.
- *
- * @name loop
- * @param {number | Pattern} on If 1, the sample is looped
- * @example
- * s("casio").loop(1)
- *
- */
- ['loop'],
- /**
- * Begin to loop at a specific point in the sample (inbetween `begin` and `end`).
- * Note that the loop point must be inbetween `begin` and `end`, and before `loopEnd`!
- * Note: Samples starting with wt_ will automatically loop! (wt = wavetable)
- *
- * @name loopBegin
- * @param {number | Pattern} time between 0 and 1, where 1 is the length of the sample
- * @synonyms loopb
- * @example
- * s("space").loop(1)
- * .loopBegin("<0 .125 .25>").scope()
- */
- ['loopBegin', 'loopb'],
- /**
- *
- * End the looping section at a specific point in the sample (inbetween `begin` and `end`).
- * Note that the loop point must be inbetween `begin` and `end`, and after `loopBegin`!
- *
- * @name loopEnd
- * @param {number | Pattern} time between 0 and 1, where 1 is the length of the sample
- * @synonyms loope
- * @example
- * s("space").loop(1)
- * .loopEnd("<1 .75 .5 .25>").scope()
- */
- ['loopEnd', 'loope'],
- /**
- * bit crusher effect.
- *
- * @name crush
- * @param {number | Pattern} depth between 1 (for drastic reduction in bit-depth) to 16 (for barely no reduction).
- * @example
- * s(",hh*3").fast(2).crush("<16 8 7 6 5 4 3 2>")
- *
- */
- // TODO: currently duplicated with "native" legato
- // TODO: superdirt legato will do more: https://youtu.be/dQPmE1WaD1k?t=419
- /**
- * a pattern of numbers from 0 to 1. Skips the beginning of each sample, e.g. `0.25` to cut off the first quarter from each sample.
- *
- * @name legato
- * @param {number | Pattern} duration between 0 and 1, where 1 is the length of the whole hap time
- * @noAutocomplete
- * @example
- * "c4 eb4 g4 bb4".legato("<0.125 .25 .5 .75 1 2 4>")
- *
- */
- // ['legato'],
- // ['clhatdecay'],
- ['crush'],
- /**
- * fake-resampling for lowering the sample rate. Caution: This effect seems to only work in chromium based browsers
- *
- * @name coarse
- * @param {number | Pattern} factor 1 for original 2 for half, 3 for a third and so on.
- * @example
- * s("bd sd,hh*4").coarse("<1 4 8 16 32>")
- *
- */
- ['coarse'],
- /**
- * choose the channel the pattern is sent to in superdirt
- *
- * @name channel
- * @param {number | Pattern} channel channel number
- *
- */
- ['channel'],
- /**
- * In the style of classic drum-machines, `cut` will stop a playing sample as soon as another samples with in same cutgroup is to be played. An example would be an open hi-hat followed by a closed one, essentially muting the open.
- *
- * @name cut
- * @param {number | Pattern} group cut group number
- * @example
- * s("rd*4").cut(1)
- *
- */
- ['cut'],
- /**
- * Applies the cutoff frequency of the **l**ow-**p**ass **f**ilter.
- *
- * When using mininotation, you can also optionally add the 'lpq' parameter, separated by ':'.
- *
- * @name lpf
- * @param {number | Pattern} frequency audible between 0 and 20000
- * @synonyms cutoff, ctf, lp
- * @example
- * s("bd sd,hh*3").lpf("<4000 2000 1000 500 200 100>")
- * @example
- * s("bd*8").lpf("1000:0 1000:10 1000:20 1000:30")
- *
- */
- [['cutoff', 'resonance'], 'ctf', 'lpf', 'lp'],
+ /**
+ * Amplitude envelope decay time: the time it takes after the attack time to reach the sustain level.
+ * Note that the decay is only audible if the sustain value is lower than 1.
+ *
+ * @name decay
+ * @param {number | Pattern} time decay time in seconds
+ * @example
+ * note("c3 e3").decay("<.1 .2 .3 .4>").sustain(0)
+ *
+ */
+ ['decay'],
+ /**
+ * Amplitude envelope sustain level: The level which is reached after attack / decay, being sustained until the offset.
+ *
+ * @name sustain
+ * @param {number | Pattern} gain sustain level between 0 and 1
+ * @synonyms sus
+ * @example
+ * note("c3 e3").decay(.2).sustain("<0 .1 .4 .6 1>")
+ *
+ */
+ ['sustain', 'sus'],
+ /**
+ * Amplitude envelope release time: The time it takes after the offset to go from sustain level to zero.
+ *
+ * @name release
+ * @param {number | Pattern} time release time in seconds
+ * @synonyms rel
+ * @example
+ * note("c3 e3 g3 c4").release("<0 .1 .4 .6 1>/2")
+ *
+ */
+ ['release', 'rel'],
+ ['hold'],
+ // TODO: in tidal, it seems to be normalized
+ /**
+ * Sets the center frequency of the **b**and-**p**ass **f**ilter. When using mininotation, you
+ * can also optionally supply the 'bpq' parameter separated by ':'.
+ *
+ * @name bpf
+ * @param {number | Pattern} frequency center frequency
+ * @synonyms bandf, bp
+ * @example
+ * s("bd sd,hh*3").bpf("<1000 2000 4000 8000>")
+ *
+ */
+ [['bandf', 'bandq'], 'bpf', 'bp'],
+ // TODO: in tidal, it seems to be normalized
+ /**
+ * Sets the **b**and-**p**ass **q**-factor (resonance).
+ *
+ * @name bpq
+ * @param {number | Pattern} q q factor
+ * @synonyms bandq
+ * @example
+ * s("bd sd").bpf(500).bpq("<0 1 2 3>")
+ *
+ */
+ // currently an alias of 'bandq' https://github.com/tidalcycles/strudel/issues/496
+ // ['bpq'],
+ ['bandq', 'bpq'],
+ /**
+ * a pattern of numbers from 0 to 1. Skips the beginning of each sample, e.g. `0.25` to cut off the first quarter from each sample.
+ *
+ * @memberof Pattern
+ * @name begin
+ * @param {number | Pattern} amount between 0 and 1, where 1 is the length of the sample
+ * @example
+ * samples({ rave: 'rave/AREUREADY.wav' }, 'github:tidalcycles/Dirt-Samples/master/')
+ * s("rave").begin("<0 .25 .5 .75>")
+ *
+ */
+ ['begin'],
+ /**
+ * The same as .begin, but cuts off the end off each sample.
+ *
+ * @memberof Pattern
+ * @name end
+ * @param {number | Pattern} length 1 = whole sample, .5 = half sample, .25 = quarter sample etc..
+ * @example
+ * s("bd*2,oh*4").end("<.1 .2 .5 1>")
+ *
+ */
+ ['end'],
+ /**
+ * Loops the sample.
+ * Note that the tempo of the loop is not synced with the cycle tempo.
+ * To change the loop region, use loopBegin / loopEnd.
+ *
+ * @name loop
+ * @param {number | Pattern} on If 1, the sample is looped
+ * @example
+ * s("casio").loop(1)
+ *
+ */
+ ['loop'],
+ /**
+ * Begin to loop at a specific point in the sample (inbetween `begin` and `end`).
+ * Note that the loop point must be inbetween `begin` and `end`, and before `loopEnd`!
+ * Note: Samples starting with wt_ will automatically loop! (wt = wavetable)
+ *
+ * @name loopBegin
+ * @param {number | Pattern} time between 0 and 1, where 1 is the length of the sample
+ * @synonyms loopb
+ * @example
+ * s("space").loop(1)
+ * .loopBegin("<0 .125 .25>").scope()
+ */
+ ['loopBegin', 'loopb'],
+ /**
+ *
+ * End the looping section at a specific point in the sample (inbetween `begin` and `end`).
+ * Note that the loop point must be inbetween `begin` and `end`, and after `loopBegin`!
+ *
+ * @name loopEnd
+ * @param {number | Pattern} time between 0 and 1, where 1 is the length of the sample
+ * @synonyms loope
+ * @example
+ * s("space").loop(1)
+ * .loopEnd("<1 .75 .5 .25>").scope()
+ */
+ ['loopEnd', 'loope'],
+ /**
+ * bit crusher effect.
+ *
+ * @name crush
+ * @param {number | Pattern} depth between 1 (for drastic reduction in bit-depth) to 16 (for barely no reduction).
+ * @example
+ * s(",hh*3").fast(2).crush("<16 8 7 6 5 4 3 2>")
+ *
+ */
+ // TODO: currently duplicated with "native" legato
+ // TODO: superdirt legato will do more: https://youtu.be/dQPmE1WaD1k?t=419
+ /**
+ * a pattern of numbers from 0 to 1. Skips the beginning of each sample, e.g. `0.25` to cut off the first quarter from each sample.
+ *
+ * @name legato
+ * @param {number | Pattern} duration between 0 and 1, where 1 is the length of the whole hap time
+ * @noAutocomplete
+ * @example
+ * "c4 eb4 g4 bb4".legato("<0.125 .25 .5 .75 1 2 4>")
+ *
+ */
+ // ['legato'],
+ // ['clhatdecay'],
+ ['crush'],
+ /**
+ * fake-resampling for lowering the sample rate. Caution: This effect seems to only work in chromium based browsers
+ *
+ * @name coarse
+ * @param {number | Pattern} factor 1 for original 2 for half, 3 for a third and so on.
+ * @example
+ * s("bd sd,hh*4").coarse("<1 4 8 16 32>")
+ *
+ */
+ ['coarse'],
+ /**
+ * choose the channel the pattern is sent to in superdirt
+ *
+ * @name channel
+ * @param {number | Pattern} channel channel number
+ *
+ */
+ ['channel'],
+ /**
+ * In the style of classic drum-machines, `cut` will stop a playing sample as soon as another samples with in same cutgroup is to be played. An example would be an open hi-hat followed by a closed one, essentially muting the open.
+ *
+ * @name cut
+ * @param {number | Pattern} group cut group number
+ * @example
+ * s("rd*4").cut(1)
+ *
+ */
+ ['cut'],
+ /**
+ * Applies the cutoff frequency of the **l**ow-**p**ass **f**ilter.
+ *
+ * When using mininotation, you can also optionally add the 'lpq' parameter, separated by ':'.
+ *
+ * @name lpf
+ * @param {number | Pattern} frequency audible between 0 and 20000
+ * @synonyms cutoff, ctf, lp
+ * @example
+ * s("bd sd,hh*3").lpf("<4000 2000 1000 500 200 100>")
+ * @example
+ * s("bd*8").lpf("1000:0 1000:10 1000:20 1000:30")
+ *
+ */
+ [['cutoff', 'resonance'], 'ctf', 'lpf', 'lp'],
- /**
- * Sets the lowpass filter envelope modulation depth.
- * @name lpenv
- * @param {number | Pattern} modulation depth of the lowpass filter envelope between 0 and _n_
- * @synonyms lpe
- * @example
- * note("")
- * .sound('sawtooth')
- * .lpf(500)
- * .lpa(.5)
- * .lpenv("<4 2 1 0 -1 -2 -4>/4")
- */
- ['lpenv', 'lpe'],
- /**
- * Sets the highpass filter envelope modulation depth.
- * @name hpenv
- * @param {number | Pattern} modulation depth of the highpass filter envelope between 0 and _n_
- * @synonyms hpe
- * @example
- * note("")
- * .sound('sawtooth')
- * .hpf(500)
- * .hpa(.5)
- * .hpenv("<4 2 1 0 -1 -2 -4>/4")
- */
- ['hpenv', 'hpe'],
- /**
- * Sets the bandpass filter envelope modulation depth.
- * @name bpenv
- * @param {number | Pattern} modulation depth of the bandpass filter envelope between 0 and _n_
- * @synonyms bpe
- * @example
- * note("")
- * .sound('sawtooth')
- * .bpf(500)
- * .bpa(.5)
- * .bpenv("<4 2 1 0 -1 -2 -4>/4")
- */
- ['bpenv', 'bpe'],
- /**
- * Sets the attack duration for the lowpass filter envelope.
- * @name lpattack
- * @param {number | Pattern} attack time of the filter envelope
- * @synonyms lpa
- * @example
- * note("")
- * .sound('sawtooth')
- * .lpf(500)
- * .lpa("<.5 .25 .1 .01>/4")
- * .lpenv(4)
- */
- ['lpattack', 'lpa'],
- /**
- * Sets the attack duration for the highpass filter envelope.
- * @name hpattack
- * @param {number | Pattern} attack time of the highpass filter envelope
- * @synonyms hpa
- * @example
- * note("")
- * .sound('sawtooth')
- * .hpf(500)
- * .hpa("<.5 .25 .1 .01>/4")
- * .hpenv(4)
- */
- ['hpattack', 'hpa'],
- /**
- * Sets the attack duration for the bandpass filter envelope.
- * @name bpattack
- * @param {number | Pattern} attack time of the bandpass filter envelope
- * @synonyms bpa
- * @example
- * note("")
- * .sound('sawtooth')
- * .bpf(500)
- * .bpa("<.5 .25 .1 .01>/4")
- * .bpenv(4)
- */
- ['bpattack', 'bpa'],
- /**
- * Sets the decay duration for the lowpass filter envelope.
- * @name lpdecay
- * @param {number | Pattern} decay time of the filter envelope
- * @synonyms lpd
- * @example
- * note("")
- * .sound('sawtooth')
- * .lpf(500)
- * .lpd("<.5 .25 .1 0>/4")
- * .lps(0.2)
- * .lpenv(4)
- */
- ['lpdecay', 'lpd'],
- /**
- * Sets the decay duration for the highpass filter envelope.
- * @name hpdecay
- * @param {number | Pattern} decay time of the highpass filter envelope
- * @synonyms hpd
- * @example
- * note("")
- * .sound('sawtooth')
- * .hpf(500)
- * .hpd("<.5 .25 .1 0>/4")
- * .hps(0.2)
- * .hpenv(4)
- */
- ['hpdecay', 'hpd'],
- /**
- * Sets the decay duration for the bandpass filter envelope.
- * @name bpdecay
- * @param {number | Pattern} decay time of the bandpass filter envelope
- * @synonyms bpd
- * @example
- * note("")
- * .sound('sawtooth')
- * .bpf(500)
- * .bpd("<.5 .25 .1 0>/4")
- * .bps(0.2)
- * .bpenv(4)
- */
- ['bpdecay', 'bpd'],
- /**
- * Sets the sustain amplitude for the lowpass filter envelope.
- * @name lpsustain
- * @param {number | Pattern} sustain amplitude of the lowpass filter envelope
- * @synonyms lps
- * @example
- * note("")
- * .sound('sawtooth')
- * .lpf(500)
- * .lpd(.5)
- * .lps("<0 .25 .5 1>/4")
- * .lpenv(4)
- */
- ['lpsustain', 'lps'],
- /**
- * Sets the sustain amplitude for the highpass filter envelope.
- * @name hpsustain
- * @param {number | Pattern} sustain amplitude of the highpass filter envelope
- * @synonyms hps
- * @example
- * note("")
- * .sound('sawtooth')
- * .hpf(500)
- * .hpd(.5)
- * .hps("<0 .25 .5 1>/4")
- * .hpenv(4)
- */
- ['hpsustain', 'hps'],
- /**
- * Sets the sustain amplitude for the bandpass filter envelope.
- * @name bpsustain
- * @param {number | Pattern} sustain amplitude of the bandpass filter envelope
- * @synonyms bps
- * @example
- * note("")
- * .sound('sawtooth')
- * .bpf(500)
- * .bpd(.5)
- * .bps("<0 .25 .5 1>/4")
- * .bpenv(4)
- */
- ['bpsustain', 'bps'],
- /**
- * Sets the release time for the lowpass filter envelope.
- * @name lprelease
- * @param {number | Pattern} release time of the filter envelope
- * @synonyms lpr
- * @example
- * note("")
- * .sound('sawtooth')
- * .clip(.5)
- * .lpf(500)
- * .lpenv(4)
- * .lpr("<.5 .25 .1 0>/4")
- * .release(.5)
- */
- ['lprelease', 'lpr'],
- /**
- * Sets the release time for the highpass filter envelope.
- * @name hprelease
- * @param {number | Pattern} release time of the highpass filter envelope
- * @synonyms hpr
- * @example
- * note("")
- * .sound('sawtooth')
- * .clip(.5)
- * .hpf(500)
- * .hpenv(4)
- * .hpr("<.5 .25 .1 0>/4")
- * .release(.5)
- */
- ['hprelease', 'hpr'],
- /**
- * Sets the release time for the bandpass filter envelope.
- * @name bprelease
- * @param {number | Pattern} release time of the bandpass filter envelope
- * @synonyms bpr
- * @example
- * note("")
- * .sound('sawtooth')
- * .clip(.5)
- * .bpf(500)
- * .bpenv(4)
- * .bpr("<.5 .25 .1 0>/4")
- * .release(.5)
- */
- ['bprelease', 'bpr'],
- /**
- * Sets the filter type. The 24db filter is more aggressive. More types might be added in the future.
- * @name ftype
- * @param {number | Pattern} type 12db (default) or 24db
- * @example
- * note("")
- * .sound('sawtooth')
- * .lpf(500)
- * .bpenv(4)
- * .ftype("<12db 24db>")
- */
- ['ftype'],
- ['fanchor'],
- /**
- * Applies the cutoff frequency of the **h**igh-**p**ass **f**ilter.
- *
- * When using mininotation, you can also optionally add the 'hpq' parameter, separated by ':'.
- *
- * @name hpf
- * @param {number | Pattern} frequency audible between 0 and 20000
- * @synonyms hp, hcutoff
- * @example
- * s("bd sd,hh*4").hpf("<4000 2000 1000 500 200 100>")
- * @example
- * s("bd sd,hh*4").hpf("<2000 2000:25>")
- *
- */
- // currently an alias of 'hcutoff' https://github.com/tidalcycles/strudel/issues/496
- // ['hpf'],
- /**
- * Applies a vibrato to the frequency of the oscillator.
- *
- * @name vib
- * @synonyms vibrato, v
- * @param {number | Pattern} frequency of the vibrato in hertz
- * @example
- * note("a")
- * .vib("<.5 1 2 4 8 16>")
- * @example
- * // change the modulation depth with ":"
- * note("a")
- * .vib("<.5 1 2 4 8 16>:12")
- */
- [['vib', 'vibmod'], 'vibrato', 'v'],
- /**
- * Sets the vibrato depth in semitones. Only has an effect if `vibrato` | `vib` | `v` is is also set
- *
- * @name vibmod
- * @synonyms vmod
- * @param {number | Pattern} depth of vibrato (in semitones)
- * @example
- * note("a").vib(4)
- * .vibmod("<.25 .5 1 2 12>")
- * @example
- * // change the vibrato frequency with ":"
- * note("a")
- * .vibmod("<.25 .5 1 2 12>:8")
- */
- [['vibmod', 'vib'], 'vmod'],
- [['hcutoff', 'hresonance'], 'hpf', 'hp'],
- /**
- * Controls the **h**igh-**p**ass **q**-value.
- *
- * @name hpq
- * @param {number | Pattern} q resonance factor between 0 and 50
- * @synonyms hresonance
- * @example
- * s("bd sd,hh*4").hpf(2000).hpq("<0 10 20 30>")
- *
- */
- ['hresonance', 'hpq'],
- /**
- * Controls the **l**ow-**p**ass **q**-value.
- *
- * @name lpq
- * @param {number | Pattern} q resonance factor between 0 and 50
- * @synonyms resonance
- * @example
- * s("bd sd,hh*4").lpf(2000).lpq("<0 10 20 30>")
- *
- */
- // currently an alias of 'resonance' https://github.com/tidalcycles/strudel/issues/496
- ['resonance', 'lpq'],
- /**
- * DJ filter, below 0.5 is low pass filter, above is high pass filter.
- *
- * @name djf
- * @param {number | Pattern} cutoff below 0.5 is low pass filter, above is high pass filter
- * @example
- * n("0 3 7 [10,24]").s('superzow').octave(3).djf("<.5 .25 .5 .75>").osc()
- *
- */
- ['djf'],
- // ['cutoffegint'],
- // TODO: does not seem to work
- /**
- * Sets the level of the delay signal.
- *
- * When using mininotation, you can also optionally add the 'delaytime' and 'delayfeedback' parameter,
- * separated by ':'.
- *
- *
- * @name delay
- * @param {number | Pattern} level between 0 and 1
- * @example
- * s("bd").delay("<0 .25 .5 1>")
- * @example
- * s("bd bd").delay("0.65:0.25:0.9 0.65:0.125:0.7")
- *
- */
- [['delay', 'delaytime', 'delayfeedback']],
- /**
- * Sets the level of the signal that is fed back into the delay.
- * Caution: Values >= 1 will result in a signal that gets louder and louder! Don't do it
- *
- * @name delayfeedback
- * @param {number | Pattern} feedback between 0 and 1
- * @synonyms delayfb, dfb
- * @example
- * s("bd").delay(.25).delayfeedback("<.25 .5 .75 1>").slow(2)
- *
- */
- ['delayfeedback', 'delayfb', 'dfb'],
- /**
- * Sets the time of the delay effect.
- *
- * @name delaytime
- * @param {number | Pattern} seconds between 0 and Infinity
- * @synonyms delayt, dt
- * @example
- * s("bd").delay(.25).delaytime("<.125 .25 .5 1>").slow(2)
- *
- */
- ['delaytime', 'delayt', 'dt'],
- /* // TODO: test
- * Specifies whether delaytime is calculated relative to cps.
- *
- * @name lock
- * @param {number | Pattern} enable When set to 1, delaytime is a direct multiple of a cycle.
- * @example
- * s("sd").delay().lock(1).osc()
- *
- */
- ['lock'],
- /**
- * Set detune of oscillators. Works only with some synths, see tidal doc
- *
- * @name detune
- * @param {number | Pattern} amount between 0 and 1
- * @synonyms det
- * @superdirtOnly
- * @example
- * n("0 3 7").s('superzow').octave(3).detune("<0 .25 .5 1 2>").osc()
- *
- */
- ['detune', 'det'],
- /**
- * Set dryness of reverb. See {@link room} and {@link size} for more information about reverb.
- *
- * @name dry
- * @param {number | Pattern} dry 0 = wet, 1 = dry
- * @example
- * n("[0,3,7](3,8)").s("superpiano").room(.7).dry("<0 .5 .75 1>").osc()
- * @superdirtOnly
- *
- */
- ['dry'],
- // TODO: does not seem to do anything
- /*
- * Used when using {@link begin}/{@link end} or {@link chop}/{@link striate} and friends, to change the fade out time of the 'grain' envelope.
- *
- * @name fadeTime
- * @param {number | Pattern} time between 0 and 1
- * @example
- * s("oh*4").end(.1).fadeTime("<0 .2 .4 .8>").osc()
- *
- */
- ['fadeTime', 'fadeOutTime'],
- // TODO: see above
- ['fadeInTime'],
- /**
- * Set frequency of sound.
- *
- * @name freq
- * @param {number | Pattern} frequency in Hz. the audible range is between 20 and 20000 Hz
- * @example
- * freq("220 110 440 110").s("superzow").osc()
- * @example
- * freq("110".mul.out(".5 1.5 .6 [2 3]")).s("superzow").osc()
- *
- */
- ['freq'],
- // TODO: https://tidalcycles.org/docs/configuration/MIDIOSC/control-voltage/#gate
- ['gate', 'gat'],
- // ['hatgrain'],
- // ['lagogo'],
- // ['lclap'],
- // ['lclaves'],
- // ['lclhat'],
- // ['lcrash'],
- // TODO:
- // https://tidalcycles.org/docs/reference/audio_effects/#leslie-1
- // https://tidalcycles.org/docs/reference/audio_effects/#leslie
- /**
- * Emulation of a Leslie speaker: speakers rotating in a wooden amplified cabinet.
- *
- * @name leslie
- * @param {number | Pattern} wet between 0 and 1
- * @example
- * n("0,4,7").s("supersquare").leslie("<0 .4 .6 1>").osc()
- * @superdirtOnly
- *
- */
- ['leslie'],
- /**
- * Rate of modulation / rotation for leslie effect
- *
- * @name lrate
- * @param {number | Pattern} rate 6.7 for fast, 0.7 for slow
- * @example
- * n("0,4,7").s("supersquare").leslie(1).lrate("<1 2 4 8>").osc()
- * @superdirtOnly
- *
- */
- // TODO: the rate seems to "lag" (in the example, 1 will be fast)
- ['lrate'],
- /**
- * Physical size of the cabinet in meters. Be careful, it might be slightly larger than your computer. Affects the Doppler amount (pitch warble)
- *
- * @name lsize
- * @param {number | Pattern} meters somewhere between 0 and 1
- * @example
- * n("0,4,7").s("supersquare").leslie(1).lrate(2).lsize("<.1 .5 1>").osc()
- * @superdirtOnly
- *
- */
- ['lsize'],
- // label for pianoroll
- ['activeLabel'],
- [['label', 'activeLabel']],
- // ['lfo'],
- // ['lfocutoffint'],
- // ['lfodelay'],
- // ['lfoint'],
- // ['lfopitchint'],
- // ['lfoshape'],
- // ['lfosync'],
- // ['lhitom'],
- // ['lkick'],
- // ['llotom'],
- // ['lophat'],
- // ['lsnare'],
- ['degree'], // TODO: what is this? not found in tidal doc
- ['mtranspose'], // TODO: what is this? not found in tidal doc
- ['ctranspose'], // TODO: what is this? not found in tidal doc
- ['harmonic'], // TODO: what is this? not found in tidal doc
- ['stepsPerOctave'], // TODO: what is this? not found in tidal doc
- ['octaveR'], // TODO: what is this? not found in tidal doc
- // TODO: why is this needed? what's the difference to late / early? Answer: it's in seconds, and delays the message at
- // OSC time (so can't be negative, at least not beyond the latency value)
- ['nudge'],
- // TODO: the following doc is just a guess, it's not documented in tidal doc.
- /**
- * Sets the default octave of a synth.
- *
- * @name octave
- * @param {number | Pattern} octave octave number
- * @example
- * n("0,4,7").s('supersquare').octave("<3 4 5 6>").osc()
- * @superDirtOnly
- */
- ['octave'],
+ /**
+ * Sets the lowpass filter envelope modulation depth.
+ * @name lpenv
+ * @param {number | Pattern} modulation depth of the lowpass filter envelope between 0 and _n_
+ * @synonyms lpe
+ * @example
+ * note("")
+ * .sound('sawtooth')
+ * .lpf(500)
+ * .lpa(.5)
+ * .lpenv("<4 2 1 0 -1 -2 -4>/4")
+ */
+ ['lpenv', 'lpe'],
+ /**
+ * Sets the highpass filter envelope modulation depth.
+ * @name hpenv
+ * @param {number | Pattern} modulation depth of the highpass filter envelope between 0 and _n_
+ * @synonyms hpe
+ * @example
+ * note("")
+ * .sound('sawtooth')
+ * .hpf(500)
+ * .hpa(.5)
+ * .hpenv("<4 2 1 0 -1 -2 -4>/4")
+ */
+ ['hpenv', 'hpe'],
+ /**
+ * Sets the bandpass filter envelope modulation depth.
+ * @name bpenv
+ * @param {number | Pattern} modulation depth of the bandpass filter envelope between 0 and _n_
+ * @synonyms bpe
+ * @example
+ * note("")
+ * .sound('sawtooth')
+ * .bpf(500)
+ * .bpa(.5)
+ * .bpenv("<4 2 1 0 -1 -2 -4>/4")
+ */
+ ['bpenv', 'bpe'],
+ /**
+ * Sets the attack duration for the lowpass filter envelope.
+ * @name lpattack
+ * @param {number | Pattern} attack time of the filter envelope
+ * @synonyms lpa
+ * @example
+ * note("")
+ * .sound('sawtooth')
+ * .lpf(500)
+ * .lpa("<.5 .25 .1 .01>/4")
+ * .lpenv(4)
+ */
+ ['lpattack', 'lpa'],
+ /**
+ * Sets the attack duration for the highpass filter envelope.
+ * @name hpattack
+ * @param {number | Pattern} attack time of the highpass filter envelope
+ * @synonyms hpa
+ * @example
+ * note("")
+ * .sound('sawtooth')
+ * .hpf(500)
+ * .hpa("<.5 .25 .1 .01>/4")
+ * .hpenv(4)
+ */
+ ['hpattack', 'hpa'],
+ /**
+ * Sets the attack duration for the bandpass filter envelope.
+ * @name bpattack
+ * @param {number | Pattern} attack time of the bandpass filter envelope
+ * @synonyms bpa
+ * @example
+ * note("")
+ * .sound('sawtooth')
+ * .bpf(500)
+ * .bpa("<.5 .25 .1 .01>/4")
+ * .bpenv(4)
+ */
+ ['bpattack', 'bpa'],
+ /**
+ * Sets the decay duration for the lowpass filter envelope.
+ * @name lpdecay
+ * @param {number | Pattern} decay time of the filter envelope
+ * @synonyms lpd
+ * @example
+ * note("")
+ * .sound('sawtooth')
+ * .lpf(500)
+ * .lpd("<.5 .25 .1 0>/4")
+ * .lps(0.2)
+ * .lpenv(4)
+ */
+ ['lpdecay', 'lpd'],
+ /**
+ * Sets the decay duration for the highpass filter envelope.
+ * @name hpdecay
+ * @param {number | Pattern} decay time of the highpass filter envelope
+ * @synonyms hpd
+ * @example
+ * note("")
+ * .sound('sawtooth')
+ * .hpf(500)
+ * .hpd("<.5 .25 .1 0>/4")
+ * .hps(0.2)
+ * .hpenv(4)
+ */
+ ['hpdecay', 'hpd'],
+ /**
+ * Sets the decay duration for the bandpass filter envelope.
+ * @name bpdecay
+ * @param {number | Pattern} decay time of the bandpass filter envelope
+ * @synonyms bpd
+ * @example
+ * note("")
+ * .sound('sawtooth')
+ * .bpf(500)
+ * .bpd("<.5 .25 .1 0>/4")
+ * .bps(0.2)
+ * .bpenv(4)
+ */
+ ['bpdecay', 'bpd'],
+ /**
+ * Sets the sustain amplitude for the lowpass filter envelope.
+ * @name lpsustain
+ * @param {number | Pattern} sustain amplitude of the lowpass filter envelope
+ * @synonyms lps
+ * @example
+ * note("")
+ * .sound('sawtooth')
+ * .lpf(500)
+ * .lpd(.5)
+ * .lps("<0 .25 .5 1>/4")
+ * .lpenv(4)
+ */
+ ['lpsustain', 'lps'],
+ /**
+ * Sets the sustain amplitude for the highpass filter envelope.
+ * @name hpsustain
+ * @param {number | Pattern} sustain amplitude of the highpass filter envelope
+ * @synonyms hps
+ * @example
+ * note("")
+ * .sound('sawtooth')
+ * .hpf(500)
+ * .hpd(.5)
+ * .hps("<0 .25 .5 1>/4")
+ * .hpenv(4)
+ */
+ ['hpsustain', 'hps'],
+ /**
+ * Sets the sustain amplitude for the bandpass filter envelope.
+ * @name bpsustain
+ * @param {number | Pattern} sustain amplitude of the bandpass filter envelope
+ * @synonyms bps
+ * @example
+ * note("")
+ * .sound('sawtooth')
+ * .bpf(500)
+ * .bpd(.5)
+ * .bps("<0 .25 .5 1>/4")
+ * .bpenv(4)
+ */
+ ['bpsustain', 'bps'],
+ /**
+ * Sets the release time for the lowpass filter envelope.
+ * @name lprelease
+ * @param {number | Pattern} release time of the filter envelope
+ * @synonyms lpr
+ * @example
+ * note("")
+ * .sound('sawtooth')
+ * .clip(.5)
+ * .lpf(500)
+ * .lpenv(4)
+ * .lpr("<.5 .25 .1 0>/4")
+ * .release(.5)
+ */
+ ['lprelease', 'lpr'],
+ /**
+ * Sets the release time for the highpass filter envelope.
+ * @name hprelease
+ * @param {number | Pattern} release time of the highpass filter envelope
+ * @synonyms hpr
+ * @example
+ * note("")
+ * .sound('sawtooth')
+ * .clip(.5)
+ * .hpf(500)
+ * .hpenv(4)
+ * .hpr("<.5 .25 .1 0>/4")
+ * .release(.5)
+ */
+ ['hprelease', 'hpr'],
+ /**
+ * Sets the release time for the bandpass filter envelope.
+ * @name bprelease
+ * @param {number | Pattern} release time of the bandpass filter envelope
+ * @synonyms bpr
+ * @example
+ * note("")
+ * .sound('sawtooth')
+ * .clip(.5)
+ * .bpf(500)
+ * .bpenv(4)
+ * .bpr("<.5 .25 .1 0>/4")
+ * .release(.5)
+ */
+ ['bprelease', 'bpr'],
+ /**
+ * Sets the filter type. The 24db filter is more aggressive. More types might be added in the future.
+ * @name ftype
+ * @param {number | Pattern} type 12db (default) or 24db
+ * @example
+ * note("")
+ * .sound('sawtooth')
+ * .lpf(500)
+ * .bpenv(4)
+ * .ftype("<12db 24db>")
+ */
+ ['ftype'],
+ ['fanchor'],
+ /**
+ * Applies the cutoff frequency of the **h**igh-**p**ass **f**ilter.
+ *
+ * When using mininotation, you can also optionally add the 'hpq' parameter, separated by ':'.
+ *
+ * @name hpf
+ * @param {number | Pattern} frequency audible between 0 and 20000
+ * @synonyms hp, hcutoff
+ * @example
+ * s("bd sd,hh*4").hpf("<4000 2000 1000 500 200 100>")
+ * @example
+ * s("bd sd,hh*4").hpf("<2000 2000:25>")
+ *
+ */
+ // currently an alias of 'hcutoff' https://github.com/tidalcycles/strudel/issues/496
+ // ['hpf'],
+ /**
+ * Applies a vibrato to the frequency of the oscillator.
+ *
+ * @name vib
+ * @synonyms vibrato, v
+ * @param {number | Pattern} frequency of the vibrato in hertz
+ * @example
+ * note("a")
+ * .vib("<.5 1 2 4 8 16>")
+ * @example
+ * // change the modulation depth with ":"
+ * note("a")
+ * .vib("<.5 1 2 4 8 16>:12")
+ */
+ [['vib', 'vibmod'], 'vibrato', 'v'],
+ /**
+ * Sets the vibrato depth in semitones. Only has an effect if `vibrato` | `vib` | `v` is is also set
+ *
+ * @name vibmod
+ * @synonyms vmod
+ * @param {number | Pattern} depth of vibrato (in semitones)
+ * @example
+ * note("a").vib(4)
+ * .vibmod("<.25 .5 1 2 12>")
+ * @example
+ * // change the vibrato frequency with ":"
+ * note("a")
+ * .vibmod("<.25 .5 1 2 12>:8")
+ */
+ [['vibmod', 'vib'], 'vmod'],
+ [['hcutoff', 'hresonance'], 'hpf', 'hp'],
+ /**
+ * Controls the **h**igh-**p**ass **q**-value.
+ *
+ * @name hpq
+ * @param {number | Pattern} q resonance factor between 0 and 50
+ * @synonyms hresonance
+ * @example
+ * s("bd sd,hh*4").hpf(2000).hpq("<0 10 20 30>")
+ *
+ */
+ ['hresonance', 'hpq'],
+ /**
+ * Controls the **l**ow-**p**ass **q**-value.
+ *
+ * @name lpq
+ * @param {number | Pattern} q resonance factor between 0 and 50
+ * @synonyms resonance
+ * @example
+ * s("bd sd,hh*4").lpf(2000).lpq("<0 10 20 30>")
+ *
+ */
+ // currently an alias of 'resonance' https://github.com/tidalcycles/strudel/issues/496
+ ['resonance', 'lpq'],
+ /**
+ * DJ filter, below 0.5 is low pass filter, above is high pass filter.
+ *
+ * @name djf
+ * @param {number | Pattern} cutoff below 0.5 is low pass filter, above is high pass filter
+ * @example
+ * n("0 3 7 [10,24]").s('superzow').octave(3).djf("<.5 .25 .5 .75>").osc()
+ *
+ */
+ ['djf'],
+ // ['cutoffegint'],
+ // TODO: does not seem to work
+ /**
+ * Sets the level of the delay signal.
+ *
+ * When using mininotation, you can also optionally add the 'delaytime' and 'delayfeedback' parameter,
+ * separated by ':'.
+ *
+ *
+ * @name delay
+ * @param {number | Pattern} level between 0 and 1
+ * @example
+ * s("bd").delay("<0 .25 .5 1>")
+ * @example
+ * s("bd bd").delay("0.65:0.25:0.9 0.65:0.125:0.7")
+ *
+ */
+ [['delay', 'delaytime', 'delayfeedback']],
+ /**
+ * Sets the level of the signal that is fed back into the delay.
+ * Caution: Values >= 1 will result in a signal that gets louder and louder! Don't do it
+ *
+ * @name delayfeedback
+ * @param {number | Pattern} feedback between 0 and 1
+ * @synonyms delayfb, dfb
+ * @example
+ * s("bd").delay(.25).delayfeedback("<.25 .5 .75 1>").slow(2)
+ *
+ */
+ ['delayfeedback', 'delayfb', 'dfb'],
+ /**
+ * Sets the time of the delay effect.
+ *
+ * @name delaytime
+ * @param {number | Pattern} seconds between 0 and Infinity
+ * @synonyms delayt, dt
+ * @example
+ * s("bd").delay(.25).delaytime("<.125 .25 .5 1>").slow(2)
+ *
+ */
+ ['delaytime', 'delayt', 'dt'],
+ /* // TODO: test
+ * Specifies whether delaytime is calculated relative to cps.
+ *
+ * @name lock
+ * @param {number | Pattern} enable When set to 1, delaytime is a direct multiple of a cycle.
+ * @example
+ * s("sd").delay().lock(1).osc()
+ *
+ */
+ ['lock'],
+ /**
+ * Set detune of oscillators. Works only with some synths, see tidal doc
+ *
+ * @name detune
+ * @param {number | Pattern} amount between 0 and 1
+ * @synonyms det
+ * @superdirtOnly
+ * @example
+ * n("0 3 7").s('superzow').octave(3).detune("<0 .25 .5 1 2>").osc()
+ *
+ */
+ ['detune', 'det'],
+ /**
+ * Set dryness of reverb. See {@link room} and {@link size} for more information about reverb.
+ *
+ * @name dry
+ * @param {number | Pattern} dry 0 = wet, 1 = dry
+ * @example
+ * n("[0,3,7](3,8)").s("superpiano").room(.7).dry("<0 .5 .75 1>").osc()
+ * @superdirtOnly
+ *
+ */
+ ['dry'],
+ // TODO: does not seem to do anything
+ /*
+ * Used when using {@link begin}/{@link end} or {@link chop}/{@link striate} and friends, to change the fade out time of the 'grain' envelope.
+ *
+ * @name fadeTime
+ * @param {number | Pattern} time between 0 and 1
+ * @example
+ * s("oh*4").end(.1).fadeTime("<0 .2 .4 .8>").osc()
+ *
+ */
+ ['fadeTime', 'fadeOutTime'],
+ // TODO: see above
+ ['fadeInTime'],
+ /**
+ * Set frequency of sound.
+ *
+ * @name freq
+ * @param {number | Pattern} frequency in Hz. the audible range is between 20 and 20000 Hz
+ * @example
+ * freq("220 110 440 110").s("superzow").osc()
+ * @example
+ * freq("110".mul.out(".5 1.5 .6 [2 3]")).s("superzow").osc()
+ *
+ */
+ ['freq'],
+ // TODO: https://tidalcycles.org/docs/configuration/MIDIOSC/control-voltage/#gate
+ ['gate', 'gat'],
+ // ['hatgrain'],
+ // ['lagogo'],
+ // ['lclap'],
+ // ['lclaves'],
+ // ['lclhat'],
+ // ['lcrash'],
+ // TODO:
+ // https://tidalcycles.org/docs/reference/audio_effects/#leslie-1
+ // https://tidalcycles.org/docs/reference/audio_effects/#leslie
+ /**
+ * Emulation of a Leslie speaker: speakers rotating in a wooden amplified cabinet.
+ *
+ * @name leslie
+ * @param {number | Pattern} wet between 0 and 1
+ * @example
+ * n("0,4,7").s("supersquare").leslie("<0 .4 .6 1>").osc()
+ * @superdirtOnly
+ *
+ */
+ ['leslie'],
+ /**
+ * Rate of modulation / rotation for leslie effect
+ *
+ * @name lrate
+ * @param {number | Pattern} rate 6.7 for fast, 0.7 for slow
+ * @example
+ * n("0,4,7").s("supersquare").leslie(1).lrate("<1 2 4 8>").osc()
+ * @superdirtOnly
+ *
+ */
+ // TODO: the rate seems to "lag" (in the example, 1 will be fast)
+ ['lrate'],
+ /**
+ * Physical size of the cabinet in meters. Be careful, it might be slightly larger than your computer. Affects the Doppler amount (pitch warble)
+ *
+ * @name lsize
+ * @param {number | Pattern} meters somewhere between 0 and 1
+ * @example
+ * n("0,4,7").s("supersquare").leslie(1).lrate(2).lsize("<.1 .5 1>").osc()
+ * @superdirtOnly
+ *
+ */
+ ['lsize'],
+ // label for pianoroll
+ ['activeLabel'],
+ [['label', 'activeLabel']],
+ // ['lfo'],
+ // ['lfocutoffint'],
+ // ['lfodelay'],
+ // ['lfoint'],
+ // ['lfopitchint'],
+ // ['lfoshape'],
+ // ['lfosync'],
+ // ['lhitom'],
+ // ['lkick'],
+ // ['llotom'],
+ // ['lophat'],
+ // ['lsnare'],
+ ['degree'], // TODO: what is this? not found in tidal doc
+ ['mtranspose'], // TODO: what is this? not found in tidal doc
+ ['ctranspose'], // TODO: what is this? not found in tidal doc
+ ['harmonic'], // TODO: what is this? not found in tidal doc
+ ['stepsPerOctave'], // TODO: what is this? not found in tidal doc
+ ['octaveR'], // TODO: what is this? not found in tidal doc
+ // TODO: why is this needed? what's the difference to late / early? Answer: it's in seconds, and delays the message at
+ // OSC time (so can't be negative, at least not beyond the latency value)
+ ['nudge'],
+ // TODO: the following doc is just a guess, it's not documented in tidal doc.
+ /**
+ * Sets the default octave of a synth.
+ *
+ * @name octave
+ * @param {number | Pattern} octave octave number
+ * @example
+ * n("0,4,7").s('supersquare').octave("<3 4 5 6>").osc()
+ * @superDirtOnly
+ */
+ ['octave'],
- // ['ophatdecay'],
- // TODO: example
- /**
- * An `orbit` is a global parameter context for patterns. Patterns with the same orbit will share the same global effects.
- *
- * @name orbit
- * @param {number | Pattern} number
- * @example
- * stack(
- * s("hh*3").delay(.5).delaytime(.25).orbit(1),
- * s("~ sd").delay(.5).delaytime(.125).orbit(2)
- * )
- */
- ['orbit'],
- ['overgain'], // TODO: what is this? not found in tidal doc Answer: gain is limited to maximum of 2. This allows you to go over that
- ['overshape'], // TODO: what is this? not found in tidal doc. Similar to above, but limited to 1
- /**
- * Sets position in stereo.
- *
- * @name pan
- * @param {number | Pattern} pan between 0 and 1, from left to right (assuming stereo), once round a circle (assuming multichannel)
- * @example
- * s("[bd hh]*2").pan("<.5 1 .5 0>")
- *
- */
- ['pan'],
- // TODO: this has no effect (see example)
- /*
- * Controls how much multichannel output is fanned out
- *
- * @name panspan
- * @param {number | Pattern} span between -inf and inf, negative is backwards ordering
- * @example
- * s("[bd hh]*2").pan("<.5 1 .5 0>").panspan("<0 .5 1>").osc()
- *
- */
- ['panspan'],
- // TODO: this has no effect (see example)
- /*
- * Controls how much multichannel output is spread
- *
- * @name pansplay
- * @param {number | Pattern} spread between 0 and 1
- * @example
- * s("[bd hh]*2").pan("<.5 1 .5 0>").pansplay("<0 .5 1>").osc()
- *
- */
- ['pansplay'],
- ['panwidth'],
- ['panorient'],
- // ['pitch1'],
- // ['pitch2'],
- // ['pitch3'],
- // ['portamento'],
- // TODO: LFO rate see https://tidalcycles.org/docs/patternlib/tutorials/synthesizers/#supersquare
- ['rate'],
- // TODO: slide param for certain synths
- ['slide'],
- // TODO: detune? https://tidalcycles.org/docs/patternlib/tutorials/synthesizers/#supersquare
- ['semitone'],
- // TODO: dedup with synth param, see https://tidalcycles.org/docs/reference/synthesizers/#superpiano
- // ['velocity'],
- ['voice'], // TODO: synth param
+ // ['ophatdecay'],
+ // TODO: example
+ /**
+ * An `orbit` is a global parameter context for patterns. Patterns with the same orbit will share the same global effects.
+ *
+ * @name orbit
+ * @param {number | Pattern} number
+ * @example
+ * stack(
+ * s("hh*3").delay(.5).delaytime(.25).orbit(1),
+ * s("~ sd").delay(.5).delaytime(.125).orbit(2)
+ * )
+ */
+ ['orbit'],
+ ['overgain'], // TODO: what is this? not found in tidal doc Answer: gain is limited to maximum of 2. This allows you to go over that
+ ['overshape'], // TODO: what is this? not found in tidal doc. Similar to above, but limited to 1
+ /**
+ * Sets position in stereo.
+ *
+ * @name pan
+ * @param {number | Pattern} pan between 0 and 1, from left to right (assuming stereo), once round a circle (assuming multichannel)
+ * @example
+ * s("[bd hh]*2").pan("<.5 1 .5 0>")
+ *
+ */
+ ['pan'],
+ // TODO: this has no effect (see example)
+ /*
+ * Controls how much multichannel output is fanned out
+ *
+ * @name panspan
+ * @param {number | Pattern} span between -inf and inf, negative is backwards ordering
+ * @example
+ * s("[bd hh]*2").pan("<.5 1 .5 0>").panspan("<0 .5 1>").osc()
+ *
+ */
+ ['panspan'],
+ // TODO: this has no effect (see example)
+ /*
+ * Controls how much multichannel output is spread
+ *
+ * @name pansplay
+ * @param {number | Pattern} spread between 0 and 1
+ * @example
+ * s("[bd hh]*2").pan("<.5 1 .5 0>").pansplay("<0 .5 1>").osc()
+ *
+ */
+ ['pansplay'],
+ ['panwidth'],
+ ['panorient'],
+ // ['pitch1'],
+ // ['pitch2'],
+ // ['pitch3'],
+ // ['portamento'],
+ // TODO: LFO rate see https://tidalcycles.org/docs/patternlib/tutorials/synthesizers/#supersquare
+ ['rate'],
+ // TODO: slide param for certain synths
+ ['slide'],
+ // TODO: detune? https://tidalcycles.org/docs/patternlib/tutorials/synthesizers/#supersquare
+ ['semitone'],
+ // TODO: dedup with synth param, see https://tidalcycles.org/docs/reference/synthesizers/#superpiano
+ // ['velocity'],
+ ['voice'], // TODO: synth param
- // voicings // https://github.com/tidalcycles/strudel/issues/506
- ['chord'], // chord to voice, like C Eb Fm7 G7. the symbols can be defined via addVoicings
- ['dictionary', 'dict'], // which dictionary to use for the voicings
- ['anchor'], // the top note to align the voicing to, defaults to c5
- ['offset'], // how the voicing is offset from the anchored position
- ['octaves'], // how many octaves are voicing steps spread apart, defaults to 1
- [['mode', 'anchor']], // below = anchor note will be removed from the voicing, useful for melody harmonization
+ // voicings // https://github.com/tidalcycles/strudel/issues/506
+ ['chord'], // chord to voice, like C Eb Fm7 G7. the symbols can be defined via addVoicings
+ ['dictionary', 'dict'], // which dictionary to use for the voicings
+ ['anchor'], // the top note to align the voicing to, defaults to c5
+ ['offset'], // how the voicing is offset from the anchored position
+ ['octaves'], // how many octaves are voicing steps spread apart, defaults to 1
+ [['mode', 'anchor']], // below = anchor note will be removed from the voicing, useful for melody harmonization
- /**
- * Sets the level of reverb.
- *
- * When using mininotation, you can also optionally add the 'size' parameter, separated by ':'.
- *
- * @name room
- * @param {number | Pattern} level between 0 and 1
- * @example
- * s("bd sd").room("<0 .2 .4 .6 .8 1>")
- * @example
- * s("bd sd").room("<0.9:1 0.9:4>")
- *
- */
- [['room', 'size']],
- /**
- * Sets the room size of the reverb, see {@link room}.
- *
- * @name roomsize
- * @param {number | Pattern} size between 0 and 10
- * @synonyms size, sz
- * @example
- * s("bd sd").room(.8).roomsize("<0 1 2 4 8>")
- *
- */
- // TODO: find out why :
- // s("bd sd").room(.8).roomsize("<0 .2 .4 .6 .8 [1,0]>").osc()
- // .. does not work. Is it because room is only one effect?
- ['size', 'sz', 'roomsize'],
- // ['sagogo'],
- // ['sclap'],
- // ['sclaves'],
- // ['scrash'],
- /**
- * Wave shaping distortion. CAUTION: it might get loud
- *
- * @name shape
- * @param {number | Pattern} distortion between 0 and 1
- * @example
- * s("bd sd,hh*4").shape("<0 .2 .4 .6 .8>")
- *
- */
- ['shape'],
- /**
- * Changes the speed of sample playback, i.e. a cheap way of changing pitch.
- *
- * @name speed
- * @param {number | Pattern} speed -inf to inf, negative numbers play the sample backwards.
- * @example
- * s("bd").speed("<1 2 4 1 -2 -4>")
- * @example
- * speed("1 1.5*2 [2 1.1]").s("piano").clip(1)
- *
- */
- ['speed'],
- /**
- * Used in conjunction with {@link speed}, accepts values of "r" (rate, default behavior), "c" (cycles), or "s" (seconds). Using `unit "c"` means `speed` will be interpreted in units of cycles, e.g. `speed "1"` means samples will be stretched to fill a cycle. Using `unit "s"` means the playback speed will be adjusted so that the duration is the number of seconds specified by `speed`.
- *
- * @name unit
- * @param {number | string | Pattern} unit see description above
- * @example
- * speed("1 2 .5 3").s("bd").unit("c").osc()
- * @superdirtOnly
- *
- */
- ['unit'],
- /**
- * Made by Calum Gunn. Reminiscent of some weird mixture of filter, ring-modulator and pitch-shifter. The SuperCollider manual defines Squiz as:
- *
- * "A simplistic pitch-raising algorithm. It's not meant to sound natural; its sound is reminiscent of some weird mixture of filter, ring-modulator and pitch-shifter, depending on the input. The algorithm works by cutting the signal into fragments (delimited by upwards-going zero-crossings) and squeezing those fragments in the time domain (i.e. simply playing them back faster than they came in), leaving silences inbetween. All the parameters apart from memlen can be modulated."
- *
- * @name squiz
- * @param {number | Pattern} squiz Try passing multiples of 2 to it - 2, 4, 8 etc.
- * @example
- * squiz("2 4/2 6 [8 16]").s("bd").osc()
- * @superdirtOnly
- *
- */
- ['squiz'],
- // ['stutterdepth'], // TODO: what is this? not found in tidal doc
- // ['stuttertime'], // TODO: what is this? not found in tidal doc
- // ['timescale'], // TODO: what is this? not found in tidal doc
- // ['timescalewin'], // TODO: what is this? not found in tidal doc
- // ['tomdecay'],
- // ['vcfegint'],
- // ['vcoegint'],
- // TODO: Use a rest (~) to override the effect <- vowel
- /**
- *
- * Formant filter to make things sound like vowels.
- *
- * @name vowel
- * @param {string | Pattern} vowel You can use a e i o u.
- * @example
- * note("c2 >").s('sawtooth')
- * .vowel(">")
- *
- */
- ['vowel'],
- /* // TODO: find out how it works
- * Made by Calum Gunn. Divides an audio stream into tiny segments, using the signal's zero-crossings as segment boundaries, and discards a fraction of them. Takes a number between 1 and 100, denoted the percentage of segments to drop. The SuperCollider manual describes the Waveloss effect this way:
- *
- * Divide an audio stream into tiny segments, using the signal's zero-crossings as segment boundaries, and discard a fraction of them (i.e. replace them with silence of the same length). The technique was described by Trevor Wishart in a lecture. Parameters: the filter drops drop out of out of chunks. mode can be 1 to drop chunks in a simple deterministic fashion (e.g. always dropping the first 30 out of a set of 40 segments), or 2 to drop chunks randomly but in an appropriate proportion.)
- *
- * mode: ?
- * waveloss: ?
- *
- * @name waveloss
- */
- ['waveloss'],
- // TODO: midi effects?
- ['dur'],
- // ['modwheel'],
- ['expression'],
- ['sustainpedal'],
- /* // TODO: doesn't seem to do anything
- *
- * Tremolo Audio DSP effect
- *
- * @name tremolodepth
- * @param {number | Pattern} depth between 0 and 1
- * @example
- * n("0,4,7").tremolodepth("<0 .3 .6 .9>").osc()
- *
- */
- ['tremolodepth', 'tremdp'],
- ['tremolorate', 'tremr'],
- // TODO: doesn't seem to do anything
- ['phaserdepth', 'phasdp'],
- ['phaserrate', 'phasr'],
+ /**
+ * Sets the level of reverb.
+ *
+ * When using mininotation, you can also optionally add the 'size' parameter, separated by ':'.
+ *
+ * @name room
+ * @param {number | Pattern} level between 0 and 1
+ * @example
+ * s("bd sd").room("<0 .2 .4 .6 .8 1>")
+ * @example
+ * s("bd sd").room("<0.9:1 0.9:4>")
+ *
+ */
+ [['room', 'size']],
+ /**
+ * Sets the room size of the reverb, see {@link room}.
+ *
+ * @name roomsize
+ * @param {number | Pattern} size between 0 and 10
+ * @synonyms size, sz
+ * @example
+ * s("bd sd").room(.8).roomsize("<0 1 2 4 8>")
+ *
+ */
+ // TODO: find out why :
+ // s("bd sd").room(.8).roomsize("<0 .2 .4 .6 .8 [1,0]>").osc()
+ // .. does not work. Is it because room is only one effect?
+ ['size', 'sz', 'roomsize'],
+ // ['sagogo'],
+ // ['sclap'],
+ // ['sclaves'],
+ // ['scrash'],
- ['fshift'],
- ['fshiftnote'],
- ['fshiftphase'],
+ /**
+ * Sets the sample to use as an impulse response for the reverb.
+ *
+ * @name iresponse
+ * @param {string | Pattern} Sets the impulse response
+ * @example
+ * s("bd sd").room(.8).ir("")
+ *
+ */
+ [['ir', 'i'], 'iresponse'],
+ /**
+ * Wave shaping distortion. CAUTION: it might get loud
+ *
+ * @name shape
+ * @param {number | Pattern} distortion between 0 and 1
+ * @example
+ * s("bd sd,hh*4").shape("<0 .2 .4 .6 .8>")
+ *
+ */
+ ['shape'],
+ /**
+ * Changes the speed of sample playback, i.e. a cheap way of changing pitch.
+ *
+ * @name speed
+ * @param {number | Pattern} speed -inf to inf, negative numbers play the sample backwards.
+ * @example
+ * s("bd").speed("<1 2 4 1 -2 -4>")
+ * @example
+ * speed("1 1.5*2 [2 1.1]").s("piano").clip(1)
+ *
+ */
+ ['speed'],
+ /**
+ * Used in conjunction with {@link speed}, accepts values of "r" (rate, default behavior), "c" (cycles), or "s" (seconds). Using `unit "c"` means `speed` will be interpreted in units of cycles, e.g. `speed "1"` means samples will be stretched to fill a cycle. Using `unit "s"` means the playback speed will be adjusted so that the duration is the number of seconds specified by `speed`.
+ *
+ * @name unit
+ * @param {number | string | Pattern} unit see description above
+ * @example
+ * speed("1 2 .5 3").s("bd").unit("c").osc()
+ * @superdirtOnly
+ *
+ */
+ ['unit'],
+ /**
+ * Made by Calum Gunn. Reminiscent of some weird mixture of filter, ring-modulator and pitch-shifter. The SuperCollider manual defines Squiz as:
+ *
+ * "A simplistic pitch-raising algorithm. It's not meant to sound natural; its sound is reminiscent of some weird mixture of filter, ring-modulator and pitch-shifter, depending on the input. The algorithm works by cutting the signal into fragments (delimited by upwards-going zero-crossings) and squeezing those fragments in the time domain (i.e. simply playing them back faster than they came in), leaving silences inbetween. All the parameters apart from memlen can be modulated."
+ *
+ * @name squiz
+ * @param {number | Pattern} squiz Try passing multiples of 2 to it - 2, 4, 8 etc.
+ * @example
+ * squiz("2 4/2 6 [8 16]").s("bd").osc()
+ * @superdirtOnly
+ *
+ */
+ ['squiz'],
+ // ['stutterdepth'], // TODO: what is this? not found in tidal doc
+ // ['stuttertime'], // TODO: what is this? not found in tidal doc
+ // ['timescale'], // TODO: what is this? not found in tidal doc
+ // ['timescalewin'], // TODO: what is this? not found in tidal doc
+ // ['tomdecay'],
+ // ['vcfegint'],
+ // ['vcoegint'],
+ // TODO: Use a rest (~) to override the effect <- vowel
+ /**
+ *
+ * Formant filter to make things sound like vowels.
+ *
+ * @name vowel
+ * @param {string | Pattern} vowel You can use a e i o u.
+ * @example
+ * note("c2 >").s('sawtooth')
+ * .vowel(">")
+ *
+ */
+ ['vowel'],
+ /* // TODO: find out how it works
+ * Made by Calum Gunn. Divides an audio stream into tiny segments, using the signal's zero-crossings as segment boundaries, and discards a fraction of them. Takes a number between 1 and 100, denoted the percentage of segments to drop. The SuperCollider manual describes the Waveloss effect this way:
+ *
+ * Divide an audio stream into tiny segments, using the signal's zero-crossings as segment boundaries, and discard a fraction of them (i.e. replace them with silence of the same length). The technique was described by Trevor Wishart in a lecture. Parameters: the filter drops drop out of out of chunks. mode can be 1 to drop chunks in a simple deterministic fashion (e.g. always dropping the first 30 out of a set of 40 segments), or 2 to drop chunks randomly but in an appropriate proportion.)
+ *
+ * mode: ?
+ * waveloss: ?
+ *
+ * @name waveloss
+ */
+ ['waveloss'],
+ // TODO: midi effects?
+ ['dur'],
+ // ['modwheel'],
+ ['expression'],
+ ['sustainpedal'],
+ /* // TODO: doesn't seem to do anything
+ *
+ * Tremolo Audio DSP effect
+ *
+ * @name tremolodepth
+ * @param {number | Pattern} depth between 0 and 1
+ * @example
+ * n("0,4,7").tremolodepth("<0 .3 .6 .9>").osc()
+ *
+ */
+ ['tremolodepth', 'tremdp'],
+ ['tremolorate', 'tremr'],
+ // TODO: doesn't seem to do anything
+ ['phaserdepth', 'phasdp'],
+ ['phaserrate', 'phasr'],
- ['triode'],
- ['krush'],
- ['kcutoff'],
- ['octer'],
- ['octersub'],
- ['octersubsub'],
- ['ring'],
- ['ringf'],
- ['ringdf'],
- ['distort'],
- ['freeze'],
- ['xsdelay'],
- ['tsdelay'],
- ['real'],
- ['imag'],
- ['enhance'],
- ['partials'],
- ['comb'],
- ['smear'],
- ['scram'],
- ['binshift'],
- ['hbrick'],
- ['lbrick'],
- ['midichan'],
- ['control'],
- ['ccn'],
- ['ccv'],
- ['polyTouch'],
- ['midibend'],
- ['miditouch'],
- ['ctlNum'],
- ['frameRate'],
- ['frames'],
- ['hours'],
- ['midicmd'],
- ['minutes'],
- ['progNum'],
- ['seconds'],
- ['songPtr'],
- ['uid'],
- ['val'],
- ['cps'],
- /**
- * Multiplies the duration with the given number. Also cuts samples off at the end if they exceed the duration.
- * In tidal, this would be done with legato, [which has a complicated history in strudel](https://github.com/tidalcycles/strudel/issues/111).
- * For now, if you're coming from tidal, just think clip = legato.
- *
- * @name clip
- * @param {number | Pattern} factor >= 0
- * @example
- * note("c a f e").s("piano").clip("<.5 1 2>")
- *
- */
- ['clip'],
+ ['fshift'],
+ ['fshiftnote'],
+ ['fshiftphase'],
- // ZZFX
- ['zrand'],
- ['curve'],
- ['slide'], // superdirt duplicate
- ['deltaSlide'],
- ['pitchJump'],
- ['pitchJumpTime'],
- ['lfo', 'repeatTime'],
- ['noise'],
- ['zmod'],
- ['zcrush'], // like crush but scaled differently
- ['zdelay'],
- ['tremolo'],
- ['zzfx'],
+ ['triode'],
+ ['krush'],
+ ['kcutoff'],
+ ['octer'],
+ ['octersub'],
+ ['octersubsub'],
+ ['ring'],
+ ['ringf'],
+ ['ringdf'],
+ ['distort'],
+ ['freeze'],
+ ['xsdelay'],
+ ['tsdelay'],
+ ['real'],
+ ['imag'],
+ ['enhance'],
+ ['partials'],
+ ['comb'],
+ ['smear'],
+ ['scram'],
+ ['binshift'],
+ ['hbrick'],
+ ['lbrick'],
+ ['midichan'],
+ ['control'],
+ ['ccn'],
+ ['ccv'],
+ ['polyTouch'],
+ ['midibend'],
+ ['miditouch'],
+ ['ctlNum'],
+ ['frameRate'],
+ ['frames'],
+ ['hours'],
+ ['midicmd'],
+ ['minutes'],
+ ['progNum'],
+ ['seconds'],
+ ['songPtr'],
+ ['uid'],
+ ['val'],
+ ['cps'],
+ /**
+ * Multiplies the duration with the given number. Also cuts samples off at the end if they exceed the duration.
+ * In tidal, this would be done with legato, [which has a complicated history in strudel](https://github.com/tidalcycles/strudel/issues/111).
+ * For now, if you're coming from tidal, just think clip = legato.
+ *
+ * @name clip
+ * @param {number | Pattern} factor >= 0
+ * @example
+ * note("c a f e").s("piano").clip("<.5 1 2>")
+ *
+ */
+ ['clip'],
+
+ // ZZFX
+ ['zrand'],
+ ['curve'],
+ ['slide'], // superdirt duplicate
+ ['deltaSlide'],
+ ['pitchJump'],
+ ['pitchJumpTime'],
+ ['lfo', 'repeatTime'],
+ ['noise'],
+ ['zmod'],
+ ['zcrush'], // like crush but scaled differently
+ ['zdelay'],
+ ['tremolo'],
+ ['zzfx'],
];
// TODO: slice / splice https://www.youtube.com/watch?v=hKhPdO0RKDQ&list=PL2lW1zNIIwj3bDkh-Y3LUGDuRcoUigoDs&index=13
controls.createParam = function (names) {
- const name = Array.isArray(names) ? names[0] : names;
+ const name = Array.isArray(names) ? names[0] : names;
- var withVal;
- if (Array.isArray(names)) {
- withVal = (xs) => {
- if (Array.isArray(xs)) {
- const result = {};
- xs.forEach((x, i) => {
- if (i < names.length) {
- result[names[i]] = x;
- }
- });
- return result;
- } else {
- return { [name]: xs };
- }
- };
- } else {
- withVal = (x) => ({ [name]: x });
- }
-
- const func = (...pats) => sequence(...pats).withValue(withVal);
-
- const setter = function (...pats) {
- if (!pats.length) {
- return this.fmap(withVal);
+ var withVal;
+ if (Array.isArray(names)) {
+ withVal = (xs) => {
+ if (Array.isArray(xs)) {
+ const result = {};
+ xs.forEach((x, i) => {
+ if (i < names.length) {
+ result[names[i]] = x;
+ }
+ });
+ return result;
+ } else {
+ return {[name]: xs};
+ }
+ };
+ } else {
+ withVal = (x) => ({[name]: x});
}
- return this.set(func(...pats));
- };
- Pattern.prototype[name] = setter;
- return func;
+
+ const func = (...pats) => sequence(...pats).withValue(withVal);
+
+ const setter = function (...pats) {
+ if (!pats.length) {
+ return this.fmap(withVal);
+ }
+ return this.set(func(...pats));
+ };
+ Pattern.prototype[name] = setter;
+ return func;
};
generic_params.forEach(([names, ...aliases]) => {
- const name = Array.isArray(names) ? names[0] : names;
- controls[name] = controls.createParam(names);
+ const name = Array.isArray(names) ? names[0] : names;
+ controls[name] = controls.createParam(names);
- aliases.forEach((alias) => {
- controls[alias] = controls[name];
- Pattern.prototype[alias] = Pattern.prototype[name];
- });
+ aliases.forEach((alias) => {
+ controls[alias] = controls[name];
+ Pattern.prototype[alias] = Pattern.prototype[name];
+ });
});
controls.createParams = (...names) =>
- names.reduce((acc, name) => Object.assign(acc, { [name]: controls.createParam(name) }), {});
+ names.reduce((acc, name) => Object.assign(acc, {[name]: controls.createParam(name)}), {});
controls.adsr = register('adsr', (adsr, pat) => {
- adsr = !Array.isArray(adsr) ? [adsr] : adsr;
- const [attack, decay, sustain, release] = adsr;
- return pat.set({ attack, decay, sustain, release });
+ adsr = !Array.isArray(adsr) ? [adsr] : adsr;
+ const [attack, decay, sustain, release] = adsr;
+ return pat.set({attack, decay, sustain, release});
});
controls.ds = register('ds', (ds, pat) => {
- ds = !Array.isArray(ds) ? [ds] : ds;
- const [decay, sustain] = ds;
- return pat.set({ decay, sustain });
+ ds = !Array.isArray(ds) ? [ds] : ds;
+ const [decay, sustain] = ds;
+ return pat.set({decay, sustain});
});
export default controls;
diff --git a/packages/superdough/reverb.mjs b/packages/superdough/reverb.mjs
index e6d31f6a..72709085 100644
--- a/packages/superdough/reverb.mjs
+++ b/packages/superdough/reverb.mjs
@@ -7,14 +7,22 @@ if (typeof AudioContext !== 'undefined') {
return impulse;
};
- AudioContext.prototype.createReverb = function (duration) {
+ AudioContext.prototype.createReverb = function (duration, buffer) {
const convolver = this.createConvolver();
- convolver.setDuration = (d) => {
- convolver.buffer = this.impulseResponse(d);
- convolver.duration = duration;
+ convolver.setDuration = (d, i) => {
+ convolver.buffer = i !== undefined ? buffer : this.impulseResponse(d);
+ convolver.duration = d;
return convolver;
};
- convolver.setDuration(duration);
+ convolver.setIR = (i) => {
+ convolver.buffer = i;
+ return convolver;
+ };
+ if (buffer !== undefined) {
+ convolver.setIR(buffer);
+ } else {
+ convolver.setDuration(duration);
+ }
return convolver;
};
}
diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs
index 289e8d97..2b46ae3c 100644
--- a/packages/superdough/superdough.mjs
+++ b/packages/superdough/superdough.mjs
@@ -12,14 +12,18 @@ import workletsUrl from './worklets.mjs?url';
import { createFilter, gainNode } from './helpers.mjs';
import { map } from 'nanostores';
import { logger } from './logger.mjs';
+import { loadBuffer } from './sampler.mjs';
export const soundMap = map();
+
export function registerSound(key, onTrigger, data = {}) {
soundMap.setKey(key, { onTrigger, data });
}
+
export function getSound(s) {
return soundMap.get()[s];
}
+
export const resetLoadedSounds = () => soundMap.set({});
let audioContext;
@@ -46,6 +50,7 @@ export const panic = () => {
};
let workletsLoading;
+
function loadWorklets() {
if (workletsLoading) {
return workletsLoading;
@@ -89,6 +94,7 @@ export async function initAudioOnFirstClick(options) {
let delays = {};
const maxfeedback = 0.98;
+
function getDelay(orbit, delaytime, delayfeedback, t) {
if (delayfeedback > maxfeedback) {
//logger(`delayfeedback was clamped to ${maxfeedback} to save your ears`);
@@ -107,10 +113,11 @@ function getDelay(orbit, delaytime, delayfeedback, t) {
}
let reverbs = {};
-function getReverb(orbit, duration = 2) {
+
+function getReverb(orbit, duration = 2, ir) {
if (!reverbs[orbit]) {
const ac = getAudioContext();
- const reverb = ac.createReverb(duration);
+ const reverb = ac.createReverb(duration, ir);
reverb.connect(getDestination());
reverbs[orbit] = reverb;
}
@@ -118,10 +125,15 @@ function getReverb(orbit, duration = 2) {
reverbs[orbit] = reverbs[orbit].setDuration(duration);
reverbs[orbit].duration = duration;
}
+ if (reverbs[orbit].ir !== ir) {
+ reverbs[orbit] = reverbs[orbit].setIR(ir);
+ reverbs[orbit].ir = ir;
+ }
return reverbs[orbit];
}
export let analyser, analyserData /* s = {} */;
+
export function getAnalyser(/* orbit, */ fftSize = 2048) {
if (!analyser /*s [orbit] */) {
const analyserNode = getAudioContext().createAnalyser();
@@ -151,7 +163,7 @@ export function getAnalyzerData(type = 'time') {
return analyserData;
}
-function effectSend(input, effect, wet) {
+function effectSend(input, effect, wet, size) {
const send = gainNode(wet);
input.connect(send);
send.connect(effect);
@@ -219,6 +231,8 @@ export const superdough = async (value, deadline, hapDuration) => {
velocity = 1,
analyze, // analyser wet
fft = 8, // fftSize 0 - 10
+ ir,
+ i = 0,
} = value;
gain *= velocity; // legacy fix for velocity
let toDisconnect = []; // audio nodes that will be disconnected when the source has ended
@@ -247,6 +261,7 @@ export const superdough = async (value, deadline, hapDuration) => {
// this can be used for things like speed(0) in the sampler
return;
}
+
if (ac.currentTime > t) {
logger('[webaudio] skip hap: still loading', ac.currentTime - t);
return;
@@ -352,10 +367,16 @@ export const superdough = async (value, deadline, hapDuration) => {
delaySend = effectSend(post, delyNode, delay);
}
// reverb
+ let buffer;
+ if (ir !== undefined) {
+ let sample = getSound(ir);
+ let url = sample.data.samples[i % sample.data.samples.length];
+ buffer = await loadBuffer(url, ac, ir, 0);
+ }
let reverbSend;
if (room > 0 && size > 0) {
- const reverbNode = getReverb(orbit, size);
- reverbSend = effectSend(post, reverbNode, room);
+ const reverbNode = getReverb(orbit, size, buffer);
+ reverbSend = effectSend(post, reverbNode, room, size);
}
// analyser