mirror of
https://github.com/eliasstepanik/strudel-docker.git
synced 2026-01-11 21:58:31 +00:00
Merge pull request #199 from tidalcycles/docs-update
document random functions
This commit is contained in:
commit
f4c31bcf2c
@ -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';
|
||||
|
||||
@ -156,8 +156,8 @@ export const chooseInWith = (pat, xs) => {
|
||||
};
|
||||
|
||||
/**
|
||||
* Chooses randomly from the given list of values.
|
||||
* @param {...any} xs
|
||||
* Chooses randomly from the given list of elements.
|
||||
* @param {...any} xs values / patterns to choose from.
|
||||
* @returns {Pattern} - a continuous pattern.
|
||||
*/
|
||||
export const choose = (...xs) => chooseWith(rand, xs);
|
||||
@ -183,6 +183,14 @@ Pattern.prototype.choose2 = function (...xs) {
|
||||
return chooseWith(this._fromBipolar(), xs);
|
||||
};
|
||||
|
||||
/**
|
||||
* Picks one of the elements at random each cycle.
|
||||
* @returns {Pattern}
|
||||
* @example
|
||||
* chooseCycles("bd", "hh", "sd").s().fast(4).out()
|
||||
* @example
|
||||
* "bd | hh | sd".s().fast(4).out()
|
||||
*/
|
||||
export const chooseCycles = (...xs) => chooseInWith(rand.segment(1), xs);
|
||||
|
||||
export const randcat = chooseCycles;
|
||||
@ -223,14 +231,53 @@ Pattern.prototype._degradeByWith = function (withPat, x) {
|
||||
return this.fmap((a) => (_) => a).appLeft(withPat._filterValues((v) => v > x));
|
||||
};
|
||||
|
||||
/**
|
||||
* Randomly removes events from the pattern by a given amount.
|
||||
* 0 = 0% chance of removal
|
||||
* 1 = 100% chance of removal
|
||||
*
|
||||
* @name degradeBy
|
||||
* @memberof Pattern
|
||||
* @param {number} amount - a number between 0 and 1
|
||||
* @returns Pattern
|
||||
* @example
|
||||
* s("hh*8").degradeBy(0.2).out()
|
||||
* @example
|
||||
* s("[hh?0.2]*8").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()
|
||||
* @example
|
||||
* s("[hh?]*8").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()
|
||||
*/
|
||||
Pattern.prototype._undegradeBy = function (x) {
|
||||
return this._degradeByWith(
|
||||
rand.fmap((r) => 1 - r),
|
||||
@ -246,6 +293,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)
|
||||
@ -253,6 +319,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));
|
||||
};
|
||||
@ -264,6 +331,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);
|
||||
};
|
||||
@ -279,6 +357,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)
|
||||
@ -286,30 +377,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);
|
||||
};
|
||||
|
||||
@ -38,7 +38,9 @@ export default defineConfig({
|
||||
'@codemirror/commands',
|
||||
'@lezer/highlight',
|
||||
'@codemirror/language',
|
||||
'@uiw/codemirror-themes'
|
||||
'@uiw/codemirror-themes',
|
||||
'@uiw/react-codemirror',
|
||||
'@lezer/highlight',
|
||||
],
|
||||
},
|
||||
target: 'esnext',
|
||||
|
||||
@ -2,8 +2,8 @@ import { Tone } from '@strudel.cycles/tone';
|
||||
import { evalScope } from '@strudel.cycles/eval';
|
||||
import { MiniRepl as _MiniRepl } from '@strudel.cycles/react';
|
||||
import controls from '@strudel.cycles/core/controls.mjs';
|
||||
import * as WebDirt from 'WebDirt';
|
||||
import { loadWebDirt } from '@strudel.cycles/webdirt';
|
||||
import { samples } from '@strudel.cycles/webaudio';
|
||||
|
||||
export const defaultSynth = new Tone.PolySynth().chain(new Tone.Gain(0.5), Tone.Destination).set({
|
||||
oscillator: { type: 'triangle' },
|
||||
@ -12,6 +12,15 @@ export const defaultSynth = new Tone.PolySynth().chain(new Tone.Gain(0.5), Tone.
|
||||
},
|
||||
});
|
||||
|
||||
samples(
|
||||
{
|
||||
bd: '808bd/BD0000.WAV',
|
||||
sd: ['808sd/SD0010.WAV', '808sd/SD0050.WAV', '808sd/SD0000.WAV'],
|
||||
hh: ['hh27/000_hh27closedhh.wav', 'hh/000_hh3closedhh.wav'],
|
||||
},
|
||||
'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/',
|
||||
);
|
||||
|
||||
evalScope(
|
||||
Tone,
|
||||
controls,
|
||||
|
||||
@ -177,11 +177,11 @@ In essence, the `x!n` is like a shortcut for `[x*n]@n`.
|
||||
|
||||
## Euclidian
|
||||
|
||||
Using round brackets, we can create rhythmical sub-divisions based on three parameters: beats, segments and offset.
|
||||
The first parameter controls how may beats will be played.
|
||||
The second parameter controls the total amount of segments the beats will be distributed over.
|
||||
Using round brackets, we can create rhythmical sub-divisions based on three parameters: beats, segments and offset.
|
||||
The first parameter controls how may beats will be played.
|
||||
The second parameter controls the total amount of segments the beats will be distributed over.
|
||||
The third (optional) parameter controls the starting position for distributing the beats.
|
||||
One popular Euclidian rhythm (going by various names, such as "Pop Clave") is "(3,8,1)" or simply "(3,8)",
|
||||
One popular Euclidian rhythm (going by various names, such as "Pop Clave") is "(3,8,1)" or simply "(3,8)",
|
||||
resulting in a rhythmical structure of "x ~ ~ x ~ ~ x ~" (3 beats over 8 segments, starting on position 1).
|
||||
|
||||
<MiniRepl tune={`"e5(2,8) b4(3,8) d5(2,8) c5(3,8)".slow(4)`} />
|
||||
@ -450,6 +450,38 @@ Stacks the given pattern to the current pattern:
|
||||
|
||||
<MiniRepl tune={`"c4,eb4,g4".stack("bb4,d5")`} />
|
||||
|
||||
## Randomness
|
||||
|
||||
These methods add random behavior to your Patterns.
|
||||
|
||||
{{ 'chooseCycles' | jsdoc }}
|
||||
|
||||
{{ '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.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user