From 88e39d22f1013b6145f498d4ac98a4d1d71f0dbf Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Wed, 14 Sep 2022 21:53:41 +0200 Subject: [PATCH 1/5] add drums to mini repl --- tutorial/MiniRepl.jsx | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tutorial/MiniRepl.jsx b/tutorial/MiniRepl.jsx index af21f362..405cd94d 100644 --- a/tutorial/MiniRepl.jsx +++ b/tutorial/MiniRepl.jsx @@ -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/SD0000.WAV', '808sd/SD0010.WAV', '808sd/SD0050.WAV'], + hh: ['hh27/000_hh27closedhh.wav', 'hh/000_hh3closedhh.wav'], + }, + 'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/', +); + evalScope( Tone, controls, From 8e61673bd68c9a84eff459541bbe83030998eefb Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Wed, 14 Sep 2022 21:54:42 +0200 Subject: [PATCH 2/5] doc: degradeBy --- packages/core/signal.mjs | 12 ++++++++++++ tutorial/tutorial.mdx | 10 ++++++---- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/packages/core/signal.mjs b/packages/core/signal.mjs index a13674f1..28fc491e 100644 --- a/packages/core/signal.mjs +++ b/packages/core/signal.mjs @@ -223,6 +223,18 @@ 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.5).out() + */ Pattern.prototype._degradeBy = function (x) { return this._degradeByWith(rand, x); }; diff --git a/tutorial/tutorial.mdx b/tutorial/tutorial.mdx index f8995a33..e95ea5fe 100644 --- a/tutorial/tutorial.mdx +++ b/tutorial/tutorial.mdx @@ -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). @@ -450,6 +450,8 @@ Stacks the given pattern to the current pattern: +{{ 'Pattern.degradeBy' | jsdoc }} + ## Tone API To make the sounds more interesting, we can use Tone.js instruments ands effects. From a022e5bb9315c8446b66355d635b2a2ddfbfc79a Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Wed, 14 Sep 2022 21:55:09 +0200 Subject: [PATCH 3/5] add missing external deps to react pkg --- packages/react/vite.config.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/react/vite.config.js b/packages/react/vite.config.js index d51ef97a..6786d022 100644 --- a/packages/react/vite.config.js +++ b/packages/react/vite.config.js @@ -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', From ce91d36b7a0059f01cfb67aff56ea61dbbfa57ab Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Wed, 14 Sep 2022 23:16:24 +0200 Subject: [PATCH 4/5] 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. From f0e412a44344d1b6b96bd9280f44ad1784c30c94 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Wed, 14 Sep 2022 23:40:48 +0200 Subject: [PATCH 5/5] doc: chooseCycles + mini shorthands --- packages/core/signal.mjs | 21 ++++++++++++++------- tutorial/MiniRepl.jsx | 2 +- tutorial/tutorial.mdx | 4 +++- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/packages/core/signal.mjs b/packages/core/signal.mjs index b43ecadf..9a4b5fe5 100644 --- a/packages/core/signal.mjs +++ b/packages/core/signal.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; @@ -234,6 +242,8 @@ Pattern.prototype._degradeByWith = function (withPat, x) { * @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); @@ -248,6 +258,8 @@ Pattern.prototype._degradeBy = function (x) { * @returns Pattern * @example * s("hh*8").degrade().out() + * @example + * s("[hh?]*8").out() */ Pattern.prototype.degrade = function () { return this._degradeBy(0.5); @@ -265,11 +277,6 @@ Pattern.prototype.degrade = function () { * @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( diff --git a/tutorial/MiniRepl.jsx b/tutorial/MiniRepl.jsx index 405cd94d..0f18c2b6 100644 --- a/tutorial/MiniRepl.jsx +++ b/tutorial/MiniRepl.jsx @@ -15,7 +15,7 @@ export const defaultSynth = new Tone.PolySynth().chain(new Tone.Gain(0.5), Tone. samples( { bd: '808bd/BD0000.WAV', - sd: ['808sd/SD0000.WAV', '808sd/SD0010.WAV', '808sd/SD0050.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/', diff --git a/tutorial/tutorial.mdx b/tutorial/tutorial.mdx index 4ff4a20a..8e1fc75e 100644 --- a/tutorial/tutorial.mdx +++ b/tutorial/tutorial.mdx @@ -452,7 +452,9 @@ Stacks the given pattern to the current pattern: ## Randomness -These methods add random behavior to your Patterns. +These methods add random behavior to your Patterns. + +{{ 'chooseCycles' | jsdoc }} {{ 'Pattern.degradeBy' | jsdoc }}