tagging a lot of superdough functions

This commit is contained in:
Felix Roos 2026-01-23 23:40:51 +01:00
parent b824ad16ae
commit 55ffb59b9c
No known key found for this signature in database
9 changed files with 314 additions and 309 deletions

File diff suppressed because it is too large Load diff

View file

@ -818,7 +818,6 @@ export class Pattern {
* @name layer * @name layer
* @tags combiners * @tags combiners
* @memberof Pattern * @memberof Pattern
* @synonyms apply
* @returns Pattern * @returns Pattern
* @example * @example
* "<0 2 4 6 ~ 4 ~ 2 0!3 ~!5>*8" * "<0 2 4 6 ~ 4 ~ 2 0!3 ~!5>*8"
@ -1265,6 +1264,7 @@ const ALIGNMENT_KEYS = ALIGNMENTS.map((how) => how.toLowerCase());
* 'add.mix', 'set.squeeze', etc. * 'add.mix', 'set.squeeze', etc.
* *
* @param {string} method Default join method to use. Options: 'in', 'out', 'mix', 'squeeze', 'squeezeout', 'reset', 'restart', 'poly' * @param {string} method Default join method to use. Options: 'in', 'out', 'mix', 'squeeze', 'squeezeout', 'reset', 'restart', 'poly'
* @tags combiners
* @example * @example
* setDefaultJoin('mix') // also try 'in', 'out', 'squeeze', etc. * setDefaultJoin('mix') // also try 'in', 'out', 'squeeze', etc.
* s("saw").vel("1 0.5").note("F A C E").delay("0 0.2 0.3") * s("saw").vel("1 0.5").note("F A C E").delay("0 0.2 0.3")
@ -1564,10 +1564,10 @@ export function arrange(...sections) {
* @tags combiners * @tags combiners
* @return {Pattern} * @return {Pattern}
* @example * @example
seqPLoop([0, 2, "bd(3,8)"], seqPLoop(
[1, 3, "cp(3,8)"] [0, 2, "bd(3,8)"],
) [1, 3, "cp(3,8)"]
.sound() ).sound()
*/ */
export function seqPLoop(...parts) { export function seqPLoop(...parts) {
let total = Fraction(0); let total = Fraction(0);
@ -1610,7 +1610,7 @@ export function sequence(...pats) {
/** Like **cat**, but the items are crammed into one cycle. /** Like **cat**, but the items are crammed into one cycle.
* @tags combiners * @tags combiners
* @synonyms seq, fastcat * @synonyms fastcat
* @example * @example
* seq("e5", "b4", ["d5", "c5"]).note() * seq("e5", "b4", ["d5", "c5"]).note()
* // "e5 b4 [d5 c5]".note() * // "e5 b4 [d5 c5]".note()
@ -2137,13 +2137,12 @@ export const { firstOf, every } = register(['firstOf', 'every'], function (n, fu
}); });
/** /**
* Like layer, but with a single function: * Applies the given function to the pattern. Like layer, but with a single function:
* @tags temporal * @tags combiners
* @name apply * @name apply
* @example * @example
* "<c3 eb3 g3>".scale('C minor').apply(scaleTranspose("0,2,4")).note() * "<c3 eb3 g3>".scale('C minor').apply(scaleTranspose("0,2,4")).note()
*/ */
// TODO: remove or dedupe with layer?
export const apply = register('apply', function (func, pat) { export const apply = register('apply', function (func, pat) {
return func(pat); return func(pat);
}); });
@ -2500,7 +2499,7 @@ export const { juxBy, juxby } = register(['juxBy', 'juxby'], function (by, func,
/** /**
* The jux function creates strange stereo effects, by applying a function to a pattern, but only in the right-hand channel. * The jux function creates strange stereo effects, by applying a function to a pattern, but only in the right-hand channel.
* @tags temporal * @tags temporal, superdough
* @example * @example
* s("bd lt [~ ht] mt cp ~ bd hh").jux(rev) * s("bd lt [~ ht] mt cp ~ bd hh").jux(rev)
* @example * @example
@ -2514,7 +2513,7 @@ export const jux = register('jux', function (func, pat) {
/** /**
* Superimpose and offset multiple times, applying the given function each time. * Superimpose and offset multiple times, applying the given function each time.
* @tags temporal * @tags temporal, functional
* @name echoWith * @name echoWith
* @synonyms echowith, stutWith, stutwith * @synonyms echowith, stutWith, stutwith
* @param {number} times how many times to repeat * @param {number} times how many times to repeat
@ -2688,7 +2687,7 @@ export const { repeatCycles } = register(
/** /**
* 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). * 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).
* @tags temporal * @tags temporal, functional
* @name chunk * @name chunk
* @synonyms slowChunk, slowchunk * @synonyms slowChunk, slowchunk
* @memberof Pattern * @memberof Pattern
@ -2852,7 +2851,7 @@ Pattern.prototype.tag = function (tag) {
/** /**
* Filters haps using the given function * Filters haps using the given function
* @name filter * @name filter
* @tags temporal * @tags temporal, functional
* @param {Function} test function to test Hap * @param {Function} test function to test Hap
* @example * @example
* s("hh!7 oh").filter(hap => hap.value.s === 'hh') * s("hh!7 oh").filter(hap => hap.value.s === 'hh')
@ -2862,7 +2861,7 @@ export const filter = register('filter', (test, pat) => pat.withHaps((haps) => h
/** /**
* Filters haps by their begin time * Filters haps by their begin time
* @name filterWhen * @name filterWhen
* @tags temporal * @tags temporal, functional
* @param {Function} test function to test Hap.whole.begin * @param {Function} test function to test Hap.whole.begin
* @example * @example
* oneCycle: s("bd*4").filterWhen((t) => t < 1) * oneCycle: s("bd*4").filterWhen((t) => t < 1)
@ -2872,7 +2871,7 @@ export const filterWhen = register('filterWhen', (test, pat) => pat.filter((h) =
/** /**
* Use within to apply a function to only a part of a pattern. * Use within to apply a function to only a part of a pattern.
* @name within * @name within
* @tags temporal * @tags temporal, functional
* @param {number} start start within cycle (0 - 1) * @param {number} start start within cycle (0 - 1)
* @param {number} end end within cycle (0 - 1). Must be > start * @param {number} end end within cycle (0 - 1). Must be > start
* @param {Function} func function to be applied to the sub-pattern * @param {Function} func function to be applied to the sub-pattern
@ -2947,7 +2946,7 @@ export function _match(span, hap_p) {
* *Experimental* * *Experimental*
* *
* Speeds a pattern up or down, to fit to the given number of steps per cycle. * Speeds a pattern up or down, to fit to the given number of steps per cycle.
* @tags temporal * @tags stepwise
* @example * @example
* sound("bd sd cp").pace(4) * sound("bd sd cp").pace(4)
* // The same as sound("{bd sd cp}%4") or sound("<bd sd cp>*4") * // The same as sound("{bd sd cp}%4") or sound("<bd sd cp>*4")
@ -2989,7 +2988,7 @@ export function _polymeterListSteps(steps, ...args) {
* *Experimental* * *Experimental*
* *
* Aligns the steps of the patterns, creating polymeters. The patterns are repeated until they all fit the cycle. For example, in the below the first pattern is repeated twice, and the second is repeated three times, to fit the lowest common multiple of six steps. * Aligns the steps of the patterns, creating polymeters. The patterns are repeated until they all fit the cycle. For example, in the below the first pattern is repeated twice, and the second is repeated three times, to fit the lowest common multiple of six steps.
* @tags temporal * @tags stepwise
* @synonyms pm * @synonyms pm
* @example * @example
* // The same as note("{c eb g, c2 g2}%6") * // The same as note("{c eb g, c2 g2}%6")
@ -3022,7 +3021,7 @@ export function polymeter(...args) {
* The steps can either be inferred from the pattern, or provided as a [length, pattern] pair. * The steps can either be inferred from the pattern, or provided as a [length, pattern] pair.
* Has the alias `timecat`. * Has the alias `timecat`.
* @name stepcat * @name stepcat
* @tags combiners * @tags stepwise
* @synonyms timeCat, timecat * @synonyms timeCat, timecat
* @return {Pattern} * @return {Pattern}
* @example * @example
@ -3080,7 +3079,7 @@ export function stepcat(...timepats) {
* Concatenates patterns stepwise, according to an inferred 'steps per cycle'. * Concatenates patterns stepwise, according to an inferred 'steps per cycle'.
* Similar to `stepcat`, but if an argument is a list, the whole pattern will alternate between the elements in the list. * Similar to `stepcat`, but if an argument is a list, the whole pattern will alternate between the elements in the list.
* *
* @tags combiners * @tags stepwise
* @return {Pattern} * @return {Pattern}
* @example * @example
* stepalt(["bd cp", "mt"], "bd").sound() * stepalt(["bd cp", "mt"], "bd").sound()
@ -3107,7 +3106,7 @@ export function stepalt(...groups) {
* *
* Takes the given number of steps from a pattern (dropping the rest). * Takes the given number of steps from a pattern (dropping the rest).
* A positive number will take steps from the start of a pattern, and a negative number from the end. * A positive number will take steps from the start of a pattern, and a negative number from the end.
* @tags temporal * @tags stepwise
* @return {Pattern} * @return {Pattern}
* @example * @example
* "bd cp ht mt".take("2").sound() * "bd cp ht mt".take("2").sound()
@ -3152,7 +3151,7 @@ export const take = stepRegister('take', function (i, pat) {
* *
* Drops the given number of steps from a pattern. * Drops the given number of steps from a pattern.
* A positive number will drop steps from the start of a pattern, and a negative number from the end. * A positive number will drop steps from the start of a pattern, and a negative number from the end.
* @tags temporal * @tags stepwise
* @return {Pattern} * @return {Pattern}
* @example * @example
* "tha dhi thom nam".drop("1").sound().bank("mridangam") * "tha dhi thom nam".drop("1").sound().bank("mridangam")
@ -3181,7 +3180,7 @@ export const drop = stepRegister('drop', function (i, pat) {
* `extend` is similar to `fast` in that it increases its density, but it also increases the step count * `extend` is similar to `fast` in that it increases its density, but it also increases the step count
* accordingly. So `stepcat("a b".extend(2), "c d")` would be the same as `"a b a b c d"`, whereas * accordingly. So `stepcat("a b".extend(2), "c d")` would be the same as `"a b a b c d"`, whereas
* `stepcat("a b".fast(2), "c d")` would be the same as `"[a b] [a b] c d"`. * `stepcat("a b".fast(2), "c d")` would be the same as `"[a b] [a b] c d"`.
* @tags temporal * @tags stepwise
* @example * @example
* stepcat( * stepcat(
* sound("bd bd - cp").extend(2), * sound("bd bd - cp").extend(2),
@ -3200,7 +3199,7 @@ export const extend = stepRegister('extend', function (factor, pat) {
* `stepcat("a b".fast(2), "c d")` would be the same as `"[a b] [a b] c d"`. * `stepcat("a b".fast(2), "c d")` would be the same as `"[a b] [a b] c d"`.
* *
* TODO: find out how this function differs from extend * TODO: find out how this function differs from extend
* @tags temporal * @tags stepwise
* @example * @example
* stepcat( * stepcat(
* sound("bd bd - cp").replicate(2), * sound("bd bd - cp").replicate(2),
@ -3215,7 +3214,7 @@ export const replicate = stepRegister('replicate', function (factor, pat) {
* *Experimental* * *Experimental*
* *
* Expands the step size of the pattern by the given factor. * Expands the step size of the pattern by the given factor.
* @tags temporal * @tags stepwise
* @example * @example
* sound("tha dhi thom nam").bank("mridangam").expand("3 2 1 1 2 3").pace(8) * sound("tha dhi thom nam").bank("mridangam").expand("3 2 1 1 2 3").pace(8)
*/ */
@ -3227,7 +3226,7 @@ export const expand = stepRegister('expand', function (factor, pat) {
* *Experimental* * *Experimental*
* *
* Contracts the step size of the pattern by the given factor. See also `expand`. * Contracts the step size of the pattern by the given factor. See also `expand`.
* @tags temporal * @tags stepwise
* @example * @example
* sound("tha dhi thom nam").bank("mridangam").contract("3 2 1 1 2 3").pace(8) * sound("tha dhi thom nam").bank("mridangam").contract("3 2 1 1 2 3").pace(8)
*/ */
@ -3282,7 +3281,7 @@ export const shrinklist = (amount, pat) => pat.shrinklist(amount);
* Progressively shrinks the pattern by 'n' steps until there's nothing left, or if a second value is given (using mininotation list syntax with `:`), * Progressively shrinks the pattern by 'n' steps until there's nothing left, or if a second value is given (using mininotation list syntax with `:`),
* that number of times. * that number of times.
* A positive number will progressively drop steps from the start of a pattern, and a negative number from the end. * A positive number will progressively drop steps from the start of a pattern, and a negative number from the end.
* @tags temporal * @tags stepwise
* @return {Pattern} * @return {Pattern}
* @example * @example
* "tha dhi thom nam".shrink("1").sound() * "tha dhi thom nam".shrink("1").sound()
@ -3322,7 +3321,7 @@ export const shrink = register(
* Progressively grows the pattern by 'n' steps until the full pattern is played, or if a second value is given (using mininotation list syntax with `:`), * Progressively grows the pattern by 'n' steps until the full pattern is played, or if a second value is given (using mininotation list syntax with `:`),
* that number of times. * that number of times.
* A positive number will progressively grow steps from the start of a pattern, and a negative number from the end. * A positive number will progressively grow steps from the start of a pattern, and a negative number from the end.
* @tags temporal * @tags stepwise
* @return {Pattern} * @return {Pattern}
* @example * @example
* "tha dhi thom nam".grow("1").sound() * "tha dhi thom nam".grow("1").sound()
@ -3363,7 +3362,7 @@ export const grow = register(
* on successive repetitions. The patterns are added together stepwise, with all repetitions taking place over a single cycle. Using `pace` to set the * on successive repetitions. The patterns are added together stepwise, with all repetitions taking place over a single cycle. Using `pace` to set the
* number of steps per cycle is therefore usually recommended. * number of steps per cycle is therefore usually recommended.
* *
* @tags combiners * @tags stepwise
* @return {Pattern} * @return {Pattern}
* @example * @example
* "[c g]".tour("e f", "e f g", "g f e c").note() * "[c g]".tour("e f", "e f g", "g f e c").note()
@ -3390,7 +3389,7 @@ Pattern.prototype.tour = function (...many) {
* 'zips' together the steps of the provided patterns. This can create a long repetition, taking place over a single, dense cycle. * 'zips' together the steps of the provided patterns. This can create a long repetition, taking place over a single, dense cycle.
* Using `pace` to set the number of steps per cycle is therefore usually recommended. * Using `pace` to set the number of steps per cycle is therefore usually recommended.
* *
* @tags combiners * @tags stepwise
* @returns {Pattern} * @returns {Pattern}
* @example * @example
* zip("e f", "e f g", "g [f e] a f4 c").note() * zip("e f", "e f g", "g [f e] a f4 c").note()
@ -3442,7 +3441,7 @@ Pattern.prototype.steps = Pattern.prototype.pace;
* Cuts each sample into the given number of parts, allowing you to explore a technique known as 'granular synthesis'. * Cuts each sample into the given number of parts, allowing you to explore a technique known as 'granular synthesis'.
* It turns a pattern of samples into a pattern of parts of samples. * It turns a pattern of samples into a pattern of parts of samples.
* @name chop * @name chop
* @tags temporal * @tags samples
* @memberof Pattern * @memberof Pattern
* @returns Pattern * @returns Pattern
* @example * @example
@ -3473,7 +3472,7 @@ export const chop = register('chop', function (n, pat) {
/** /**
* Cuts each sample into the given number of parts, triggering progressive portions of each sample at each loop. * Cuts each sample into the given number of parts, triggering progressive portions of each sample at each loop.
* @name striate * @name striate
* @tags temporal * @tags samples
* @memberof Pattern * @memberof Pattern
* @returns Pattern * @returns Pattern
* @example * @example
@ -3492,14 +3491,13 @@ export const striate = register('striate', function (n, pat) {
/** /**
* Makes the sample fit the given number of cycles by changing the speed. * Makes the sample fit the given number of cycles by changing the speed.
* @name loopAt * @name loopAt
* @tags temporal * @tags samples, pitch
* @memberof Pattern * @memberof Pattern
* @returns Pattern * @returns Pattern
* @example * @example
* samples({ rhodes: 'https://cdn.freesound.org/previews/132/132051_316502-lq.mp3' }) * samples({ rhodes: 'https://cdn.freesound.org/previews/132/132051_316502-lq.mp3' })
* s("rhodes").loopAt(2) * s("rhodes").loopAt(2)
*/ */
// TODO - global cps clock
const _loopAt = function (factor, pat, cps = 0.5) { const _loopAt = function (factor, pat, cps = 0.5) {
return pat return pat
.speed((1 / factor) * cps) .speed((1 / factor) * cps)
@ -3507,11 +3505,16 @@ const _loopAt = function (factor, pat, cps = 0.5) {
.slow(factor); .slow(factor);
}; };
export const { loopAt, loopat } = register(['loopAt', 'loopat'], function (factor, pat) {
const steps = pat._steps ? pat._steps.div(factor) : undefined;
return new Pattern((state) => _loopAt(factor, pat, state.controls._cps).query(state), steps);
});
/** /**
* Chops samples into the given number of slices, triggering those slices with a given pattern of slice numbers. * Chops samples into the given number of slices, triggering those slices with a given pattern of slice numbers.
* Instead of a number, it also accepts a list of numbers from 0 to 1 to slice at specific points. * Instead of a number, it also accepts a list of numbers from 0 to 1 to slice at specific points.
* @name slice * @name slice
* @tags temporal * @tags samples
* @memberof Pattern * @memberof Pattern
* @returns Pattern * @returns Pattern
* @example * @example
@ -3565,7 +3568,7 @@ Pattern.prototype.onTriggerTime = function (func) {
/** /**
* Works the same as slice, but changes the playback speed of each slice to match the duration of its step. * Works the same as slice, but changes the playback speed of each slice to match the duration of its step.
* @name splice * @name splice
* @tags temporal * @tags samples, pitch
* @example * @example
* samples('github:tidalcycles/dirt-samples') * samples('github:tidalcycles/dirt-samples')
* s("breaks165") * s("breaks165")
@ -3594,16 +3597,11 @@ export const splice = register(
false, // turns off auto-patternification false, // turns off auto-patternification
); );
export const { loopAt, loopat } = register(['loopAt', 'loopat'], function (factor, pat) {
const steps = pat._steps ? pat._steps.div(factor) : undefined;
return new Pattern((state) => _loopAt(factor, pat, state.controls._cps).query(state), steps);
});
/** /**
* Makes the sample fit its event duration. Good for rhythmical loops like drum breaks. * Makes the sample fit its event duration. Good for rhythmical loops like drum breaks.
* Similar to `loopAt`. * Similar to `loopAt`.
* @name fit * @name fit
* @tags temporal * @tags samples, pitch
* @example * @example
* samples({ rhodes: 'https://cdn.freesound.org/previews/132/132051_316502-lq.mp3' }) * samples({ rhodes: 'https://cdn.freesound.org/previews/132/132051_316502-lq.mp3' })
* s("rhodes/2").fit() * s("rhodes/2").fit()
@ -3625,18 +3623,16 @@ export const fit = register('fit', (pat) =>
/** /**
* Makes the sample fit the given number of cycles and cps value, by * Makes the sample fit the given number of cycles and cps value, by
* changing the speed. Please note that at some point cps will be * changing the speed. deprecated: use loopAt or fit instead, together with setCps / setCpm.
* given by a global clock and this function will be
* deprecated/removed.
* @name loopAtCps * @name loopAtCps
* @tags temporal * @tags samples, pitch
* @memberof Pattern * @memberof Pattern
* @deprecated
* @returns Pattern * @returns Pattern
* @example * @example
* samples({ rhodes: 'https://cdn.freesound.org/previews/132/132051_316502-lq.mp3' }) * samples({ rhodes: 'https://cdn.freesound.org/previews/132/132051_316502-lq.mp3' })
* s("rhodes").loopAtCps(4,1.5).cps(1.5) * s("rhodes").loopAtCps(4,1.5).cps(1.5)
*/ */
// TODO - global cps clock
export const { loopAtCps, loopatcps } = register(['loopAtCps', 'loopatcps'], function (factor, cps, pat) { export const { loopAtCps, loopatcps } = register(['loopAtCps', 'loopatcps'], function (factor, cps, pat) {
return _loopAt(factor, pat, cps); return _loopAt(factor, pat, cps);
}); });
@ -3658,7 +3654,7 @@ let fadeGain = (p) => (p < 0.5 ? 1 : 1 - (p - 0.5) / 0.5);
* - 1 = (no left, full right) * - 1 = (no left, full right)
* *
* @name xfade * @name xfade
* @tags combiners * @tags amplitude
* @example * @example
* xfade(s("bd*2"), "<0 .25 .5 .75 1>", s("hh*8")) * xfade(s("bd*2"), "<0 .25 .5 .75 1>", s("hh*8"))
*/ */
@ -3784,7 +3780,7 @@ const _distortWithAlg = function (name) {
* Soft-clipping distortion * Soft-clipping distortion
* *
* @name soft * @name soft
* @tags fx * @tags distortion, superdough
* @param {number | Pattern} distortion amount of distortion to apply * @param {number | Pattern} distortion amount of distortion to apply
* @param {number | Pattern} volume linear postgain of the distortion * @param {number | Pattern} volume linear postgain of the distortion
* *
@ -3795,7 +3791,7 @@ export const soft = _distortWithAlg('soft');
* Hard-clipping distortion * Hard-clipping distortion
* *
* @name hard * @name hard
* @tags fx * @tags distortion, superdough
* @param {number | Pattern} distortion amount of distortion to apply * @param {number | Pattern} distortion amount of distortion to apply
* @param {number | Pattern} volume linear postgain of the distortion * @param {number | Pattern} volume linear postgain of the distortion
* *
@ -3806,7 +3802,7 @@ export const hard = _distortWithAlg('hard');
* Cubic polynomial distortion * Cubic polynomial distortion
* *
* @name cubic * @name cubic
* @tags fx * @tags distortion, superdough
* @param {number | Pattern} distortion amount of distortion to apply * @param {number | Pattern} distortion amount of distortion to apply
* @param {number | Pattern} volume linear postgain of the distortion * @param {number | Pattern} volume linear postgain of the distortion
* *
@ -3817,7 +3813,7 @@ export const cubic = _distortWithAlg('cubic');
* Diode-emulating distortion * Diode-emulating distortion
* *
* @name diode * @name diode
* @tags fx * @tags distortion, superdough
* @param {number | Pattern} distortion amount of distortion to apply * @param {number | Pattern} distortion amount of distortion to apply
* @param {number | Pattern} volume linear postgain of the distortion * @param {number | Pattern} volume linear postgain of the distortion
* *
@ -3828,7 +3824,7 @@ export const diode = _distortWithAlg('diode');
* Asymmetrical diode distortion * Asymmetrical diode distortion
* *
* @name asym * @name asym
* @tags fx * @tags distortion, superdough
* @param {number | Pattern} distortion amount of distortion to apply * @param {number | Pattern} distortion amount of distortion to apply
* @param {number | Pattern} volume linear postgain of the distortion * @param {number | Pattern} volume linear postgain of the distortion
* *
@ -3839,7 +3835,7 @@ export const asym = _distortWithAlg('asym');
* Wavefolding distortion * Wavefolding distortion
* *
* @name fold * @name fold
* @tags fx * @tags distortion, superdough
* @param {number | Pattern} distortion amount of distortion to apply * @param {number | Pattern} distortion amount of distortion to apply
* @param {number | Pattern} volume linear postgain of the distortion * @param {number | Pattern} volume linear postgain of the distortion
* *
@ -3850,7 +3846,7 @@ export const fold = _distortWithAlg('fold');
* Wavefolding distortion composed with sinusoid * Wavefolding distortion composed with sinusoid
* *
* @name sinefold * @name sinefold
* @tags fx * @tags distortion, superdough
* @param {number | Pattern} distortion amount of distortion to apply * @param {number | Pattern} distortion amount of distortion to apply
* @param {number | Pattern} volume linear postgain of the distortion * @param {number | Pattern} volume linear postgain of the distortion
* *
@ -3861,7 +3857,7 @@ export const sinefold = _distortWithAlg('sinefold');
* Distortion via Chebyshev polynomials * Distortion via Chebyshev polynomials
* *
* @name chebyshev * @name chebyshev
* @tags fx * @tags distortion, superdough
* @param {number | Pattern} distortion amount of distortion to apply * @param {number | Pattern} distortion amount of distortion to apply
* @param {number | Pattern} volume linear postgain of the distortion * @param {number | Pattern} volume linear postgain of the distortion
* *
@ -3895,7 +3891,7 @@ const _ensureListPattern = (list) => {
* Can also be used to create a new synth via `s('user').partials(...)` * Can also be used to create a new synth via `s('user').partials(...)`
* *
* @name partials * @name partials
* @tags fx, superdough * @tags superdough
* @param {number[] | Pattern} magnitudes List of [0, 1] magnitudes for partials. 0th entry is the fundamental harmonic (i.e. DC offset is skipped) * @param {number[] | Pattern} magnitudes List of [0, 1] magnitudes for partials. 0th entry is the fundamental harmonic (i.e. DC offset is skipped)
* @example * @example
* s("user").seg(16).n(irand(8)).scale("A:major") * s("user").seg(16).n(irand(8)).scale("A:major")
@ -3917,7 +3913,7 @@ export const partials = (list) => {
* Rotates the harmonics of one of the core synths ('sine', 'tri', 'saw', 'user', ..) by a list of phases * Rotates the harmonics of one of the core synths ('sine', 'tri', 'saw', 'user', ..) by a list of phases
* *
* @name phases * @name phases
* @tags fx, superdough * @tags superdough
* @param {number[] | Pattern} phases List of [0, 1) phases for partials. 0th entry is the fundamental phase (i.e. DC offset is skipped) * @param {number[] | Pattern} phases List of [0, 1) phases for partials. 0th entry is the fundamental phase (i.e. DC offset is skipped)
* @example * @example
* // Phase cancellation * // Phase cancellation
@ -3939,7 +3935,7 @@ export const phases = (list) => {
* calls and/or in a single .FX(fx1, fx2, ..) call. The fx1, .. are _patterns_ which * calls and/or in a single .FX(fx1, fx2, ..) call. The fx1, .. are _patterns_ which
* establish the controls of the given effect. See examples. * establish the controls of the given effect. See examples.
* @name FX * @name FX
* @tags fx, superdough * @tags superdough
* @memberof Pattern * @memberof Pattern
* @returns Pattern * @returns Pattern
* @example * @example
@ -3990,7 +3986,7 @@ const _asArrayPattern = (pats) => {
* by wrapping them inside a function in K (see example). * by wrapping them inside a function in K (see example).
* *
* @name K * @name K
* @tags generators, fx, superdough * @tags generators, superdough
* @param {KabelsalatExpression | Function} expr Kabelsalat graph definition * @param {KabelsalatExpression | Function} expr Kabelsalat graph definition
* @memberof Pattern * @memberof Pattern
* @returns Pattern * @returns Pattern

View file

@ -78,7 +78,7 @@ export const pickmod = register('pickmod', function (lookup, pat) {
* s("bd [rim hh]").pickF("<0 1 2>", [rev,jux(rev),fast(2)]) * s("bd [rim hh]").pickF("<0 1 2>", [rev,jux(rev),fast(2)])
* @example * @example
* note("<c2 d2>(3,8)").s("square") * note("<c2 d2>(3,8)").s("square")
* .pickF("<0 2> 1", [jux(rev),fast(2),x=>x.lpf(800)]) * .pickF("<0 2> 1", [jux(rev), fast(2), x=>x.lpf(800)])
*/ */
export const pickF = register('pickF', function (lookup, funcs, pat) { export const pickF = register('pickF', function (lookup, funcs, pat) {
return pat.apply(pick(lookup, funcs)); return pat.apply(pick(lookup, funcs));
@ -167,20 +167,22 @@ export const pickmodReset = register('pickmodReset', function (lookup, pat) {
}); });
/** Picks patterns (or plain values) either from a list (by index) or a lookup table (by name). /** Picks patterns (or plain values) either from a list (by index) or a lookup table (by name).
* Similar to `pick`, but cycles are squeezed into the target ('inhabited') pattern. * Similar to `pick`, but cycles are squeezed into the target ('inhabited') pattern.
* @name inhabit * @name inhabit
* @tags combiners * @tags combiners
* @synonyms pickSqueeze * @synonyms pickSqueeze
* @param {Pattern} pat * @param {Pattern} pat
* @param {*} xs * @param {*} xs
* @returns {Pattern} * @returns {Pattern}
* @example * @example
* "<a b [a,b]>".inhabit({a: s("bd(3,8)"), * let a = s("bd(3,8)")
b: s("cp sd") * let b = s("cp sd")
}) * "<a b [a,b]>".inhabit({ a, b })
* @example * @example
* s("a@2 [a b] a".inhabit({a: "bd(3,8)", b: "sd sd"})).slow(4) * s("a@2 [a b] a"
*/ * .inhabit({a: "bd(3,8)", b: "sd sd"}))
* .slow(4)
*/
export const { inhabit, pickSqueeze } = register(['inhabit', 'pickSqueeze'], function (lookup, pat) { export const { inhabit, pickSqueeze } = register(['inhabit', 'pickSqueeze'], function (lookup, pat) {
return _pick(lookup, pat, false).squeezeJoin(); return _pick(lookup, pat, false).squeezeJoin();
}); });

View file

@ -138,7 +138,7 @@ function githubPath(base, subpath = '') {
/** /**
* configures the default midimap, which is used when no "midimap" port is set * configures the default midimap, which is used when no "midimap" port is set
* @tags external_io * @tags external_io, midi
* @example * @example
* defaultmidimap({ lpf: 74 }) * defaultmidimap({ lpf: 74 })
* $: note("c a f e").midi(); * $: note("c a f e").midi();
@ -152,7 +152,7 @@ let loadCache = {};
/** /**
* Adds midimaps to the registry. Inside each midimap, control names (e.g. lpf) are mapped to cc numbers. * Adds midimaps to the registry. Inside each midimap, control names (e.g. lpf) are mapped to cc numbers.
* @tags external_io * @tags external_io, midi
* @example * @example
* midimaps({ mymap: { lpf: 74 } }) * midimaps({ mymap: { lpf: 74 } })
* $: note("c a f e") * $: note("c a f e")
@ -529,7 +529,7 @@ async function _initialize(input) {
* The output is a function that accepts a midi cc value to query as well as (optionally) a midi channel * The output is a function that accepts a midi cc value to query as well as (optionally) a midi channel
* *
* @name midin * @name midin
* @tags external_io * @tags external_io, midi
* @param {string | number} input MIDI device name or index defaulting to 0 * @param {string | number} input MIDI device name or index defaulting to 0
* @returns {function(number, number=): Pattern} A function from (cc, channel?) to a pattern. * @returns {function(number, number=): Pattern} A function from (cc, channel?) to a pattern.
* When queried, the pattern will produces the most recently received midi value (normalized to 0 to 1) * When queried, the pattern will produces the most recently received midi value (normalized to 0 to 1)
@ -577,7 +577,7 @@ export async function midin(input) {
* note durations * note durations
* *
* @name midikeys * @name midikeys
* @tags external_io * @tags external_io, midi
* @param {string | number} input MIDI device name or index defaulting to 0 * @param {string | number} input MIDI device name or index defaulting to 0
* @returns {function((number | Pattern)=): Pattern} A function that produces a pattern. * @returns {function((number | Pattern)=): Pattern} A function that produces a pattern.
* When queried, the pattern will produces the most recently played midi notes and velocities, * When queried, the pattern will produces the most recently played midi notes and velocities,

View file

@ -40,7 +40,7 @@ export let maxPolyphony = DEFAULT_MAX_POLYPHONY;
* start to die out in first-in-first-out order once the max polyphony has been hit * start to die out in first-in-first-out order once the max polyphony has been hit
* *
* @name setMaxPolyphony * @name setMaxPolyphony
* @tags fx, superdough * @tags superdough
* @param {number} Max polyphony. Defaults to 128 * @param {number} Max polyphony. Defaults to 128
* @example * @example
* setMaxPolyphony(4) * setMaxPolyphony(4)
@ -74,7 +74,7 @@ export function applyGainCurve(val) {
* quadratic, exponential, etc. rather than linear * quadratic, exponential, etc. rather than linear
* *
* @name setGainCurve * @name setGainCurve
* @tags fx, superdough * @tags amplitude, superdough
* @param {Function} function to apply to all gain values * @param {Function} function to apply to all gain values
* @example * @example
* setGainCurve((x) => x * x) // quadratic gain * setGainCurve((x) => x * x) // quadratic gain

View file

@ -186,7 +186,7 @@ export function registerWaveTable(key, tables, params) {
* Loads a collection of wavetables to use with `s` * Loads a collection of wavetables to use with `s`
* *
* @name tables * @name tables
* @tags fx * @tags wavetable
*/ */
export const tables = async (url, frameLen, json, options = {}) => { export const tables = async (url, frameLen, json, options = {}) => {
if (json !== undefined) return _processTables(json, url, frameLen); if (json !== undefined) return _processTables(json, url, frameLen);

View file

@ -100,7 +100,7 @@ function scaleOffset(scale, offset, note) {
* - 5P = perfect fifth * - 5P = perfect fifth
* - 5d = diminished fifth * - 5d = diminished fifth
* *
* @tags music_theory * @tags tonal
* @param {string | number} amount Either number of semitones or interval string. * @param {string | number} amount Either number of semitones or interval string.
* @returns Pattern * @returns Pattern
* @memberof Pattern * @memberof Pattern
@ -155,7 +155,7 @@ export const { transpose, trans } = register(['transpose', 'trans'], function tr
* *
* @memberof Pattern * @memberof Pattern
* @name scaleTranspose * @name scaleTranspose
* @tags music_theory * @tags tonal
* @param {offset} offset number of steps inside the scale * @param {offset} offset number of steps inside the scale
* @returns Pattern * @returns Pattern
* @synonyms scaleTrans, strans * @synonyms scaleTrans, strans
@ -246,7 +246,7 @@ function _getNearestScaleNote(scaleName, note, preferHigher = true) {
* The root note defaults to octave 3, if no octave number is given. * The root note defaults to octave 3, if no octave number is given.
* *
* @name scale * @name scale
* @tags music_theory * @tags tonal
* @param {string} scale Name of scale * @param {string} scale Name of scale
* @returns Pattern * @returns Pattern
* @example * @example

View file

@ -90,7 +90,7 @@ export const setVoicingRange = (name, range) => addVoicings(name, voicingRegistr
* Adds a new custom voicing dictionary. * Adds a new custom voicing dictionary.
* *
* @name addVoicings * @name addVoicings
* @tags music_theory * @tags tonal
* @memberof Pattern * @memberof Pattern
* @param {string} name identifier for the voicing dictionary * @param {string} name identifier for the voicing dictionary
* @param {Object} dictionary maps chord symbol to possible voicings * @param {Object} dictionary maps chord symbol to possible voicings
@ -134,7 +134,7 @@ const getVoicing = (chord, dictionaryName, lastVoicing) => {
* Uses [chord-voicings package](https://github.com/felixroos/chord-voicings#chord-voicings). * Uses [chord-voicings package](https://github.com/felixroos/chord-voicings#chord-voicings).
* *
* @name voicings * @name voicings
* @tags music_theory * @tags tonal
* @memberof Pattern * @memberof Pattern
* @param {string} dictionary which voicing dictionary to use. * @param {string} dictionary which voicing dictionary to use.
* @returns Pattern * @returns Pattern
@ -159,7 +159,7 @@ export const voicings = register('voicings', function (dictionary, pat) {
* Maps the chords of the incoming pattern to root notes in the given octave. * Maps the chords of the incoming pattern to root notes in the given octave.
* *
* @name rootNotes * @name rootNotes
* @tags music_theory * @tags tonal
* @memberof Pattern * @memberof Pattern
* @param {octave} octave octave to use * @param {octave} octave octave to use
* @returns Pattern * @returns Pattern
@ -192,7 +192,7 @@ export const rootNotes = register('rootNotes', function (octave, pat) {
* If you pass a pattern of strings to voicing, they will be interpreted as chords. * If you pass a pattern of strings to voicing, they will be interpreted as chords.
* *
* @name voicing * @name voicing
* @tags music_theory * @tags tonal
* @returns Pattern * @returns Pattern
* @example * @example
* n("0 1 2 3").chord("<C Am F G>").voicing() * n("0 1 2 3").chord("<C Am F G>").voicing()

View file

@ -4,7 +4,11 @@ import jsdocJson from '../../../../../doc.json';
import { Textbox } from '@src/repl/components/panel/SettingsTab'; import { Textbox } from '@src/repl/components/panel/SettingsTab';
import { settingsMap, useSettings } from '@src/settings.mjs'; import { settingsMap, useSettings } from '@src/settings.mjs';
const isValid = ({ name, description }) => name && !name.startsWith('_') && !!description; const isValid = ({ name, description, tags = [] }) => {
const isSupradoughOnly = tags.includes('supradough') && !tags.includes('superdough');
const isSuperdirtOnly = tags.includes('superdirt') && !tags.includes('superdough');
return name && !name.startsWith('_') && !!description && !isSupradoughOnly && !isSuperdirtOnly;
};
const availableFunctions = (() => { const availableFunctions = (() => {
const seen = new Set(); // avoid repetition const seen = new Set(); // avoid repetition
@ -14,7 +18,7 @@ const availableFunctions = (() => {
if (seen.has(doc.name)) continue; if (seen.has(doc.name)) continue;
// jsdoc also uses "tags" for when you use @something in the comments and it doesn't know what // jsdoc also uses "tags" for when you use @something in the comments and it doesn't know what
// @something is. We only want data from comments like `@tags fx, superdough` here. // @something is. We only want data from comments like `@tags superdough` here.
// If nothing is specified, we default to "untagged" for debugging // If nothing is specified, we default to "untagged" for debugging
doc.tags = doc.tags?.filter((t) => t && typeof t === 'string') || ['untagged']; doc.tags = doc.tags?.filter((t) => t && typeof t === 'string') || ['untagged'];
functions.push(doc); functions.push(doc);
@ -39,11 +43,12 @@ const availableFunctions = (() => {
})(); })();
const tagCounts = {}; const tagCounts = {};
const ignoredTags = ['supradough', 'superdirt'];
// const tagOptions = { all: `all (${availableFunctions.length})` }; // const tagOptions = { all: `all (${availableFunctions.length})` };
const tagOptions = { all: `all` }; const tagOptions = { all: `all` };
for (const doc of availableFunctions) { for (const doc of availableFunctions) {
(doc.tags || ['untagged']).forEach((t) => { (doc.tags || ['untagged']).forEach((t) => {
if (typeof t === 'string' && t) { if (typeof t === 'string' && t && !ignoredTags.includes(t)) {
tagCounts[t] = (tagCounts[t] || 0) + 1; tagCounts[t] = (tagCounts[t] || 0) + 1;
//tagOptions[t] = `${t} (${tagCounts[t]})`; //tagOptions[t] = `${t} (${tagCounts[t]})`;
tagOptions[t] = t; tagOptions[t] = t;
@ -204,7 +209,7 @@ export const Reference = memo(function Reference() {
</h3> </h3>
{entry.tags && ( {entry.tags && (
<span className="ml-2 text-xs text-foreground border border-muted px-1 py-0.5"> <span className="ml-2 text-xs text-foreground border border-muted px-1 py-0.5">
{entry.tags.join(', ')} {entry.tags.filter((t) => !ignoredTags.includes(t)).join(', ')}
</span> </span>
)} )}
</div> </div>