From ce91d36b7a0059f01cfb67aff56ea61dbbfa57ab Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Wed, 14 Sep 2022 23:16:24 +0200 Subject: [PATCH] doc: random functions --- packages/core/signal.mjs | 146 ++++++++++++++++++++++++++++++++++++++- tutorial/tutorial.mdx | 28 ++++++++ 2 files changed, 172 insertions(+), 2 deletions(-) diff --git a/packages/core/signal.mjs b/packages/core/signal.mjs index 28fc491e..b43ecadf 100644 --- a/packages/core/signal.mjs +++ b/packages/core/signal.mjs @@ -5,7 +5,7 @@ This program is free software: you can redistribute it and/or modify it under th */ import { Hap } from './hap.mjs'; -import { Pattern, fastcat, reify, silence, stack } from './pattern.mjs'; +import { Pattern, fastcat, reify, silence, stack, isPattern } from './pattern.mjs'; import Fraction from './fraction.mjs'; import { id } from './util.mjs'; @@ -233,16 +233,44 @@ Pattern.prototype._degradeByWith = function (withPat, x) { * @param {number} amount - a number between 0 and 1 * @returns Pattern * @example - * s("hh*8").degradeBy(0.5).out() + * s("hh*8").degradeBy(0.2).out() */ Pattern.prototype._degradeBy = function (x) { return this._degradeByWith(rand, x); }; +/** + * + * Randomly removes 50% of events from the pattern. Shorthand for `.degradeBy(0.5)` + * + * @name degrade + * @memberof Pattern + * @returns Pattern + * @example + * s("hh*8").degrade().out() + */ Pattern.prototype.degrade = function () { return this._degradeBy(0.5); }; +/** + * Inverse of {@link Pattern#degradeBy}: Randomly removes events from the pattern by a given amount. + * 0 = 100% chance of removal + * 1 = 0% chance of removal + * Events that would be removed by degradeBy are let through by undegradeBy and vice versa (see second example). + * + * @name undegradeBy + * @memberof Pattern + * @param {number} amount - a number between 0 and 1 + * @returns Pattern + * @example + * s("hh*8").undegradeBy(0.2).out() + * @example + * stack( + * s("hh*8").undegradeBy(0.2), + * s("bd*8").degradeBy(0.8) + * ).out() + */ Pattern.prototype._undegradeBy = function (x) { return this._degradeByWith( rand.fmap((r) => 1 - r), @@ -258,6 +286,25 @@ Pattern.prototype._sometimesBy = function (x, func) { return stack(this._degradeBy(x), func(this._undegradeBy(1 - x))); }; +// https://github.com/tidalcycles/strudel/discussions/198 +/* Pattern.prototype._sometimesBy = function (x, other) { + other = typeof other === 'function' ? other(this._undegradeBy(1 - x)) : reify(other)._undegradeBy(1 - x); + return stack(this._degradeBy(x), other); +}; */ + +/** + * + * Randomly applies the given function by the given probability. + * Similar to {@link Pattern#someCyclesBy} + * + * @name sometimesBy + * @memberof Pattern + * @param {number | Pattern} probability - a number between 0 and 1 + * @param {function} function - the transformation to apply + * @returns Pattern + * @example + * s("hh(3,8)").sometimesBy(.4, x=>x.speed("0.5")).out() + */ Pattern.prototype.sometimesBy = function (patx, func) { const pat = this; return reify(patx) @@ -265,6 +312,7 @@ Pattern.prototype.sometimesBy = function (patx, func) { .innerJoin(); }; +// why does this exist? it is identical to sometimesBy Pattern.prototype._sometimesByPre = function (x, func) { return stack(this._degradeBy(x), func(this).undegradeBy(1 - x)); }; @@ -276,6 +324,17 @@ Pattern.prototype.sometimesByPre = function (patx, func) { .innerJoin(); }; +/** + * + * Applies the given function with a 50% chance + * + * @name sometimes + * @memberof Pattern + * @param {function} function - the transformation to apply + * @returns Pattern + * @example + * s("hh*4").sometimes(x=>x.speed("0.5")).out() + */ Pattern.prototype.sometimes = function (func) { return this._sometimesBy(0.5, func); }; @@ -291,6 +350,19 @@ Pattern.prototype._someCyclesBy = function (x, func) { ); }; +/** + * + * Randomly applies the given function by the given probability on a cycle by cycle basis. + * Similar to {@link Pattern#sometimesBy} + * + * @name someCyclesBy + * @memberof Pattern + * @param {number | Pattern} probability - a number between 0 and 1 + * @param {function} function - the transformation to apply + * @returns Pattern + * @example + * s("hh(3,8)").someCyclesBy(.3, x=>x.speed("0.5")).out() + */ Pattern.prototype.someCyclesBy = function (patx, func) { const pat = this; return reify(patx) @@ -298,30 +370,100 @@ Pattern.prototype.someCyclesBy = function (patx, func) { .innerJoin(); }; +/** + * + * Shorthand for `.someCyclesBy(0.5, fn)` + * + * @name someCycles + * @memberof Pattern + * @returns Pattern + * @example + * s("hh(3,8)").someCycles(x=>x.speed("0.5")).out() + */ Pattern.prototype.someCycles = function (func) { return this._someCyclesBy(0.5, func); }; +/** + * + * Shorthand for `.sometimesBy(0.75, fn)` + * + * @name often + * @memberof Pattern + * @returns Pattern + * @example + * s("hh*8").often(x=>x.speed("0.5")).out() + */ Pattern.prototype.often = function (func) { return this.sometimesBy(0.75, func); }; +/** + * + * Shorthand for `.sometimesBy(0.25, fn)` + * + * @name rarely + * @memberof Pattern + * @returns Pattern + * @example + * s("hh*8").rarely(x=>x.speed("0.5")).out() + */ Pattern.prototype.rarely = function (func) { return this.sometimesBy(0.25, func); }; +/** + * + * Shorthand for `.sometimesBy(0.1, fn)` + * + * @name almostNever + * @memberof Pattern + * @returns Pattern + * @example + * s("hh*8").almostNever(x=>x.speed("0.5")).out() + */ Pattern.prototype.almostNever = function (func) { return this.sometimesBy(0.1, func); }; +/** + * + * Shorthand for `.sometimesBy(0.9, fn)` + * + * @name almostAlways + * @memberof Pattern + * @returns Pattern + * @example + * s("hh*8").almostAlways(x=>x.speed("0.5")).out() + */ Pattern.prototype.almostAlways = function (func) { return this.sometimesBy(0.9, func); }; +/** + * + * Shorthand for `.sometimesBy(0, fn)` (never calls fn) + * + * @name never + * @memberof Pattern + * @returns Pattern + * @example + * s("hh*8").never(x=>x.speed("0.5")).out() + */ Pattern.prototype.never = function (func) { return this; }; +/** + * + * Shorthand for `.sometimesBy(1, fn)` (always calls fn) + * + * @name always + * @memberof Pattern + * @returns Pattern + * @example + * s("hh*8").always(x=>x.speed("0.5")).out() + */ Pattern.prototype.always = function (func) { return func(this); }; diff --git a/tutorial/tutorial.mdx b/tutorial/tutorial.mdx index e95ea5fe..4ff4a20a 100644 --- a/tutorial/tutorial.mdx +++ b/tutorial/tutorial.mdx @@ -450,8 +450,36 @@ Stacks the given pattern to the current pattern: +## Randomness + +These methods add random behavior to your Patterns. + {{ 'Pattern.degradeBy' | jsdoc }} +{{ 'Pattern.degrade' | jsdoc }} + +{{ 'Pattern.undegradeBy' | jsdoc }} + +{{ 'Pattern.sometimesBy' | jsdoc }} + +{{ 'Pattern.sometimes' | jsdoc }} + +{{ 'Pattern.someCyclesBy' | jsdoc }} + +{{ 'Pattern.someCycles' | jsdoc }} + +{{ 'Pattern.often' | jsdoc }} + +{{ 'Pattern.rarely' | jsdoc }} + +{{ 'Pattern.almostNever' | jsdoc }} + +{{ 'Pattern.almostAlways' | jsdoc }} + +{{ 'Pattern.never' | jsdoc }} + +{{ 'Pattern.always' | jsdoc }} + ## Tone API To make the sounds more interesting, we can use Tone.js instruments ands effects.