// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// πΈ CrumbMidi ADVANCED COLLABORATIVE TECHNIQUES
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// Inspired by @eefano's patterns
// Techniques: register(), .pickRestart(), .superimpose(), velocity notation
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// π― TECHNIQUE 1: .superimpose() - Self-layering
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// Creates copies of a pattern with transformations
/*
// Basic: Add octave layer
$: note("
.s("triangle")
.superimpose(x => x.add(12).gain(0.5)) // +1 octave, quieter
.room(0.3)
// Advanced: Multiple delay layers for stereo spread
$: note("
.s("sine")
.superimpose(x => x.late(0.125).pan(1).gain(0.6)) // Right, delayed
.superimpose(x => x.late(0.25).pan(0).gain(0.3)) // Left, more delayed
.room(0.4)
// @eefano style: Complex superimpose with room and pan
$: note("
.s("gm_oboe")
.superimpose(x => x.late(2).gain(0.5).pan("<0 1>/16").room(1.5))
*/
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// π― TECHNIQUE 2: .pickRestart() - Pattern selection with restart
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// Selects patterns AND restarts from beginning
/*
// Song structure: Verse β Chorus β Verse β Bridge
$: note("<0 1 0 2>".pickRestart([
// 0 = Verse
"
// 1 = Chorus
"
// 2 = Bridge
"
]))
.s("piano")
.room(0.3)
.slow(2)
// With duration control (@)
$: note("<0@7 1 2@4>".pickRestart([
"
"
"
]))
.s("gm_electric_guitar_muted")
*/
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// π― TECHNIQUE 3: : Velocity Notation
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// Add velocity/gain directly in the pattern string
/*
// Basic velocity
$: note("c4:0.5 e4:0.7 g4:1 e4:0.7") // Crescendo effect
.s("piano")
// Dynamic drums
$: s("bd:1 bd:0.5 bd:0.7 bd:0.5") // Accented first beat
.bank("tr909")
// Hi-hat groove with accents
$: s("hh:0.3 hh:0.5 hh:0.3 hh:1 hh:0.3 hh:0.5 hh:0.3 hh:0.7")
.bank("tr909")
// Complex pattern with multiple parameters
// note:velocity:param2:param3
$: note("d4:0.7!3 d4:1 c4:0.7!4")
.s("sine")
*/
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// π― TECHNIQUE 4: register() - Custom Functions
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// Create your own pattern functions!
/*
// Simple: Octave doubler
const double = register('double', (amount, pat) =>
pat.superimpose(x => x.add(amount))
)
// Usage:
$: note("
$: note("
// More complex: Split function (from @eefano)
// Splits pattern values into multiple parameters
const split = register('split', (deflt, callback, pat) =>
callback(deflt.map((d,i) => pat.withValue((v) => {
const isobj = v.value !== undefined
const value = isobj ? v.value : v
const result = Array.isArray(value)
? (i < value.length ? value[i] : d)
: (i == 0 ? value : d)
return (i == 0 && isobj) ? {...v, value: result} : result
})))
)
*/
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// π― TECHNIQUE 5: samples() - Load Custom Sounds
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// Load sounds from URLs (freesound.org etc.)
/*
// Load a guitar sample
samples({
'gtr': {
'g3': 'https://cdn.freesound.org/previews/705/705412_11110011-lq.mp3'
}
})
// Use it:
$: s("gtr")
.note("
.room(0.5)
.slow(2)
// Load multiple samples
samples({
'mykit': {
'kick': 'https://url.to/kick.mp3',
'snare': 'https://url.to/snare.mp3',
'hat': 'https://url.to/hat.mp3'
}
})
*/
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// π― TECHNIQUE 6: .begin() .end() .clip() - Sample Manipulation
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// Control which part of a sample plays
/*
// Play only part of a sample
$: s("gtr")
.begin(0.045) // Start at 4.5%
.end(0.5) // End at 50%
.clip(1) // Clip to pattern length
.note("g3")
// Create variations from one sample
$: s("bd")
.begin("<0 0.1 0.2 0.3>") // Different start points
.end("<0.5 0.6 0.7 0.8>") // Different end points
*/
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// πΈ COMPLETE EXAMPLE: Collaborative Jam Template
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
/*
// === TAB 1: DRUMS & BASS ===
setcps(119/60/4)
$: s("bd ~ bd ~").bank("RolandMT32").gain(0.4).room(0.2)
$: s("~ sd ~ sd").bank("RolandMT32").gain(0.2).room(0.2)
$: s("hh*8").bank("RolandMT32").gain(0.1)
$: note("
.s("triangle")
.lpf(300)
.gain(0.5)
.slow(2)
// === TAB 2: CHORDS & MELODY ===
setcps(119/60/4)
$: n("0 1 2 3")
.chord("
.anchor("g4")
.voicing()
.s("gm_electric_guitar_muted")
.gain(0.4)
.slow(2)
$: note("
.s("sine")
.vib(5).vibmod(0.2)
.gain(0.3)
.superimpose(x => x.late(0.5).gain(0.15).pan(1))
*/
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// π QUICK REFERENCE
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
/
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β
β .superimpose(x => x.transform()) Layer with transformation β
β .pickRestart([patterns]) Select pattern, restart from beginning β
β "note:velocity" Inline velocity (0-1) β
β register('name', fn) Create custom function β
β samples({name: {note: 'url'}}) Load custom sounds β
β .begin(0.1).end(0.5) Play part of sample β
β .clip(1) Clip to pattern length β
β β
β MULTIPLAYER: β
β - Open multiple browser tabs β
β - They sync automatically! β
β - Jam together! πΈπ₯ β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
/
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// π CREDITS
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// Pattern techniques learned from @eefano
// Documented by CrumbMidi / FunkFox π¦
// License: CKL (Children's Knowledge License)
// πΈ Zusammen spielen - Zusammen wachsen! π²