Merge pull request #212 from tidalcycles/even-more-docs

Even more docs
This commit is contained in:
Felix Roos 2022-09-17 23:47:43 +02:00 committed by GitHub
commit c1a27aa6e4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 481 additions and 464 deletions

View File

@ -513,11 +513,14 @@ export class Pattern {
}
/**
* Assumes a numerical pattern, containing unipolar values in the range 0 ..
* 1. Returns a new pattern with values scaled to the given min/max range.
* @param {Number} min
* @param {Number} max
* Assumes a numerical pattern, containing unipolar values in the range 0 .. 1.
* Returns a new pattern with values scaled to the given min/max range.
* Most useful in combination with continuous patterns.
* @name range
* @memberof Pattern
* @returns Pattern
* @example
* s("bd sd,hh*4").cutoff(sine.range(500,2000).slow(4)).out()
*/
range(min, max) {
return this.mul(max - min).add(min);
@ -683,6 +686,16 @@ export class Pattern {
return func(this);
}
/**
* Layers the result of the given function(s). Like {@link superimpose}, but without the original pattern:
* @name layer
* @memberof Pattern
* @returns Pattern
* @example
* "<0 2 4 6 ~ 4 ~ 2 0!3 ~!5>*4"
* .layer(x=>x.add("0,2"))
* .scale('C minor').note().out()
*/
layer(...funcs) {
return stack(...funcs.map((func) => func(this)));
}
@ -734,14 +747,14 @@ export class Pattern {
}
/**
* Speed up a pattern by the given factor.
* Speed up a pattern by the given factor. Used by "*" in mini notation.
*
* @name fast
* @memberof Pattern
* @param {number | Pattern} factor speed up factor
* @returns Pattern
* @example
* seq(e5, b4, d5, c5).fast(2)
* s("<bd sd> hh").fast(2).out() // s("[<bd sd> hh]*2").out()
*/
_fast(factor) {
const fastQuery = this.withQueryTime((t) => t.mul(factor));
@ -749,14 +762,14 @@ export class Pattern {
}
/**
* Slow down a pattern over the given number of cycles.
* Slow down a pattern over the given number of cycles. Like the "/" operator in mini notation.
*
* @name slow
* @memberof Pattern
* @param {number | Pattern} factor slow down factor
* @returns Pattern
* @example
* seq(e5, b4, d5, c5).slow(2)
* s("<bd sd> hh").slow(2).out() // s("[<bd sd> hh]/2").out()
*/
_slow(factor) {
return this._fast(Fraction(1).div(factor));
@ -795,14 +808,32 @@ export class Pattern {
return this._fast(cpm / 60);
}
/**
* Nudge a pattern to start earlier in time. Equivalent of Tidal's <~ operator
*
* @name early
* @memberof Pattern
* @param {number | Pattern} cycles number of cycles to nudge left
* @returns Pattern
* @example
* "bd ~".stack("hh ~".early(.1)).s().out()
*/
_early(offset) {
// Equivalent of Tidal's <~ operator
offset = Fraction(offset);
return this.withQueryTime((t) => t.add(offset)).withHapTime((t) => t.sub(offset));
}
/**
* Nudge a pattern to start later in time. Equivalent of Tidal's ~> operator
*
* @name late
* @memberof Pattern
* @param {number | Pattern} cycles number of cycles to nudge right
* @returns Pattern
* @example
* "bd ~".stack("hh ~".late(.1)).s().out()
*/
_late(offset) {
// Equivalent of Tidal's ~> operator
offset = Fraction(offset);
return this._early(Fraction(0).sub(offset));
}
@ -829,6 +860,17 @@ export class Pattern {
return this._zoom(0, t)._slow(t);
}
/**
* Applies the given structure to the pattern:
*
* @name struct
* @memberof Pattern
* @returns Pattern
* @example
* "c3,eb3,g3"
* .struct("x ~ x ~ ~ x ~ x ~ ~ ~ x ~ x ~ ~")
* .slow(4).note().out()
*/
// struct(...binary_pats) {
// // Re structure the pattern according to a binary pattern (false values are dropped)
// const binary_pat = sequence(binary_pats);
@ -876,6 +918,16 @@ export class Pattern {
return this.invert();
}
/**
* Applies the given function whenever the given pattern is in a true state.
* @name when
* @memberof Pattern
* @param {Pattern} binary_pat
* @param {function} func
* @returns Pattern
* @example
* "c3 eb3 g3".when("<0 1>/2", x=>x.sub(5))
*/
when(binary_pat, func) {
//binary_pat = sequence(binary_pat)
const true_pat = binary_pat._filterValues(id);
@ -885,10 +937,47 @@ export class Pattern {
return stack(with_pat, without_pat);
}
/**
* Superimposes the function result on top of the original pattern, delayed by the given time.
* @name off
* @memberof Pattern
* @param {Pattern | number} time offset time
* @param {function} func function to apply
* @returns Pattern
* @example
* "c3 eb3 g3".off(1/8, x=>x.add(7))
*/
off(time_pat, func) {
return stack(this, func(this.late(time_pat)));
}
/**
* Applies the given function every n cycles.
* @name every
* @memberof Pattern
* @param {number} n how many cycles
* @param {function} func function to apply
* @returns Pattern
* @example
* note("c3 d3 e3 g3").every(4, x=>x.rev()).out()
*/
every(n, func) {
const pat = this;
const pats = Array(n - 1).fill(pat);
// pats.unshift(func(pat));
pats.push(func(pat));
return slowcatPrime(...pats);
}
/**
* Applies the given function every n cycles, starting from the first cycle.
* @name every
* @memberof Pattern
* @param {number} n how many cycles
* @param {function} func function to apply
* @returns Pattern
* @example
* note("c3 d3 e3 g3").every(4, x=>x.rev()).out()
*/
every(n, func) {
const pat = this;
const pats = Array(n - 1).fill(pat);
@ -896,6 +985,23 @@ export class Pattern {
return slowcatPrime(...pats);
}
/**
* Applies the given function every n cycles, starting from the last cycle.
* @name each
* @memberof Pattern
* @param {number} n how many cycles
* @param {function} func function to apply
* @returns Pattern
* @example
* note("c3 d3 e3 g3").every(4, x=>x.rev()).out()
*/
each(n, func) {
const pat = this;
const pats = Array(n - 1).fill(pat);
pats.push(func(pat));
return slowcatPrime(...pats);
}
/**
* Returns a new pattern where every other cycle is played once, twice as
* fast, and offset in time by one quarter of a cycle. Creates a kind of
@ -906,6 +1012,15 @@ export class Pattern {
return this.when(slowcat(false, true), (x) => fastcat(x, silence)._late(0.25));
}
/**
* Reverse all haps in a pattern
*
* @name rev
* @memberof Pattern
* @returns Pattern
* @example
* "c3 d3 e3 g3".rev()
*/
rev() {
const pat = this;
const query = function (state) {
@ -948,6 +1063,15 @@ export class Pattern {
return this.juxBy(1, func);
}
/**
* Stacks the given pattern(s) to the current pattern.
* @name stack
* @memberof Pattern
* @example
* s("hh*2").stack(
* n("c2(3,8)")
* ).out()
*/
stack(...pats) {
return stack(this, ...pats);
}
@ -956,11 +1080,28 @@ export class Pattern {
return sequence(this, ...pats);
}
// shorthand for sequence
/**
* Appends the given pattern(s) to the current pattern. Synonyms: .sequence .fastcat
* @name seq
* @memberof Pattern
* @example
* s("hh*2").seq(
* n("c2(3,8)")
* ).out()
*/
seq(...pats) {
return sequence(this, ...pats);
}
/**
* Appends the given pattern(s) to the next cycle. Synonym: .slowcat
* @name cat
* @memberof Pattern
* @example
* s("hh*2").cat(
* n("c2(3,8)")
* ).out()
*/
cat(...pats) {
return cat(this, ...pats);
}
@ -973,6 +1114,16 @@ export class Pattern {
return slowcat(this, ...pats);
}
/**
* Superimposes the result of the given function(s) on top of the original pattern:
* @name superimpose
* @memberof Pattern
* @returns Pattern
* @example
* "<0 2 4 6 ~ 4 ~ 2 0!3 ~!5>*4"
* .superimpose(x=>x.add(2))
* .scale('C minor').note().out()
*/
superimpose(...funcs) {
return this.stack(...funcs.map((func) => func(this)));
}
@ -1184,6 +1335,11 @@ Pattern.prototype.patternified = [
'slow',
'velocity',
];
// aliases
export const polyrhythm = stack;
export const pr = stack;
// methods that create patterns, which are added to patternified Pattern methods
Pattern.prototype.factories = {
pure,
@ -1206,12 +1362,11 @@ Pattern.prototype.factories = {
// Nothing
export const silence = new Pattern((_) => []);
/** A discrete value that repeats once per cycle:
/** A discrete value that repeats once per cycle.
*
* @param {any} value - The value to repeat
* @returns {Pattern}
* @example
* pure('e4')
* pure('e4') // "e4"
*/
export function pure(value) {
function query(state) {
@ -1241,12 +1396,11 @@ export function reify(thing) {
return pure(thing);
}
/** The given items are played at the same time at the same length:
/** The given items are played at the same time at the same length.
*
* @param {...any} items - The items to stack
* @return {Pattern}
* @example
* stack(g3, b3, [e4, d4])
* stack(g3, b3, [e4, d4]) // "g3,b3,[e4,d4]"
*/
export function stack(...pats) {
// Array test here is to avoid infinite recursions..
@ -1259,7 +1413,6 @@ export function stack(...pats) {
*
* synonyms: {@link cat}
*
* @param {...any} items - The items to concatenate
* @return {Pattern}
* @example
* slowcat(e5, b4, [d5, c5])
@ -1315,16 +1468,22 @@ export function fastcat(...pats) {
return slowcat(...pats)._fast(pats.length);
}
/** See {@link slowcat} */
/** The given items are con**cat**enated, where each one takes one cycle. Synonym: slowcat
*
* @param {...any} items - The items to concatenate
* @return {Pattern}
* @example
* cat(e5, b4, [d5, c5]) // "<e5 b4 [d5 c5]>"
*
*/
export function cat(...pats) {
return slowcat(...pats);
}
/** Like {@link fastcat}, but where each step has a temporal weight:
* @param {...Array} items - The items to concatenate
/** Like {@link seq}, but each step has a length, relative to the whole.
* @return {Pattern}
* @example
* timeCat([3,e3],[1, g3])
* timeCat([3,e3],[1, g3]) // "e3@3 g3"
*/
export function timeCat(...timepats) {
const total = timepats.map((a) => a[0]).reduce((a, b) => a.add(b), Fraction(0));
@ -1343,7 +1502,11 @@ export function sequence(...pats) {
return fastcat(...pats);
}
/** See {@link fastcat} */
/** Like **cat**, but the items are crammed into one cycle. Synonyms: fastcat, sequence
* @example
* seq(e5, b4, [d5, c5]) // "e5 b4 [d5 c5]"
*
*/
export function seq(...pats) {
return fastcat(...pats);
}
@ -1392,20 +1555,6 @@ export function pm(...args) {
polymeter(...args);
}
export function polyrhythm(...xs) {
const seqs = xs.map((a) => sequence(a));
if (seqs.length == 0) {
return silence;
}
return stack(...seqs);
}
// alias
export function pr(args) {
polyrhythm(args);
}
export const add = curry((a, pat) => pat.add(a));
export const chop = curry((a, pat) => pat.chop(a));
export const chunk = curry((a, pat) => pat.chunk(a));

View File

@ -74,7 +74,7 @@ export const square2 = square._toBipolar();
*
* @return {Pattern}
* @example
* triangle.segment(2).range(0,7).scale('C minor')
* tri.segment(8).range(0,7).scale('C minor')
*
*/
export const tri = fastcat(isaw, saw);
@ -111,7 +111,17 @@ const timeToRandsPrime = (seed, n) => {
const timeToRands = (t, n) => timeToRandsPrime(timeToIntSeed(t), n);
/**
* A continuous pattern of random numbers, between 0 and 1
*
*/
/**
* A continuous pattern of random numbers, between 0 and 1.
*
* @name rand
* @example
* // randomly change the cutoff
* s("bd sd,hh*4").cutoff(rand.range(500,2000)).out()
*
*/
export const rand = signal(timeToRand);
/**
@ -124,6 +134,17 @@ export const brandBy = (pPat) => reify(pPat).fmap(_brandBy).innerJoin();
export const brand = _brandBy(0.5);
export const _irand = (i) => rand.fmap((x) => Math.trunc(x * i));
/**
* A continuous pattern of random integers, between 0 and n-1.
*
* @name irand
* @param {number} n max value (exclusive)
* @example
* // randomly select scale notes from 0 - 7 (= C to C)
* irand(8).struct("x(3,8)").scale('C minor').note().out()
*
*/
export const irand = (ipat) => reify(ipat).fmap(_irand).innerJoin();
export const __chooseWith = (pat, xs) => {
@ -225,6 +246,15 @@ export const perlinWith = (pat) => {
return pat.sub(pata).fmap(interp).appBoth(pata.fmap(timeToRand)).appBoth(patb.fmap(timeToRand));
};
/**
* Generates a continuous pattern of [perlin noise](https://en.wikipedia.org/wiki/Perlin_noise), in the range 0..1.
*
* @name perlin
* @example
* // randomly change the cutoff
* s("bd sd,hh*4").cutoff(perlin.range(500,2000)).out()
*
*/
export const perlin = perlinWith(time);
Pattern.prototype._degradeByWith = function (withPat, x) {

View File

@ -413,65 +413,21 @@ The above is the same as:
Using strings, you can also use "#".
## Functions that create Patterns
## Pattern Factories
The following functions will return a pattern. We will see later what that means.
The following functions will return a pattern.
## pure(value)
To create a pattern from a value, you can wrap the value in pure:
<MiniRepl tune={`pure('e4')`} />
{{ 'pure' | jsdoc }}
Most of the time, you won't need that function as input values of pattern creating functions are purified by default.
### cat(...values)
{{ 'cat' | jsdoc }}
The given items are con**cat**enated, where each one takes one cycle:
{{ 'seq' | jsdoc }}
<MiniRepl tune={`cat(e5, b4, [d5, c5])`} />
{{ 'stack' | jsdoc }}
- Square brackets will create a subsequence
- The function **slowcat** does the same as **cat**.
### seq(...values)
Like **cat**, but the items are crammed into one cycle:
<MiniRepl tune={`seq(e5, b4, [d5, c5])`} />
- Synonyms: **fastcat**, **sequence**
### stack(...values)
The given items are played at the same time at the same length:
<MiniRepl tune={`stack(g3, b3, [e4, d4])`} />
- Square Brackets will create a subsequence
### Nesting functions
You can nest functions inside one another:
<MiniRepl
tune={`cat(
stack(g3,b3,e4),
stack(a3,c3,e4),
stack(b3,d3,fs4),
stack(b3,e4,g4)
)`}
/>
The above is equivalent to
<MiniRepl tune={`"<[g3,b3,e4] [a3,c3,e4] [b3,d3,f#4] [b3,e4,g4]>"`} />
### timeCat(...[weight,value])
Like with "@" in mini notation, we can specify weights to the items in a sequence:
<MiniRepl tune={`timeCat([3,e3],[1, g3])`} />
{{ 'timeCat' | jsdoc }}
<!-- ## polymeter
@ -479,6 +435,10 @@ how to use?
<MiniRepl tune={`polymeter(3, e3, g3, b3)`} /> -->
<!--
see https://github.com/tidalcycles/strudel/discussions/211
### polyrhythm(...[...values])
Plays the given items at the same time, within the same length:
@ -491,59 +451,82 @@ We can write the same with **stack** and **cat**:
You can also use the shorthand **pr** instead of **polyrhythm**.
## Pattern modifier functions
-->
The following functions modify a pattern.
## Combining Patterns
### slow(factor)
You can freely mix JS patterns, mini patterns and values! For example, this pattern:
Like "/" in mini notation, **slow** will slow down a pattern over the given number of cycles:
<MiniRepl
tune={`cat(
stack(g3,b3,e4),
stack(a3,c3,e4),
stack(b3,d3,fs4),
stack(b3,e4,g4)
)`}
/>
<MiniRepl tune={`seq(e5, b4, d5, c5).slow(2)`} />
...is equivalent to:
The same in mini notation:
<MiniRepl
tune={`cat(
"g3,b3,e4",
"a3,c3,e4",
"b3,d3,f#4",
"b3,e4,g4"
)`}
/>
<MiniRepl tune={`"[e5 b4 d5 c5]/2"`} />
... as well as:
### fast(factor)
<MiniRepl tune={`"<[g3,b3,e4] [a3,c3,e4] [b3,d3,f#4] [b3,e4,g4]>"`} />
Like "\*" in mini notation, **fast** will play a pattern times the given number in one cycle:
While mini notation is almost always shorter, it only has a handful of modifiers: \* / ! @.
When using JS patterns, there is a lot more you can do.
<MiniRepl tune={`seq(e5, b4, d5, c5).fast(2)`} />
## Time Modifiers
### early(cycles)
The following functions modify a pattern temporal structure in some way.
With early, you can nudge a pattern to start earlier in time:
{{ 'Pattern.slow' | jsdoc }}
<MiniRepl tune={`seq(e5, b4.early(0.5))`} />
{{ 'Pattern.fast' | jsdoc }}
### late(cycles)
{{ 'Pattern.early' | jsdoc }}
Like early, but in the other direction:
{{ 'Pattern.late' | jsdoc }}
<MiniRepl tune={`seq(e5, b4.late(0.5))`} />
{{ 'Pattern.rev' | jsdoc }}
<!-- TODO: shouldn't it sound different? -->
{{ 'Pattern.struct' | jsdoc }}
### rev()
{{ 'Pattern.legato' | jsdoc }}
Will reverse the pattern:
## Conditional Modifiers
<MiniRepl tune={`seq(c3,d3,e3,f3).rev()`} />
{{ 'Pattern.every' | jsdoc }}
### every(n, func)
{{ 'Pattern.each' | jsdoc }}
Will apply the given function every n cycles:
{{ 'Pattern.when' | jsdoc }}
<MiniRepl tune={`seq(e5, "b4".every(4, late(0.5)))`} />
## Accumulation Modifiers
<!-- TODO: should be able to do b4.every => like already possible with fast slow etc.. -->
{{ 'Pattern.stack' | jsdoc }}
Note that late is called directly. This is a shortcut for:
{{ 'Pattern.superimpose' | jsdoc }}
<MiniRepl tune={`seq(e5, "b4".every(4, x => x.late(0.5)))`} />
{{ 'Pattern.layer' | jsdoc }}
<!-- TODO: should the function really run the first cycle? -->
{{ 'Pattern.off' | jsdoc }}
## Concat Modifiers
{{ 'Pattern.seq' | jsdoc }}
{{ 'Pattern.cat' | jsdoc }}
## Value Modifiers
### add(n)
@ -597,56 +580,42 @@ Rounds all values to the nearest integer:
<MiniRepl tune={`"0.5 1.5 2.5".round().scale('C major')`} />
### struct(binary_pat)
Applies the given structure to the pattern:
<MiniRepl tune={`"c3,eb3,g3".struct("x ~ x ~ ~ x ~ x ~ ~ ~ x ~ x ~ ~").slow(4)`} />
This is also useful to sample signals:
<MiniRepl
tune={`sine.struct("x ~ x ~ ~ x ~ x ~ ~ ~ x ~ x ~ ~").mul(7).round()
.scale('C minor').slow(4)`}
/>
### when(binary_pat, func)
Applies the given function whenever the given pattern is in a true state.
<MiniRepl tune={`"c3 eb3 g3".when("<0 1>/2", sub(5))`} />
### superimpose(...func)
Superimposes the result of the given function(s) on top of the original pattern:
<MiniRepl tune={`"<c3 eb3 g3>".scale('C minor').superimpose(scaleTranspose("2,4"))`} />
### layer(...func)
Layers the result of the given function(s) on top of each other. Like superimpose, but the original pattern is not part of the result.
<MiniRepl tune={`"<c3 eb3 g3>".scale('C minor').layer(scaleTranspose("0,2,4"))`} />
### apply(func)
Like layer, but with a single function:
<MiniRepl tune={`"<c3 eb3 g3>".scale('C minor').apply(scaleTranspose("0,2,4"))`} />
### off(time, func)
{{ 'Pattern.range' | jsdoc }}
Applies the given function by the given time offset:
## Continuous Signals
<MiniRepl tune={`"c3 eb3 g3".off(1/8, add(7))`} />
Signals are patterns with continuous values, meaning they have theoretically infinite steps.
They can provide streams of numbers that can be sampled at discrete points in time.
### stack(pat)
##
Stacks the given pattern to the current pattern:
{{ 'saw' | jsdoc }}
<MiniRepl tune={`"c4,eb4,g4".stack("bb4,d5")`} />
{{ 'sine' | jsdoc }}
## Randomness
{{ 'cosine' | jsdoc }}
{{ 'tri' | jsdoc }}
{{ 'square' | jsdoc }}
### Ranges from -1 to 1
There is also `saw2`, `sine2`, `cosine2`, `tri2` and `square2` which have a range from -1 to 1!
{{ 'rand' | jsdoc }}
{{ 'perlin' | jsdoc }}
{{ 'irand' | jsdoc }}
## Random Modifiers
These methods add random behavior to your Patterns.
@ -678,11 +647,186 @@ These methods add random behavior to your Patterns.
{{ 'Pattern.always' | jsdoc }}
## Tone API
# Tonal API
To make the sounds more interesting, we can use Tone.js instruments ands effects.
The Tonal API, uses [tonaljs](https://github.com/tonaljs/tonal) to provide helpers for musical operations.
[Show Source on Github](https://github.com/tidalcycles/strudel/blob/main/repl/src/tone.ts)
### transpose(semitones)
Transposes all notes to the given number of semitones:
<MiniRepl tune={`"c2 c3".fast(2).transpose("<0 -2 5 3>".slow(2)).transpose(0)`} />
This method gets really exciting when we use it with a pattern as above.
Instead of numbers, scientific interval notation can be used as well:
<MiniRepl tune={`"c2 c3".fast(2).transpose("<1P -2M 4P 3m>".slow(2)).transpose(1)`} />
### scale(name)
Turns numbers into notes in the scale (zero indexed). Also sets scale for other scale operations, like scaleTranpose.
<MiniRepl
tune={`"0 2 4 6 4 2"
.scale(seq('C2 major', 'C2 minor').slow(2))`}
/>
Note that the scale root is octaved here. You can also omit the octave, then index zero will default to octave 3.
All the available scale names can be found [here](https://github.com/tonaljs/tonal/blob/main/packages/scale-type/data.ts).
### scaleTranspose(steps)
Transposes notes inside the scale by the number of steps:
<MiniRepl
tune={`"-8 [2,4,6]"
.scale('C4 bebop major')
.scaleTranspose("<0 -1 -2 -3 -4 -5 -6 -4>")`}
/>
### voicings(range?)
Turns chord symbols into voicings, using the smoothest voice leading possible:
<MiniRepl tune={`stack("<C^7 A7 Dm7 G7>".voicings(), "<C3 A2 D3 G2>")`} />
<!-- TODO: use voicing collection as first param + patternify. -->
### rootNotes(octave = 2)
Turns chord symbols into root notes of chords in given octave.
<MiniRepl tune={`"<C^7 A7b13 Dm7 G7>".rootNotes(3)`} />
Together with layer, struct and voicings, this can be used to create a basic backing track:
<MiniRepl
tune={`"<C^7 A7b13 Dm7 G7>".layer(
x => x.voicings(['d3','g4']).struct("~ x"),
x => x.rootNotes(2).tone(synth(osc('sawtooth4')).chain(out()))
)`}
/>
<!-- TODO: use range instead of octave. -->
<!-- TODO: find out why composition does not work -->
## Microtonal API
TODO
## MIDI API
Strudel also supports midi via [webmidi](https://npmjs.com/package/webmidi).
### midi(outputName?)
Make sure to have a midi device connected or to use an IAC Driver.
If no outputName is given, it uses the first midi output it finds.
Midi is currently not supported by the mini repl used here, but you can [open the midi example in the repl](https://strudel.tidalcycles.org/#c3RhY2soIjxDXjcgQTcgRG03IEc3PiIubS52b2ljaW5ncygpLCAnPEMzIEEyIEQzIEcyPicubSkKICAubWlkaSgp).
In the REPL, you will se a log of the available MIDI devices.
<!--<MiniRepl
tune={`stack("<C^7 A7 Dm7 G7>".voicings(), "<C3 A2 D3 G2>")
.midi()`}
/>-->
# Superdirt API
In mainline tidal, the actual sound is generated via Superdirt, which runs inside Supercollider.
Strudel also supports using Superdirt as a backend, although it requires some developer tooling to run.
## Prequisites
Getting Superdirt to work with Strudel, you need to
1. install SuperCollider + sc3 plugins, see [Tidal Docs](https://tidalcycles.org/docs/) (Install Tidal) for more info.
2. install [node.js](https://nodejs.org/en/)
3. download [Strudel Repo](https://github.com/tidalcycles/strudel/) (or git clone, if you have git installed)
4. run `npm i` in the strudel directory
5. run `npm run osc` to start the osc server, which forwards OSC messages from Strudel REPL to SuperCollider
Now you're all set!
## Usage
1. Start SuperCollider, either using SuperCollider IDE or by running `sclang` in a terminal
2. Open the [Strudel REPL](https://strudel.tidalcycles.org/#cygiYmQgc2QiKS5vc2MoKQ%3D%3D)
...or test it here:
<MiniRepl tune={`s("bd sd").osc()`} />
If you now hear sound, congratulations! If not, you can get help on the [#strudel channel in the TidalCycles discord](https://discord.com/invite/HGEdXmRkzT).
{{ 'Pattern.osc' | jsdoc }}
## Superdirt Params
The following functions can be used with superdirt:
- s
- n
- freq
- channel
- orbit
- cutoff
- resonance
- hcutoff
- hresonance
- bandf
- bandq
- djf
- vowelSa
- cut
- begin
- end
- loop
- fadeTime
- speed
- unitA
- gain
- amp
- accelerate
- crush
- coarse
- delay
- lock
- leslie
- lrate
- lsize
- pan
- panspan
- pansplay
- room
- size
- dry
- shape
- squiz
- waveloss
- attack
- decayS
- octave
- detune
- tremolodepth
Please refer to [Tidal Docs](https://tidalcycles.org/) for more info.
# Webdirt API (deprecated)
You can use the powerful sampling engine [Webdirt](https://github.com/dktr0/WebDirt) with Strudel.
{{ 'Pattern.webdirt' | jsdoc }}
<br />
<br />
# Tone API (deprecated)
The Tone API uses Tone.js instruments ands effects to create sounds.
<MiniRepl
tune={`stack(
@ -819,309 +963,3 @@ Helper to set the envelope of a Tone.js instrument. Intended to be used with Ton
tune={`"[c4 c4 bb3 c4] [~ g3 ~ g3] [c4 f4 e4 c4] ~".slow(4)
.tone(synth(adsr(0,.1,0,0)).chain(out()))`}
/>
## Tonal API
The Tonal API, uses [tonaljs](https://github.com/tonaljs/tonal) to provide helpers for musical operations.
### transpose(semitones)
Transposes all notes to the given number of semitones:
<MiniRepl tune={`"c2 c3".fast(2).transpose("<0 -2 5 3>".slow(2)).transpose(0)`} />
This method gets really exciting when we use it with a pattern as above.
Instead of numbers, scientific interval notation can be used as well:
<MiniRepl tune={`"c2 c3".fast(2).transpose("<1P -2M 4P 3m>".slow(2)).transpose(1)`} />
### scale(name)
Turns numbers into notes in the scale (zero indexed). Also sets scale for other scale operations, like scaleTranpose.
<MiniRepl
tune={`"0 2 4 6 4 2"
.scale(seq('C2 major', 'C2 minor').slow(2))`}
/>
Note that the scale root is octaved here. You can also omit the octave, then index zero will default to octave 3.
All the available scale names can be found [here](https://github.com/tonaljs/tonal/blob/main/packages/scale-type/data.ts).
### scaleTranspose(steps)
Transposes notes inside the scale by the number of steps:
<MiniRepl
tune={`"-8 [2,4,6]"
.scale('C4 bebop major')
.scaleTranspose("<0 -1 -2 -3 -4 -5 -6 -4>")`}
/>
### voicings(range?)
Turns chord symbols into voicings, using the smoothest voice leading possible:
<MiniRepl tune={`stack("<C^7 A7 Dm7 G7>".voicings(), "<C3 A2 D3 G2>")`} />
<!-- TODO: use voicing collection as first param + patternify. -->
### rootNotes(octave = 2)
Turns chord symbols into root notes of chords in given octave.
<MiniRepl tune={`"<C^7 A7b13 Dm7 G7>".rootNotes(3)`} />
Together with layer, struct and voicings, this can be used to create a basic backing track:
<MiniRepl
tune={`"<C^7 A7b13 Dm7 G7>".layer(
x => x.voicings(['d3','g4']).struct("~ x"),
x => x.rootNotes(2).tone(synth(osc('sawtooth4')).chain(out()))
)`}
/>
<!-- TODO: use range instead of octave. -->
<!-- TODO: find out why composition does not work -->
## Microtonal API
TODO
## MIDI API
Strudel also supports midi via [webmidi](https://npmjs.com/package/webmidi).
### midi(outputName?)
Make sure to have a midi device connected or to use an IAC Driver.
If no outputName is given, it uses the first midi output it finds.
Midi is currently not supported by the mini repl used here, but you can [open the midi example in the repl](https://strudel.tidalcycles.org/#c3RhY2soIjxDXjcgQTcgRG03IEc3PiIubS52b2ljaW5ncygpLCAnPEMzIEEyIEQzIEcyPicubSkKICAubWlkaSgp).
In the REPL, you will se a log of the available MIDI devices.
<!--<MiniRepl
tune={`stack("<C^7 A7 Dm7 G7>".voicings(), "<C3 A2 D3 G2>")
.midi()`}
/>-->
# Contributing
Contributions of any sort are very welcome! You can contribute by editing [this file](https://github.com/tidalcycles/strudel/blob/main/repl/src/tutorial/tutorial.mdx).
All you need is a github account.
If you want to run the tutorial locally, you can clone the and run:
```sh
cd repl && npm i && npm run tutorial
```
If you want to contribute in another way, either
- [fork strudel repo on GitHub](https://github.com/tidalcycles/strudel)
- [Join the Discord Channel](https://discord.gg/remJ6gQA)
- [play with the Strudel REPL](https://strudel.tidalcycles.org/)
<br />
<br />
# API Docs
The following is generated from the source documentation.
## Pattern Factories
The following functions will return a pattern. We will see later what that means.
{{ 'pure' | jsdoc }}
{{ 'slowcat' | jsdoc }}
{{ 'fastcat' | jsdoc }}
{{ 'stack' | jsdoc }}
{{ 'timeCat' | jsdoc }}
{{ 'polyrhythm' | jsdoc }}
## Pattern Modifiers
{{ 'Pattern.slow' | jsdoc }}
{{ 'Pattern.fast' | jsdoc }}
{{ 'Pattern.early' | jsdoc }}
{{ 'Pattern.late' | jsdoc }}
{{ 'Pattern.rev' | jsdoc }}
{{ 'Pattern.legato' | jsdoc }}
## Continuous Signals
Signals are patterns with continuous values, meaning they have theoretically infinite steps.
They can provide streams of numbers that can be sampled at discrete points in time.
{{ 'Pattern.range' | jsdoc }}
{{ 'saw' | jsdoc }}
{{ 'saw2' | jsdoc }}
{{ 'sine' | jsdoc }}
{{ 'sine2' | jsdoc }}
{{ 'cosine' | jsdoc }}
{{ 'cosine2' | jsdoc }}
{{ 'tri' | jsdoc }}
{{ 'tri2' | jsdoc }}
{{ 'square' | jsdoc }}
{{ 'square2' | jsdoc }}
## Using Samples with Webdirt
You can use the powerful sampling engine [Webdirt](https://github.com/dktr0/WebDirt) with Strudel.
{{ 'Pattern.webdirt' | jsdoc }}
## Using Superdirt via OSC
In mainline tidal, the actual sound is generated via Superdirt, which runs inside Supercollider.
Strudel also supports using Superdirt as a backend, although it requires some developer tooling to run.
### Getting Started
Getting Superdirt to work with Strudel, you need to
1. install SuperCollider + sc3 plugins, see [Tidal Docs](https://tidalcycles.org/docs/) (Install Tidal) for more info.
2. install [node.js](https://nodejs.org/en/)
3. download [Strudel Repo](https://github.com/tidalcycles/strudel/) (or git clone, if you have git installed)
4. run `npm i` in the strudel directory
5. run `npm run osc` to start the osc server, which forwards OSC messages from Strudel REPL to SuperCollider
Now you're all set!
### Usage
1. Start SuperCollider, either using SuperCollider IDE or by running `sclang` in a terminal
2. Open the [Strudel REPL](https://strudel.tidalcycles.org/#cygiYmQgc2QiKS5vc2MoKQ%3D%3D)
...or test it here:
<MiniRepl tune={`s("bd sd").osc()`} />
If you now hear sound, congratulations! If not, you can get help on the [#strudel channel in the TidalCycles discord](https://discord.com/invite/HGEdXmRkzT).
{{ 'Pattern.osc' | jsdoc }}
# Superdirt Params
The following functions are specific to SuperDirt and won't work with other Strudel outputs.
## Basic Types
{{ 's' | jsdoc }}
{{ 'n' | jsdoc }}
{{ 'freq' | jsdoc }}
{{ 'channel' | jsdoc }}
{{ 'orbit' | jsdoc }}
## Filters
{{ 'cutoff' | jsdoc }}
{{ 'resonance' | jsdoc }}
{{ 'hcutoff' | jsdoc }}
{{ 'hresonance' | jsdoc }}
{{ 'bandf' | jsdoc }}
{{ 'bandq' | jsdoc }}
{{ 'djf' | jsdoc }}
{{ 'vowel' | jsdoc }}
## Sample Editing
{{ 'cut' | jsdoc }}
{{ 'begin' | jsdoc }}
{{ 'end' | jsdoc }}
{{ 'loop' | jsdoc }}
{{ 'fadeTime' | jsdoc }}
{{ 'speed' | jsdoc }}
{{ 'unit' | jsdoc }}
## Audio Effects
{{ 'gain' | jsdoc }}
{{ 'amp' | jsdoc }}
{{ 'accelerate' | jsdoc }}
{{ 'crush' | jsdoc }}
{{ 'coarse' | jsdoc }}
{{ 'delay' | jsdoc }}
{{ 'lock' | jsdoc }}
{{ 'leslie' | jsdoc }}
{{ 'lrate' | jsdoc }}
{{ 'lsize' | jsdoc }}
{{ 'pan' | jsdoc }}
{{ 'panspan' | jsdoc }}
{{ 'pansplay' | jsdoc }}
{{ 'room' | jsdoc }}
{{ 'size' | jsdoc }}
{{ 'dry' | jsdoc }}
{{ 'shape' | jsdoc }}
{{ 'squiz' | jsdoc }}
{{ 'waveloss' | jsdoc }}
{{ 'attack' | jsdoc }}
{{ 'decay' | jsdoc }}
## Synth Effects
{{ 'octave' | jsdoc }}
{{ 'detune' | jsdoc }}
{{ 'tremolodepth' | jsdoc }}