make 0.5hz cps the default (#931)

* 0.5 default cps

* 1 -> 0.5 cps defaults

* start moving examples to 2Hz

* more 2Hz doc edits

* small tweaks

* format

* adapt cycles page

* adapt pitch page

* tonal page

* accumulation

* synth page

* adapt conditional-modifiers

* audio effects page

* adapt signals doc

* fix: errors for signals

* adapt signals page

* start time modifiers

* adapt time modifiers

* adapt factories

* hydra + pattern intro

* adapt mini notation page

* start recipes

* adapt recipes page

* use code_v1 table

* delete old dbdump + add new csv based tool

* fix: tests

* fix: cpm

* shuffle featured patterns

* fix: snapshot

---------

Co-authored-by: Felix Roos <flix91@gmail.com>
This commit is contained in:
Alex McLean 2024-01-22 19:02:34 +00:00 committed by GitHub
parent 46c2c72637
commit 6422047cff
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
40 changed files with 3852 additions and 2386 deletions

View File

@ -57,6 +57,9 @@ const visibleMiniLocations = StateField.define({
// this is why we need to find a way to update the existing decorations, showing the ones that have an active range // this is why we need to find a way to update the existing decorations, showing the ones that have an active range
const haps = new Map(); const haps = new Map();
for (let hap of e.value.haps) { for (let hap of e.value.haps) {
if (!hap.context?.locations || !hap.whole) {
continue;
}
for (let { start, end } of hap.context.locations) { for (let { start, end } of hap.context.locations) {
let id = `${start}:${end}`; let id = `${start}:${end}`;
if (!haps.has(id) || haps.get(id).whole.begin.lt(hap.whole.begin)) { if (!haps.has(id) || haps.get(id).whole.begin.lt(hap.whole.begin)) {
@ -64,7 +67,6 @@ const visibleMiniLocations = StateField.define({
} }
} }
} }
visible = { atTime: e.value.atTime, haps }; visible = { atTime: e.value.atTime, haps };
} }
} }

View File

@ -40,7 +40,7 @@ const generic_params = [
* @name n * @name n
* @param {number | Pattern} value sample index starting from 0 * @param {number | Pattern} value sample index starting from 0
* @example * @example
* s("bd sd,hh*3").n("<0 1>") * s("bd sd [~ bd] sd,hh*6").n("<0 1>")
*/ */
// also see https://github.com/tidalcycles/strudel/pull/63 // also see https://github.com/tidalcycles/strudel/pull/63
['n'], ['n'],
@ -82,7 +82,7 @@ const generic_params = [
* @name gain * @name gain
* @param {number | Pattern} amount gain. * @param {number | Pattern} amount gain.
* @example * @example
* s("hh*8").gain(".4!2 1 .4!2 1 .4 1") * s("hh*8").gain(".4!2 1 .4!2 1 .4 1").fast(2)
* *
*/ */
['gain'], ['gain'],
@ -91,7 +91,7 @@ const generic_params = [
* *
* @name postgain * @name postgain
* @example * @example
* s("bd sd,hh*4") * s("bd sd [~ bd] sd,hh*8")
* .compressor("-20:20:10:.002:.02").postgain(1.5) * .compressor("-20:20:10:.002:.02").postgain(1.5)
* *
*/ */
@ -114,7 +114,7 @@ const generic_params = [
* @param {number | Pattern} attack time in seconds. * @param {number | Pattern} attack time in seconds.
* @synonyms att * @synonyms att
* @example * @example
* note("c3 e3").attack("<0 .1 .5>") * note("c3 e3 f3 g3").attack("<0 .1 .5>")
* *
*/ */
['attack', 'att'], ['attack', 'att'],
@ -128,7 +128,7 @@ const generic_params = [
* @name fmh * @name fmh
* @param {number | Pattern} harmonicity * @param {number | Pattern} harmonicity
* @example * @example
* note("c e g b") * note("c e g b g e")
* .fm(4) * .fm(4)
* .fmh("<1 2 1.5 1.61>") * .fmh("<1 2 1.5 1.61>")
* .scope() * .scope()
@ -143,7 +143,7 @@ const generic_params = [
* @param {number | Pattern} brightness modulation index * @param {number | Pattern} brightness modulation index
* @synonyms fmi * @synonyms fmi
* @example * @example
* note("c e g b") * note("c e g b g e")
* .fm("<0 1 2 8 32>") * .fm("<0 1 2 8 32>")
* .scope() * .scope()
* *
@ -156,7 +156,7 @@ const generic_params = [
* @name fmenv * @name fmenv
* @param {number | Pattern} type lin | exp * @param {number | Pattern} type lin | exp
* @example * @example
* note("c e g b") * note("c e g b g e")
* .fm(4) * .fm(4)
* .fmdecay(.2) * .fmdecay(.2)
* .fmsustain(0) * .fmsustain(0)
@ -171,7 +171,7 @@ const generic_params = [
* @name fmattack * @name fmattack
* @param {number | Pattern} time attack time * @param {number | Pattern} time attack time
* @example * @example
* note("c e g b") * note("c e g b g e")
* .fm(4) * .fm(4)
* .fmattack("<0 .05 .1 .2>") * .fmattack("<0 .05 .1 .2>")
* .scope() * .scope()
@ -184,7 +184,7 @@ const generic_params = [
* @name fmdecay * @name fmdecay
* @param {number | Pattern} time decay time * @param {number | Pattern} time decay time
* @example * @example
* note("c e g b") * note("c e g b g e")
* .fm(4) * .fm(4)
* .fmdecay("<.01 .05 .1 .2>") * .fmdecay("<.01 .05 .1 .2>")
* .fmsustain(.4) * .fmsustain(.4)
@ -198,7 +198,7 @@ const generic_params = [
* @name fmsustain * @name fmsustain
* @param {number | Pattern} level sustain level * @param {number | Pattern} level sustain level
* @example * @example
* note("c e g b") * note("c e g b g e")
* .fm(4) * .fm(4)
* .fmdecay(.1) * .fmdecay(.1)
* .fmsustain("<1 .75 .5 0>") * .fmsustain("<1 .75 .5 0>")
@ -216,7 +216,7 @@ const generic_params = [
* @name bank * @name bank
* @param {string | Pattern} bank the name of the bank * @param {string | Pattern} bank the name of the bank
* @example * @example
* s("bd sd").bank('RolandTR909') // = s("RolandTR909_bd RolandTR909_sd") * s("bd sd [~ bd] sd").bank('RolandTR909') // = s("RolandTR909_bd RolandTR909_sd")
* *
*/ */
['bank'], ['bank'],
@ -231,7 +231,7 @@ const generic_params = [
* @name decay * @name decay
* @param {number | Pattern} time decay time in seconds * @param {number | Pattern} time decay time in seconds
* @example * @example
* note("c3 e3").decay("<.1 .2 .3 .4>").sustain(0) * note("c3 e3 f3 g3").decay("<.1 .2 .3 .4>").sustain(0)
* *
*/ */
['decay', 'dec'], ['decay', 'dec'],
@ -242,7 +242,7 @@ const generic_params = [
* @param {number | Pattern} gain sustain level between 0 and 1 * @param {number | Pattern} gain sustain level between 0 and 1
* @synonyms sus * @synonyms sus
* @example * @example
* note("c3 e3").decay(.2).sustain("<0 .1 .4 .6 1>") * note("c3 e3 f3 g3").decay(.2).sustain("<0 .1 .4 .6 1>")
* *
*/ */
['sustain', 'sus'], ['sustain', 'sus'],
@ -267,7 +267,7 @@ const generic_params = [
* @param {number | Pattern} frequency center frequency * @param {number | Pattern} frequency center frequency
* @synonyms bandf, bp * @synonyms bandf, bp
* @example * @example
* s("bd sd,hh*3").bpf("<1000 2000 4000 8000>") * s("bd sd [~ bd] sd,hh*6").bpf("<1000 2000 4000 8000>")
* *
*/ */
[['bandf', 'bandq', 'bpenv'], 'bpf', 'bp'], [['bandf', 'bandq', 'bpenv'], 'bpf', 'bp'],
@ -279,7 +279,7 @@ const generic_params = [
* @param {number | Pattern} q q factor * @param {number | Pattern} q q factor
* @synonyms bandq * @synonyms bandq
* @example * @example
* s("bd sd").bpf(500).bpq("<0 1 2 3>") * s("bd sd [~ bd] sd").bpf(500).bpq("<0 1 2 3>")
* *
*/ */
// currently an alias of 'bandq' https://github.com/tidalcycles/strudel/issues/496 // currently an alias of 'bandq' https://github.com/tidalcycles/strudel/issues/496
@ -293,7 +293,7 @@ const generic_params = [
* @param {number | Pattern} amount between 0 and 1, where 1 is the length of the sample * @param {number | Pattern} amount between 0 and 1, where 1 is the length of the sample
* @example * @example
* samples({ rave: 'rave/AREUREADY.wav' }, 'github:tidalcycles/Dirt-Samples/master/') * samples({ rave: 'rave/AREUREADY.wav' }, 'github:tidalcycles/Dirt-Samples/master/')
* s("rave").begin("<0 .25 .5 .75>") * s("rave").begin("<0 .25 .5 .75>").fast(2)
* *
*/ */
['begin'], ['begin'],
@ -304,7 +304,7 @@ const generic_params = [
* @name end * @name end
* @param {number | Pattern} length 1 = whole sample, .5 = half sample, .25 = quarter sample etc.. * @param {number | Pattern} length 1 = whole sample, .5 = half sample, .25 = quarter sample etc..
* @example * @example
* s("bd*2,oh*4").end("<.1 .2 .5 1>") * s("bd*2,oh*4").end("<.1 .2 .5 1>").fast(2)
* *
*/ */
['end'], ['end'],
@ -376,7 +376,7 @@ const generic_params = [
* @name coarse * @name coarse
* @param {number | Pattern} factor 1 for original 2 for half, 3 for a third and so on. * @param {number | Pattern} factor 1 for original 2 for half, 3 for a third and so on.
* @example * @example
* s("bd sd,hh*4").coarse("<1 4 8 16 32>") * s("bd sd [~ bd] sd,hh*8").coarse("<1 4 8 16 32>")
* *
*/ */
['coarse'], ['coarse'],
@ -463,7 +463,7 @@ const generic_params = [
* @name cut * @name cut
* @param {number | Pattern} group cut group number * @param {number | Pattern} group cut group number
* @example * @example
* s("rd*4").cut(1) * s("[oh hh]*4").cut(1)
* *
*/ */
['cut'], ['cut'],
@ -476,9 +476,9 @@ const generic_params = [
* @param {number | Pattern} frequency audible between 0 and 20000 * @param {number | Pattern} frequency audible between 0 and 20000
* @synonyms cutoff, ctf, lp * @synonyms cutoff, ctf, lp
* @example * @example
* s("bd sd,hh*3").lpf("<4000 2000 1000 500 200 100>") * s("bd sd [~ bd] sd,hh*6").lpf("<4000 2000 1000 500 200 100>")
* @example * @example
* s("bd*8").lpf("1000:0 1000:10 1000:20 1000:30") * s("bd*16").lpf("1000:0 1000:10 1000:20 1000:30")
* *
*/ */
[['cutoff', 'resonance', 'lpenv'], 'ctf', 'lpf', 'lp'], [['cutoff', 'resonance', 'lpenv'], 'ctf', 'lpf', 'lp'],
@ -489,7 +489,7 @@ const generic_params = [
* @param {number | Pattern} modulation depth of the lowpass filter envelope between 0 and _n_ * @param {number | Pattern} modulation depth of the lowpass filter envelope between 0 and _n_
* @synonyms lpe * @synonyms lpe
* @example * @example
* note("<c2 e2 f2 g2>") * note("c2 e2 f2 g2")
* .sound('sawtooth') * .sound('sawtooth')
* .lpf(500) * .lpf(500)
* .lpa(.5) * .lpa(.5)
@ -502,7 +502,7 @@ const generic_params = [
* @param {number | Pattern} modulation depth of the highpass filter envelope between 0 and _n_ * @param {number | Pattern} modulation depth of the highpass filter envelope between 0 and _n_
* @synonyms hpe * @synonyms hpe
* @example * @example
* note("<c2 e2 f2 g2>") * note("c2 e2 f2 g2")
* .sound('sawtooth') * .sound('sawtooth')
* .hpf(500) * .hpf(500)
* .hpa(.5) * .hpa(.5)
@ -515,7 +515,7 @@ const generic_params = [
* @param {number | Pattern} modulation depth of the bandpass filter envelope between 0 and _n_ * @param {number | Pattern} modulation depth of the bandpass filter envelope between 0 and _n_
* @synonyms bpe * @synonyms bpe
* @example * @example
* note("<c2 e2 f2 g2>") * note("c2 e2 f2 g2")
* .sound('sawtooth') * .sound('sawtooth')
* .bpf(500) * .bpf(500)
* .bpa(.5) * .bpa(.5)
@ -528,7 +528,7 @@ const generic_params = [
* @param {number | Pattern} attack time of the filter envelope * @param {number | Pattern} attack time of the filter envelope
* @synonyms lpa * @synonyms lpa
* @example * @example
* note("<c2 e2 f2 g2>") * note("c2 e2 f2 g2")
* .sound('sawtooth') * .sound('sawtooth')
* .lpf(500) * .lpf(500)
* .lpa("<.5 .25 .1 .01>/4") * .lpa("<.5 .25 .1 .01>/4")
@ -541,7 +541,7 @@ const generic_params = [
* @param {number | Pattern} attack time of the highpass filter envelope * @param {number | Pattern} attack time of the highpass filter envelope
* @synonyms hpa * @synonyms hpa
* @example * @example
* note("<c2 e2 f2 g2>") * note("c2 e2 f2 g2")
* .sound('sawtooth') * .sound('sawtooth')
* .hpf(500) * .hpf(500)
* .hpa("<.5 .25 .1 .01>/4") * .hpa("<.5 .25 .1 .01>/4")
@ -554,7 +554,7 @@ const generic_params = [
* @param {number | Pattern} attack time of the bandpass filter envelope * @param {number | Pattern} attack time of the bandpass filter envelope
* @synonyms bpa * @synonyms bpa
* @example * @example
* note("<c2 e2 f2 g2>") * note("c2 e2 f2 g2")
* .sound('sawtooth') * .sound('sawtooth')
* .bpf(500) * .bpf(500)
* .bpa("<.5 .25 .1 .01>/4") * .bpa("<.5 .25 .1 .01>/4")
@ -567,7 +567,7 @@ const generic_params = [
* @param {number | Pattern} decay time of the filter envelope * @param {number | Pattern} decay time of the filter envelope
* @synonyms lpd * @synonyms lpd
* @example * @example
* note("<c2 e2 f2 g2>") * note("c2 e2 f2 g2")
* .sound('sawtooth') * .sound('sawtooth')
* .lpf(500) * .lpf(500)
* .lpd("<.5 .25 .1 0>/4") * .lpd("<.5 .25 .1 0>/4")
@ -581,7 +581,7 @@ const generic_params = [
* @param {number | Pattern} decay time of the highpass filter envelope * @param {number | Pattern} decay time of the highpass filter envelope
* @synonyms hpd * @synonyms hpd
* @example * @example
* note("<c2 e2 f2 g2>") * note("c2 e2 f2 g2")
* .sound('sawtooth') * .sound('sawtooth')
* .hpf(500) * .hpf(500)
* .hpd("<.5 .25 .1 0>/4") * .hpd("<.5 .25 .1 0>/4")
@ -595,7 +595,7 @@ const generic_params = [
* @param {number | Pattern} decay time of the bandpass filter envelope * @param {number | Pattern} decay time of the bandpass filter envelope
* @synonyms bpd * @synonyms bpd
* @example * @example
* note("<c2 e2 f2 g2>") * note("c2 e2 f2 g2")
* .sound('sawtooth') * .sound('sawtooth')
* .bpf(500) * .bpf(500)
* .bpd("<.5 .25 .1 0>/4") * .bpd("<.5 .25 .1 0>/4")
@ -609,7 +609,7 @@ const generic_params = [
* @param {number | Pattern} sustain amplitude of the lowpass filter envelope * @param {number | Pattern} sustain amplitude of the lowpass filter envelope
* @synonyms lps * @synonyms lps
* @example * @example
* note("<c2 e2 f2 g2>") * note("c2 e2 f2 g2")
* .sound('sawtooth') * .sound('sawtooth')
* .lpf(500) * .lpf(500)
* .lpd(.5) * .lpd(.5)
@ -623,7 +623,7 @@ const generic_params = [
* @param {number | Pattern} sustain amplitude of the highpass filter envelope * @param {number | Pattern} sustain amplitude of the highpass filter envelope
* @synonyms hps * @synonyms hps
* @example * @example
* note("<c2 e2 f2 g2>") * note("c2 e2 f2 g2")
* .sound('sawtooth') * .sound('sawtooth')
* .hpf(500) * .hpf(500)
* .hpd(.5) * .hpd(.5)
@ -637,7 +637,7 @@ const generic_params = [
* @param {number | Pattern} sustain amplitude of the bandpass filter envelope * @param {number | Pattern} sustain amplitude of the bandpass filter envelope
* @synonyms bps * @synonyms bps
* @example * @example
* note("<c2 e2 f2 g2>") * note("c2 e2 f2 g2")
* .sound('sawtooth') * .sound('sawtooth')
* .bpf(500) * .bpf(500)
* .bpd(.5) * .bpd(.5)
@ -651,7 +651,7 @@ const generic_params = [
* @param {number | Pattern} release time of the filter envelope * @param {number | Pattern} release time of the filter envelope
* @synonyms lpr * @synonyms lpr
* @example * @example
* note("<c2 e2 f2 g2>") * note("c2 e2 f2 g2")
* .sound('sawtooth') * .sound('sawtooth')
* .clip(.5) * .clip(.5)
* .lpf(500) * .lpf(500)
@ -666,7 +666,7 @@ const generic_params = [
* @param {number | Pattern} release time of the highpass filter envelope * @param {number | Pattern} release time of the highpass filter envelope
* @synonyms hpr * @synonyms hpr
* @example * @example
* note("<c2 e2 f2 g2>") * note("c2 e2 f2 g2")
* .sound('sawtooth') * .sound('sawtooth')
* .clip(.5) * .clip(.5)
* .hpf(500) * .hpf(500)
@ -681,7 +681,7 @@ const generic_params = [
* @param {number | Pattern} release time of the bandpass filter envelope * @param {number | Pattern} release time of the bandpass filter envelope
* @synonyms bpr * @synonyms bpr
* @example * @example
* note("<c2 e2 f2 g2>") * note("c2 e2 f2 g2")
* .sound('sawtooth') * .sound('sawtooth')
* .clip(.5) * .clip(.5)
* .bpf(500) * .bpf(500)
@ -695,11 +695,11 @@ const generic_params = [
* @name ftype * @name ftype
* @param {number | Pattern} type 12db (default) or 24db * @param {number | Pattern} type 12db (default) or 24db
* @example * @example
* note("<c2 e2 f2 g2>") * note("c2 e2 f2 g2")
* .sound('sawtooth') * .sound('sawtooth')
* .lpf(500) * .lpf(500)
* .bpenv(4) * .bpenv(4)
* .ftype("<12db 24db>") * .ftype("12db 24db")
*/ */
['ftype'], ['ftype'],
['fanchor'], ['fanchor'],
@ -712,9 +712,9 @@ const generic_params = [
* @param {number | Pattern} frequency audible between 0 and 20000 * @param {number | Pattern} frequency audible between 0 and 20000
* @synonyms hp, hcutoff * @synonyms hp, hcutoff
* @example * @example
* s("bd sd,hh*4").hpf("<4000 2000 1000 500 200 100>") * s("bd sd [~ bd] sd,hh*8").hpf("<4000 2000 1000 500 200 100>")
* @example * @example
* s("bd sd,hh*4").hpf("<2000 2000:25>") * s("bd sd [~ bd] sd,hh*8").hpf("<2000 2000:25>")
* *
*/ */
// currently an alias of 'hcutoff' https://github.com/tidalcycles/strudel/issues/496 // currently an alias of 'hcutoff' https://github.com/tidalcycles/strudel/issues/496
@ -726,11 +726,11 @@ const generic_params = [
* @synonyms vibrato, v * @synonyms vibrato, v
* @param {number | Pattern} frequency of the vibrato in hertz * @param {number | Pattern} frequency of the vibrato in hertz
* @example * @example
* note("a") * note("a e")
* .vib("<.5 1 2 4 8 16>") * .vib("<.5 1 2 4 8 16>")
* @example * @example
* // change the modulation depth with ":" * // change the modulation depth with ":"
* note("a") * note("a e")
* .vib("<.5 1 2 4 8 16>:12") * .vib("<.5 1 2 4 8 16>:12")
*/ */
[['vib', 'vibmod'], 'vibrato', 'v'], [['vib', 'vibmod'], 'vibrato', 'v'],
@ -750,11 +750,11 @@ const generic_params = [
* @synonyms vmod * @synonyms vmod
* @param {number | Pattern} depth of vibrato (in semitones) * @param {number | Pattern} depth of vibrato (in semitones)
* @example * @example
* note("a").vib(4) * note("a e").vib(4)
* .vibmod("<.25 .5 1 2 12>") * .vibmod("<.25 .5 1 2 12>")
* @example * @example
* // change the vibrato frequency with ":" * // change the vibrato frequency with ":"
* note("a") * note("a e")
* .vibmod("<.25 .5 1 2 12>:8") * .vibmod("<.25 .5 1 2 12>:8")
*/ */
[['vibmod', 'vib'], 'vmod'], [['vibmod', 'vib'], 'vmod'],
@ -766,7 +766,7 @@ const generic_params = [
* @param {number | Pattern} q resonance factor between 0 and 50 * @param {number | Pattern} q resonance factor between 0 and 50
* @synonyms hresonance * @synonyms hresonance
* @example * @example
* s("bd sd,hh*4").hpf(2000).hpq("<0 10 20 30>") * s("bd sd [~ bd] sd,hh*8").hpf(2000).hpq("<0 10 20 30>")
* *
*/ */
['hresonance', 'hpq'], ['hresonance', 'hpq'],
@ -777,7 +777,7 @@ const generic_params = [
* @param {number | Pattern} q resonance factor between 0 and 50 * @param {number | Pattern} q resonance factor between 0 and 50
* @synonyms resonance * @synonyms resonance
* @example * @example
* s("bd sd,hh*4").lpf(2000).lpq("<0 10 20 30>") * s("bd sd [~ bd] sd,hh*8").lpf(2000).lpq("<0 10 20 30>")
* *
*/ */
// currently an alias of 'resonance' https://github.com/tidalcycles/strudel/issues/496 // currently an alias of 'resonance' https://github.com/tidalcycles/strudel/issues/496
@ -804,7 +804,7 @@ const generic_params = [
* @name delay * @name delay
* @param {number | Pattern} level between 0 and 1 * @param {number | Pattern} level between 0 and 1
* @example * @example
* s("bd").delay("<0 .25 .5 1>") * s("bd bd").delay("<0 .25 .5 1>")
* @example * @example
* s("bd bd").delay("0.65:0.25:0.9 0.65:0.125:0.7") * s("bd bd").delay("0.65:0.25:0.9 0.65:0.125:0.7")
* *
@ -818,7 +818,7 @@ const generic_params = [
* @param {number | Pattern} feedback between 0 and 1 * @param {number | Pattern} feedback between 0 and 1
* @synonyms delayfb, dfb * @synonyms delayfb, dfb
* @example * @example
* s("bd").delay(.25).delayfeedback("<.25 .5 .75 1>").slow(2) * s("bd").delay(.25).delayfeedback("<.25 .5 .75 1>")
* *
*/ */
['delayfeedback', 'delayfb', 'dfb'], ['delayfeedback', 'delayfb', 'dfb'],
@ -829,7 +829,7 @@ const generic_params = [
* @param {number | Pattern} seconds between 0 and Infinity * @param {number | Pattern} seconds between 0 and Infinity
* @synonyms delayt, dt * @synonyms delayt, dt
* @example * @example
* s("bd").delay(.25).delaytime("<.125 .25 .5 1>").slow(2) * s("bd bd").delay(.25).delaytime("<.125 .25 .5 1>")
* *
*/ */
['delaytime', 'delayt', 'dt'], ['delaytime', 'delayt', 'dt'],
@ -899,7 +899,7 @@ const generic_params = [
* @synonyms patt * @synonyms patt
* @param {number | Pattern} time time in seconds * @param {number | Pattern} time time in seconds
* @example * @example
* note("<c eb g bb>").pattack("<0 .1 .25 .5>") * note("c eb g bb").pattack("0 .1 .25 .5").slow(2)
* *
*/ */
['pattack', 'patt'], ['pattack', 'patt'],
@ -947,7 +947,7 @@ const generic_params = [
* @name pcurve * @name pcurve
* @param {number | Pattern} type 0 = linear, 1 = exponential * @param {number | Pattern} type 0 = linear, 1 = exponential
* @example * @example
* note("g1*2") * note("g1*4")
* .s("sine").pdec(.5) * .s("sine").pdec(.5)
* .penv(32) * .penv(32)
* .pcurve("<0 1>") * .pcurve("<0 1>")
@ -963,7 +963,7 @@ const generic_params = [
* @name panchor * @name panchor
* @param {number | Pattern} anchor anchor offset * @param {number | Pattern} anchor anchor offset
* @example * @example
* note("c").penv(12).panchor("<0 .5 1 .5>") * note("c c4").penv(12).panchor("<0 .5 1 .5>")
* *
*/ */
['panchor'], ['panchor'],
@ -1062,8 +1062,8 @@ const generic_params = [
* @param {number | Pattern} number * @param {number | Pattern} number
* @example * @example
* stack( * stack(
* s("hh*3").delay(.5).delaytime(.25).orbit(1), * s("hh*6").delay(.5).delaytime(.25).orbit(1),
* s("~ sd").delay(.5).delaytime(.125).orbit(2) * s("~ sd ~ sd").delay(.5).delaytime(.125).orbit(2)
* ) * )
*/ */
['orbit'], ['orbit'],
@ -1076,6 +1076,8 @@ const generic_params = [
* @param {number | Pattern} pan between 0 and 1, from left to right (assuming stereo), once round a circle (assuming multichannel) * @param {number | Pattern} pan between 0 and 1, from left to right (assuming stereo), once round a circle (assuming multichannel)
* @example * @example
* s("[bd hh]*2").pan("<.5 1 .5 0>") * s("[bd hh]*2").pan("<.5 1 .5 0>")
* @example
* s("bd rim sd rim bd ~ cp rim").pan(sine.slow(2))
* *
*/ */
['pan'], ['pan'],
@ -1133,9 +1135,9 @@ const generic_params = [
* @name room * @name room
* @param {number | Pattern} level between 0 and 1 * @param {number | Pattern} level between 0 and 1
* @example * @example
* s("bd sd").room("<0 .2 .4 .6 .8 1>") * s("bd sd [~ bd] sd").room("<0 .2 .4 .6 .8 1>")
* @example * @example
* s("bd sd").room("<0.9:1 0.9:4>") * s("bd sd [~ bd] sd").room("<0.9:1 0.9:4>")
* *
*/ */
[['room', 'size']], [['room', 'size']],
@ -1147,9 +1149,9 @@ const generic_params = [
* @synonyms rlp * @synonyms rlp
* @param {number} frequency between 0 and 20000hz * @param {number} frequency between 0 and 20000hz
* @example * @example
* s("bd sd").room(0.5).rlp(10000) * s("bd sd [~ bd] sd").room(0.5).rlp(10000)
* @example * @example
* s("bd sd").room(0.5).rlp(5000) * s("bd sd [~ bd] sd").room(0.5).rlp(5000)
*/ */
['roomlp', 'rlp'], ['roomlp', 'rlp'],
/** /**
@ -1160,9 +1162,9 @@ const generic_params = [
* @synonyms rdim * @synonyms rdim
* @param {number} frequency between 0 and 20000hz * @param {number} frequency between 0 and 20000hz
* @example * @example
* s("bd sd").room(0.5).rlp(10000).rdim(8000) * s("bd sd [~ bd] sd").room(0.5).rlp(10000).rdim(8000)
* @example * @example
* s("bd sd").room(0.5).rlp(5000).rdim(400) * s("bd sd [~ bd] sd").room(0.5).rlp(5000).rdim(400)
* *
*/ */
['roomdim', 'rdim'], ['roomdim', 'rdim'],
@ -1174,9 +1176,9 @@ const generic_params = [
* @synonyms rfade * @synonyms rfade
* @param {number} seconds for the reverb to fade * @param {number} seconds for the reverb to fade
* @example * @example
* s("bd sd").room(0.5).rlp(10000).rfade(0.5) * s("bd sd [~ bd] sd").room(0.5).rlp(10000).rfade(0.5)
* @example * @example
* s("bd sd").room(0.5).rlp(5000).rfade(4) * s("bd sd [~ bd] sd").room(0.5).rlp(5000).rfade(4)
* *
*/ */
['roomfade', 'rfade'], ['roomfade', 'rfade'],
@ -1186,7 +1188,7 @@ const generic_params = [
* @param {string | Pattern} sample to use as an impulse response * @param {string | Pattern} sample to use as an impulse response
* @synonyms ir * @synonyms ir
* @example * @example
* s("bd sd").room(.8).ir("<shaker_large:0 shaker_large:2>") * s("bd sd [~ bd] sd").room(.8).ir("<shaker_large:0 shaker_large:2>")
* *
*/ */
[['ir', 'i'], 'iresponse'], [['ir', 'i'], 'iresponse'],
@ -1198,13 +1200,13 @@ const generic_params = [
* @param {number | Pattern} size between 0 and 10 * @param {number | Pattern} size between 0 and 10
* @synonyms rsize, sz, size * @synonyms rsize, sz, size
* @example * @example
* s("bd sd").room(.8).rsize(1) * s("bd sd [~ bd] sd").room(.8).rsize(1)
* @example * @example
* s("bd sd").room(.8).rsize(4) * s("bd sd [~ bd] sd").room(.8).rsize(4)
* *
*/ */
// TODO: find out why : // TODO: find out why :
// s("bd sd").room(.8).roomsize("<0 .2 .4 .6 .8 [1,0]>").osc() // s("bd sd [~ bd] sd").room(.8).roomsize("<0 .2 .4 .6 .8 [1,0]>").osc()
// .. does not work. Is it because room is only one effect? // .. does not work. Is it because room is only one effect?
['roomsize', 'size', 'sz', 'rsize'], ['roomsize', 'size', 'sz', 'rsize'],
// ['sagogo'], // ['sagogo'],
@ -1217,7 +1219,7 @@ const generic_params = [
* @name shape * @name shape
* @param {number | Pattern} distortion between 0 and 1 * @param {number | Pattern} distortion between 0 and 1
* @example * @example
* s("bd sd,hh*4").shape("<0 .2 .4 .6 .8>") * s("bd sd [~ bd] sd,hh*8").shape("<0 .2 .4 .6 .8>")
* *
*/ */
['shape'], ['shape'],
@ -1227,7 +1229,7 @@ const generic_params = [
* *
* @name compressor * @name compressor
* @example * @example
* s("bd sd,hh*4") * s("bd sd [~ bd] sd,hh*8")
* .compressor("-20:20:10:.002:.02") * .compressor("-20:20:10:.002:.02")
* *
*/ */
@ -1242,7 +1244,7 @@ const generic_params = [
* @name speed * @name speed
* @param {number | Pattern} speed -inf to inf, negative numbers play the sample backwards. * @param {number | Pattern} speed -inf to inf, negative numbers play the sample backwards.
* @example * @example
* s("bd").speed("<1 2 4 1 -2 -4>") * s("bd*6").speed("1 2 4 1 -2 -4")
* @example * @example
* speed("1 1.5*2 [2 1.1]").s("piano").clip(1) * speed("1 1.5*2 [2 1.1]").s("piano").clip(1)
* *
@ -1287,8 +1289,10 @@ const generic_params = [
* @name vowel * @name vowel
* @param {string | Pattern} vowel You can use a e i o u ae aa oe ue y uh un en an on, corresponding to [a] [e] [i] [o] [u] [æ] [ɑ] [ø] [y] [ɯ] [ʌ] [œ̃] [ɛ̃] [ɑ̃] [ɔ̃]. Aliases: aa = å = ɑ, oe = ø = ö, y = ı, ae = æ. * @param {string | Pattern} vowel You can use a e i o u ae aa oe ue y uh un en an on, corresponding to [a] [e] [i] [o] [u] [æ] [ɑ] [ø] [y] [ɯ] [ʌ] [œ̃] [ɛ̃] [ɑ̃] [ɔ̃]. Aliases: aa = å = ɑ, oe = ø = ö, y = ı, ae = æ.
* @example * @example
* note("c2 <eb2 <g2 g1>>").s('sawtooth') * note("[c2 <eb2 <g2 g1>>]*2").s('sawtooth')
* .vowel("<a e i <o u>>") * .vowel("<a e i <o u>>")
* @example
* s("bd sd mt ht bd [~ cp] ht lt").vowel("[a|e|i|o|u]")
* *
*/ */
['vowel'], ['vowel'],
@ -1463,7 +1467,7 @@ controls.createParams = (...names) =>
* @param {number | Pattern} gain sustain level (0 to 1) * @param {number | Pattern} gain sustain level (0 to 1)
* @param {number | Pattern} time release time in seconds * @param {number | Pattern} time release time in seconds
* @example * @example
* note("<c3 bb2 f3 eb3>").sound("sawtooth").lpf(600).adsr(".1:.1:.5:.2") * note("[c3 bb2 f3 eb3]*2").sound("sawtooth").lpf(600).adsr(".1:.1:.5:.2")
*/ */
controls.adsr = register('adsr', (adsr, pat) => { controls.adsr = register('adsr', (adsr, pat) => {
adsr = !Array.isArray(adsr) ? [adsr] : adsr; adsr = !Array.isArray(adsr) ? [adsr] : adsr;

View File

@ -10,7 +10,7 @@ import { logger } from './logger.mjs';
export class Cyclist { export class Cyclist {
constructor({ interval, onTrigger, onToggle, onError, getTime, latency = 0.1 }) { constructor({ interval, onTrigger, onToggle, onError, getTime, latency = 0.1 }) {
this.started = false; this.started = false;
this.cps = 1; this.cps = 0.5;
this.num_ticks_since_cps_change = 0; this.num_ticks_since_cps_change = 0;
this.lastTick = 0; // absolute time when last tick (clock callback) happened this.lastTick = 0; // absolute time when last tick (clock callback) happened
this.lastBegin = 0; // query begin of last tick this.lastBegin = 0; // query begin of last tick
@ -96,7 +96,7 @@ export class Cyclist {
this.start(); this.start();
} }
} }
setCps(cps = 1) { setCps(cps = 0.5) {
if (this.cps === cps) { if (this.cps === cps) {
return; return;
} }

View File

@ -134,7 +134,7 @@ export class Drawer {
this.lastFrame = phase; this.lastFrame = phase;
this.visibleHaps = (this.visibleHaps || []) this.visibleHaps = (this.visibleHaps || [])
// filter out haps that are too far in the past (think left edge of screen for pianoroll) // filter out haps that are too far in the past (think left edge of screen for pianoroll)
.filter((h) => h.whole.end >= phase - lookbehind - lookahead) .filter((h) => h.whole?.end >= phase - lookbehind - lookahead)
// add new haps with onset (think right edge bars scrolling in) // add new haps with onset (think right edge bars scrolling in)
.concat(haps.filter((h) => h.hasOnset())); .concat(haps.filter((h) => h.hasOnset()));
const time = phase - lookahead; const time = phase - lookahead;

View File

@ -148,7 +148,7 @@ export const { euclidrot, euclidRot } = register(['euclidrot', 'euclidRot'], fun
* @param {number} pulses the number of onsets / beats * @param {number} pulses the number of onsets / beats
* @param {number} steps the number of steps to fill * @param {number} steps the number of steps to fill
* @example * @example
* n("g2").decay(.1).sustain(.3).euclidLegato(3,8) * note("c3").euclidLegato(3,8)
*/ */
const _euclidLegato = function (pulses, steps, rotation, pat) { const _euclidLegato = function (pulses, steps, rotation, pat) {

View File

@ -697,7 +697,7 @@ export class Pattern {
* @synonyms apply * @synonyms apply
* @returns Pattern * @returns Pattern
* @example * @example
* "<0 2 4 6 ~ 4 ~ 2 0!3 ~!5>*4" * "<0 2 4 6 ~ 4 ~ 2 0!3 ~!5>*8"
* .layer(x=>x.add("0,2")) * .layer(x=>x.add("0,2"))
* .scale('C minor').note() * .scale('C minor').note()
*/ */
@ -711,7 +711,7 @@ export class Pattern {
* @memberof Pattern * @memberof Pattern
* @returns Pattern * @returns Pattern
* @example * @example
* "<0 2 4 6 ~ 4 ~ 2 0!3 ~!5>*4" * "<0 2 4 6 ~ 4 ~ 2 0!3 ~!5>*8"
* .superimpose(x=>x.add(2)) * .superimpose(x=>x.add(2))
* .scale('C minor').note() * .scale('C minor').note()
*/ */
@ -727,8 +727,8 @@ export class Pattern {
* @name stack * @name stack
* @memberof Pattern * @memberof Pattern
* @example * @example
* s("hh*2").stack( * s("hh*4").stack(
* note("c2(3,8)") * note("c4(5,8)")
* ) * )
*/ */
stack(...pats) { stack(...pats) {
@ -745,8 +745,8 @@ export class Pattern {
* @memberof Pattern * @memberof Pattern
* @synonyms sequence, fastcat * @synonyms sequence, fastcat
* @example * @example
* s("hh*2").seq( * s("hh*4").seq(
* note("c2(3,8)") * note("c4(5,8)")
* ) * )
*/ */
seq(...pats) { seq(...pats) {
@ -759,8 +759,8 @@ export class Pattern {
* @memberof Pattern * @memberof Pattern
* @synonyms slowcat * @synonyms slowcat
* @example * @example
* s("hh*2").cat( * s("hh*4").cat(
* note("c2(3,8)") * note("c4(5,8)")
* ) * )
*/ */
cat(...pats) { cat(...pats) {
@ -858,7 +858,7 @@ Pattern.prototype.arpWith = function (func) {
* Selects indices in in stacked notes. * Selects indices in in stacked notes.
* @example * @example
* note("<[c,eb,g]!2 [c,f,ab] [d,f,ab]>") * note("<[c,eb,g]!2 [c,f,ab] [d,f,ab]>")
* .arp("0 [0,2] 1 [0,2]").slow(2) * .arp("0 [0,2] 1 [0,2]")
* */ * */
Pattern.prototype.arp = function (pat) { Pattern.prototype.arp = function (pat) {
return this.arpWith((haps) => pat.fmap((i) => haps[i % haps.length])); return this.arpWith((haps) => pat.fmap((i) => haps[i % haps.length]));
@ -929,14 +929,14 @@ function _composeOp(a, b, func) {
* @memberof Pattern * @memberof Pattern
* @example * @example
* // Here, the triad 0, 2, 4 is shifted by different amounts * // Here, the triad 0, 2, 4 is shifted by different amounts
* "0 2 4".add("<0 3 4 0>").scale('C major').note() * n("0 2 4".add("<0 3 4 0>")).scale("C:major")
* // Without add, the equivalent would be: * // Without add, the equivalent would be:
* // "<[0 2 4] [3 5 7] [4 6 8] [0 2 4]>".scale('C major').note() * // n("<[0 2 4] [3 5 7] [4 6 8] [0 2 4]>").scale("C:major")
* @example * @example
* // You can also use add with notes: * // You can also use add with notes:
* "c3 e3 g3".add("<0 5 7 0>").note() * note("c3 e3 g3".add("<0 5 7 0>"))
* // Behind the scenes, the notes are converted to midi numbers: * // Behind the scenes, the notes are converted to midi numbers:
* // "48 52 55".add("<0 5 7 0>").note() * // note("48 52 55".add("<0 5 7 0>"))
*/ */
add: [numeralArgs((a, b) => a + b)], // support string concatenation add: [numeralArgs((a, b) => a + b)], // support string concatenation
/** /**
@ -945,7 +945,7 @@ function _composeOp(a, b, func) {
* @name sub * @name sub
* @memberof Pattern * @memberof Pattern
* @example * @example
* "0 2 4".sub("<0 1 2 3>").scale('C4 minor').note() * n("0 2 4".sub("<0 1 2 3>")).scale("C4:minor")
* // See add for more information. * // See add for more information.
*/ */
sub: [numeralArgs((a, b) => a - b)], sub: [numeralArgs((a, b) => a - b)],
@ -955,7 +955,7 @@ function _composeOp(a, b, func) {
* @name mul * @name mul
* @memberof Pattern * @memberof Pattern
* @example * @example
* "1 1.5 [1.66, <2 2.33>]".mul(150).freq() * "<1 1.5 [1.66, <2 2.33>]>*4".mul(150).freq()
*/ */
mul: [numeralArgs((a, b) => a * b)], mul: [numeralArgs((a, b) => a * b)],
/** /**
@ -1049,9 +1049,9 @@ function _composeOp(a, b, func) {
* Applies the given structure to the pattern: * Applies the given structure to the pattern:
* *
* @example * @example
* note("c3,eb3,g3") * note("c,eb,g")
* .struct("x ~ x ~ ~ x ~ x ~ ~ ~ x ~ x ~ ~") * .struct("x ~ x ~ ~ x ~ x ~ ~ ~ x ~ x ~ ~")
* .slow(4) * .slow(2)
*/ */
Pattern.prototype.struct = function (...args) { Pattern.prototype.struct = function (...args) {
return this.keepif.out(...args); return this.keepif.out(...args);
@ -1063,7 +1063,7 @@ function _composeOp(a, b, func) {
* Returns silence when mask is 0 or "~" * Returns silence when mask is 0 or "~"
* *
* @example * @example
* note("c [eb,g] d [eb,g]").mask("<1 [0 1]>").slow(2) * note("c [eb,g] d [eb,g]").mask("<1 [0 1]>")
*/ */
Pattern.prototype.mask = function (...args) { Pattern.prototype.mask = function (...args) {
return this.keepif.in(...args); return this.keepif.in(...args);
@ -1075,7 +1075,7 @@ function _composeOp(a, b, func) {
* Resets the pattern to the start of the cycle for each onset of the reset pattern. * Resets the pattern to the start of the cycle for each onset of the reset pattern.
* *
* @example * @example
* s("<bd lt> sd, hh*4").reset("<x@3 x(3,8)>") * s("[<bd lt> sd]*2, hh*8").reset("<x@3 x(5,8)>")
*/ */
Pattern.prototype.reset = function (...args) { Pattern.prototype.reset = function (...args) {
return this.keepif.trig(...args); return this.keepif.trig(...args);
@ -1088,7 +1088,7 @@ function _composeOp(a, b, func) {
* While reset will only reset the current cycle, restart will start from cycle 0. * While reset will only reset the current cycle, restart will start from cycle 0.
* *
* @example * @example
* s("<bd lt> sd, hh*4").restart("<x@3 x(3,8)>") * s("[<bd lt> sd]*2, hh*8").restart("<x@3 x(5,8)>")
*/ */
Pattern.prototype.restart = function (...args) { Pattern.prototype.restart = function (...args) {
return this.keepif.trigzero(...args); return this.keepif.trigzero(...args);
@ -1178,7 +1178,8 @@ export function reify(thing) {
* @return {Pattern} * @return {Pattern}
* @synonyms polyrhythm, pr * @synonyms polyrhythm, pr
* @example * @example
* stack("g3", "b3", ["e4", "d4"]).note() // "g3,b3,[e4,d4]".note() * stack("g3", "b3", ["e4", "d4"]).note()
* // "g3,b3,[e4,d4]".note()
*/ */
export function stack(...pats) { export function stack(...pats) {
// Array test here is to avoid infinite recursions.. // Array test here is to avoid infinite recursions..
@ -1237,7 +1238,8 @@ export function slowcatPrime(...pats) {
* @synonyms slowcat * @synonyms slowcat
* @return {Pattern} * @return {Pattern}
* @example * @example
* cat("e5", "b4", ["d5", "c5"]).note() // "<e5 b4 [d5 c5]>".note() * cat("e5", "b4", ["d5", "c5"]).note()
* // "<e5 b4 [d5 c5]>".note()
* *
*/ */
export function cat(...pats) { export function cat(...pats) {
@ -1247,7 +1249,8 @@ export function cat(...pats) {
/** Like `seq`, but each step has a length, relative to the whole. /** Like `seq`, but each step has a length, relative to the whole.
* @return {Pattern} * @return {Pattern}
* @example * @example
* timeCat([3,"e3"],[1, "g3"]).note() // "e3@3 g3".note() * timeCat([3,"e3"],[1, "g3"]).note()
* // "e3@3 g3".note()
*/ */
export function timeCat(...timepats) { export function timeCat(...timepats) {
const total = timepats.map((a) => a[0]).reduce((a, b) => a.add(b), Fraction(0)); const total = timepats.map((a) => a[0]).reduce((a, b) => a.add(b), Fraction(0));
@ -1267,7 +1270,10 @@ export function timeCat(...timepats) {
* *
* @return {Pattern} * @return {Pattern}
* @example * @example
* arrange([4, "<c a f e>(3,8)"],[2, "<g a>(5,8)"]).note() * arrange(
* [4, "<c a f e>(3,8)"],
* [2, "<g a>(5,8)"]
* ).note()
*/ */
export function arrange(...sections) { export function arrange(...sections) {
const total = sections.reduce((sum, [cycles]) => sum + cycles, 0); const total = sections.reduce((sum, [cycles]) => sum + cycles, 0);
@ -1287,7 +1293,8 @@ export function sequence(...pats) {
/** Like **cat**, but the items are crammed into one cycle. /** Like **cat**, but the items are crammed into one cycle.
* @synonyms fastcat, sequence * @synonyms fastcat, sequence
* @example * @example
* seq("e5", "b4", ["d5", "c5"]).note() // "e5 b4 [d5 c5]".note() * seq("e5", "b4", ["d5", "c5"]).note()
* // "e5 b4 [d5 c5]".note()
* *
*/ */
export function seq(...pats) { export function seq(...pats) {
@ -1313,9 +1320,9 @@ function _sequenceCount(x) {
* @param {number} steps how many items are placed in one cycle * @param {number} steps how many items are placed in one cycle
* @param {any[]} sequences one or more arrays of Patterns / values * @param {any[]} sequences one or more arrays of Patterns / values
* @example * @example
* polymeterSteps(2, ["c", "d", "e", "f", "g", "f", "e", "d"]) * polymeterSteps(4, ["c", "d", "e"])
* .note().stack(s("bd")) // 1 cycle = 1 bd = 2 notes * .note().stack(s("bd"))
* // note("{c d e f g f e d}%2").stack(s("bd")) * // note("{c d e}%4").stack(s("bd"))
*/ */
export function polymeterSteps(steps, ...args) { export function polymeterSteps(steps, ...args) {
const seqs = args.map((a) => _sequenceCount(a)); const seqs = args.map((a) => _sequenceCount(a));
@ -1463,7 +1470,7 @@ export function register(name, func, patternify = true) {
* @memberof Pattern * @memberof Pattern
* @returns Pattern * @returns Pattern
* @example * @example
* "0.5 1.5 2.5".round().scale('C major').note() * n("0.5 1.5 2.5".round()).scale("C:major")
*/ */
export const round = register('round', function (pat) { export const round = register('round', function (pat) {
return pat.asNumber().fmap((v) => Math.round(v)); return pat.asNumber().fmap((v) => Math.round(v));
@ -1477,7 +1484,7 @@ export const round = register('round', function (pat) {
* @memberof Pattern * @memberof Pattern
* @returns Pattern * @returns Pattern
* @example * @example
* "42 42.1 42.5 43".floor().note() * note("42 42.1 42.5 43".floor())
*/ */
export const floor = register('floor', function (pat) { export const floor = register('floor', function (pat) {
return pat.asNumber().fmap((v) => Math.floor(v)); return pat.asNumber().fmap((v) => Math.floor(v));
@ -1491,7 +1498,7 @@ export const floor = register('floor', function (pat) {
* @memberof Pattern * @memberof Pattern
* @returns Pattern * @returns Pattern
* @example * @example
* "42 42.1 42.5 43".ceil().note() * note("42 42.1 42.5 43".ceil())
*/ */
export const ceil = register('ceil', function (pat) { export const ceil = register('ceil', function (pat) {
return pat.asNumber().fmap((v) => Math.ceil(v)); return pat.asNumber().fmap((v) => Math.ceil(v));
@ -1524,7 +1531,8 @@ export const fromBipolar = register('fromBipolar', function (pat) {
* @memberof Pattern * @memberof Pattern
* @returns Pattern * @returns Pattern
* @example * @example
* s("bd sd,hh*4").cutoff(sine.range(500,2000).slow(4)) * s("[bd sd]*2,hh*8")
* .cutoff(sine.range(500,4000))
*/ */
export const range = register('range', function (min, max, pat) { export const range = register('range', function (min, max, pat) {
return pat.mul(max - min).add(min); return pat.mul(max - min).add(min);
@ -1538,7 +1546,8 @@ export const range = register('range', function (min, max, pat) {
* @memberof Pattern * @memberof Pattern
* @returns Pattern * @returns Pattern
* @example * @example
* s("bd sd,hh*4").cutoff(sine.rangex(500,2000).slow(4)) * s("[bd sd]*2,hh*8")
* .cutoff(sine.rangex(500,4000))
*/ */
export const rangex = register('rangex', function (min, max, pat) { export const rangex = register('rangex', function (min, max, pat) {
return pat._range(Math.log(min), Math.log(max)).fmap(Math.exp); return pat._range(Math.log(min), Math.log(max)).fmap(Math.exp);
@ -1551,7 +1560,8 @@ export const rangex = register('rangex', function (min, max, pat) {
* @memberof Pattern * @memberof Pattern
* @returns Pattern * @returns Pattern
* @example * @example
* s("bd sd,hh*4").cutoff(sine2.range2(500,2000).slow(4)) * s("[bd sd]*2,hh*8")
* .cutoff(sine2.range2(500,4000))
*/ */
export const range2 = register('range2', function (min, max, pat) { export const range2 = register('range2', function (min, max, pat) {
return pat.fromBipolar()._range(min, max); return pat.fromBipolar()._range(min, max);
@ -1564,7 +1574,8 @@ export const range2 = register('range2', function (min, max, pat) {
* @memberof Pattern * @memberof Pattern
* @returns Pattern * @returns Pattern
* @example * @example
* ratio("1, 5:4, 3:2").mul(110).freq().s("piano").slow(2) * ratio("1, 5:4, 3:2").mul(110)
* .freq().s("piano")
*/ */
export const ratio = register('ratio', (pat) => export const ratio = register('ratio', (pat) =>
pat.fmap((v) => { pat.fmap((v) => {
@ -1667,7 +1678,7 @@ export const ply = register('ply', function (factor, pat) {
* @param {number | Pattern} factor speed up factor * @param {number | Pattern} factor speed up factor
* @returns Pattern * @returns Pattern
* @example * @example
* s("<bd sd> hh").fast(2) // s("[<bd sd> hh]*2") * s("bd hh sd hh").fast(2) // s("[bd hh sd hh]*2")
*/ */
export const { fast, density } = register(['fast', 'density'], function (factor, pat) { export const { fast, density } = register(['fast', 'density'], function (factor, pat) {
if (factor === 0) { if (factor === 0) {
@ -1696,7 +1707,7 @@ export const hurry = register('hurry', function (r, pat) {
* @param {number | Pattern} factor slow down factor * @param {number | Pattern} factor slow down factor
* @returns Pattern * @returns Pattern
* @example * @example
* s("<bd sd> hh").slow(2) // s("[<bd sd> hh]/2") * s("bd hh sd hh").slow(2) // s("[bd hh sd hh]/2")
*/ */
export const { slow, sparsity } = register(['slow', 'sparsity'], function (factor, pat) { export const { slow, sparsity } = register(['slow', 'sparsity'], function (factor, pat) {
if (factor === 0) { if (factor === 0) {
@ -1785,9 +1796,9 @@ export const apply = register('apply', function (func, pat) {
* @example * @example
* s("<bd sd>,hh*2").cpm(90) // = 90 bpm * s("<bd sd>,hh*2").cpm(90) // = 90 bpm
*/ */
// TODO - global clock // this is redefined in repl.mjs, using the current cps as divisor
export const cpm = register('cpm', function (cpm, pat) { export const cpm = register('cpm', function (cpm, pat) {
return pat._fast(cpm / 60); return pat._fast(cpm / 60 / 1);
}); });
/** /**
@ -1860,7 +1871,7 @@ export const linger = register('linger', function (t, pat) {
* Samples the pattern at a rate of n events per cycle. Useful for turning a continuous pattern into a discrete one. * Samples the pattern at a rate of n events per cycle. Useful for turning a continuous pattern into a discrete one.
* @param {number} segments number of segments per cycle * @param {number} segments number of segments per cycle
* @example * @example
* note(saw.range(0,12).segment(24)).add(40) * note(saw.range(40,52).segment(24))
*/ */
export const segment = register('segment', function (rate, pat) { export const segment = register('segment', function (rate, pat) {
return pat.struct(pure(true)._fast(rate)); return pat.struct(pure(true)._fast(rate));
@ -1886,7 +1897,7 @@ export const { invert, inv } = register(['invert', 'inv'], function (pat) {
* @param {function} func * @param {function} func
* @returns Pattern * @returns Pattern
* @example * @example
* "c3 eb3 g3".when("<0 1>/2", x=>x.sub(5)).note() * "c3 eb3 g3".when("<0 1>/2", x=>x.sub("5")).note()
*/ */
export const when = register('when', function (on, func, pat) { export const when = register('when', function (on, func, pat) {
return on ? func(pat) : pat; return on ? func(pat) : pat;
@ -1923,7 +1934,7 @@ export const brak = register('brak', function (pat) {
* @memberof Pattern * @memberof Pattern
* @returns Pattern * @returns Pattern
* @example * @example
* note("c3 d3 e3 g3").rev() * note("c d e g").rev()
*/ */
export const rev = register('rev', function (pat) { export const rev = register('rev', function (pat) {
const query = function (state) { const query = function (state) {
@ -1993,7 +2004,7 @@ export const palindrome = register('palindrome', function (pat) {
* @name juxBy * @name juxBy
* @synonyms juxby * @synonyms juxby
* @example * @example
* s("lt ht mt ht hh").juxBy("<0 .5 1>/2", rev) * s("bd lt [~ ht] mt cp ~ bd hh").juxBy("<0 .5 1>/2", rev)
*/ */
export const { juxBy, juxby } = register(['juxBy', 'juxby'], function (by, func, pat) { export const { juxBy, juxby } = register(['juxBy', 'juxby'], function (by, func, pat) {
by /= 2; by /= 2;
@ -2012,7 +2023,11 @@ 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.
* @example * @example
* s("lt ht mt ht hh").jux(rev) * s("bd lt [~ ht] mt cp ~ bd hh").jux(rev)
* @example
* s("bd lt [~ ht] mt cp ~ bd hh").jux(press)
* @example
* s("bd lt [~ ht] mt cp ~ bd hh").jux(iter(4))
*/ */
export const jux = register('jux', function (func, pat) { export const jux = register('jux', function (func, pat) {
return pat._juxBy(1, func, pat); return pat._juxBy(1, func, pat);
@ -2028,7 +2043,7 @@ export const jux = register('jux', function (func, pat) {
* @example * @example
* "<0 [2 4]>" * "<0 [2 4]>"
* .echoWith(4, 1/8, (p,n) => p.add(n*2)) * .echoWith(4, 1/8, (p,n) => p.add(n*2))
* .scale('C minor').note().clip(.2) * .scale("C:minor").note()
*/ */
export const { echoWith, echowith, stutWith, stutwith } = register( export const { echoWith, echowith, stutWith, stutwith } = register(
['echoWith', 'echowith', 'stutWith', 'stutwith'], ['echoWith', 'echowith', 'stutWith', 'stutwith'],
@ -2121,7 +2136,8 @@ const { repeatCycles } = register('repeatCycles', _repeatCycles);
* @memberof Pattern * @memberof Pattern
* @returns Pattern * @returns Pattern
* @example * @example
* "0 1 2 3".chunk(4, x=>x.add(7)).scale('A minor').note() * "0 1 2 3".chunk(4, x=>x.add(7))
* .scale("A:minor").note()
*/ */
const _chunk = function (n, func, pat, back = false, fast = false) { const _chunk = function (n, func, pat, back = false, fast = false) {
const binary = Array(n - 1).fill(false); const binary = Array(n - 1).fill(false);
@ -2146,7 +2162,8 @@ const { chunk, slowchunk, slowChunk } = register(['chunk', 'slowchunk', 'slowChu
* @memberof Pattern * @memberof Pattern
* @returns Pattern * @returns Pattern
* @example * @example
* "0 1 2 3".chunkBack(4, x=>x.add(7)).scale('A minor').note() * "0 1 2 3".chunkBack(4, x=>x.add(7))
* .scale("A:minor").note()
*/ */
export const { chunkBack, chunkback } = register(['chunkBack', 'chunkback'], function (n, func, pat) { export const { chunkBack, chunkback } = register(['chunkBack', 'chunkback'], function (n, func, pat) {
return _chunk(n, func, pat, true); return _chunk(n, func, pat, true);
@ -2160,10 +2177,11 @@ export const { chunkBack, chunkback } = register(['chunkBack', 'chunkback'], fun
* @memberof Pattern * @memberof Pattern
* @returns Pattern * @returns Pattern
* @example * @example
* "<0 8> 1 2 3 4 5 6 7".fastChunk(4, x => x.color('red')).slow(4).scale("C2:major").note() * "<0 8> 1 2 3 4 5 6 7"
.s("folkharp") * .fastChunk(4, x => x.color('red')).slow(2)
* .scale("C2:major").note()
*/ */
const { fastchunk, fastChunk } = register(['fastchunk', 'fastChunk'], function (n, func, pat) { export const { fastchunk, fastChunk } = register(['fastchunk', 'fastChunk'], function (n, func, pat) {
return _chunk(n, func, pat, false, true); return _chunk(n, func, pat, false, true);
}); });
@ -2178,6 +2196,8 @@ export const bypass = register('bypass', function (on, pat) {
* @param {number} offset start point of loop in cycles * @param {number} offset start point of loop in cycles
* @param {number} cycles loop length in cycles * @param {number} cycles loop length in cycles
* @example * @example
* note("<c d e f>").ribbon(1, 2).fast(2)
* @example
* // Looping a portion of randomness * // Looping a portion of randomness
* note(irand(8).segment(4).scale('C3 minor')).ribbon(1337, 2) * note(irand(8).segment(4).scale('C3 minor')).ribbon(1337, 2)
*/ */
@ -2251,7 +2271,7 @@ export const legato = register('legato', function (value, pat) {
* s("rhodes") * s("rhodes")
* .chop(4) * .chop(4)
* .rev() // reverse order of chops * .rev() // reverse order of chops
* .loopAt(4) // fit sample into 4 cycles * .loopAt(2) // fit sample into 2 cycles
* *
*/ */
export const chop = register('chop', function (n, pat) { export const chop = register('chop', function (n, pat) {
@ -2269,7 +2289,7 @@ export const chop = register('chop', function (n, pat) {
* @memberof Pattern * @memberof Pattern
* @returns Pattern * @returns Pattern
* @example * @example
* s("numbers:0 numbers:1 numbers:2").striate(6).slow(6) * s("numbers:0 numbers:1 numbers:2").striate(6).slow(3)
*/ */
export const striate = register('striate', function (n, pat) { export const striate = register('striate', function (n, pat) {
const slices = Array.from({ length: n }, (x, i) => i); const slices = Array.from({ length: n }, (x, i) => i);
@ -2285,10 +2305,10 @@ export const striate = register('striate', function (n, pat) {
* @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(4) * s("rhodes").loopAt(2)
*/ */
// TODO - global cps clock // TODO - global cps clock
const _loopAt = function (factor, pat, cps = 1) { const _loopAt = function (factor, pat, cps = 0.5) {
return pat return pat
.speed((1 / factor) * cps) .speed((1 / factor) * cps)
.unit('c') .unit('c')
@ -2303,10 +2323,10 @@ const _loopAt = function (factor, pat, cps = 1) {
* @returns Pattern * @returns Pattern
* @example * @example
* await samples('github:tidalcycles/Dirt-Samples/master') * await samples('github:tidalcycles/Dirt-Samples/master')
* s("breaks165").slice(8, "0 1 <2 2*2> 3 [4 0] 5 6 7".every(3, rev)).slow(1.5) * s("breaks165").slice(8, "0 1 <2 2*2> 3 [4 0] 5 6 7".every(3, rev)).slow(0.75)
* @example * @example
* await samples('github:tidalcycles/Dirt-Samples/master') * await samples('github:tidalcycles/Dirt-Samples/master')
* s("breaks125/2").fit().slice([0,.25,.5,.75], "0 1 1 <2 3>") * s("breaks125").fit().slice([0,.25,.5,.75], "0 1 1 <2 3>")
*/ */
export const slice = register( export const slice = register(
@ -2334,7 +2354,6 @@ export const slice = register(
* await samples('github:tidalcycles/Dirt-Samples/master') * await samples('github:tidalcycles/Dirt-Samples/master')
* s("breaks165") * s("breaks165")
* .splice(8, "0 1 [2 3 0]@2 3 0@2 7") * .splice(8, "0 1 [2 3 0]@2 3 0@2 7")
* .hurry(0.65)
*/ */
export const splice = register( export const splice = register(
@ -2369,7 +2388,7 @@ export const { loopAt, loopat } = register(['loopAt', 'loopat'], function (facto
* @name fit * @name fit
* @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/4").fit() * s("rhodes/2").fit()
*/ */
export const fit = register('fit', (pat) => export const fit = register('fit', (pat) =>
pat.withHaps((haps, state) => pat.withHaps((haps, state) =>

View File

@ -101,9 +101,13 @@ export function repl({
} catch (err) { } catch (err) {
console.warn('injectPatternMethods: error:', err); console.warn('injectPatternMethods: error:', err);
} }
const cpm = register('cpm', function (cpm, pat) {
return pat._fast(cpm / 60 / scheduler.cps);
});
evalScope({ evalScope({
all, all,
hush, hush,
cpm,
setCps, setCps,
setcps: setCps, setcps: setCps,
setCpm, setCpm,

View File

@ -27,9 +27,11 @@ export const isaw2 = isaw.toBipolar();
* *
* @return {Pattern} * @return {Pattern}
* @example * @example
* "c3 [eb3,g3] g2 [g3,bb3]".note().clip(saw.slow(4)) * note("<c3 [eb3,g3] g2 [g3,bb3]>*8")
* .clip(saw.slow(2))
* @example * @example
* saw.range(0,8).segment(8).scale('C major').slow(4).note() * n(saw.range(0,8).segment(8))
* .scale('C major')
* *
*/ */
export const saw = signal((t) => t % 1); export const saw = signal((t) => t % 1);
@ -42,7 +44,8 @@ export const sine2 = signal((t) => Math.sin(Math.PI * 2 * t));
* *
* @return {Pattern} * @return {Pattern}
* @example * @example
* sine.segment(16).range(0,15).slow(2).scale('C minor').note() * n(sine.segment(16).range(0,15))
* .scale("C:minor")
* *
*/ */
export const sine = sine2.fromBipolar(); export const sine = sine2.fromBipolar();
@ -52,7 +55,8 @@ export const sine = sine2.fromBipolar();
* *
* @return {Pattern} * @return {Pattern}
* @example * @example
* stack(sine,cosine).segment(16).range(0,15).slow(2).scale('C minor').note() * n(stack(sine,cosine).segment(16).range(0,15))
* .scale("C:minor")
* *
*/ */
export const cosine = sine._early(Fraction(1).div(4)); export const cosine = sine._early(Fraction(1).div(4));
@ -63,7 +67,7 @@ export const cosine2 = sine2._early(Fraction(1).div(4));
* *
* @return {Pattern} * @return {Pattern}
* @example * @example
* square.segment(2).range(0,7).scale('C minor').note() * n(square.segment(4).range(0,7)).scale("C:minor")
* *
*/ */
export const square = signal((t) => Math.floor((t * 2) % 2)); export const square = signal((t) => Math.floor((t * 2) % 2));
@ -74,7 +78,7 @@ export const square2 = square.toBipolar();
* *
* @return {Pattern} * @return {Pattern}
* @example * @example
* tri.segment(8).range(0,7).scale('C minor').note() * n(tri.segment(8).range(0,7)).scale("C:minor")
* *
*/ */
export const tri = fastcat(isaw, saw); export const tri = fastcat(isaw, saw);
@ -118,8 +122,8 @@ const timeToRands = (t, n) => timeToRandsPrime(timeToIntSeed(t), n);
/** /**
* A discrete pattern of numbers from 0 to n-1 * A discrete pattern of numbers from 0 to n-1
* @example * @example
* run(4).scale('C4 major').note() * n(run(4)).scale("C4:pentatonic")
* // "0 1 2 3".scale('C4 major').note() * // n("0 1 2 3").scale("C4:pentatonic")
*/ */
export const run = (n) => saw.range(0, n).floor().segment(n); export const run = (n) => saw.range(0, n).floor().segment(n);
@ -129,7 +133,7 @@ export const run = (n) => saw.range(0, n).floor().segment(n);
* @name rand * @name rand
* @example * @example
* // randomly change the cutoff * // randomly change the cutoff
* s("bd sd,hh*4").cutoff(rand.range(500,2000)) * s("bd*4,hh*8").cutoff(rand.range(500,8000))
* *
*/ */
export const rand = signal(timeToRand); export const rand = signal(timeToRand);
@ -151,7 +155,7 @@ export const _irand = (i) => rand.fmap((x) => Math.trunc(x * i));
* @param {number} n max value (exclusive) * @param {number} n max value (exclusive)
* @example * @example
* // randomly select scale notes from 0 - 7 (= C to C) * // randomly select scale notes from 0 - 7 (= C to C)
* irand(8).struct("x(3,8)").scale('C minor').note() * n(irand(8)).struct("x x*2 x x*3").scale("C:minor")
* *
*/ */
export const irand = (ipat) => reify(ipat).fmap(_irand).innerJoin(); export const irand = (ipat) => reify(ipat).fmap(_irand).innerJoin();
@ -360,9 +364,9 @@ Pattern.prototype.choose2 = function (...xs) {
* Picks one of the elements at random each cycle. * Picks one of the elements at random each cycle.
* @returns {Pattern} * @returns {Pattern}
* @example * @example
* chooseCycles("bd", "hh", "sd").s().fast(4) * chooseCycles("bd", "hh", "sd").s().fast(8)
* @example * @example
* "bd | hh | sd".s().fast(4) * s("bd | hh | sd").fast(8)
*/ */
export const chooseCycles = (...xs) => chooseInWith(rand.segment(1), xs); export const chooseCycles = (...xs) => chooseInWith(rand.segment(1), xs);
@ -405,7 +409,7 @@ export const perlinWith = (pat) => {
* @name perlin * @name perlin
* @example * @example
* // randomly change the cutoff * // randomly change the cutoff
* s("bd sd,hh*4").cutoff(perlin.range(500,2000)) * s("bd*4,hh*8").cutoff(perlin.range(500,8000))
* *
*/ */
export const perlin = perlinWith(time.fmap((v) => Number(v))); export const perlin = perlinWith(time.fmap((v) => Number(v)));
@ -479,7 +483,7 @@ export const undegrade = register('undegrade', (pat) => pat._undegradeBy(0.5));
* @param {function} function - the transformation to apply * @param {function} function - the transformation to apply
* @returns Pattern * @returns Pattern
* @example * @example
* s("hh(3,8)").sometimesBy(.4, x=>x.speed("0.5")) * s("hh*8").sometimesBy(.4, x=>x.speed("0.5"))
*/ */
export const sometimesBy = register('sometimesBy', function (patx, func, pat) { export const sometimesBy = register('sometimesBy', function (patx, func, pat) {
@ -497,7 +501,7 @@ export const sometimesBy = register('sometimesBy', function (patx, func, pat) {
* @param {function} function - the transformation to apply * @param {function} function - the transformation to apply
* @returns Pattern * @returns Pattern
* @example * @example
* s("hh*4").sometimes(x=>x.speed("0.5")) * s("hh*8").sometimes(x=>x.speed("0.5"))
*/ */
export const sometimes = register('sometimes', function (func, pat) { export const sometimes = register('sometimes', function (func, pat) {
return pat._sometimesBy(0.5, func); return pat._sometimesBy(0.5, func);
@ -514,7 +518,7 @@ export const sometimes = register('sometimes', function (func, pat) {
* @param {function} function - the transformation to apply * @param {function} function - the transformation to apply
* @returns Pattern * @returns Pattern
* @example * @example
* s("hh(3,8)").someCyclesBy(.3, x=>x.speed("0.5")) * s("bd,hh*8").someCyclesBy(.3, x=>x.speed("0.5"))
*/ */
export const someCyclesBy = register('someCyclesBy', function (patx, func, pat) { export const someCyclesBy = register('someCyclesBy', function (patx, func, pat) {
@ -536,7 +540,7 @@ export const someCyclesBy = register('someCyclesBy', function (patx, func, pat)
* @memberof Pattern * @memberof Pattern
* @returns Pattern * @returns Pattern
* @example * @example
* s("hh(3,8)").someCycles(x=>x.speed("0.5")) * s("bd,hh*8").someCycles(x=>x.speed("0.5"))
*/ */
export const someCycles = register('someCycles', function (func, pat) { export const someCycles = register('someCycles', function (func, pat) {
return pat._someCyclesBy(0.5, func); return pat._someCyclesBy(0.5, func);

View File

@ -157,9 +157,9 @@ export const scaleTranspose = register('scaleTranspose', function (offset /* : n
* .scale("C:<major minor>/2") * .scale("C:<major minor>/2")
* .s("piano") * .s("piano")
* @example * @example
* n(rand.range(0,12).segment(8).round()) * n(rand.range(0,12).segment(8))
* .scale("C:ritusen") * .scale("C:ritusen")
* .s("folkharp") * .s("piano")
*/ */
export const scale = register('scale', function (scale, pat) { export const scale = register('scale', function (scale, pat) {

32
pnpm-lock.yaml generated
View File

@ -476,6 +476,12 @@ importers:
specifier: ^1.1.0 specifier: ^1.1.0
version: 1.1.0(@vitest/ui@1.1.0) version: 1.1.0(@vitest/ui@1.1.0)
tools/dbpatch:
dependencies:
csv:
specifier: ^6.3.6
version: 6.3.6
website: website:
dependencies: dependencies:
'@algolia/client-search': '@algolia/client-search':
@ -6223,6 +6229,28 @@ packages:
resolution: {integrity: sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==} resolution: {integrity: sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==}
dev: false dev: false
/csv-generate@4.3.1:
resolution: {integrity: sha512-7YeeJq+44/I/O5N2sr2qBMcHZXhpfe38eh7DOFxyMtYO+Pir7kIfgFkW5MPksqKqqR6+/wX7UGoZm1Ot11151w==}
dev: false
/csv-parse@5.5.3:
resolution: {integrity: sha512-v0KW6C0qlZzoGjk6u5tLmVfyZxNgPGXZsWTXshpAgKVGmGXzaVWGdlCFxNx5iuzcXT/oJN1HHM9DZKwtAtYa+A==}
dev: false
/csv-stringify@6.4.5:
resolution: {integrity: sha512-SPu1Vnh8U5EnzpNOi1NDBL5jU5Rx7DVHr15DNg9LXDTAbQlAVAmEbVt16wZvEW9Fu9Qt4Ji8kmeCJ2B1+4rFTQ==}
dev: false
/csv@6.3.6:
resolution: {integrity: sha512-jsEsX2HhGp7xiwrJu5srQavKsh+HUJcCi78Ar3m4jlmFKRoTkkMy7ZZPP+LnQChmaztW+uj44oyfMb59daAs/Q==}
engines: {node: '>= 0.1.90'}
dependencies:
csv-generate: 4.3.1
csv-parse: 5.5.3
csv-stringify: 6.4.5
stream-transform: 3.3.0
dev: false
/dargs@7.0.0: /dargs@7.0.0:
resolution: {integrity: sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==} resolution: {integrity: sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==}
engines: {node: '>=8'} engines: {node: '>=8'}
@ -12474,6 +12502,10 @@ packages:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
/stream-transform@3.3.0:
resolution: {integrity: sha512-pG1NeDdmErNYKtvTpFayrEueAmL0xVU5wd22V7InGnatl4Ocq3HY7dcXIKj629kXvYQvglCC7CeDIGAlx1RNGA==}
dev: false
/stream-via@1.0.4: /stream-via@1.0.4:
resolution: {integrity: sha512-DBp0lSvX5G9KGRDTkR/R+a29H+Wk2xItOF+MpZLLNDWbEV9tGPnqLPxHEYjmiz8xGtJHRIqmI+hCjmNzqoA4nQ==} resolution: {integrity: sha512-DBp0lSvX5G9KGRDTkR/R+a29H+Wk2xItOF+MpZLLNDWbEV9tGPnqLPxHEYjmiz8xGtJHRIqmI+hCjmNzqoA4nQ==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}

View File

@ -2,4 +2,5 @@ packages:
# all packages in direct subdirs of packages/ # all packages in direct subdirs of packages/
- "packages/*" - "packages/*"
- "examples/*" - "examples/*"
- "tools/dbpatch"
- "website/" - "website/"

File diff suppressed because it is too large Load Diff

View File

@ -339,402 +339,6 @@ exports[`renders tunes > tune: blippyRhodes 1`] = `
] ]
`; `;
exports[`renders tunes > tune: bridgeIsOver 1`] = `
[
"[ -155/52 ⇜ (0/1 → 5/52) | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]",
"[ -75/26 ⇜ (0/1 → 5/26) | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]",
"[ -145/52 ⇜ (0/1 → 15/52) | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]",
"[ -35/13 ⇜ (0/1 → 5/13) | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]",
"[ -35/13 ⇜ (0/1 → 5/13) | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]",
"[ -135/52 ⇜ (0/1 → 5/13) ⇝ 25/52 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]",
"[ -5/2 ⇜ (0/1 → 5/13) ⇝ 15/26 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]",
"[ -125/52 ⇜ (0/1 → 5/13) ⇝ 35/52 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]",
"[ -30/13 ⇜ (0/1 → 5/13) ⇝ 10/13 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]",
"[ -115/52 ⇜ (0/1 → 5/13) ⇝ 45/52 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]",
"[ -55/26 ⇜ (0/1 → 5/13) ⇝ 25/26 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]",
"[ -105/52 ⇜ (0/1 → 5/13) ⇝ 55/52 | clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]",
"[ 0/1 → 5/13 | note:c3 gain:0.8 clip:1 s:piano release:0.1 pan:0.4722222222222222 ]",
"[ -135/52 ⇜ (0/1 → 25/52) | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]",
"[ -5/2 ⇜ (0/1 → 15/26) | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]",
"[ -125/52 ⇜ (0/1 → 35/52) | clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]",
"[ -30/13 ⇜ (0/1 → 10/13) | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]",
"[ -115/52 ⇜ (0/1 → 10/13) ⇝ 45/52 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]",
"[ -55/26 ⇜ (0/1 → 10/13) ⇝ 25/26 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]",
"[ -105/52 ⇜ (0/1 → 10/13) ⇝ 55/52 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]",
"[ -25/13 ⇜ (0/1 → 10/13) ⇝ 15/13 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]",
"[ -95/52 ⇜ (0/1 → 10/13) ⇝ 5/4 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]",
"[ -45/26 ⇜ (0/1 → 10/13) ⇝ 35/26 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]",
"[ -85/52 ⇜ (0/1 → 10/13) ⇝ 75/52 | clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]",
"[ (0/1 → 1/1) ⇝ 40/13 | clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]",
"[ (0/1 → 1/1) ⇝ 80/13 | s:mad ]",
"[ (5/52 → 1/1) ⇝ 165/52 | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]",
"[ (5/26 → 1/1) ⇝ 85/26 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]",
"[ (15/52 → 1/1) ⇝ 175/52 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]",
"[ -135/52 ⇜ (5/13 → 25/52) | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]",
"[ -5/2 ⇜ (5/13 → 15/26) | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]",
"[ -125/52 ⇜ (5/13 → 35/52) | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]",
"[ -30/13 ⇜ (5/13 → 10/13) | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]",
"[ 5/13 → 10/13 | note:c3 gain:0.8 clip:1 s:piano release:0.1 pan:0.4722222222222222 ]",
"[ -115/52 ⇜ (5/13 → 45/52) | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]",
"[ -55/26 ⇜ (5/13 → 25/26) | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]",
"[ -105/52 ⇜ (5/13 → 1/1) ⇝ 55/52 | clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]",
"[ (5/13 → 1/1) ⇝ 45/13 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]",
"[ (5/13 → 1/1) ⇝ 45/13 | clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]",
"[ (25/52 → 1/1) ⇝ 185/52 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]",
"[ (25/52 → 1/1) ⇝ 185/52 | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]",
"[ (15/26 → 1/1) ⇝ 95/26 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]",
"[ (15/26 → 1/1) ⇝ 95/26 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]",
"[ (35/52 → 1/1) ⇝ 15/4 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]",
"[ (35/52 → 1/1) ⇝ 15/4 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]",
"[ -115/52 ⇜ (10/13 → 45/52) | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]",
"[ -55/26 ⇜ (10/13 → 25/26) | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]",
"[ 10/13 → 155/156 | note:c3 gain:0.8 clip:1 s:piano release:0.1 pan:0.4722222222222222 ]",
"[ -105/52 ⇜ (10/13 → 1/1) ⇝ 55/52 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]",
"[ -25/13 ⇜ (10/13 → 1/1) ⇝ 15/13 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]",
"[ -95/52 ⇜ (10/13 → 1/1) ⇝ 5/4 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]",
"[ -45/26 ⇜ (10/13 → 1/1) ⇝ 35/26 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]",
"[ -85/52 ⇜ (10/13 → 1/1) ⇝ 75/52 | clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]",
"[ (10/13 → 1/1) ⇝ 50/13 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]",
"[ (10/13 → 1/1) ⇝ 50/13 | clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]",
"[ (45/52 → 1/1) ⇝ 205/52 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]",
"[ (45/52 → 1/1) ⇝ 205/52 | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]",
"[ (25/26 → 1/1) ⇝ 105/26 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]",
"[ (25/26 → 1/1) ⇝ 105/26 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]",
"[ (155/156 → 1/1) ⇝ 15/13 | note:bb2 gain:0.8 clip:1 s:piano release:0.1 pan:0.46296296296296297 ]",
"[ -105/52 ⇜ (1/1 → 55/52) | clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]",
"[ -105/52 ⇜ (1/1 → 55/52) | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]",
"[ -25/13 ⇜ (1/1 → 15/13) | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]",
"[ 155/156 ⇜ (1/1 → 15/13) | note:bb2 gain:0.8 clip:1 s:piano release:0.1 pan:0.46296296296296297 ]",
"[ -95/52 ⇜ (1/1 → 5/4) | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]",
"[ -45/26 ⇜ (1/1 → 35/26) | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]",
"[ -85/52 ⇜ (1/1 → 75/52) | clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]",
"[ 0/1 ⇜ (1/1 → 2/1) ⇝ 40/13 | clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]",
"[ 0/1 ⇜ (1/1 → 2/1) ⇝ 80/13 | s:mad ]",
"[ 5/52 ⇜ (1/1 → 2/1) ⇝ 165/52 | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]",
"[ 5/26 ⇜ (1/1 → 2/1) ⇝ 85/26 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]",
"[ 15/52 ⇜ (1/1 → 2/1) ⇝ 175/52 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]",
"[ 5/13 ⇜ (1/1 → 2/1) ⇝ 45/13 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]",
"[ 5/13 ⇜ (1/1 → 2/1) ⇝ 45/13 | clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]",
"[ 25/52 ⇜ (1/1 → 2/1) ⇝ 185/52 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]",
"[ 25/52 ⇜ (1/1 → 2/1) ⇝ 185/52 | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]",
"[ 15/26 ⇜ (1/1 → 2/1) ⇝ 95/26 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]",
"[ 15/26 ⇜ (1/1 → 2/1) ⇝ 95/26 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]",
"[ 35/52 ⇜ (1/1 → 2/1) ⇝ 15/4 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]",
"[ 35/52 ⇜ (1/1 → 2/1) ⇝ 15/4 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]",
"[ 10/13 ⇜ (1/1 → 2/1) ⇝ 50/13 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]",
"[ 10/13 ⇜ (1/1 → 2/1) ⇝ 50/13 | clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]",
"[ 45/52 ⇜ (1/1 → 2/1) ⇝ 205/52 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]",
"[ 45/52 ⇜ (1/1 → 2/1) ⇝ 205/52 | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]",
"[ 25/26 ⇜ (1/1 → 2/1) ⇝ 105/26 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]",
"[ 25/26 ⇜ (1/1 → 2/1) ⇝ 105/26 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]",
"[ (55/52 → 2/1) ⇝ 215/52 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]",
"[ (55/52 → 2/1) ⇝ 215/52 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]",
"[ 15/13 → 20/13 | note:ab2 gain:0.8 clip:1 s:piano release:0.1 pan:0.4537037037037037 ]",
"[ (15/13 → 2/1) ⇝ 55/13 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]",
"[ (5/4 → 2/1) ⇝ 225/52 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]",
"[ (35/26 → 2/1) ⇝ 115/26 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]",
"[ (75/52 → 2/1) ⇝ 235/52 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]",
"[ 20/13 → 25/13 | note:gb2 gain:0.8 clip:1 s:piano release:0.1 pan:0.4444444444444444 ]",
"[ (25/13 → 2/1) ⇝ 30/13 | note:gb2 gain:0.8 clip:1 s:piano release:0.1 pan:0.4444444444444444 ]",
"[ 25/13 ⇜ (2/1 → 30/13) | note:gb2 gain:0.8 clip:1 s:piano release:0.1 pan:0.4444444444444444 ]",
"[ 0/1 ⇜ (2/1 → 3/1) ⇝ 40/13 | clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]",
"[ 0/1 ⇜ (2/1 → 3/1) ⇝ 80/13 | s:mad ]",
"[ 5/52 ⇜ (2/1 → 3/1) ⇝ 165/52 | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]",
"[ 5/26 ⇜ (2/1 → 3/1) ⇝ 85/26 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]",
"[ 15/52 ⇜ (2/1 → 3/1) ⇝ 175/52 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]",
"[ 5/13 ⇜ (2/1 → 3/1) ⇝ 45/13 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]",
"[ 5/13 ⇜ (2/1 → 3/1) ⇝ 45/13 | clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]",
"[ 25/52 ⇜ (2/1 → 3/1) ⇝ 185/52 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]",
"[ 25/52 ⇜ (2/1 → 3/1) ⇝ 185/52 | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]",
"[ 15/26 ⇜ (2/1 → 3/1) ⇝ 95/26 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]",
"[ 15/26 ⇜ (2/1 → 3/1) ⇝ 95/26 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]",
"[ 35/52 ⇜ (2/1 → 3/1) ⇝ 15/4 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]",
"[ 35/52 ⇜ (2/1 → 3/1) ⇝ 15/4 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]",
"[ 10/13 ⇜ (2/1 → 3/1) ⇝ 50/13 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]",
"[ 10/13 ⇜ (2/1 → 3/1) ⇝ 50/13 | clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]",
"[ 45/52 ⇜ (2/1 → 3/1) ⇝ 205/52 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]",
"[ 45/52 ⇜ (2/1 → 3/1) ⇝ 205/52 | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]",
"[ 25/26 ⇜ (2/1 → 3/1) ⇝ 105/26 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]",
"[ 25/26 ⇜ (2/1 → 3/1) ⇝ 105/26 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]",
"[ 55/52 ⇜ (2/1 → 3/1) ⇝ 215/52 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]",
"[ 55/52 ⇜ (2/1 → 3/1) ⇝ 215/52 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]",
"[ 15/13 ⇜ (2/1 → 3/1) ⇝ 55/13 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]",
"[ 5/4 ⇜ (2/1 → 3/1) ⇝ 225/52 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]",
"[ 35/26 ⇜ (2/1 → 3/1) ⇝ 115/26 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]",
"[ 75/52 ⇜ (2/1 → 3/1) ⇝ 235/52 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]",
"[ 30/13 → 395/156 | note:gb2 gain:0.8 clip:1 s:piano release:0.1 pan:0.4444444444444444 ]",
"[ 395/156 → 35/13 | note:ab2 gain:0.8 clip:1 s:piano release:0.1 pan:0.4537037037037037 ]",
"[ (35/13 → 3/1) ⇝ 40/13 | note:bb2 gain:0.8 clip:1 s:piano release:0.1 pan:0.46296296296296297 ]",
"[ 0/1 ⇜ (3/1 → 40/13) | clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]",
"[ 0/1 ⇜ (3/1 → 40/13) ⇝ 80/13 | s:mad ]",
"[ 5/52 ⇜ (3/1 → 40/13) ⇝ 165/52 | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]",
"[ 5/26 ⇜ (3/1 → 40/13) ⇝ 85/26 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]",
"[ 15/52 ⇜ (3/1 → 40/13) ⇝ 175/52 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]",
"[ 5/13 ⇜ (3/1 → 40/13) ⇝ 45/13 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]",
"[ 5/13 ⇜ (3/1 → 40/13) ⇝ 45/13 | clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]",
"[ 25/52 ⇜ (3/1 → 40/13) ⇝ 185/52 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]",
"[ 25/52 ⇜ (3/1 → 40/13) ⇝ 185/52 | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]",
"[ 15/26 ⇜ (3/1 → 40/13) ⇝ 95/26 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]",
"[ 15/26 ⇜ (3/1 → 40/13) ⇝ 95/26 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]",
"[ 35/52 ⇜ (3/1 → 40/13) ⇝ 15/4 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]",
"[ 35/52 ⇜ (3/1 → 40/13) ⇝ 15/4 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]",
"[ 10/13 ⇜ (3/1 → 40/13) ⇝ 50/13 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]",
"[ 10/13 ⇜ (3/1 → 40/13) ⇝ 50/13 | clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]",
"[ 45/52 ⇜ (3/1 → 40/13) ⇝ 205/52 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]",
"[ 45/52 ⇜ (3/1 → 40/13) ⇝ 205/52 | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]",
"[ 25/26 ⇜ (3/1 → 40/13) ⇝ 105/26 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]",
"[ 25/26 ⇜ (3/1 → 40/13) ⇝ 105/26 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]",
"[ 55/52 ⇜ (3/1 → 40/13) ⇝ 215/52 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]",
"[ 55/52 ⇜ (3/1 → 40/13) ⇝ 215/52 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]",
"[ 15/13 ⇜ (3/1 → 40/13) ⇝ 55/13 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]",
"[ 5/4 ⇜ (3/1 → 40/13) ⇝ 225/52 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]",
"[ 35/26 ⇜ (3/1 → 40/13) ⇝ 115/26 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]",
"[ 75/52 ⇜ (3/1 → 40/13) ⇝ 235/52 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]",
"[ 35/13 ⇜ (3/1 → 40/13) | note:bb2 gain:0.8 clip:1 s:piano release:0.1 pan:0.46296296296296297 ]",
"[ 5/52 ⇜ (40/13 → 165/52) | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]",
"[ 5/26 ⇜ (40/13 → 85/26) | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]",
"[ 15/52 ⇜ (40/13 → 175/52) | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]",
"[ 5/13 ⇜ (40/13 → 45/13) | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]",
"[ 5/13 ⇜ (40/13 → 45/13) | clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]",
"[ 25/52 ⇜ (40/13 → 45/13) ⇝ 185/52 | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]",
"[ 15/26 ⇜ (40/13 → 45/13) ⇝ 95/26 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]",
"[ 35/52 ⇜ (40/13 → 45/13) ⇝ 15/4 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]",
"[ 10/13 ⇜ (40/13 → 45/13) ⇝ 50/13 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]",
"[ 45/52 ⇜ (40/13 → 45/13) ⇝ 205/52 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]",
"[ 25/26 ⇜ (40/13 → 45/13) ⇝ 105/26 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]",
"[ 55/52 ⇜ (40/13 → 45/13) ⇝ 215/52 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]",
"[ 40/13 → 45/13 | note:c3 gain:0.8 clip:1 s:piano release:0.1 pan:0.4722222222222222 ]",
"[ 25/52 ⇜ (40/13 → 185/52) | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]",
"[ 15/26 ⇜ (40/13 → 95/26) | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]",
"[ 35/52 ⇜ (40/13 → 15/4) | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]",
"[ 10/13 ⇜ (40/13 → 50/13) | clip:1 note:C4 s:piano release:0.1 pan:0.5277777777777778 ]",
"[ 45/52 ⇜ (40/13 → 50/13) ⇝ 205/52 | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]",
"[ 25/26 ⇜ (40/13 → 50/13) ⇝ 105/26 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]",
"[ 55/52 ⇜ (40/13 → 50/13) ⇝ 215/52 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]",
"[ 15/13 ⇜ (40/13 → 50/13) ⇝ 55/13 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]",
"[ 5/4 ⇜ (40/13 → 50/13) ⇝ 225/52 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]",
"[ 35/26 ⇜ (40/13 → 50/13) ⇝ 115/26 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]",
"[ 75/52 ⇜ (40/13 → 50/13) ⇝ 235/52 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]",
"[ 0/1 ⇜ (40/13 → 4/1) ⇝ 80/13 | s:mad ]",
"[ (40/13 → 4/1) ⇝ 80/13 | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]",
"[ (165/52 → 4/1) ⇝ 25/4 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]",
"[ (85/26 → 4/1) ⇝ 165/26 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]",
"[ (175/52 → 4/1) ⇝ 335/52 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]",
"[ 25/52 ⇜ (45/13 → 185/52) | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]",
"[ 15/26 ⇜ (45/13 → 95/26) | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]",
"[ 35/52 ⇜ (45/13 → 15/4) | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]",
"[ 10/13 ⇜ (45/13 → 50/13) | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]",
"[ 45/13 → 50/13 | note:c3 gain:0.8 clip:1 s:piano release:0.1 pan:0.4722222222222222 ]",
"[ 45/52 ⇜ (45/13 → 205/52) | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]",
"[ 25/26 ⇜ (45/13 → 4/1) ⇝ 105/26 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]",
"[ 55/52 ⇜ (45/13 → 4/1) ⇝ 215/52 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]",
"[ (45/13 → 4/1) ⇝ 85/13 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]",
"[ (45/13 → 4/1) ⇝ 85/13 | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]",
"[ (185/52 → 4/1) ⇝ 345/52 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]",
"[ (185/52 → 4/1) ⇝ 345/52 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]",
"[ (95/26 → 4/1) ⇝ 175/26 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]",
"[ (95/26 → 4/1) ⇝ 175/26 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]",
"[ (15/4 → 4/1) ⇝ 355/52 | clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]",
"[ (15/4 → 4/1) ⇝ 355/52 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]",
"[ 45/52 ⇜ (50/13 → 205/52) | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]",
"[ 25/26 ⇜ (50/13 → 4/1) ⇝ 105/26 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]",
"[ 55/52 ⇜ (50/13 → 4/1) ⇝ 215/52 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]",
"[ 15/13 ⇜ (50/13 → 4/1) ⇝ 55/13 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]",
"[ 5/4 ⇜ (50/13 → 4/1) ⇝ 225/52 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]",
"[ 35/26 ⇜ (50/13 → 4/1) ⇝ 115/26 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]",
"[ 75/52 ⇜ (50/13 → 4/1) ⇝ 235/52 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]",
"[ (50/13 → 4/1) ⇝ 635/156 | note:c3 gain:0.8 clip:1 s:piano release:0.1 pan:0.4722222222222222 ]",
"[ (50/13 → 4/1) ⇝ 90/13 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]",
"[ (50/13 → 4/1) ⇝ 90/13 | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]",
"[ (205/52 → 4/1) ⇝ 365/52 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]",
"[ (205/52 → 4/1) ⇝ 365/52 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]",
"[ 25/26 ⇜ (4/1 → 105/26) | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]",
"[ 25/26 ⇜ (4/1 → 105/26) | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]",
"[ 50/13 ⇜ (4/1 → 635/156) | note:c3 gain:0.8 clip:1 s:piano release:0.1 pan:0.4722222222222222 ]",
"[ 55/52 ⇜ (4/1 → 215/52) | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]",
"[ 55/52 ⇜ (4/1 → 215/52) | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]",
"[ 15/13 ⇜ (4/1 → 55/13) | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]",
"[ 5/4 ⇜ (4/1 → 225/52) | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]",
"[ 35/26 ⇜ (4/1 → 115/26) | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]",
"[ 75/52 ⇜ (4/1 → 235/52) | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]",
"[ 0/1 ⇜ (4/1 → 5/1) ⇝ 80/13 | s:mad ]",
"[ 40/13 ⇜ (4/1 → 5/1) ⇝ 80/13 | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]",
"[ 165/52 ⇜ (4/1 → 5/1) ⇝ 25/4 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]",
"[ 85/26 ⇜ (4/1 → 5/1) ⇝ 165/26 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]",
"[ 175/52 ⇜ (4/1 → 5/1) ⇝ 335/52 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]",
"[ 45/13 ⇜ (4/1 → 5/1) ⇝ 85/13 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]",
"[ 45/13 ⇜ (4/1 → 5/1) ⇝ 85/13 | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]",
"[ 185/52 ⇜ (4/1 → 5/1) ⇝ 345/52 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]",
"[ 185/52 ⇜ (4/1 → 5/1) ⇝ 345/52 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]",
"[ 95/26 ⇜ (4/1 → 5/1) ⇝ 175/26 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]",
"[ 95/26 ⇜ (4/1 → 5/1) ⇝ 175/26 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]",
"[ 15/4 ⇜ (4/1 → 5/1) ⇝ 355/52 | clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]",
"[ 15/4 ⇜ (4/1 → 5/1) ⇝ 355/52 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]",
"[ 50/13 ⇜ (4/1 → 5/1) ⇝ 90/13 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]",
"[ 50/13 ⇜ (4/1 → 5/1) ⇝ 90/13 | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]",
"[ 205/52 ⇜ (4/1 → 5/1) ⇝ 365/52 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]",
"[ 205/52 ⇜ (4/1 → 5/1) ⇝ 365/52 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]",
"[ (105/26 → 5/1) ⇝ 185/26 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]",
"[ (105/26 → 5/1) ⇝ 185/26 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]",
"[ 635/156 → 55/13 | note:bb2 gain:0.8 clip:1 s:piano release:0.1 pan:0.46296296296296297 ]",
"[ (215/52 → 5/1) ⇝ 375/52 | clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]",
"[ (215/52 → 5/1) ⇝ 375/52 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]",
"[ 55/13 → 60/13 | note:ab2 gain:0.8 clip:1 s:piano release:0.1 pan:0.4537037037037037 ]",
"[ (55/13 → 5/1) ⇝ 95/13 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]",
"[ (225/52 → 5/1) ⇝ 385/52 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]",
"[ (115/26 → 5/1) ⇝ 15/2 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]",
"[ (235/52 → 5/1) ⇝ 395/52 | clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]",
"[ 60/13 → 5/1 | note:gb2 gain:0.8 clip:1 s:piano release:0.1 pan:0.4444444444444444 ]",
"[ 5/1 → 70/13 | note:gb2 gain:0.8 clip:1 s:piano release:0.1 pan:0.4444444444444444 ]",
"[ 0/1 ⇜ (5/1 → 6/1) ⇝ 80/13 | s:mad ]",
"[ 40/13 ⇜ (5/1 → 6/1) ⇝ 80/13 | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]",
"[ 165/52 ⇜ (5/1 → 6/1) ⇝ 25/4 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]",
"[ 85/26 ⇜ (5/1 → 6/1) ⇝ 165/26 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]",
"[ 175/52 ⇜ (5/1 → 6/1) ⇝ 335/52 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]",
"[ 45/13 ⇜ (5/1 → 6/1) ⇝ 85/13 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]",
"[ 45/13 ⇜ (5/1 → 6/1) ⇝ 85/13 | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]",
"[ 185/52 ⇜ (5/1 → 6/1) ⇝ 345/52 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]",
"[ 185/52 ⇜ (5/1 → 6/1) ⇝ 345/52 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]",
"[ 95/26 ⇜ (5/1 → 6/1) ⇝ 175/26 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]",
"[ 95/26 ⇜ (5/1 → 6/1) ⇝ 175/26 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]",
"[ 15/4 ⇜ (5/1 → 6/1) ⇝ 355/52 | clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]",
"[ 15/4 ⇜ (5/1 → 6/1) ⇝ 355/52 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]",
"[ 50/13 ⇜ (5/1 → 6/1) ⇝ 90/13 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]",
"[ 50/13 ⇜ (5/1 → 6/1) ⇝ 90/13 | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]",
"[ 205/52 ⇜ (5/1 → 6/1) ⇝ 365/52 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]",
"[ 205/52 ⇜ (5/1 → 6/1) ⇝ 365/52 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]",
"[ 105/26 ⇜ (5/1 → 6/1) ⇝ 185/26 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]",
"[ 105/26 ⇜ (5/1 → 6/1) ⇝ 185/26 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]",
"[ 215/52 ⇜ (5/1 → 6/1) ⇝ 375/52 | clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]",
"[ 215/52 ⇜ (5/1 → 6/1) ⇝ 375/52 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]",
"[ 55/13 ⇜ (5/1 → 6/1) ⇝ 95/13 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]",
"[ 225/52 ⇜ (5/1 → 6/1) ⇝ 385/52 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]",
"[ 115/26 ⇜ (5/1 → 6/1) ⇝ 15/2 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]",
"[ 235/52 ⇜ (5/1 → 6/1) ⇝ 395/52 | clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]",
"[ (70/13 → 6/1) ⇝ 80/13 | note:gb2 gain:0.8 clip:1 s:piano release:0.1 pan:0.4444444444444444 ]",
"[ 0/1 ⇜ (6/1 → 80/13) | s:mad ]",
"[ 40/13 ⇜ (6/1 → 80/13) | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]",
"[ 165/52 ⇜ (6/1 → 80/13) ⇝ 25/4 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]",
"[ 85/26 ⇜ (6/1 → 80/13) ⇝ 165/26 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]",
"[ 175/52 ⇜ (6/1 → 80/13) ⇝ 335/52 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]",
"[ 45/13 ⇜ (6/1 → 80/13) ⇝ 85/13 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]",
"[ 45/13 ⇜ (6/1 → 80/13) ⇝ 85/13 | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]",
"[ 185/52 ⇜ (6/1 → 80/13) ⇝ 345/52 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]",
"[ 185/52 ⇜ (6/1 → 80/13) ⇝ 345/52 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]",
"[ 95/26 ⇜ (6/1 → 80/13) ⇝ 175/26 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]",
"[ 95/26 ⇜ (6/1 → 80/13) ⇝ 175/26 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]",
"[ 15/4 ⇜ (6/1 → 80/13) ⇝ 355/52 | clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]",
"[ 15/4 ⇜ (6/1 → 80/13) ⇝ 355/52 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]",
"[ 50/13 ⇜ (6/1 → 80/13) ⇝ 90/13 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]",
"[ 50/13 ⇜ (6/1 → 80/13) ⇝ 90/13 | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]",
"[ 205/52 ⇜ (6/1 → 80/13) ⇝ 365/52 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]",
"[ 205/52 ⇜ (6/1 → 80/13) ⇝ 365/52 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]",
"[ 105/26 ⇜ (6/1 → 80/13) ⇝ 185/26 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]",
"[ 105/26 ⇜ (6/1 → 80/13) ⇝ 185/26 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]",
"[ 215/52 ⇜ (6/1 → 80/13) ⇝ 375/52 | clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]",
"[ 215/52 ⇜ (6/1 → 80/13) ⇝ 375/52 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]",
"[ 55/13 ⇜ (6/1 → 80/13) ⇝ 95/13 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]",
"[ 225/52 ⇜ (6/1 → 80/13) ⇝ 385/52 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]",
"[ 115/26 ⇜ (6/1 → 80/13) ⇝ 15/2 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]",
"[ 235/52 ⇜ (6/1 → 80/13) ⇝ 395/52 | clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]",
"[ 70/13 ⇜ (6/1 → 80/13) | note:gb2 gain:0.8 clip:1 s:piano release:0.1 pan:0.4444444444444444 ]",
"[ 165/52 ⇜ (80/13 → 25/4) | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]",
"[ 85/26 ⇜ (80/13 → 165/26) | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]",
"[ 175/52 ⇜ (80/13 → 335/52) | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]",
"[ 45/13 ⇜ (80/13 → 85/13) | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]",
"[ 45/13 ⇜ (80/13 → 85/13) | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]",
"[ 185/52 ⇜ (80/13 → 85/13) ⇝ 345/52 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]",
"[ 95/26 ⇜ (80/13 → 85/13) ⇝ 175/26 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]",
"[ 15/4 ⇜ (80/13 → 85/13) ⇝ 355/52 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]",
"[ 50/13 ⇜ (80/13 → 85/13) ⇝ 90/13 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]",
"[ 205/52 ⇜ (80/13 → 85/13) ⇝ 365/52 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]",
"[ 105/26 ⇜ (80/13 → 85/13) ⇝ 185/26 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]",
"[ 215/52 ⇜ (80/13 → 85/13) ⇝ 375/52 | clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]",
"[ 80/13 → 85/13 | note:c3 gain:0.8 clip:1 s:piano release:0.1 pan:0.4722222222222222 ]",
"[ 185/52 ⇜ (80/13 → 345/52) | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]",
"[ 95/26 ⇜ (80/13 → 175/26) | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]",
"[ 15/4 ⇜ (80/13 → 355/52) | clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]",
"[ 50/13 ⇜ (80/13 → 90/13) | clip:1 note:D4 s:piano release:0.1 pan:0.537037037037037 ]",
"[ 205/52 ⇜ (80/13 → 90/13) ⇝ 365/52 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]",
"[ 105/26 ⇜ (80/13 → 90/13) ⇝ 185/26 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]",
"[ 215/52 ⇜ (80/13 → 90/13) ⇝ 375/52 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]",
"[ 55/13 ⇜ (80/13 → 90/13) ⇝ 95/13 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]",
"[ 225/52 ⇜ (80/13 → 90/13) ⇝ 385/52 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]",
"[ 115/26 ⇜ (80/13 → 90/13) ⇝ 15/2 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]",
"[ 235/52 ⇜ (80/13 → 90/13) ⇝ 395/52 | clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]",
"[ (80/13 → 7/1) ⇝ 120/13 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]",
"[ (80/13 → 7/1) ⇝ 160/13 | s:mad ]",
"[ (25/4 → 7/1) ⇝ 485/52 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]",
"[ (165/26 → 7/1) ⇝ 245/26 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]",
"[ (335/52 → 7/1) ⇝ 495/52 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]",
"[ 185/52 ⇜ (85/13 → 345/52) | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]",
"[ 95/26 ⇜ (85/13 → 175/26) | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]",
"[ 15/4 ⇜ (85/13 → 355/52) | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]",
"[ 50/13 ⇜ (85/13 → 90/13) | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]",
"[ 85/13 → 90/13 | note:c3 gain:0.8 clip:1 s:piano release:0.1 pan:0.4722222222222222 ]",
"[ 205/52 ⇜ (85/13 → 7/1) ⇝ 365/52 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]",
"[ 105/26 ⇜ (85/13 → 7/1) ⇝ 185/26 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]",
"[ 215/52 ⇜ (85/13 → 7/1) ⇝ 375/52 | clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]",
"[ (85/13 → 7/1) ⇝ 125/13 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]",
"[ (85/13 → 7/1) ⇝ 125/13 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]",
"[ (345/52 → 7/1) ⇝ 505/52 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]",
"[ (345/52 → 7/1) ⇝ 505/52 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]",
"[ (175/26 → 7/1) ⇝ 255/26 | clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]",
"[ (175/26 → 7/1) ⇝ 255/26 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]",
"[ (355/52 → 7/1) ⇝ 515/52 | clip:1 note:F#5 s:piano release:0.1 pan:0.6111111111111112 ]",
"[ (355/52 → 7/1) ⇝ 515/52 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]",
"[ 205/52 ⇜ (90/13 → 7/1) ⇝ 365/52 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]",
"[ 105/26 ⇜ (90/13 → 7/1) ⇝ 185/26 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]",
"[ 215/52 ⇜ (90/13 → 7/1) ⇝ 375/52 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]",
"[ 55/13 ⇜ (90/13 → 7/1) ⇝ 95/13 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]",
"[ 225/52 ⇜ (90/13 → 7/1) ⇝ 385/52 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]",
"[ 115/26 ⇜ (90/13 → 7/1) ⇝ 15/2 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]",
"[ 235/52 ⇜ (90/13 → 7/1) ⇝ 395/52 | clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]",
"[ (90/13 → 7/1) ⇝ 1115/156 | note:c3 gain:0.8 clip:1 s:piano release:0.1 pan:0.4722222222222222 ]",
"[ (90/13 → 7/1) ⇝ 10/1 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]",
"[ (90/13 → 7/1) ⇝ 10/1 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]",
"[ 205/52 ⇜ (7/1 → 365/52) | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]",
"[ 205/52 ⇜ (7/1 → 365/52) | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]",
"[ 105/26 ⇜ (7/1 → 185/26) | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]",
"[ 105/26 ⇜ (7/1 → 185/26) | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]",
"[ 90/13 ⇜ (7/1 → 1115/156) | note:c3 gain:0.8 clip:1 s:piano release:0.1 pan:0.4722222222222222 ]",
"[ 215/52 ⇜ (7/1 → 375/52) | clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]",
"[ 215/52 ⇜ (7/1 → 375/52) | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]",
"[ 55/13 ⇜ (7/1 → 95/13) | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]",
"[ 225/52 ⇜ (7/1 → 385/52) | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]",
"[ 115/26 ⇜ (7/1 → 15/2) | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]",
"[ 235/52 ⇜ (7/1 → 395/52) | clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]",
"[ 80/13 ⇜ (7/1 → 8/1) ⇝ 120/13 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]",
"[ 80/13 ⇜ (7/1 → 8/1) ⇝ 160/13 | s:mad ]",
"[ 25/4 ⇜ (7/1 → 8/1) ⇝ 485/52 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]",
"[ 165/26 ⇜ (7/1 → 8/1) ⇝ 245/26 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]",
"[ 335/52 ⇜ (7/1 → 8/1) ⇝ 495/52 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]",
"[ 85/13 ⇜ (7/1 → 8/1) ⇝ 125/13 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]",
"[ 85/13 ⇜ (7/1 → 8/1) ⇝ 125/13 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]",
"[ 345/52 ⇜ (7/1 → 8/1) ⇝ 505/52 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]",
"[ 345/52 ⇜ (7/1 → 8/1) ⇝ 505/52 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]",
"[ 175/26 ⇜ (7/1 → 8/1) ⇝ 255/26 | clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]",
"[ 175/26 ⇜ (7/1 → 8/1) ⇝ 255/26 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]",
"[ 355/52 ⇜ (7/1 → 8/1) ⇝ 515/52 | clip:1 note:F#5 s:piano release:0.1 pan:0.6111111111111112 ]",
"[ 355/52 ⇜ (7/1 → 8/1) ⇝ 515/52 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]",
"[ 90/13 ⇜ (7/1 → 8/1) ⇝ 10/1 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]",
"[ 90/13 ⇜ (7/1 → 8/1) ⇝ 10/1 | clip:1 note:E4 s:piano release:0.1 pan:0.5462962962962963 ]",
"[ (365/52 → 8/1) ⇝ 525/52 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]",
"[ (365/52 → 8/1) ⇝ 525/52 | clip:1 note:F#4 s:piano release:0.1 pan:0.5555555555555556 ]",
"[ (185/26 → 8/1) ⇝ 265/26 | clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]",
"[ (185/26 → 8/1) ⇝ 265/26 | clip:1 note:G#4 s:piano release:0.1 pan:0.5648148148148149 ]",
"[ 1115/156 → 95/13 | note:bb2 gain:0.8 clip:1 s:piano release:0.1 pan:0.46296296296296297 ]",
"[ (375/52 → 8/1) ⇝ 535/52 | clip:1 note:F#5 s:piano release:0.1 pan:0.6111111111111112 ]",
"[ (375/52 → 8/1) ⇝ 535/52 | clip:1 note:A#4 s:piano release:0.1 pan:0.5740740740740741 ]",
"[ 95/13 → 100/13 | note:ab2 gain:0.8 clip:1 s:piano release:0.1 pan:0.4537037037037037 ]",
"[ (95/13 → 8/1) ⇝ 135/13 | clip:1 note:C5 s:piano release:0.1 pan:0.5833333333333333 ]",
"[ (385/52 → 8/1) ⇝ 545/52 | clip:1 note:D5 s:piano release:0.1 pan:0.5925925925925926 ]",
"[ (15/2 → 8/1) ⇝ 275/26 | clip:1 note:E5 s:piano release:0.1 pan:0.6018518518518519 ]",
"[ (395/52 → 8/1) ⇝ 555/52 | clip:1 note:F#5 s:piano release:0.1 pan:0.6111111111111112 ]",
"[ (100/13 → 8/1) ⇝ 105/13 | note:gb2 gain:0.8 clip:1 s:piano release:0.1 pan:0.4444444444444444 ]",
]
`;
exports[`renders tunes > tune: caverave 1`] = ` exports[`renders tunes > tune: caverave 1`] = `
[ [
"[ 0/1 → 1/2 | s:bd gain:0.8 ]", "[ 0/1 → 1/2 | s:bd gain:0.8 ]",
@ -1507,14 +1111,14 @@ exports[`renders tunes > tune: caverave 1`] = `
exports[`renders tunes > tune: chop 1`] = ` exports[`renders tunes > tune: chop 1`] = `
[ [
"[ 0/1 → 1/4 | s:p speed:0.03125 unit:c begin:0 end:0.0078125 pan:0 shape:0.4 decay:0.1 sustain:0.6 ]", "[ 0/1 → 1/4 | s:p speed:0.015625 unit:c begin:0 end:0.0078125 pan:0 shape:0.4 decay:0.1 sustain:0.6 ]",
"[ 0/1 → 1/4 | s:p speed:0.03125 unit:c begin:0.0234375 end:0.03125 pan:1 shape:0.4 decay:0.1 sustain:0.6 ]", "[ 0/1 → 1/4 | s:p speed:0.015625 unit:c begin:0.0234375 end:0.03125 pan:1 shape:0.4 decay:0.1 sustain:0.6 ]",
"[ 1/4 → 1/2 | s:p speed:0.03125 unit:c begin:0.0078125 end:0.015625 pan:0 shape:0.4 decay:0.1 sustain:0.6 ]", "[ 1/4 → 1/2 | s:p speed:0.015625 unit:c begin:0.0078125 end:0.015625 pan:0 shape:0.4 decay:0.1 sustain:0.6 ]",
"[ 1/4 → 1/2 | s:p speed:0.03125 unit:c begin:0.015625 end:0.0234375 pan:1 shape:0.4 decay:0.1 sustain:0.6 ]", "[ 1/4 → 1/2 | s:p speed:0.015625 unit:c begin:0.015625 end:0.0234375 pan:1 shape:0.4 decay:0.1 sustain:0.6 ]",
"[ 1/2 → 3/4 | s:p speed:0.03125 unit:c begin:0.015625 end:0.0234375 pan:0 shape:0.4 decay:0.1 sustain:0.6 ]", "[ 1/2 → 3/4 | s:p speed:0.015625 unit:c begin:0.015625 end:0.0234375 pan:0 shape:0.4 decay:0.1 sustain:0.6 ]",
"[ 1/2 → 3/4 | s:p speed:0.03125 unit:c begin:0.0078125 end:0.015625 pan:1 shape:0.4 decay:0.1 sustain:0.6 ]", "[ 1/2 → 3/4 | s:p speed:0.015625 unit:c begin:0.0078125 end:0.015625 pan:1 shape:0.4 decay:0.1 sustain:0.6 ]",
"[ 3/4 → 1/1 | s:p speed:0.03125 unit:c begin:0.0234375 end:0.03125 pan:0 shape:0.4 decay:0.1 sustain:0.6 ]", "[ 3/4 → 1/1 | s:p speed:0.015625 unit:c begin:0.0234375 end:0.03125 pan:0 shape:0.4 decay:0.1 sustain:0.6 ]",
"[ 3/4 → 1/1 | s:p speed:0.03125 unit:c begin:0 end:0.0078125 pan:1 shape:0.4 decay:0.1 sustain:0.6 ]", "[ 3/4 → 1/1 | s:p speed:0.015625 unit:c begin:0 end:0.0078125 pan:1 shape:0.4 decay:0.1 sustain:0.6 ]",
] ]
`; `;
@ -1545,7 +1149,7 @@ exports[`renders tunes > tune: dinofunk 1`] = `
"[ 0/1 → 1/4 | note:Ab4 s:sawtooth cutoff:1239.2541394619345 gain:0.8 decay:0.05125097280354112 sustain:0 delay:0.2561353071307281 room:1 ]", "[ 0/1 → 1/4 | note:Ab4 s:sawtooth cutoff:1239.2541394619345 gain:0.8 decay:0.05125097280354112 sustain:0 delay:0.2561353071307281 room:1 ]",
"[ 0/1 → 1/4 | note:68.1 s:sawtooth cutoff:1239.2541394619345 gain:0.8 decay:0.05125097280354112 sustain:0 delay:0.2561353071307281 room:1 ]", "[ 0/1 → 1/4 | note:68.1 s:sawtooth cutoff:1239.2541394619345 gain:0.8 decay:0.05125097280354112 sustain:0 delay:0.2561353071307281 room:1 ]",
"[ 0/1 → 1/2 | s:bd ]", "[ 0/1 → 1/2 | s:bd ]",
"[ (0/1 → 1/1) ⇝ 8/1 | s:bass speed:0.125 unit:c clip:1 ]", "[ (0/1 → 1/1) ⇝ 8/1 | s:bass speed:0.0625 unit:c clip:1 ]",
"[ (0/1 → 1/1) ⇝ 8/1 | note:b4 s:dino delay:0.8 room:0.5 ]", "[ (0/1 → 1/1) ⇝ 8/1 | note:b4 s:dino delay:0.8 room:0.5 ]",
"[ 1/4 → 1/2 | s:hh ]", "[ 1/4 → 1/2 | s:hh ]",
"[ 1/4 → 1/2 | note:Gb3 ]", "[ 1/4 → 1/2 | note:Gb3 ]",

View File

@ -1,10 +0,0 @@
import { createClient } from '@supabase/supabase-js';
const supabase = createClient(
'https://pidxdsxphlhzjnzmifth.supabase.co',
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InBpZHhkc3hwaGxoempuem1pZnRoIiwicm9sZSI6ImFub24iLCJpYXQiOjE2NTYyMzA1NTYsImV4cCI6MTk3MTgwNjU1Nn0.bqlw7802fsWRnqU5BLYtmXk_k-D1VFmbkHMywWc15NM',
);
const { data } = await supabase.from('code');
console.log(JSON.stringify(data));

File diff suppressed because one or more lines are too long

View File

@ -175,6 +175,7 @@ evalScope(
loadCSound, loadCSound,
loadCsound, loadCsound,
loadcsound, loadcsound,
setcps: id,
Clock: {}, // whatever Clock: {}, // whatever
// Tone, // Tone,
}, },

View File

@ -1,17 +0,0 @@
import { queryCode } from '../runtime.mjs';
import { describe, it } from 'vitest';
import data from './dbdump.json';
describe('renders shared tunes', async () => {
data.forEach(({ id, code, hash }) => {
const url = `https://strudel.cc/?${hash}`;
it(`shared tune ${id} ${url}`, async ({ expect }) => {
if (code.includes('import(')) {
console.log('skip', url);
return;
}
const haps = await queryCode(code, 1);
expect(haps).toMatchSnapshot();
});
});
});

10
tools/dbpatch/README.md Normal file
View File

@ -0,0 +1,10 @@
# dbpatch
this is a little script to update all patterns in the db. Go to supabase and export as csv as `code_rows.csv` to this folder.
Then run
```sh
node dbpatch.mjs > code_rows_patched.csv
```
It will output a csv file with the changes implemented in dbpatch.mjs

31
tools/dbpatch/dbpatch.mjs Normal file
View File

@ -0,0 +1,31 @@
import { parse } from 'csv-parse/sync';
import { readFileSync } from 'fs';
import { stringify } from 'csv-stringify/sync';
const hasCpsCall = (code) =>
['setcps', 'setCps', 'setCpm', 'setcpm'].reduce((acc, m) => acc || code.includes(`${m}`), false);
function withCps(code, cps) {
if (hasCpsCall(code)) {
return code;
}
const lines = code.split('\n');
const firstNonLineComment = lines.findIndex((l) => !l.startsWith('//'));
const cpsCall = `setcps(${cps})`;
lines.splice(firstNonLineComment, 0, cpsCall);
return lines.join('\n');
}
const dumpNew = readFileSync('./code_rows.csv', { encoding: 'utf-8' });
const records = parse(dumpNew, {
columns: true,
skip_empty_lines: true,
});
const edited = records.map((entry) => ({
...entry,
code: withCps(entry.code, 1),
}));
console.log(stringify(edited));

View File

@ -0,0 +1,5 @@
{
"dependencies": {
"csv": "^6.3.6"
}
}

View File

@ -33,7 +33,7 @@ While the Mini Notation is a powerful way to write rhythms concisely, it also ha
client:idle client:idle
tune={`stack( tune={`stack(
note("c2 eb2(3,8)").s('sawtooth').cutoff(800), note("c2 eb2(3,8)").s('sawtooth').cutoff(800),
s("bd,~ sd,hh*4") s("bd(5,8), hh*8")
)`} )`}
/> />

View File

@ -28,6 +28,10 @@ import { JsDoc } from '../../docs/JsDoc';
<JsDoc client:idle name="Pattern.chunkBack" h={0} /> <JsDoc client:idle name="Pattern.chunkBack" h={0} />
### fastChunk
<JsDoc client:idle name="Pattern.fastChunk" h={0} />
## arp ## arp
<JsDoc client:idle name="Pattern#arp" h={0} /> <JsDoc client:idle name="Pattern#arp" h={0} />

View File

@ -150,7 +150,7 @@ Pitch envelopes can breathe life into static sounds:
.s("gm_electric_guitar_jazz") .s("gm_electric_guitar_jazz")
.penv("<.5 0 7 -2>*2").vib("4:.1") .penv("<.5 0 7 -2>*2").vib("4:.1")
.phaser(2).delay(.25).room(.3) .phaser(2).delay(.25).room(.3)
.size(4).fast(.75)`} .size(4).fast(1.5)`}
/> />
You also create some lovely chiptune-style sounds: You also create some lovely chiptune-style sounds:
@ -163,7 +163,7 @@ You also create some lovely chiptune-style sounds:
.voicing().add(note("<0 1>/8")) .voicing().add(note("<0 1>/8"))
.dec(.1).room(.2) .dec(.1).room(.2)
.segment("<4 [2 8]>") .segment("<4 [2 8]>")
.penv("<0 <2 -2>>").patt(.02)`} .penv("<0 <2 -2>>").patt(.02).fast(2)`}
/> />
Let's break down all pitch envelope controls: Let's break down all pitch envelope controls:

View File

@ -36,7 +36,8 @@ osc(1, -0.9, 300)
.scale(2) .scale(2)
.out() .out()
note("[a,c,e,<a4 ab4 g4 gb4>,b4]/4").s("sawtooth").vib(2) note("[a,c,e,<a4 ab4 g4 gb4>,b4]/2")
.s("sawtooth").vib(2)
.lpf(600).lpa(2).lpenv(6) .lpf(600).lpa(2).lpenv(6)
`} `}
/> />
@ -90,7 +91,7 @@ src(s0).kaleid(H("<4 5 6>"))
.out() .out()
// //
stack( stack(
s("bd*2,[hh:0:<.5 1>]*4,~ rim").bank("RolandTR909").speed(.9), s("bd*4,[hh:0:<.5 1>]*8,~ rim").bank("RolandTR909").speed(.9),
note("[<g1!3 <bb1 <f1 d1>>>]*3").s("sawtooth") note("[<g1!3 <bb1 <f1 d1>>>]*3").s("sawtooth")
.room(.75).sometimes(add(note(12))).clip(.3) .room(.75).sometimes(add(note(12))).clip(.3)
.lpa(.05).lpenv(-4).lpf(2000).lpq(8).ftype('24db') .lpa(.05).lpenv(-4).lpf(2000).lpq(8).ftype('24db')

View File

@ -22,27 +22,25 @@ Before diving deeper into the details, here is a flavour of how the Mini-Notatio
<MiniRepl <MiniRepl
client:idle client:idle
tune={`note(\`[ tune={`note(\`<
[ [e5 [b4 c5] d5 [c5 b4]]
[e5 [b4 c5] d5 [c5 b4]] [a4 [a4 c5] e5 [d5 c5]]
[a4 [a4 c5] e5 [d5 c5]] [b4 [~ c5] d5 e5]
[b4 [~ c5] d5 e5] [c5 a4 a4 ~]
[c5 a4 a4 ~] [[~ d5] [~ f5] a5 [g5 f5]]
[[~ d5] [~ f5] a5 [g5 f5]] [e5 [~ c5] e5 [d5 c5]]
[e5 [~ c5] e5 [d5 c5]] [b4 [b4 c5] d5 e5]
[b4 [b4 c5] d5 e5] [c5 a4 a4 ~]
[c5 a4 a4 ~] ,
],[ [[e2 e3]*4]
[[e2 e3]*4] [[a2 a3]*4]
[[a2 a3]*4] [[g#2 g#3]*2 [e2 e3]*2]
[[g#2 g#3]*2 [e2 e3]*2] [a2 a3 a2 a3 a2 a3 b1 c2]
[a2 a3 a2 a3 a2 a3 b1 c2] [[d2 d3]*4]
[[d2 d3]*4] [[c2 c3]*4]
[[c2 c3]*4] [[b1 b2]*2 [e2 e3]*2]
[[b1 b2]*2 [e2 e3]*2] [[a1 a2]*4]
[[a1 a2]*4] >\`)`}
]
]/16\`)`}
/> />
## Mini Notation Format ## Mini Notation Format
@ -74,9 +72,21 @@ Taking the two examples above, we have four and eight events respectively, and s
This is perhaps counter-intuitive if you are used to adding notes in a sequencer or piano roll and the overall length increasing. This is perhaps counter-intuitive if you are used to adding notes in a sequencer or piano roll and the overall length increasing.
But, it will begin to make sense as we go through more elements of mini-notation. But, it will begin to make sense as we go through more elements of mini-notation.
## Multiplication
A sequence can be sped up by multiplying it by a number using the asterisk symbol (`*`):
<MiniRepl client:idle tune={`note("[e5 b4 d5 c5]*2")`} punchcard />
The multiplication by two here means that the sequence will play twice per cycle.
Multiplications can also be decimal (`*2.75`):
<MiniRepl client:idle tune={`note("[e5 b4 d5 c5]*2.75")`} punchcard />
## Division ## Division
We can slow the sequence down by enclosing it in brackets and dividing it by a number (`/2`): Contrary to multiplication, division can slow the sequence down by enclosing it in brackets and dividing it by a number (`/2`):
<MiniRepl client:idle tune={`note("[e5 b4 d5 c5]/2")`} punchcard /> <MiniRepl client:idle tune={`note("[e5 b4 d5 c5]/2")`} punchcard />
@ -102,18 +112,11 @@ The advantage of the angle brackets, is that we can add more events without need
<MiniRepl client:idle tune={`note("<e5 b4 d5 c5 e5 b4>")`} punchcard /> <MiniRepl client:idle tune={`note("<e5 b4 d5 c5 e5 b4>")`} punchcard />
This is more similar to traditional music sequencers and piano rolls, where adding a note increases the perceived overall duration. This is more similar to traditional music sequencers and piano rolls, where adding a note increases the perceived overall duration.
We can also play a certain number of notes per cycle by using angle brackets with multiplication:
## Multiplication <MiniRepl client:idle tune={`note("<e5 b4 d5 c5 a4 c5>*8")`} punchcard />
Contrary to division, a sequence can be sped up by multiplying it by a number using the asterisk symbol (`*`): Now we are playing 8 notes per cycle!
<MiniRepl client:idle tune={`note("[e5 b4 d5 c5]*2")`} punchcard />
The multiplication by two here means that the sequence will play twice per cycle.
As with divisions, multiplications can be decimal (`*2.75`):
<MiniRepl client:idle tune={`note("[e5 b4 d5 c5]*2.75")`} punchcard />
## Subdividing time with bracket nesting ## Subdividing time with bracket nesting
@ -149,13 +152,13 @@ The following are the same:
But to play multiple chords in a sequence, we have to wrap them in brackets: But to play multiple chords in a sequence, we have to wrap them in brackets:
<MiniRepl client:idle tune={`note("<[g3,b3,e4] [a3,c3,e4] [b3,d3,f#4] [b3,e4,g4]>")`} punchcard /> <MiniRepl client:idle tune={`note("<[g3,b3,e4] [a3,c3,e4] [b3,d3,f#4] [b3,e4,g4]>*2")`} punchcard />
## Elongation ## Elongation
With the "@" symbol, we can specify temporal "weight" of a sequence child: With the "@" symbol, we can specify temporal "weight" of a sequence child:
<MiniRepl client:idle tune={`note("<[g3,b3,e4]@2 [a3,c3,e4] [b3,d3,f#4]>")`} punchcard /> <MiniRepl client:idle tune={`note("<[g3,b3,e4]@2 [a3,c3,e4] [b3,d3,f#4]>*2")`} punchcard />
Here, the first chord has a weight of 2, making it twice the length of the other chords. The default weight is 1. Here, the first chord has a weight of 2, making it twice the length of the other chords. The default weight is 1.
@ -163,19 +166,19 @@ Here, the first chord has a weight of 2, making it twice the length of the other
Using "!" we can repeat without speeding up: Using "!" we can repeat without speeding up:
<MiniRepl client:idle tune={`note("<[g3,b3,e4]!2 [a3,c3,e4] [b3,d3,f#4]>")`} punchcard /> <MiniRepl client:idle tune={`note("<[g3,b3,e4]!2 [a3,c3,e4] [b3,d3,f#4]>*2")`} punchcard />
## Mini-notation review ## Mini-notation review
To recap what we've learned so far, compare the following patterns: To recap what we've learned so far, compare the following patterns:
<MiniRepl client:idle tune={`note("<g3 b3 e4 [a3,c3,e4] [b3,d3,f#4]>")`} /> <MiniRepl client:idle tune={`note("<g3 b3 e4 [a3,c3,e4] [b3,d3,f#4]>*2")`} />
<MiniRepl client:idle tune={`note("<[g3,b3,e4] [a3,c3,e4] [b3,d3,f#4]>")`} /> <MiniRepl client:idle tune={`note("<[g3,b3,e4] [a3,c3,e4] [b3,d3,f#4]>*2")`} />
<MiniRepl client:idle tune={`note("<[g3,b3,e4]/2 [a3,c3,e4] [b3,d3,f#4]>")`} /> <MiniRepl client:idle tune={`note("<[g3,b3,e4]/2 [a3,c3,e4] [b3,d3,f#4]>*2")`} />
<MiniRepl client:idle tune={`note("<[g3,b3,e4]*2 [a3,c3,e4] [b3,d3,f#4]>")`} /> <MiniRepl client:idle tune={`note("<[g3,b3,e4]*2 [a3,c3,e4] [b3,d3,f#4]>*2")`} />
<MiniRepl client:idle tune={`note("<[g3,b3,e4] _ [a3,c3,e4] [b3,d3,f#4]>")`} /> <MiniRepl client:idle tune={`note("<[g3,b3,e4] _ [a3,c3,e4] [b3,d3,f#4]>*2")`} />
<MiniRepl client:idle tune={`note("<[g3,b3,e4]@2 [a3,c3,e4] [b3,d3,f#4]>")`} /> <MiniRepl client:idle tune={`note("<[g3,b3,e4]@2 [a3,c3,e4] [b3,d3,f#4]>*2")`} />
<MiniRepl client:idle tune={`note("<[g3,b3,e4]!2 [a3,c3,e4] [b3,d3,f#4]>")`} /> <MiniRepl client:idle tune={`note("<[g3,b3,e4]!2 [a3,c3,e4] [b3,d3,f#4]>*2")`} />
## Euclidian rhythms ## Euclidian rhythms
@ -196,7 +199,7 @@ But using the Euclidian rhythm notation, we only need to express "3 beats over 8
This makes it easy to write patterns with interesting rhythmic structures and variations that still sound familiar: This makes it easy to write patterns with interesting rhythmic structures and variations that still sound familiar:
<MiniRepl client:idle tune={`note("e5(2,8) b4(3,8) d5(2,8) c5(3,8)").slow(4)`} punchcard canvasHeight={50} /> <MiniRepl client:idle tune={`note("e5(2,8) b4(3,8) d5(2,8) c5(3,8)").slow(2)`} punchcard canvasHeight={50} />
Note that since the example above does not use the third `offset` parameter, it can be written simply as `"(3,8)"`. Note that since the example above does not use the third `offset` parameter, it can be written simply as `"(3,8)"`.

View File

@ -18,7 +18,7 @@ Strudel allows loading samples in the form of audio files of various formats (wa
By default, strudel comes with a built-in "sample map", providing a solid base to play with. By default, strudel comes with a built-in "sample map", providing a solid base to play with.
<MiniRepl client:idle tune={`s("bd sd,hh*8, misc/2")`} /> <MiniRepl client:idle tune={`s("bd sd [~ bd] sd,hh*16, misc")`} />
Here, we are using the `s` function to play back different default samples (`bd`, `sd`, `hh` and `misc`) to get a drum beat. Here, we are using the `s` function to play back different default samples (`bd`, `sd`, `hh` and `misc`) to get a drum beat.
@ -59,15 +59,15 @@ If we open the `sounds` tab and then `drum machines`, we can see that the drum s
We _could_ use them like this: We _could_ use them like this:
<MiniRepl client:idle tune={`s("RolandTR808_bd RolandTR808_sd,RolandTR808_hh*8")`} /> <MiniRepl client:idle tune={`s("RolandTR808_bd RolandTR808_sd,RolandTR808_hh*16")`} />
... but thats obviously a bit much to write. Using the `bank` function, we can shorten this to: ... but thats obviously a bit much to write. Using the `bank` function, we can shorten this to:
<MiniRepl client:idle tune={`s("bd sd,hh*8").bank("RolandTR808")`} /> <MiniRepl client:idle tune={`s("bd sd bd sd,hh*16").bank("RolandTR808")`} />
You could even pattern the bank to switch between different drum machines: You could even pattern the bank to switch between different drum machines:
<MiniRepl client:idle tune={`s("bd sd,hh*8").bank("<RolandTR808 RolandTR909>")`} /> <MiniRepl client:idle tune={`s("bd sd bd sd,hh*16").bank("RolandTR808 RolandTR909")`} />
Behind the scenes, `bank` will just prepend the drum machine name to the sample name with `_` to get the full name. Behind the scenes, `bank` will just prepend the drum machine name to the sample name with `_` to get the full name.
This of course only works because the name after `_` (`bd`, `sd` etc..) is standardized. This of course only works because the name after `_` (`bd`, `sd` etc..) is standardized.
@ -79,17 +79,21 @@ If we open the `sounds` tab again, followed by tab `drum machines`, there is als
For example `RolandTR909_hh(4)` means there are 4 samples of a TR909 hihat available. For example `RolandTR909_hh(4)` means there are 4 samples of a TR909 hihat available.
By default, `s` will play the first sample, but we can select the other ones using `n`, starting from 0: By default, `s` will play the first sample, but we can select the other ones using `n`, starting from 0:
<MiniRepl client:idle tune={`s("hh*4").bank("RolandTR909").n("<0 1 2 3>")`} /> <MiniRepl client:idle tune={`s("hh*8").bank("RolandTR909").n("0 1 2 3")`} />
Numbers that are too high will just wrap around to the beginning Numbers that are too high will just wrap around to the beginning
<MiniRepl client:idle tune={`s("hh*4").bank("RolandTR909").n("<0 1 2 3 4 5 6 7>")`} /> <MiniRepl client:idle tune={`s("hh*8").bank("RolandTR909").n("0 1 2 3 4 5 6 7")`} />
Here, 0-3 will play the same sounds as 4-7, because `RolandTR909_hh` only has 4 sounds. Here, 0-3 will play the same sounds as 4-7, because `RolandTR909_hh` only has 4 sounds.
Selecting sounds also works inside the mini notation, using "`:`" like this: Selecting sounds also works inside the mini notation, using "`:`" like this:
<MiniRepl client:idle tune={`s("bd:1 bd:2,hh:0 hh:1 hh:2 hh:3").bank("RolandTR909")`} /> <MiniRepl
client:idle
tune={`s("bd*4,hh:0 hh:1 hh:2 hh:3 hh:4 hh:5 hh:6 hh:7")
.bank("RolandTR909")`}
/>
# Loading Custom Samples # Loading Custom Samples
@ -103,7 +107,7 @@ In this example we create a map using sounds from the default sample map:
sd: 'sd/rytm-01-classic.wav', sd: 'sd/rytm-01-classic.wav',
hh: 'hh27/000_hh27closedhh.wav', hh: 'hh27/000_hh27closedhh.wav',
}, 'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/'); }, 'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/');
s("bd sd,hh*8")`} s("bd sd bd sd,hh*16")`}
/> />
When you load your own samples, you can choose the names that you will then refer to in your pattern string inside the `s` function. When you load your own samples, you can choose the names that you will then refer to in your pattern string inside the `s` function.
@ -116,7 +120,7 @@ Compare with this example which uses the same samples, but with different names.
snaredrum: 'sd/rytm-01-classic.wav', snaredrum: 'sd/rytm-01-classic.wav',
hihat: 'hh27/000_hh27closedhh.wav', hihat: 'hh27/000_hh27closedhh.wav',
}, 'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/'); }, 'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/');
s("bassdrum snaredrum, hihat*8")`} s("bassdrum snaredrum bassdrum snaredrum, hihat*16")`}
/> />
Here we have changed the "map" to include longer sample names. Here we have changed the "map" to include longer sample names.
@ -140,7 +144,7 @@ Because GitHub is a popular place for uploading open source samples, it has its
sd: 'sd/rytm-01-classic.wav', sd: 'sd/rytm-01-classic.wav',
hh: 'hh27/000_hh27closedhh.wav', hh: 'hh27/000_hh27closedhh.wav',
}, 'github:tidalcycles/Dirt-Samples/master/'); }, 'github:tidalcycles/Dirt-Samples/master/');
s("bd sd,hh*8")`} s("bd sd bd sd,hh*16")`}
/> />
The format is `github:user/repo/branch/`. The format is `github:user/repo/branch/`.
@ -157,7 +161,7 @@ We can see there are some guitar samples inside the `/samples` folder, so let's
g3: 'samples/guitar/guitar_3.wav', g3: 'samples/guitar/guitar_3.wav',
g4: 'samples/guitar/guitar_4.wav' g4: 'samples/guitar/guitar_4.wav'
}, 'github:jarmitage/jarmitage.github.io/master/'); }, 'github:jarmitage/jarmitage.github.io/master/');
s("[g0 g1 g2 g3 g4]/5")`} s("<g0 g1 g2 g3 g4>/2")`}
/> />
## Multiple Samples per Sound ## Multiple Samples per Sound
@ -171,7 +175,7 @@ It is also possible, to declare multiple files for one sound, using the array no
sd: ['sd/rytm-01-classic.wav','sd/rytm-00-hard.wav'], sd: ['sd/rytm-01-classic.wav','sd/rytm-00-hard.wav'],
hh: ['hh27/000_hh27closedhh.wav','hh/000_hh3closedhh.wav'], hh: ['hh27/000_hh27closedhh.wav','hh/000_hh3closedhh.wav'],
}, 'github:tidalcycles/Dirt-Samples/master/'); }, 'github:tidalcycles/Dirt-Samples/master/');
s("<bd:0 bd:1>,~ <sd:0 sd:1>,[hh:0 hh:1]*2")`} s("bd:0 bd:1,~ <sd:0 sd:1> ~ sd:0,[hh:0 hh:1]*4")`}
/> />
The `:0` `:1` etc. are the indices of the array. The `:0` `:1` etc. are the indices of the array.
@ -184,7 +188,7 @@ The sample number can also be set using `n`:
sd: ['sd/rytm-01-classic.wav','sd/rytm-00-hard.wav'], sd: ['sd/rytm-01-classic.wav','sd/rytm-00-hard.wav'],
hh: ['hh27/000_hh27closedhh.wav','hh/000_hh3closedhh.wav'], hh: ['hh27/000_hh27closedhh.wav','hh/000_hh3closedhh.wav'],
}, 'github:tidalcycles/Dirt-Samples/master/'); }, 'github:tidalcycles/Dirt-Samples/master/');
s("bd,~ sd,hh*4").n("<0 1>")`} s("bd bd,~ sd ~ sd,hh*8").n("<0 1>")`}
/> />
In that case, we might load our guitar sample map a different way: In that case, we might load our guitar sample map a different way:
@ -200,7 +204,7 @@ In that case, we might load our guitar sample map a different way:
'samples/guitar/guitar_4.wav' 'samples/guitar/guitar_4.wav'
] ]
}, 'github:jarmitage/jarmitage.github.io/master/'); }, 'github:jarmitage/jarmitage.github.io/master/');
s("[guitar:0 guitar:1 guitar:2 guitar:3 guitar:4]/5")`} s("<guitar:0 guitar:1 guitar:2 guitar:3 guitar:4>*2")`}
/> />
And as above, we can choose the sample number using `n` for even more flexibility: And as above, we can choose the sample number using `n` for even more flexibility:
@ -216,7 +220,7 @@ And as above, we can choose the sample number using `n` for even more flexibilit
'samples/guitar/guitar_4.wav' 'samples/guitar/guitar_4.wav'
] ]
}, 'github:jarmitage/jarmitage.github.io/master/'); }, 'github:jarmitage/jarmitage.github.io/master/');
n("<0 1 2 3 4>").s("guitar")`} n("<0 1 2 3 4>*2").s("guitar")`}
/> />
## Pitched Sounds ## Pitched Sounds
@ -271,7 +275,7 @@ We can also declare different samples for different regions of the keyboard:
}}, 'github:tidalcycles/Dirt-Samples/master/'); }}, 'github:tidalcycles/Dirt-Samples/master/');
note("g2!2 <bb2 c3>!2, <c4@3 [<eb4 bb3> g4 f4]>") note("g2!2 <bb2 c3>!2, <c4@3 [<eb4 bb3> g4 f4]>")
.s('moog').clip(1) .s('moog').clip(1)
.gain(.5)`} .gain(.5).cpm(60)`}
/> />
The sampler will always pick the closest matching sample for the current note! The sampler will always pick the closest matching sample for the current note!
@ -285,9 +289,9 @@ With it, you can enter any sample name(s) to query from [freesound.org](https://
client:idle client:idle
tune={`await samples('shabda:bass:4,hihat:4,rimshot:2') tune={`await samples('shabda:bass:4,hihat:4,rimshot:2')
stack( stack(
n("0 1 2 3").s('bass').slow(2), n("0 1 2 3 0 1 2 3").s('bass'),
n("0 1*2 2 3*2").s('hihat'), n("0 1*2 2 3*2").s('hihat'),
n("~ 0 ~ 1").s('rimshot') n("~ 0 ~ 1 ~ 0 0 1").s('rimshot')
).clip(1)`} ).clip(1)`}
/> />
@ -299,8 +303,8 @@ Note that the language code and the gender parameters are optional and default t
tune={`await samples('shabda/speech:the_drum,forever') tune={`await samples('shabda/speech:the_drum,forever')
await samples('shabda/speech/fr-FR/m:magnifique') await samples('shabda/speech/fr-FR/m:magnifique')
stack( stack(
s("the_drum").chop(16).speed(rand.range(0.85,1.1)), s("the_drum*2").chop(16).speed(rand.range(0.85,1.1)),
s("forever magnifique").slow(8).late(0.25) s("forever magnifique").slow(4).late(0.125)
)`} )`}
/> />

View File

@ -16,7 +16,7 @@ The basic waveforms are `sine`, `sawtooth`, `square` and `triangle`, which can b
<MiniRepl <MiniRepl
client:idle client:idle
tune={`note("c2 <eb2 <g2 g1>>") tune={`note("c2 <eb2 <g2 g1>>".fast(2))
.sound("<sawtooth square triangle sine>") .sound("<sawtooth square triangle sine>")
.scope()`} .scope()`}
/> />
@ -28,7 +28,7 @@ If you don't set a `sound` but a `note` the default value for `sound` is `triang
You can also use noise as a source by setting the waveform to: `white`, `pink` or `brown`. These are different You can also use noise as a source by setting the waveform to: `white`, `pink` or `brown`. These are different
flavours of noise, here written from hard to soft. flavours of noise, here written from hard to soft.
<MiniRepl client:idle tune={`sound("<white pink brown>/2").scope()`} /> <MiniRepl client:idle tune={`sound("<white pink brown>").scope()`} />
Here's a more musical example of how to use noise for hihats: Here's a more musical example of how to use noise for hihats:
@ -44,7 +44,7 @@ Some amount of pink noise can also be added to any oscillator by using the `nois
You can also use the `crackle` type to play some subtle noise crackles. You can control noise amount by using the `density` parameter: You can also use the `crackle` type to play some subtle noise crackles. You can control noise amount by using the `density` parameter:
<MiniRepl client:idle tune={`s("crackle*4").density("<0.01 0.04 0.2 0.5>".slow(4)).scope()`} /> <MiniRepl client:idle tune={`s("crackle*4").density("<0.01 0.04 0.2 0.5>".slow(2)).scope()`} />
### Additive Synthesis ### Additive Synthesis
@ -52,7 +52,7 @@ To tame the harsh sound of the basic waveforms, we can set the `n` control to li
<MiniRepl <MiniRepl
client:idle client:idle
tune={`note("c2 <eb2 <g2 g1>>") tune={`note("c2 <eb2 <g2 g1>>".fast(2))
.sound("sawtooth") .sound("sawtooth")
.n("<32 16 8 4>") .n("<32 16 8 4>")
.scope()`} .scope()`}
@ -63,7 +63,7 @@ You can also set `n` directly in mini notation with `sound`:
<MiniRepl <MiniRepl
client:idle client:idle
tune={`note("c2 <eb2 <g2 g1>>") tune={`note("c2 <eb2 <g2 g1>>".fast(2))
.sound("sawtooth:<32 16 8 4>") .sound("sawtooth:<32 16 8 4>")
.scope()`} .scope()`}
/> />
@ -125,7 +125,7 @@ note("<[g3,b3,e4]!2 [a3,c3,e4] [b3,d3,f#4]>")
.n("<1 2 3 4 5 6 7 8 9 10>/2").room(0.5).size(0.9) .n("<1 2 3 4 5 6 7 8 9 10>/2").room(0.5).size(0.9)
.s('wt_flute').velocity(0.25).often(n => n.ply(2)) .s('wt_flute').velocity(0.25).often(n => n.ply(2))
.release(0.125).decay("<0.1 0.25 0.3 0.4>").sustain(0) .release(0.125).decay("<0.1 0.25 0.3 0.4>").sustain(0)
.cutoff(2000).scope({}).cutoff("<1000 2000 4000>").fast(2)`} .cutoff(2000).scope({}).cutoff("<1000 2000 4000>").fast(4)`}
/> />
## ZZFX ## ZZFX
@ -137,8 +137,8 @@ It has 20 parameters in total, here is a snippet that uses all:
<MiniRepl <MiniRepl
client:idle client:idle
tune={`note("<c2 eb2 f2 g2>") // also supports freq tune={`note("c2 eb2 f2 g2") // also supports freq
.s("<z_sawtooth z_tan z_noise z_sine z_square>") .s("{z_sawtooth z_tan z_noise z_sine z_square}%4")
.zrand(0) // randomization .zrand(0) // randomization
// zzfx envelope // zzfx envelope
.attack(0.001) .attack(0.001)

View File

@ -14,6 +14,19 @@ These functions use [tonaljs](https://github.com/tonaljs/tonal) to provide helpe
<JsDoc client:idle name="voicing" h={0} /> <JsDoc client:idle name="voicing" h={0} />
Here's an example of how you can play chords and a bassline:
<MiniRepl
client:idle
tune={`chord("<C^7 A7b13 Dm7 G7>*2")
.dict('ireal').layer(
x=>x.struct("[~ x]*2").voicing()
,
x=>n("0*4").set(x).mode("root:g2").voicing()
.s('sawtooth').cutoff("800:4:2")
)`}
/>
### scale(name) ### scale(name)
<JsDoc client:idle name="scale" h={0} /> <JsDoc client:idle name="scale" h={0} />
@ -22,13 +35,13 @@ These functions use [tonaljs](https://github.com/tonaljs/tonal) to provide helpe
Transposes all notes to the given number of semitones: Transposes all notes to the given number of semitones:
<MiniRepl client:only="react" tune={`"c2 c3".fast(2).transpose("<0 -2 5 3>".slow(2)).note()`} /> <MiniRepl client:only="react" tune={`"[c2 c3]*4".transpose("<0 -2 5 3>").note()`} />
This method gets really exciting when we use it with a pattern as above. 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: Instead of numbers, scientific interval notation can be used as well:
<MiniRepl client:only="react" tune={`"c2 c3".fast(2).transpose("<1P -2M 4P 3m>".slow(2)).note()`} /> <MiniRepl client:only="react" tune={`"[c2 c3]*4".transpose("<1P -2M 4P 3m>").note()`} />
### scaleTranspose(steps) ### scaleTranspose(steps)
@ -36,9 +49,9 @@ Transposes notes inside the scale by the number of steps:
<MiniRepl <MiniRepl
client:idle client:idle
tune={`"-8 [2,4,6]" tune={`"[-8 [2,4,6]]*2"
.scale('C4 bebop major') .scale('C4 bebop major')
.scaleTranspose("<0 -1 -2 -3 -4 -5 -6 -4>") .scaleTranspose("<0 -1 -2 -3 -4 -5 -6 -4>*2")
.note()`} .note()`}
/> />
@ -46,22 +59,28 @@ Transposes notes inside the scale by the number of steps:
Turns chord symbols into voicings, using the smoothest voice leading possible: Turns chord symbols into voicings, using the smoothest voice leading possible:
<MiniRepl client:only="react" tune={`stack("<C^7 A7 Dm7 G7>".voicings('lefthand'), "<C3 A2 D3 G2>").note()`} /> <MiniRepl
client:only="react"
tune={`stack(
"<C^7 A7 Dm7 G7>".voicings('lefthand'),
"<C3 A2 D3 G2>"
).note()`}
/>
Note: This function might be removed, as `voicing` (without s) is a newer implementation.
### rootNotes(octave = 2) ### rootNotes(octave = 2)
Turns chord symbols into root notes of chords in given octave. Turns chord symbols into root notes of chords in given octave.
<MiniRepl client:only="react" tune={`"<C^7 A7b13 Dm7 G7>".rootNotes(3).note()`} /> <MiniRepl client:only="react" tune={`"<C^7 A7b13 Dm7 G7>*2".rootNotes(3).note()`} />
Together with layer, struct and voicings, this can be used to create a basic backing track: Together with layer, struct and voicings, this can be used to create a basic backing track:
<MiniRepl <MiniRepl
client:idle client:idle
tune={`"<C^7 A7b13 Dm7 G7>".layer( tune={`"<C^7 A7b13 Dm7 G7>*2".layer(
x => x.voicings('lefthand').struct("~ x").note(), x => x.voicings('lefthand').struct("[~ x]*2").note(),
x => x.rootNotes(2).note().s('sawtooth').cutoff(800) x => x.rootNotes(2).note().s('sawtooth').cutoff(800)
)`} )`}
/> />
So far, we've stayed within the browser. [MIDI and OSC](/learn/input-output/) are ways to break out of it.

View File

@ -61,7 +61,7 @@ A sample can be looped and chopped like this:
<MiniRepl <MiniRepl
client:visible client:visible
tune={`await samples('github:yaxu/clean-breaks/main') tune={`await samples('github:yaxu/clean-breaks/main')
s("amen/8").fit().chop(16)`} s("amen/4").fit().chop(32)`}
punchcard punchcard
/> />
@ -72,9 +72,9 @@ Let's add randmized doubling + reversing:
<MiniRepl <MiniRepl
client:visible client:visible
tune={`await samples('github:yaxu/clean-breaks/main') tune={`await samples('github:yaxu/clean-breaks/main')
s("amen/8").fit().chop(16).cut(1) s("amen/4").fit().chop(16).cut(1)
.sometimesBy(.5, ply(2)) .sometimesBy(.5, ply("2"))
.sometimesBy(.25, mul(speed(-1)))`} .sometimesBy(.25, mul(speed("-1")))`}
punchcard punchcard
/> />
@ -83,9 +83,9 @@ If we want to specify the order of samples, we can replace `chop` with `slice`:
<MiniRepl <MiniRepl
client:visible client:visible
tune={`await samples('github:yaxu/clean-breaks/main') tune={`await samples('github:yaxu/clean-breaks/main')
s("amen/8").fit() s("amen/4").fit()
.slice(8, "<0 1 2 3 4*2 5 6 [6 7]>") .slice(8, "<0 1 2 3 4*2 5 6 [6 7]>*2")
.cut(1).rarely(ply(2))`} .cut(1).rarely(ply("2"))`}
punchcard punchcard
/> />
@ -95,8 +95,8 @@ If we use `splice` instead of `slice`, the speed adjusts to the duration of the
client:visible client:visible
tune={`await samples('github:yaxu/clean-breaks/main') tune={`await samples('github:yaxu/clean-breaks/main')
s("amen") s("amen")
.splice(8, "<0 1 2 3 4*2 5 6 [6 7]>") .splice(8, "<0 1 2 3 4*2 5 6 [6 7]>*2")
.cut(1).rarely(ply(2))`} .cut(1).rarely(ply("2"))`}
punchcard punchcard
/> />
@ -104,26 +104,38 @@ Note that we don't need `fit`, because `splice` will do that by itself.
## Filter Envelopes ## Filter Envelopes
A minimal filter envelope looks like this: Using `lpenv`, we can make the filter move:
<MiniRepl <MiniRepl
client:visible client:visible
tune={`note("g1 bb1 <c2 eb2> d2") tune={`note("g1 bb1 <c2 eb2> d2")
.s("sawtooth") .s("sawtooth")
.lpf(400).lpa(.2).lpenv(4) .lpf(400).lpenv(4)
.scope()`} .scope()`}
/> />
We can flip the envelope by setting `lpenv` negative + add some resonance `lpq`: The type of envelope depends on the methods you're setting. Let's set `lpa`:
<MiniRepl <MiniRepl
client:visible client:visible
tune={`note("g1 bb1 <c2 eb2> d2") tune={`note("g1 bb1 <c2 eb2> d2")
.s("sawtooth").lpq(8) .s("sawtooth").lpq(8)
.lpf(400).lpa(.2).lpenv(-4) .lpf(400).lpa(.2).lpenv(4)
.scope()`} .scope()`}
/> />
Now the filter is attacking, rather than decaying as before (decay is the default). We can also do both
<MiniRepl
client:visible
tune={`note("g1 bb1 <c2 eb2> d2")
.s("sawtooth").lpq(8)
.lpf(400).lpa(.1).lpd(.1).lpenv(4)
.scope()`}
/>
You can play around with `lpa` | `lpd` | `lps` | `lpd` to see what the filter envelope will do.
## Layering Sounds ## Layering Sounds
We can layer sounds by separating them with ",": We can layer sounds by separating them with ",":
@ -183,7 +195,7 @@ A polyrhythm is when 2 different tempos happen at the same time.
This is a polymeter: This is a polymeter:
<MiniRepl client:visible tune={`s("<bd rim>,<hh hh oh>").fast(2)`} punchcard /> <MiniRepl client:visible tune={`s("<bd rim, hh hh oh>*4")`} punchcard />
A polymeter is when 2 different bar lengths play at the same tempo. A polymeter is when 2 different bar lengths play at the same tempo.
@ -201,8 +213,8 @@ Using `run` with `n`, we can rush through a sample bank:
<MiniRepl <MiniRepl
client:visible client:visible
tune={`await samples('github:Bubobubobubobubo/Dough-Fox/main') tune={`await samples('bubo:fox')
n(run(8)).s("ftabla")`} n(run(8)).s("ftabla")`}
punchcard punchcard
/> />
@ -212,17 +224,17 @@ In this case, I hear the beginning at the third sample, which can be accounted f
<MiniRepl <MiniRepl
client:visible client:visible
tune={`await samples('github:Bubobubobubobubo/Dough-Fox/main') tune={`await samples('bubo:fox')
n(run(8)).s("ftabla").early(2/8)`} n(run(8)).s("ftabla").early(2/8)`}
/> />
Let's add some randomness: Let's add some randomness:
<MiniRepl <MiniRepl
client:visible client:visible
tune={`await samples('github:Bubobubobubobubo/Dough-Fox/main') tune={`await samples('bubo:fox')
n(run(8)).s("ftabla").early(2/8) n(run(8)).s("ftabla").early(2/8)
.sometimes(mul(speed(1.5)))`} .sometimes(mul(speed("1.5")))`}
/> />
## Tape Warble ## Tape Warble
@ -231,7 +243,7 @@ We can emulate a pitch warbling effect like this:
<MiniRepl <MiniRepl
client:visible client:visible
tune={`note("c4 bb f eb") tune={`note("<c4 bb f eb>*8")
.add(note(perlin.range(0,.5))) // <------ warble .add(note(perlin.range(0,.5))) // <------ warble
.clip(2).s("gm_electric_guitar_clean")`} .clip(2).s("gm_electric_guitar_clean")`}
/> />
@ -243,7 +255,7 @@ There are a number of ways to change the sound duration. Using clip:
<MiniRepl <MiniRepl
client:visible client:visible
tune={`note("f ab bb c") tune={`note("f ab bb c")
.clip("<2 1 .5 .25>/2")`} .clip("<2 1 .5 .25>")`}
/> />
The value of clip is relative to the duration of each event. The value of clip is relative to the duration of each event.
@ -252,20 +264,18 @@ We can also create overlaps using release:
<MiniRepl <MiniRepl
client:visible client:visible
tune={`note("f ab bb c") tune={`note("f ab bb c")
.release("<2 1 .5 .002>/2")`} .release("<2 1 .5 .25>")`}
/> />
This will smoothly fade out each sound for the given number of seconds. This will smoothly fade out each sound for the given number of seconds.
We could also make the notes shorter with decay / sustain: We could also make the notes shorter by using a decay envelope:
<MiniRepl <MiniRepl
client:visible client:visible
tune={`note("f ab bb c") tune={`note("f ab bb c")
.decay("<.2 .1 .02>/2").sustain(0)`} .decay("<2 1 .5 .25>")`}
/> />
For now, there is a limitation where decay values that exceed the event duration may cause little cracks, so use higher numbers with caution..
When using samples, we also have `.end` to cut relative to the sample length: When using samples, we also have `.end` to cut relative to the sample length:
<MiniRepl client:visible tune={`s("oh*4").end("<1 .5 .25 .1>")`} /> <MiniRepl client:visible tune={`s("oh*4").end("<1 .5 .25 .1>")`} />
@ -274,9 +284,9 @@ Compare that to clip:
<MiniRepl client:visible tune={`s("oh*4").clip("<1 .5 .25 .1>")`} /> <MiniRepl client:visible tune={`s("oh*4").clip("<1 .5 .25 .1>")`} />
or decay / sustain or decay:
<MiniRepl client:visible tune={`s("oh*4").decay("<.2 .12 .06 .01>").sustain(0)`} /> <MiniRepl client:visible tune={`s("oh*4").decay("<1 .5 .25 .1>")`} />
## Wavetable Synthesis ## Wavetable Synthesis

View File

@ -15,20 +15,20 @@ Strudel's mother language, TidalCycles, even has it in its name.
## Cycles and BPM ## Cycles and BPM
In most music software, the unit BPM (beats per minute) is used to set the tempo. In most music software, the unit BPM (beats per minute) is used to set the tempo.
Strudel expresses tempo as CPS (cycles per second), with a default of 1CPS: Strudel expresses tempo as CPS (cycles per second), with a default of 0.5 CPS:
<MiniRepl client:visible tune={`s("bd")`} /> <MiniRepl client:visible tune={`s("bd")`} />
Here we can hear the 1CPS in action: The kick repeats once per second like a clock. Here we can hear the 0.5CPS in action: The kick repeats once every two seconds.
We could say 1CPS = 1BPS (beats per second) = 60BPM. Let's add another kick: Let's make it 4 kicks:
<MiniRepl client:visible tune={`s("bd bd")`} /> <MiniRepl client:visible tune={`s("bd bd bd bd")`} />
Now we have 2 kicks per second, but the whole pattern still plays at 1CPS. Now we have 4 kicks per cycle, but the whole pattern still plays at 0.5CPS.
In terms of BPM, most musicians would tell you this is playing at 120bpm. In terms of BPM, most musicians would tell you this is playing at 120bpm.
What about this one: What about this one:
<MiniRepl client:visible tune={`s("bd hh")`} /> <MiniRepl client:visible tune={`s("bd hh bd hh")`} />
Because the second sound is now a hihat, the tempo feels slower again. Because the second sound is now a hihat, the tempo feels slower again.
This brings us to an important realization: This brings us to an important realization:
@ -103,7 +103,7 @@ To get a time signature, just change the number of elements per bar. Here is a r
or with 5: or with 5:
<MiniRepl client:visible tune={`s("<bd hh hh bd hh hh bd rim bd hh>*5")`} /> <MiniRepl client:visible tune={`s("bd hh hh bd hh hh bd rim bd hh")`} />
We could also write multiple bars with different time signatures: We could also write multiple bars with different time signatures:

View File

@ -35,7 +35,7 @@ The upper limit decreases with age. What's your upper limit?
In Strudel, we can play frequencies directly with the `freq` control: In Strudel, we can play frequencies directly with the `freq` control:
<MiniRepl client:visible tune={`freq("200 [300,500] 400 [500,<600 670 712 670>]")`} /> <MiniRepl client:visible tune={`freq("<200 [300,500] 400 [500,<600 670 712 670>]>*8")`} />
## Frequency vs Pitch Perception ## Frequency vs Pitch Perception

View File

@ -18,7 +18,7 @@ We have sounds, we have notes, now let's look at effects!
<MiniRepl <MiniRepl
client:visible client:visible
tune={`note("<[c2 c3]*4 [bb1 bb2]*4 [f2 f3]*4 [eb2 eb3]*4>/2") tune={`note("<[c2 c3]*4 [bb1 bb2]*4 [f2 f3]*4 [eb2 eb3]*4>")
.sound("sawtooth").lpf(800)`} .sound("sawtooth").lpf(800)`}
/> />
@ -35,8 +35,8 @@ lpf = **l**ow **p**ass **f**ilter
<MiniRepl <MiniRepl
client:visible client:visible
tune={`note("<[c2 c3]*4 [bb1 bb2]*4 [f2 f3]*4 [eb2 eb3]*4>/2") tune={`note("<[c2 c3]*4 [bb1 bb2]*4 [f2 f3]*4 [eb2 eb3]*4>")
.sound("sawtooth").lpf("200 1000")`} .sound("sawtooth").lpf("200 1000 200 1000")`}
/> />
<Box> <Box>
@ -52,8 +52,8 @@ We will learn how to automate with waves later...
<MiniRepl <MiniRepl
client:visible client:visible
tune={`note("<[c3,g3,e4] [bb2,f3,d4] [a2,f3,c4] [bb2,g3,eb4]>/2") tune={`note("<[c3,g3,e4] [bb2,f3,d4] [a2,f3,c4] [bb2,g3,eb4]>")
.sound("sawtooth").vowel("<a e i o>/2")`} .sound("sawtooth").vowel("<a e i o>")`}
/> />
**gain** **gain**
@ -61,8 +61,8 @@ We will learn how to automate with waves later...
<MiniRepl <MiniRepl
client:visible client:visible
tune={`stack( tune={`stack(
sound("hh*8").gain("[.25 1]*2"), sound("hh*16").gain("[.25 1]*4"),
sound("bd*2,~ sd:1") sound("bd*4,[~ sd:1]*2")
) `} ) `}
punchcard punchcard
/> />
@ -84,13 +84,13 @@ Let's combine all of the above into a little tune:
client:visible client:visible
tune={`stack( tune={`stack(
stack( stack(
sound("hh*8").gain("[.25 1]*2"), sound("hh*8").gain("[.25 1]*4"),
sound("bd*2,~ sd:1") sound("bd*4,[~ sd:1]*2")
), ),
note("<[c2 c3]*4 [bb1 bb2]*4 [f2 f3]*4 [eb2 eb3]*4>/2") note("<[c2 c3]*4 [bb1 bb2]*4 [f2 f3]*4 [eb2 eb3]*4>")
.sound("sawtooth").lpf("200 1000"), .sound("sawtooth").lpf("200 1000 200 1000"),
note("<[c3,g3,e4] [bb2,f3,d4] [a2,f3,c4] [bb2,g3,eb4]>/2") note("<[c3,g3,e4] [bb2,f3,d4] [a2,f3,c4] [bb2,g3,eb4]>")
.sound("sawtooth").vowel("<a e i o>/2") .sound("sawtooth").vowel("<a e i o>")
) `} ) `}
/> />
@ -105,7 +105,7 @@ The 3 parts (drums, bassline, chords) are exactly as earlier, just stacked toget
<MiniRepl <MiniRepl
client:visible client:visible
tune={`note("<c3 bb2 f3 eb3>") tune={`note("c3 bb2 f3 eb3")
.sound("sawtooth").lpf(600) .sound("sawtooth").lpf(600)
.attack(.1) .attack(.1)
.decay(.1) .decay(.1)
@ -141,7 +141,7 @@ Can you guess what they do?
<MiniRepl <MiniRepl
client:visible client:visible
tune={`note("<c3 bb2 f3 eb3>") tune={`note("c3 bb2 f3 eb3")
.sound("sawtooth").lpf(600) .sound("sawtooth").lpf(600)
.adsr(".1:.1:.5:.2") .adsr(".1:.1:.5:.2")
`} `}
@ -152,7 +152,7 @@ Can you guess what they do?
<MiniRepl <MiniRepl
client:visible client:visible
tune={`stack( tune={`stack(
note("~ [<[d3,a3,f4]!2 [d3,bb3,g4]!2> ~]") note("[~ [<[d3,a3,f4]!2 [d3,bb3,g4]!2> ~]]*2")
.sound("gm_electric_guitar_muted"), .sound("gm_electric_guitar_muted"),
sound("<bd rim>").bank("RolandTR707") sound("<bd rim>").bank("RolandTR707")
).delay(".5")`} ).delay(".5")`}
@ -182,7 +182,7 @@ What happens if you use `.delay(".8:.06:.8")` ? Can you guess what the third num
<MiniRepl <MiniRepl
client:visible client:visible
tune={`n("<4 [3@3 4] [<2 0> ~@16] ~>/2") tune={`n("<4 [3@3 4] [<2 0> ~@16] ~>")
.scale("D4:minor").sound("gm_accordion:2") .scale("D4:minor").sound("gm_accordion:2")
.room(2)`} .room(2)`}
/> />
@ -200,10 +200,10 @@ Add a delay too!
<MiniRepl <MiniRepl
client:visible client:visible
tune={`stack( tune={`stack(
note("~ [<[d3,a3,f4]!2 [d3,bb3,g4]!2> ~]") note("[~ [<[d3,a3,f4]!2 [d3,bb3,g4]!2> ~]]*2")
.sound("gm_electric_guitar_muted").delay(.5), .sound("gm_electric_guitar_muted").delay(.5),
sound("<bd rim>").bank("RolandTR707").delay(.5), sound("<bd rim>").bank("RolandTR707").delay(.5),
n("<4 [3@3 4] [<2 0> ~@16] ~>/2") n("<4 [3@3 4] [<2 0> ~@16] ~>")
.scale("D4:minor").sound("gm_accordion:2") .scale("D4:minor").sound("gm_accordion:2")
.room(2).gain(.5) .room(2).gain(.5)
)`} )`}
@ -214,13 +214,13 @@ Let's add a bass to make this complete:
<MiniRepl <MiniRepl
client:visible client:visible
tune={`stack( tune={`stack(
note("~ [<[d3,a3,f4]!2 [d3,bb3,g4]!2> ~]") note("[~ [<[d3,a3,f4]!2 [d3,bb3,g4]!2> ~]]*2")
.sound("gm_electric_guitar_muted").delay(.5), .sound("gm_electric_guitar_muted").delay(.5),
sound("<bd rim>").bank("RolandTR707").delay(.5), sound("<bd rim>").bank("RolandTR707").delay(.5),
n("<4 [3@3 4] [<2 0> ~@16] ~>/2") n("<4 [3@3 4] [<2 0> ~@16] ~>")
.scale("D4:minor").sound("gm_accordion:2") .scale("D4:minor").sound("gm_accordion:2")
.room(2).gain(.4), .room(2).gain(.4),
n("<0 [~ 0] 4 [3 2] [0 ~] [0 ~] <0 2> ~>*2") n("[0 [~ 0] 4 [3 2] [0 ~] [0 ~] <0 2> ~]/2")
.scale("D2:minor") .scale("D2:minor")
.sound("sawtooth,triangle").lpf(800) .sound("sawtooth,triangle").lpf(800)
)`} )`}
@ -237,19 +237,18 @@ Try adding `.hush()` at the end of one of the patterns in the stack...
<MiniRepl <MiniRepl
client:visible client:visible
tune={`sound("numbers:1 numbers:2 numbers:3 numbers:4") tune={`sound("numbers:1 numbers:2 numbers:3 numbers:4")
.pan("0 0.3 .6 1") .pan("0 0.3 .6 1")`}
.slow(2)`}
/> />
**speed** **speed**
<MiniRepl client:visible tune={`sound("bd rim").speed("<1 2 -1 -2>").room(.2)`} /> <MiniRepl client:visible tune={`sound("bd rim [~ bd] rim").speed("<1 2 -1 -2>").room(.2)`} />
**fast and slow** **fast and slow**
We can use `fast` and `slow` to change the tempo of a pattern outside of Mini-Notation: We can use `fast` and `slow` to change the tempo of a pattern outside of Mini-Notation:
<MiniRepl client:visible tune={`sound("bd*2,~ rim").slow(2)`} /> <MiniRepl client:visible tune={`sound("bd*4,~ rim ~ cp").slow(2)`} />
<Box> <Box>
@ -261,13 +260,13 @@ What happens if you use a pattern like `.fast("<1 [2 4]>")`?
By the way, inside Mini-Notation, `fast` is `*` and `slow` is `/`. By the way, inside Mini-Notation, `fast` is `*` and `slow` is `/`.
<MiniRepl client:visible tune={`sound("[bd*2,~ rim]*<1 [2 4]>")`} /> <MiniRepl client:visible tune={`sound("[bd*4,~ rim ~ cp]*<1 [2 4]>")`} />
## automation with signals ## automation with signals
Instead of changing values stepwise, we can also control them with signals: Instead of changing values stepwise, we can also control them with signals:
<MiniRepl client:visible tune={`sound("hh*16").gain(sine)`} punchcard punchcardLabels={false} /> <MiniRepl client:visible tune={`sound("hh*32").gain(sine)`} punchcard punchcardLabels={false} />
<Box> <Box>
@ -283,7 +282,7 @@ The gain is visualized as transparency in the pianoroll.
By default, waves oscillate between 0 to 1. We can change that with `range`: By default, waves oscillate between 0 to 1. We can change that with `range`:
<MiniRepl client:visible tune={`sound("hh*8").lpf(saw.range(500, 2000))`} /> <MiniRepl client:visible tune={`sound("hh*16").lpf(saw.range(500, 2000))`} />
<Box> <Box>
@ -295,9 +294,9 @@ We can change the automation speed with slow / fast:
<MiniRepl <MiniRepl
client:visible client:visible
tune={`note("<[c2 c3]*4 [bb1 bb2]*4 [f2 f3]*4 [eb2 eb3]*4>/2") tune={`note("<[c2 c3]*4 [bb1 bb2]*4 [f2 f3]*4 [eb2 eb3]*4>")
.sound("sawtooth") .sound("sawtooth")
.lpf(sine.range(100, 2000).slow(8))`} .lpf(sine.range(100, 2000).slow(4))`}
/> />
<Box> <Box>
@ -308,15 +307,15 @@ The whole automation will now take 8 cycles to repeat.
## Recap ## Recap
| name | example | | name | example |
| ----- | --------------------------------------------------------------------------------------- | | ----- | ---------------------------------------------------------------------------------------- |
| lpf | <MiniRepl client:visible tune={`note("c2 c3").s("sawtooth").lpf("<400 2000>")`} /> | | lpf | <MiniRepl client:visible tune={`note("c2 c3 c2 c3").s("sawtooth").lpf("<400 2000>")`} /> |
| vowel | <MiniRepl client:visible tune={`note("c3 eb3 g3").s("sawtooth").vowel("<a e i o>")`} /> | | vowel | <MiniRepl client:visible tune={`note("c3 eb3 g3").s("sawtooth").vowel("<a e i o>")`} /> |
| gain | <MiniRepl client:visible tune={`s("hh*8").gain("[.25 1]*2")`} /> | | gain | <MiniRepl client:visible tune={`s("hh*16").gain("[.25 1]*2")`} /> |
| delay | <MiniRepl client:visible tune={`s("bd rim").delay(.5)`} /> | | delay | <MiniRepl client:visible tune={`s("bd rim bd cp").delay(.5)`} /> |
| room | <MiniRepl client:visible tune={`s("bd rim").room(.5)`} /> | | room | <MiniRepl client:visible tune={`s("bd rim bd cp").room(.5)`} /> |
| pan | <MiniRepl client:visible tune={`s("bd rim").pan("0 1")`} /> | | pan | <MiniRepl client:visible tune={`s("bd rim bd cp").pan("0 1")`} /> |
| speed | <MiniRepl client:visible tune={`s("bd rim").speed("<1 2 -1 -2>")`} /> | | speed | <MiniRepl client:visible tune={`s("bd rim bd cp").speed("<1 2 -1 -2>")`} /> |
| range | <MiniRepl client:visible tune={`s("hh*16").lpf(saw.range(200,4000))`} /> | | range | <MiniRepl client:visible tune={`s("hh*16").lpf(saw.range(200,4000))`} /> |
Let us now take a look at some of Tidal's typical [pattern effects](/workshop/pattern-effects). Let us now take a look at some of Tidal's typical [pattern effects](/workshop/pattern-effects).

View File

@ -175,11 +175,11 @@ Try adding more notes inside the brackets and notice how it does **not** get fas
**Play one sequence per cycle** **Play one sequence per cycle**
{/* <[c2 c3]*4 [bb1 bb2]*4 [f2 f3]*4 [eb2 eb3]*4>/2 */} {/* <[c2 c3]*4 [bb1 bb2]*4 [f2 f3]*4 [eb2 eb3]*4> */}
<MiniRepl <MiniRepl
client:visible client:visible
tune={`note("<[36 48]*4 [34 46]*4 [41 53]*4 [39 51]*4>/2") tune={`note("<[36 48]*4 [34 46]*4 [41 53]*4 [39 51]*4>")
.sound("gm_acoustic_bass")`} .sound("gm_acoustic_bass")`}
punchcard punchcard
/> />
@ -197,7 +197,7 @@ This is also useful for unpitched sounds:
<MiniRepl <MiniRepl
client:visible client:visible
tune={`sound("bd*2, ~ <sd cp>, [~ hh]*2") tune={`sound("bd*4, [~ <sd cp>]*2, [~ hh]*4")
.bank("RolandTR909")`} .bank("RolandTR909")`}
punchcard punchcard
/> />
@ -209,7 +209,7 @@ Finding the right notes can be difficult.. Scales are here to help:
<MiniRepl <MiniRepl
client:visible client:visible
tune={`n("0 2 4 <[6,8] [7,9]>") tune={`n("0 2 4 <[6,8] [7,9]>")
.scale("C:minor").sound("piano")`} .scale("C:minor").sound("piano").cpm(60)`}
punchcard punchcard
/> />
@ -236,7 +236,7 @@ Just like anything, we can automate the scale with a pattern:
client:visible client:visible
tune={`n("<0 -3>, 2 4 <[6,8] [7,9]>") tune={`n("<0 -3>, 2 4 <[6,8] [7,9]>")
.scale("<C:major D:mixolydian>/4") .scale("<C:major D:mixolydian>/4")
.sound("piano")`} .sound("piano").cpm(60)`}
punchcard punchcard
/> />
@ -269,7 +269,7 @@ Try changing that number!
client:visible client:visible
tune={`n("<[4@2 4] [5@2 5] [6@2 6] [5@2 5]>*2") tune={`n("<[4@2 4] [5@2 5] [6@2 6] [5@2 5]>*2")
.scale("<C2:mixolydian F2:mixolydian>/4") .scale("<C2:mixolydian F2:mixolydian>/4")
.sound("gm_acoustic_bass")`} .sound("gm_acoustic_bass").cpm(60)`}
punchcard punchcard
/> />
@ -283,7 +283,7 @@ This is also sometimes called triplet swing. You'll often find it in blues and j
**Replicate** **Replicate**
<MiniRepl client:visible tune={`note("c!2 [eb,<g a bb a>]").sound("piano")`} punchcard /> <MiniRepl client:visible tune={`note("c!2 [eb,<g a bb a>]").sound("piano").cpm(60)`} punchcard />
<Box> <Box>
@ -300,7 +300,7 @@ Let's recap what we've learned in this chapter:
| Concept | Syntax | Example | | Concept | Syntax | Example |
| --------- | ------ | -------------------------------------------------------- | | --------- | ------ | -------------------------------------------------------- |
| Slow down | \/ | <MiniRepl client:visible tune={`note("[c a f e]/2")`} /> | | Slow down | \/ | <MiniRepl client:visible tune={`note("[c a f e]/2")`} /> |
| Alternate | \<\> | <MiniRepl client:visible tune={`note("c <e g>")`} /> | | Alternate | \<\> | <MiniRepl client:visible tune={`note("c a f <e g>")`} /> |
| Elongate | @ | <MiniRepl client:visible tune={`note("c@3 e")`} /> | | Elongate | @ | <MiniRepl client:visible tune={`note("c@3 e")`} /> |
| Replicate | ! | <MiniRepl client:visible tune={`note("c!3 e")`} /> | | Replicate | ! | <MiniRepl client:visible tune={`note("c!3 e")`} /> |
@ -318,7 +318,7 @@ New functions:
<MiniRepl <MiniRepl
client:visible client:visible
tune={`note("<[c2 c3]*4 [bb1 bb2]*4 [f2 f3]*4 [eb2 eb3]*4>/2") tune={`note("<[c2 c3]*4 [bb1 bb2]*4 [f2 f3]*4 [eb2 eb3]*4>")
.sound("gm_synth_bass_1") .sound("gm_synth_bass_1")
.lpf(800) // <-- we'll learn about this soon`} .lpf(800) // <-- we'll learn about this soon`}
/> />
@ -332,7 +332,7 @@ New functions:
[~ 0] 1 [0 1] [~ 1] [~ 0] 1 [0 1] [~ 1]
[~ 0] 3 [0 3] [~ 3] [~ 0] 3 [0 3] [~ 3]
[~ 0] 2 [0 2] [~ 2] [~ 0] 2 [0 2] [~ 2]
>*2\`).scale("C4:minor") >*4\`).scale("C4:minor")
.sound("gm_synth_strings_1")`} .sound("gm_synth_strings_1")`}
/> />
@ -340,7 +340,7 @@ New functions:
<MiniRepl <MiniRepl
client:visible client:visible
tune={`sound("bd*2, ~ <sd cp>, [~ hh]*2") tune={`sound("bd*4, [~ <sd cp>]*2, [~ hh]*4")
.bank("RolandTR909")`} .bank("RolandTR909")`}
/> />
@ -355,16 +355,16 @@ It's called `stack` 😙
<MiniRepl <MiniRepl
client:visible client:visible
tune={`stack( tune={`stack(
note("<[c2 c3]*4 [bb1 bb2]*4 [f2 f3]*4 [eb2 eb3]*4>/2") note("<[c2 c3]*4 [bb1 bb2]*4 [f2 f3]*4 [eb2 eb3]*4>")
.sound("gm_synth_bass_1").lpf(800), .sound("gm_synth_bass_1").lpf(800),
n(\`< n(\`<
[~ 0] 2 [0 2] [~ 2] [~ 0] 2 [0 2] [~ 2]
[~ 0] 1 [0 1] [~ 1] [~ 0] 1 [0 1] [~ 1]
[~ 0] 3 [0 3] [~ 3] [~ 0] 3 [0 3] [~ 3]
[~ 0] 2 [0 2] [~ 2] [~ 0] 2 [0 2] [~ 2]
>*2\`).scale("C4:minor") >*4\`).scale("C4:minor")
.sound("gm_synth_strings_1"), .sound("gm_synth_strings_1"),
sound("bd*2, ~ <sd cp>, [~ hh]*2") sound("bd*4, [~ <sd cp>]*2, [~ hh]*4")
.bank("RolandTR909") .bank("RolandTR909")
)`} )`}
/> />

View File

@ -147,11 +147,11 @@ We will look at other ways to change the tempo later!
**Add a rests in a sequence with '~'** **Add a rests in a sequence with '~'**
<MiniRepl client:visible tune={`sound("bd hh ~ rim")`} punchcard /> <MiniRepl client:visible tune={`sound("bd hh ~ rim ~ bd hh rim")`} punchcard />
**Sub-Sequences with [brackets]** **Sub-Sequences with [brackets]**
<MiniRepl client:visible tune={`sound("bd [hh hh] sd [hh bd]")`} punchcard /> <MiniRepl client:visible tune={`sound("bd [hh hh] sd [hh bd] bd ~ [hh sd] cp")`} punchcard />
<Box> <Box>
@ -163,15 +163,15 @@ Similar to the whole sequence, the content of a sub-sequence will be squished to
**Multiplication: Speed things up** **Multiplication: Speed things up**
<MiniRepl client:visible tune={`sound("bd hh*2 rim hh*3")`} punchcard /> <MiniRepl client:visible tune={`sound("bd hh*2 rim hh*3 bd [~ hh*2] rim hh*2")`} punchcard />
**Multiplication: Speed up sequences** **Multiplication: Speed up subsequences**
<MiniRepl client:visible tune={`sound("bd [hh rim]*2")`} punchcard /> <MiniRepl client:visible tune={`sound("bd [hh rim]*2 bd [hh rim]*1.5")`} punchcard />
**Multiplication: Speeeeeeeeed things up** **Multiplication: Speeeeeeeeed things up**
<MiniRepl client:visible tune={`sound("bd hh*16 rim hh*8")`} punchcard /> <MiniRepl client:visible tune={`sound("bd hh*32 rim hh*16")`} punchcard />
<Box> <Box>
@ -181,7 +181,7 @@ Pitch = really fast rhythm
**Sub-Sub-Sequences with [[brackets]]** **Sub-Sub-Sequences with [[brackets]]**
<MiniRepl client:visible tune={`sound("bd [[rim rim] hh]")`} punchcard /> <MiniRepl client:visible tune={`sound("bd [[rim rim] hh] bd cp")`} punchcard />
<Box> <Box>
@ -234,34 +234,39 @@ This is shorter and more readable than:
Now we've learned the basics of the so called Mini-Notation, the rhythm language of Tidal. Now we've learned the basics of the so called Mini-Notation, the rhythm language of Tidal.
This is what we've leared so far: This is what we've leared so far:
| Concept | Syntax | Example | | Concept | Syntax | Example |
| ----------------- | -------- | --------------------------------------------------------------------- | | ----------------- | -------- | ----------------------------------------------------------------------- |
| Sequence | space | <MiniRepl client:visible tune={`sound("bd bd sd hh")`} /> | | Sequence | space | <MiniRepl client:visible tune={`sound("bd bd sd hh")`} /> |
| Sample Number | :x | <MiniRepl client:visible tune={`sound("hh:0 hh:1 hh:2 hh:3")`} /> | | Sample Number | :x | <MiniRepl client:visible tune={`sound("hh:0 hh:1 hh:2 hh:3")`} /> |
| Rests | ~ | <MiniRepl client:visible tune={`sound("metal ~ jazz jazz:1")`} /> | | Rests | ~ | <MiniRepl client:visible tune={`sound("metal ~ jazz jazz:1")`} /> |
| Sub-Sequences | \[\] | <MiniRepl client:visible tune={`sound("bd wind [metal jazz] hh")`} /> | | Sub-Sequences | \[\] | <MiniRepl client:visible tune={`sound("bd wind [metal jazz] hh")`} /> |
| Sub-Sub-Sequences | \[\[\]\] | <MiniRepl client:visible tune={`sound("bd [metal [jazz sd]]")`} /> | | Sub-Sub-Sequences | \[\[\]\] | <MiniRepl client:visible tune={`sound("bd [metal [jazz [sd cp]]]")`} /> |
| Speed up | \* | <MiniRepl client:visible tune={`sound("bd sd*2 cp*3")`} /> | | Speed up | \* | <MiniRepl client:visible tune={`sound("bd sd*2 cp*3")`} /> |
| Parallel | , | <MiniRepl client:visible tune={`sound("bd*2, hh*2 [hh oh]")`} /> | | Parallel | , | <MiniRepl client:visible tune={`sound("bd*2, hh*2 [hh oh]")`} /> |
The Mini-Notation is usually used inside some function. These are the functions we've seen so far: The Mini-Notation is usually used inside some function. These are the functions we've seen so far:
| Name | Description | Example | | Name | Description | Example |
| ----- | ----------------------------------- | ----------------------------------------------------------------------- | | ----- | ----------------------------------- | --------------------------------------------------------------------------------- |
| sound | plays the sound of the given name | <MiniRepl client:visible tune={`sound("bd sd")`} /> | | sound | plays the sound of the given name | <MiniRepl client:visible tune={`sound("bd sd [~ bd] sd")`} /> |
| bank | selects the sound bank | <MiniRepl client:visible tune={`sound("bd sd").bank("RolandTR909")`} /> | | bank | selects the sound bank | <MiniRepl client:visible tune={`sound("bd sd [~ bd] sd").bank("RolandTR909")`} /> |
| cpm | sets the tempo in cycles per minute | <MiniRepl client:visible tune={`sound("bd sd").cpm(90)`} /> | | cpm | sets the tempo in cycles per minute | <MiniRepl client:visible tune={`sound("bd sd [~ bd] sd").cpm(45)`} /> |
| n | select sample number | <MiniRepl client:visible tune={`n("0 1 4 2").sound("jazz")`} /> | | n | select sample number | <MiniRepl client:visible tune={`n("0 1 4 2 0 6 3 2").sound("jazz")`} /> |
## Examples ## Examples
**Basic rock beat** **Basic rock beat**
<MiniRepl client:visible tune={`sound("bd sd, hh*4").bank("RolandTR505").cpm(100/2)`} punchcard /> <MiniRepl
client:visible
tune={`sound("[bd sd]*2, hh*8").bank("RolandTR505")
.cpm(100/4)`}
punchcard
/>
**Classic house** **Classic house**
<MiniRepl client:visible tune={`sound("bd*2, ~ cp, [~ hh]*2").bank("RolandTR909")`} punchcard /> <MiniRepl client:visible tune={`sound("bd*4, [~ cp]*2, [~ hh]*4").bank("RolandTR909")`} punchcard />
<Box> <Box>
@ -279,7 +284,7 @@ We Will Rock you
<MiniRepl <MiniRepl
client:visible client:visible
tune={`sound("bd sd, ~ ~ ~ hh ~ hh ~ ~, ~ perc ~ perc:1*2") tune={`sound("bd sd, ~ ~ ~ hh ~ hh ~ ~, ~ perc ~ perc:1*2")
.bank("RolandCompurhythm1000")`} .bank("RolandCompurhythm1000").cpm(120/2)`}
punchcard punchcard
/> />

View File

@ -15,19 +15,19 @@ In this chapter, we are going to look at functions that are more unique to tidal
**reverse patterns with rev** **reverse patterns with rev**
<MiniRepl client:visible tune={`n("0 1 [4 3] 2").sound("jazz").rev()`} /> <MiniRepl client:visible tune={`n("0 1 [4 3] 2 0 2 [~ 3] 4").sound("jazz").rev()`} />
**play pattern left and modify it right with jux** **play pattern left and modify it right with jux**
<MiniRepl client:visible tune={`n("0 1 [4 3] 2").sound("jazz").jux(rev)`} /> <MiniRepl client:visible tune={`n("0 1 [4 3] 2 0 2 [~ 3] 4").sound("jazz").jux(rev)`} />
This is the same as: This is the same as:
<MiniRepl <MiniRepl
client:visible client:visible
tune={`stack( tune={`stack(
n("0 1 [4 3] 2").sound("jazz").pan(0), n("0 1 [4 3] 2 0 2 [~ 3] 4").sound("jazz").pan(0),
n("0 1 [4 3] 2").sound("jazz").pan(1).rev() n("0 1 [4 3] 2 0 2 [~ 3] 4").sound("jazz").pan(1).rev()
)`} )`}
/> />
@ -36,8 +36,8 @@ Let's visualize what happens here:
<MiniRepl <MiniRepl
client:visible client:visible
tune={`stack( tune={`stack(
n("0 1 [4 3] 2").sound("jazz").pan(0).color("cyan"), n("0 1 [4 3] 2 0 2 [~ 3] 4").sound("jazz").pan(0).color("cyan"),
n("0 1 [4 3] 2").sound("jazz").pan(1).color("magenta").rev() n("0 1 [4 3] 2 0 2 [~ 3] 4").sound("jazz").pan(1).color("magenta").rev()
)`} )`}
punchcard punchcard
/> />
@ -50,16 +50,16 @@ Try commenting out one of the two by adding `//` before a line
**multiple tempos** **multiple tempos**
<MiniRepl client:visible tune={`note("c2, eb3 g3 [bb3 c4]").sound("piano").slow("1,2,3")`} /> <MiniRepl client:visible tune={`note("c2, eb3 g3 [bb3 c4]").sound("piano").slow("0.5,1,1.5")`} />
This is like doing This is like doing
<MiniRepl <MiniRepl
client:visible client:visible
tune={`stack( tune={`stack(
note("c2, eb3 g3 [bb3 c4]").s("piano").slow(1).color('cyan'), note("c2, eb3 g3 [bb3 c4]").s("piano").slow(0.5).color('cyan'),
note("c2, eb3 g3 [bb3 c4]").s("piano").slow(2).color('magenta'), note("c2, eb3 g3 [bb3 c4]").s("piano").slow(1).color('magenta'),
note("c2, eb3 g3 [bb3 c4]").s("piano").slow(3).color('yellow') note("c2, eb3 g3 [bb3 c4]").s("piano").slow(1.5).color('yellow')
)`} )`}
punchcard punchcard
/> />
@ -74,9 +74,9 @@ Try commenting out one or more by adding `//` before a line
<MiniRepl <MiniRepl
client:visible client:visible
tune={`note("c2 [eb3,g3]".add("<0 <1 -1>>")) tune={`note("c2 [eb3,g3] ".add("<0 <1 -1>>"))
.color("<cyan <magenta yellow>>").adsr("[.1 0]:.2:[1 0]") .color("<cyan <magenta yellow>>").adsr("[.1 0]:.2:[1 0]")
.sound("gm_acoustic_bass").room(.5)`} .sound("gm_acoustic_bass").room(.5).cpm(60)`}
punchcard punchcard
/> />
@ -92,7 +92,7 @@ We can add as often as we like:
client:visible client:visible
tune={`note("c2 [eb3,g3]".add("<0 <1 -1>>").add("0,7")) tune={`note("c2 [eb3,g3]".add("<0 <1 -1>>").add("0,7"))
.color("<cyan <magenta yellow>>").adsr("[.1 0]:.2:[1 0]") .color("<cyan <magenta yellow>>").adsr("[.1 0]:.2:[1 0]")
.sound("gm_acoustic_bass").room(.5)`} .sound("gm_acoustic_bass").room(.5).cpm(60)`}
punchcard punchcard
/> />
@ -100,7 +100,7 @@ We can add as often as we like:
<MiniRepl <MiniRepl
client:visible client:visible
tune={`n("<0 [2 4] <3 5> [~ <4 1>]>*2".add("<0 [0,2,4]>/4")) tune={`n("0 [2 4] <3 5> [~ <4 1>]".add("<0 [0,2,4]>"))
.scale("C5:minor").release(.5) .scale("C5:minor").release(.5)
.sound("gm_xylophone").room(.5)`} .sound("gm_xylophone").room(.5)`}
punchcard punchcard
@ -111,7 +111,7 @@ We can add as often as we like:
<MiniRepl <MiniRepl
client:visible client:visible
tune={`stack( tune={`stack(
n("<0 [2 4] <3 5> [~ <4 1>]>*2".add("<0 [0,2,4]>/4")) n("0 [2 4] <3 5> [~ <4 1>]".add("<0 [0,2,4]>"))
.scale("C5:minor") .scale("C5:minor")
.sound("gm_xylophone") .sound("gm_xylophone")
.room(.4).delay(.125), .room(.4).delay(.125),
@ -119,17 +119,17 @@ We can add as often as we like:
.adsr("[.1 0]:.2:[1 0]") .adsr("[.1 0]:.2:[1 0]")
.sound("gm_acoustic_bass") .sound("gm_acoustic_bass")
.room(.5), .room(.5),
n("0 1 [2 3] 2").sound("jazz").jux(rev).slow(2) n("0 1 [2 3] 2").sound("jazz").jux(rev)
)`} )`}
/> />
**ply** **ply**
<MiniRepl client:visible tune={`sound("hh, bd rim").bank("RolandTR707").ply(2)`} punchcard /> <MiniRepl client:visible tune={`sound("hh hh, bd rim [~ cp] rim").bank("RolandTR707").ply(2)`} punchcard />
this is like writing: this is like writing:
<MiniRepl client:visible tune={`sound("hh*2, bd*2 rim*2").bank("RolandTR707")`} punchcard /> <MiniRepl client:visible tune={`sound("hh*2 hh*2, bd*2 rim*2 [~ cp*2] rim*2").bank("RolandTR707")`} punchcard />
<Box> <Box>
@ -141,10 +141,10 @@ Try patterning the `ply` function, for example using `"<1 2 1 3>"`
<MiniRepl <MiniRepl
client:visible client:visible
tune={`n("<0 [4 <3 2>] <2 3> [~ 1]>" tune={`n("0 [4 <3 2>] <2 3> [~ 1]"
.off(1/8, x=>x.add(4)) .off(1/16, x=>x.add(4))
//.off(1/4, x=>x.add(7)) //.off(1/8, x=>x.add(7))
).scale("<C5:minor Db5:mixolydian>/4") ).scale("<C5:minor Db5:mixolydian>/2")
.s("triangle").room(.5).ds(".1:0").delay(.5)`} .s("triangle").room(.5).ds(".1:0").delay(.5)`}
punchcard punchcard
/> />
@ -159,14 +159,14 @@ off is also useful for sounds:
<MiniRepl <MiniRepl
client:visible client:visible
tune={`s("bd sd,[~ hh]*2").bank("CasioRZ1") tune={`s("bd sd [rim bd] sd,[~ hh]*4").bank("CasioRZ1")
.off(1/8, x=>x.speed(1.5).gain(.25))`} .off(1/16, x=>x.speed(1.5).gain(.25))`}
/> />
| name | description | example | | name | description | example |
| ---- | ------------------------------ | ----------------------------------------------------------------------------------- | | ---- | ------------------------------ | ------------------------------------------------------------------------------------------- |
| rev | reverse | <MiniRepl client:visible tune={`n("0 2 4 6").scale("C:minor").rev()`} /> | | rev | reverse | <MiniRepl client:visible tune={`n("0 2 4 6 ~ 7 9 5").scale("C:minor").rev()`} /> |
| jux | split left/right, modify right | <MiniRepl client:visible tune={`n("0 2 4 6").scale("C:minor").jux(rev)`} /> | | jux | split left/right, modify right | <MiniRepl client:visible tune={`n("0 2 4 6 ~ 7 9 5").scale("C:minor").jux(rev)`} /> |
| add | add numbers / notes | <MiniRepl client:visible tune={`n("0 2 4 6".add("<0 1 2 1>")).scale("C:minor")`} /> | | add | add numbers / notes | <MiniRepl client:visible tune={`n("0 2 4 6 ~ 7 9 5".add("<0 1 2 1>")).scale("C:minor")`} /> |
| ply | speed up each event n times | <MiniRepl client:visible tune={`s("bd sd").ply("<1 2 3>")`} /> | | ply | speed up each event n times | <MiniRepl client:visible tune={`s("bd sd [~ bd] sd").ply("<1 2 3>")`} /> |
| off | copy, shift time & modify | <MiniRepl client:visible tune={`s("bd sd, hh*4").off(1/8, x=>x.speed(2))`} /> | | off | copy, shift time & modify | <MiniRepl client:visible tune={`s("bd sd [~ bd] sd, hh*8").off(1/16, x=>x.speed(2))`} /> |

View File

@ -13,12 +13,12 @@ This page is just a listing of all functions covered in the workshop!
| Concept | Syntax | Example | | Concept | Syntax | Example |
| ----------------- | -------- | --------------------------------------------------------------------- | | ----------------- | -------- | --------------------------------------------------------------------- |
| Sequence | space | <MiniRepl client:visible tune={`sound("bd bd sn hh")`} /> | | Sequence | space | <MiniRepl client:visible tune={`sound("bd bd sd hh bd cp sd hh")`} /> |
| Sample Number | :x | <MiniRepl client:visible tune={`sound("hh:0 hh:1 hh:2 hh:3")`} /> | | Sample Number | :x | <MiniRepl client:visible tune={`sound("hh:0 hh:1 hh:2 hh:3")`} /> |
| Rests | ~ | <MiniRepl client:visible tune={`sound("metal ~ jazz jazz:1")`} /> | | Rests | ~ | <MiniRepl client:visible tune={`sound("metal ~ jazz jazz:1")`} /> |
| Sub-Sequences | \[\] | <MiniRepl client:visible tune={`sound("bd wind [metal jazz] hh")`} /> | | Sub-Sequences | \[\] | <MiniRepl client:visible tune={`sound("bd wind [metal jazz] hh")`} /> |
| Sub-Sub-Sequences | \[\[\]\] | <MiniRepl client:visible tune={`sound("bd [metal [jazz sn]]")`} /> | | Sub-Sub-Sequences | \[\[\]\] | <MiniRepl client:visible tune={`sound("bd [metal [jazz sd]]")`} /> |
| Speed up | \* | <MiniRepl client:visible tune={`sound("bd sn*2 cp*3")`} /> | | Speed up | \* | <MiniRepl client:visible tune={`sound("bd sd*2 cp*3")`} /> |
| Parallel | , | <MiniRepl client:visible tune={`sound("bd*2, hh*2 [hh oh]")`} /> | | Parallel | , | <MiniRepl client:visible tune={`sound("bd*2, hh*2 [hh oh]")`} /> |
| Slow down | \/ | <MiniRepl client:visible tune={`note("[c a f e]/2")`} /> | | Slow down | \/ | <MiniRepl client:visible tune={`note("[c a f e]/2")`} /> |
| Alternate | \<\> | <MiniRepl client:visible tune={`note("c <e g>")`} /> | | Alternate | \<\> | <MiniRepl client:visible tune={`note("c <e g>")`} /> |
@ -45,22 +45,22 @@ This page is just a listing of all functions covered in the workshop!
| name | example | | name | example |
| ----- | --------------------------------------------------------------------------------------- | | ----- | --------------------------------------------------------------------------------------- |
| lpf | <MiniRepl client:visible tune={`note("c2 c3").s("sawtooth").lpf("<400 2000>")`} /> | | lpf | <MiniRepl client:visible tune={`note("c2 c3 c2 c3").s("sawtooth").lpf("400 2000")`} /> |
| vowel | <MiniRepl client:visible tune={`note("c3 eb3 g3").s("sawtooth").vowel("<a e i o>")`} /> | | vowel | <MiniRepl client:visible tune={`note("c3 eb3 g3").s("sawtooth").vowel("<a e i o>")`} /> |
| gain | <MiniRepl client:visible tune={`s("hh*8").gain("[.25 1]*2")`} /> | | gain | <MiniRepl client:visible tune={`s("hh*16").gain("[.25 1]*4")`} /> |
| delay | <MiniRepl client:visible tune={`s("bd rim").delay(.5)`} /> | | delay | <MiniRepl client:visible tune={`s("bd rim bd cp").delay(.5)`} /> |
| room | <MiniRepl client:visible tune={`s("bd rim").room(.5)`} /> | | room | <MiniRepl client:visible tune={`s("bd rim bd cp").room(.5)`} /> |
| pan | <MiniRepl client:visible tune={`s("bd rim").pan("0 1")`} /> | | pan | <MiniRepl client:visible tune={`s("bd rim bd cp").pan("0 1")`} /> |
| speed | <MiniRepl client:visible tune={`s("bd rim").speed("<1 2 -1 -2>")`} /> | | speed | <MiniRepl client:visible tune={`s("bd rim bd cp").speed("<1 2 -1 -2>")`} /> |
| range | <MiniRepl client:visible tune={`s("hh*16").lpf(saw.range(200,4000))`} /> | | range | <MiniRepl client:visible tune={`s("hh*32").lpf(saw.range(200,4000))`} /> |
## Pattern Effects ## Pattern Effects
| name | description | example | | name | description | example |
| ---- | ----------------------------------- | ----------------------------------------------------------------------------------- | | ---- | ----------------------------------- | ----------------------------------------------------------------------------------- |
| cpm | sets the tempo in cycles per minute | <MiniRepl client:visible tune={`sound("bd sd").cpm(90)`} /> | | cpm | sets the tempo in cycles per minute | <MiniRepl client:visible tune={`sound("bd sd [~ bd] sd").cpm(45)`} /> |
| fast | speed up | <MiniRepl client:visible tune={`sound("bd sd").fast(2)`} /> | | fast | speed up | <MiniRepl client:visible tune={`sound("bd sd [~ bd] sd").fast(2)`} /> |
| slow | slow down | <MiniRepl client:visible tune={`sound("bd sd").slow(2)`} /> | | slow | slow down | <MiniRepl client:visible tune={`sound("bd sd [~ bd] sd").slow(2)`} /> |
| rev | reverse | <MiniRepl client:visible tune={`n("0 2 4 6").scale("C:minor").rev()`} /> | | rev | reverse | <MiniRepl client:visible tune={`n("0 2 4 6").scale("C:minor").rev()`} /> |
| jux | split left/right, modify right | <MiniRepl client:visible tune={`n("0 2 4 6").scale("C:minor").jux(rev)`} /> | | jux | split left/right, modify right | <MiniRepl client:visible tune={`n("0 2 4 6").scale("C:minor").jux(rev)`} /> |
| add | add numbers / notes | <MiniRepl client:visible tune={`n("0 2 4 6".add("<0 1 2 1>")).scale("C:minor")`} /> | | add | add numbers / notes | <MiniRepl client:visible tune={`n("0 2 4 6".add("<0 1 2 1>")).scale("C:minor")`} /> |

View File

@ -30,7 +30,6 @@ import { getRandomTune, initCode, loadModules, shareCode, ReplContext } from './
import PlayCircleIcon from '@heroicons/react/20/solid/PlayCircleIcon'; import PlayCircleIcon from '@heroicons/react/20/solid/PlayCircleIcon';
import './Repl.css'; import './Repl.css';
const { code: randomTune, name } = getRandomTune();
const { latestCode } = settingsMap.get(); const { latestCode } = settingsMap.get();
let modulesLoading, presets, drawContext, clearCanvas, isIframe; let modulesLoading, presets, drawContext, clearCanvas, isIframe;
@ -98,7 +97,7 @@ export function Repl({ embedded = false }) {
// init settings // init settings
initCode().then((decoded) => { initCode().then(async (decoded) => {
let msg; let msg;
if (decoded) { if (decoded) {
editor.setCode(decoded); editor.setCode(decoded);
@ -107,6 +106,7 @@ export function Repl({ embedded = false }) {
editor.setCode(latestCode); editor.setCode(latestCode);
msg = `Your last session has been loaded!`; msg = `Your last session has been loaded!`;
} else { } else {
const { code: randomTune, name } = await getRandomTune();
editor.setCode(randomTune); editor.setCode(randomTune);
msg = `A random code snippet named "${name}" has been loaded!`; msg = `A random code snippet named "${name}" has been loaded!`;
} }
@ -159,7 +159,7 @@ export function Repl({ embedded = false }) {
const resetEditor = async () => { const resetEditor = async () => {
clearCanvas(); clearCanvas();
resetLoadedSounds(); resetLoadedSounds();
editorRef.current.repl.setCps(1); editorRef.current.repl.setCps(0.5);
await prebake(); // declare default samples await prebake(); // declare default samples
}; };
@ -176,7 +176,7 @@ export function Repl({ embedded = false }) {
editorRef.current.evaluate(); editorRef.current.evaluate();
}; };
const handleShuffle = async () => { const handleShuffle = async () => {
const patternData = getRandomTune(); const patternData = await getRandomTune();
const code = patternData.code; const code = patternData.code;
logger(`[repl] ✨ loading random tune "${patternData.id}"`); logger(`[repl] ✨ loading random tune "${patternData.id}"`);
setActivePattern(patternData.id); setActivePattern(patternData.id);

View File

@ -314,7 +314,7 @@ stack(
) )
.fast(2/3) .fast(2/3)
.pianoroll()`; .pianoroll()`;
/*
export const bridgeIsOver = `// "Bridge is over" export const bridgeIsOver = `// "Bridge is over"
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ // @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// @by Felix Roos, bassline by BDP - The Bridge Is Over // @by Felix Roos, bassline by BDP - The Bridge Is Over
@ -333,7 +333,7 @@ stack(
s("mad").slow(2) s("mad").slow(2)
).cpm(78).slow(4) ).cpm(78).slow(4)
.pianoroll() .pianoroll()
`; `; */
export const goodTimes = `// "Good times" export const goodTimes = `// "Good times"
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ // @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
@ -709,6 +709,8 @@ export const dinofunk = `// "Dinofunk"
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ // @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// @by Felix Roos // @by Felix Roos
setcps(1)
samples({bass:'https://cdn.freesound.org/previews/614/614637_2434927-hq.mp3', samples({bass:'https://cdn.freesound.org/previews/614/614637_2434927-hq.mp3',
dino:{b4:'https://cdn.freesound.org/previews/316/316403_5123851-hq.mp3'}}) dino:{b4:'https://cdn.freesound.org/previews/316/316403_5123851-hq.mp3'}})
setVoicingRange('lefthand', ['c3','a4']) setVoicingRange('lefthand', ['c3','a4'])

View File

@ -9,8 +9,7 @@ import { createClient } from '@supabase/supabase-js';
import { nanoid } from 'nanoid'; import { nanoid } from 'nanoid';
import { writeText } from '@tauri-apps/api/clipboard'; import { writeText } from '@tauri-apps/api/clipboard';
import { createContext } from 'react'; import { createContext } from 'react';
import { stockPatterns } from './useExamplePatterns'; import { $featuredPatterns, loadDBPatterns } from '@src/user_pattern_utils.mjs';
import { loadDBPatterns } from '@src/user_pattern_utils.mjs';
// Create a single supabase client for interacting with your database // Create a single supabase client for interacting with your database
export const supabase = createClient( export const supabase = createClient(
@ -18,8 +17,9 @@ export const supabase = createClient(
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InBpZHhkc3hwaGxoempuem1pZnRoIiwicm9sZSI6ImFub24iLCJpYXQiOjE2NTYyMzA1NTYsImV4cCI6MTk3MTgwNjU1Nn0.bqlw7802fsWRnqU5BLYtmXk_k-D1VFmbkHMywWc15NM', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InBpZHhkc3hwaGxoempuem1pZnRoIiwicm9sZSI6ImFub24iLCJpYXQiOjE2NTYyMzA1NTYsImV4cCI6MTk3MTgwNjU1Nn0.bqlw7802fsWRnqU5BLYtmXk_k-D1VFmbkHMywWc15NM',
); );
let dbLoaded;
if (typeof window !== 'undefined') { if (typeof window !== 'undefined') {
loadDBPatterns(); dbLoaded = loadDBPatterns();
} }
export async function initCode() { export async function initCode() {
@ -34,7 +34,7 @@ export async function initCode() {
return hash2code(codeParam); return hash2code(codeParam);
} else if (hash) { } else if (hash) {
return supabase return supabase
.from('code') .from('code_v1')
.select('code') .select('code')
.eq('hash', hash) .eq('hash', hash)
.then(({ data, error }) => { .then(({ data, error }) => {
@ -61,10 +61,11 @@ export const parseJSON = (json) => {
} }
}; };
export function getRandomTune() { export async function getRandomTune() {
const allTunes = Object.entries(stockPatterns); await dbLoaded;
const featuredTunes = Object.entries($featuredPatterns.get());
const randomItem = (arr) => arr[Math.floor(Math.random() * arr.length)]; const randomItem = (arr) => arr[Math.floor(Math.random() * arr.length)];
const [id, data] = randomItem(allTunes); const [_, data] = randomItem(featuredTunes);
return data; return data;
} }
@ -111,7 +112,7 @@ export async function shareCode(codeToShare) {
// generate uuid in the browser // generate uuid in the browser
const hash = nanoid(12); const hash = nanoid(12);
const shareUrl = window.location.origin + window.location.pathname + '?' + hash; const shareUrl = window.location.origin + window.location.pathname + '?' + hash;
const { error } = await supabase.from('code').insert([{ code: codeToShare, hash, ['public']: isPublic }]); const { error } = await supabase.from('code_v1').insert([{ code: codeToShare, hash, ['public']: isPublic }]);
if (!error) { if (!error) {
lastShared = codeToShare; lastShared = codeToShare;
// copy shareUrl to clipboard // copy shareUrl to clipboard

View File

@ -44,11 +44,11 @@ export const setViewingPatternData = (data) => {
}; };
export function loadPublicPatterns() { export function loadPublicPatterns() {
return supabase.from('code').select().eq('public', true).limit(20).order('id', { ascending: false }); return supabase.from('code_v1').select().eq('public', true).limit(20).order('id', { ascending: false });
} }
export function loadFeaturedPatterns() { export function loadFeaturedPatterns() {
return supabase.from('code').select().eq('featured', true).limit(20).order('id', { ascending: false }); return supabase.from('code_v1').select().eq('featured', true).limit(20).order('id', { ascending: false });
} }
export async function loadDBPatterns() { export async function loadDBPatterns() {