diff --git a/talk/MaxiRepl.jsx b/talk/MaxiRepl.jsx index 78213974b..388b974fe 100644 --- a/talk/MaxiRepl.jsx +++ b/talk/MaxiRepl.jsx @@ -44,7 +44,7 @@ export function MaxiRepl({ code, canvasHeight = 500 }) { cleanupUi(); }, [exampleIndex]); return ( -
+
{examples.length > 1 && (
{examples.map((c, i) => ( @@ -56,16 +56,14 @@ export function MaxiRepl({ code, canvasHeight = 500 }) { ))}
)} -
- <_MiniRepl - key={exampleIndex} - tune={examples[exampleIndex]} - defaultSynth={defaultSynth} - hideOutsideView={true} - theme={materialPalenightLarge} - init={ready} - /> -
+ <_MiniRepl + key={exampleIndex} + tune={examples[exampleIndex]} + defaultSynth={defaultSynth} + hideOutsideView={true} + theme={materialPalenightLarge} + init={ready} + /> + + +
+ +- How to represent and control music with code? +- How to leverage unique features of computing? +- How to break loose from old conventions? + +
+ +
+ +## About Me + +
+ +- 💻 Studied Computer Science and Media, working as a software developer by day +- 🎺 Trumpet Player, studied Jazz and Popular Music +- 🎤 Dilettante Music Producer of all kinds of genres +- 💿 ocassionally publishes music with Lui Mafuta & Puste +- 🔌 Modular Synth & Electronics Lover, Dilettante DJ .. +- 💌 Coding Blog: [Loophole Letters](https://loophole-letters.vercel.app/) +- 👀 Loves visualizations + +
+ + {/* */} + + + + + {/* */} + {/* + */} +
+ +
+ +
+ ## What is Live Coding? @@ -30,7 +79,13 @@ import ImgTile from './ImgTile'; Roberts & Wakefield, 2016 -

Screenshot: "Olivia Jack - Hydra, Live Coding Visuals in the Browser"

+

+ Screenshot: "Olivia Jack -{' '} + + Hydra + + , Live Coding Visuals in the Browser".{' '} +

@@ -45,7 +100,12 @@ import ImgTile from './ImgTile';
-

Screenshot: "Yaxu & hellocatfood - LIVE code for Noise Quest"

+

+ Screenshot:{' '} + + "Yaxu & hellocatfood - LIVE code for Noise Quest" + +

@@ -67,7 +127,12 @@ import ImgTile from './ImgTile';
-

Screenshot: "Algorave 10th Birthday March 2022 - froos"

+

+ Screenshot:{' '} + + "Algorave 10th Birthday March 2022 - froos" + +

@@ -76,13 +141,84 @@ import ImgTile from './ImgTile'; ", - "<[f3,c4] [f3,b3] [e3,b3]@2>" - .early(1/4).struct("x(3,8)".slow(2))) - .transpose("<0 1>/4".early(1/4)) - .tone((await piano()).toDestination()) - .pianoroll({overscan:2})`, - `"0 4 <5 7> 2" + `// froos - xylophone on the floor +const t = x => x.scaleTranspose("<0 2 4 3>/4").transpose(-2) +const s = x => x.scale( + cat('C3 minor pentatonic','G3 minor pentatonic') + .slow(4)) +const delay = new FeedbackDelay(1/8, .6).chain(vol(0.1), out()); +const chorus = new Chorus(1,2.5,0.5).start(); +stack( + // melody + "<<10 7> <8 3>>/4".struct("x*3").apply(s) + .scaleTranspose("<0 3 2> <1 4 3>") + .superimpose(scaleTranspose(2).early(1/8)) + .apply(t).tone(polysynth().set({ + ...osc('triangle4'), + ...adsr(0,.08,0) + }) + .chain(vol(0.2).connect(delay),chorus,out())) + .mask("<~@3 x>/16".early(1/8)), + // pad + "[1,3]/4".scale('G3 minor pentatonic').apply(t) + .tone(polysynth().set({ + ...osc('square2'), + ...adsr(0.1,.4,0.8) + }).chain(vol(0.2),chorus,out())).mask("<~ x>/32"), + // xylophone + "c3,g3,c4".struct("").fast("<1 <2!3 [4 8]>>") + .apply(s) + .scaleTranspose("<0 <1 [2 [3 <4 5>]]>>").apply(t) + .tone(polysynth().set({ + ...osc('sawtooth4'), + ...adsr(0,.1,0) + }).chain(vol(0.4).connect(delay),out())) + .mask("/16".early(1/8)), + // bass + "c2 [c2 ~]*2".scale('C hirajoshi').apply(t) + .tone(synth({ + ...osc('sawtooth6'), + ...adsr(0,.03,.4,.1) + }).chain(vol(0.4),out())), + // kick + "*2".tone(membrane().chain(vol(0.8),out())), + // snare + "~ ".tone(noise().chain(vol(0.8),out())), + // hihat + "c3*4".transpose("[-24 0]*2").tone(metal(adsr(0,.02)) + .chain(vol(0.5).connect(delay),out())) +).slow(1)`, + // + `// froos - giant steps, chiptune version +stack( + // melody + seq( + "[F#5 D5] [B4 G4] Bb4 [B4 A4]", + "[D5 Bb4] [G4 Eb4] F#4 [G4 F4]", + "Bb4 [B4 A4] D5 [D#5 C#5]", + "F#5 [G5 F5] Bb5 [F#5 [F#5 ~@3]]", + ), + // chords + seq( + "[B^7 D7] [G^7 Bb7] Eb^7 [Am7 D7]", + "[G^7 Bb7] [Eb^7 F#7] B^7 [Fm7 Bb7]", + "Eb^7 [Am7 D7] G^7 [C#m7 F#7]", + "B^7 [Fm7 Bb7] Eb^7 [C#m7 F#7]" + ) + .struct("~ [x ~]".fast(4*8)) + .voicings(['E3', 'G4']), + // bass + seq( + "[B2 D2] [G2 D2] [Eb2 Bb2] [A2 D2]", + "[G2 Bb2] [Eb2 F#2] [B2 F#2] [F2 Bb2]", + "[Eb2 Bb2] [A2 D2] [G2 D2] [C#2 F#2]", + "[B2 F#2] [F2 Bb2] [Eb2 Bb2] [C#2 F#2]" + ) + .struct("x ~".fast(4*8)) +).slow(25)`, + // + `// froos - piano tune #3829 +"0 4 <5 7> 2" .off(1/16,x=>x.add(5).color('salmon')) .echo(4,.125,.7) .scale(cat( @@ -92,7 +228,45 @@ import ImgTile from './ImgTile'; .slow(4) .tone((await piano()).toDestination()) .pianoroll({ cycles:16, fold:1, vertical:0 })`, - `samples({ + // + `// froos - if so what else +const mix = (key) => vol({ + chords: .2, + lead: 0.8, + bass: .4, + snare: .95, + kick: .9, + hihat: .35, +}[key]||0); +const delay = new FeedbackDelay(1/6, .3).chain(vol(.7), out()); +const delay2 = new FeedbackDelay(1/6, .2).chain(vol(.15), out()); +const chorus = new Chorus(1,2.5,0.5).start(); +// instruments +const instr = (instrument) => ({ + organ: polysynth().set({...osc('sawtooth4'), ...adsr(.01,.2,0)}).chain(mix('chords').connect(delay),out()), + lead: polysynth().set({...osc('triangle4'),...adsr(0.01,.05,0)}).chain(mix('lead').connect(delay2), out()), + bass: polysynth().set({...osc('sawtooth8'),...adsr(.02,.05,.3,.2)}).chain(mix('bass'),lowpass(3000), out()), + pad: polysynth().set({...osc('square2'),...adsr(0.1,.4,0.8)}).chain(vol(0.15),chorus,out()), + hihat: metal(adsr(0, .02, 0)).chain(mix('hihat'), out()), + snare: noise(adsr(0, .15, 0.01)).chain(mix('snare'), lowpass(5000), out()), + kick: membrane().chain(mix('kick'), out()) +}[instrument]); +// harmony +const t = transpose("<0 0 1 0>/8"); +const sowhat = scaleTranspose("0,3,6,9,11"); +// track +stack( + "[<0 4 [3 [2 1]]>]/4".struct("[x]*3").mask("[~ x ~]").scale('D5 dorian').off(1/6, scaleTranspose(-7)).off(1/3, scaleTranspose(-5)).apply(t).tone(instr('lead')).mask("<~ ~ x x>/8"), + "< <[d3 ~] [c3 f3] g3>>".scale('D dorian').apply(sowhat).apply(t).tone(instr('organ')).mask("/8"), + "<[d2 [d2 ~]*3]!3 >".apply(t).tone(instr('bass')), + "c1*6".tone(instr('hihat')), + "~ c3".tone(instr('snare')), + "<[c1@5 c1] >".tone(instr('kick')), + "[2,4]/4".scale('D dorian').apply(t).tone(instr('pad')).mask("/8") +).fast(6/8)`, + // + `// froos - strudel schneckno +samples({ clubkick: 'clubkick/2.wav', sd: ['808sd/SD0010.WAV','808sd/SD0050.WAV'], hh: 'hh/000_hh3closedhh.wav', @@ -103,26 +277,113 @@ stack( s(",[~ ],hh(3,4,2)").n("<0 1 2>").speed(.8), n("<0 1*2 4(3,8) 2>").speed(.6).off(1/8,x=>x.speed(1.2).degradeBy(.5)).s("jvbass") ).reset(">").cutoff(perlin.slow(7).range(100,20000)).webdirt().slow(3/2)`, - `stack( + `stack( // drum pattern by yaxu "24*2 [~ 25]".chunk(4, x => x.sub("12").fast(2)) .tone(membrane().toDestination()), "~ x ~ x".every(2, x => x.fast(2)).iter(4) .tone(noise().toDestination()), "c4*8".add(saw.mul(12).slow(1.5)).degrade(0.05) .tone(metal().set(adsr(0,.06,0,0)).chain(vol(0.5),out())) -) -// by yaxu`, - `"c3 d3 eb3 g3".iter(4).every(3,x=>x.transpose(7)) // TODO: bug when using .every on initial load - .superimpose( - x=>x.late(1/8).transpose(7).color('white'), - x=>x.late(1/4).transpose(12).color('yellow'), - ) - .velocity(rand.range(.5,1)) - .legato(rand.range(.5,2).slow(2)) - .slow(2) - //.degradeBy(.2) - .tone((await piano()).toDestination()) - .pianoroll({minMidi:40,maxMidi:80})`, +)`, + ]} +/> + + + +## How it started + +![strudel port quote](https://loophole-letters.vercel.app/img/strudel-port.png) + +
+ +- Started by Alex McLean, based on a port of a port of a rewrite of Tidal +- I implemented the REPL +- Help from Tidal Community Members +- Started with Tone.js, then added Web MIDI, OSC and Web Audio API outputs +- Inspired by: Tidal Vortex, Gibber, Estuary, Hydra, WAGS and Feedforward. + +
+ +
+ +## REPL = Read Eval Play Loop + +
+ +1. Read: User code is parsed, syntax sugar is dissolved +2. Eval: Transformed code is evaluated, creating a **Pattern** +3. Play: The **Pattern** is queried for events, which trigger sounds and effects +4. Loop: The new output is fed back into the ears of the human, informing the next move + +
+ +
+ +## Mini Notation + +
+ +- Embedded Domain Specific Language +- PEG.js grammar based on krill by Marc Resibois +- \* \[\] ~ , / <\> ! @ \(\) + +
+ +\` + .legato(.95), + // sub melody + \`< + [~ g4]!2 [~ ab4]!2 [~ a4]!2 [~ bb4]!2 + [~ a4]!2 [~ g4]!2 [d4 e4] [f4 gb4] ~!2 + [~ g4]!2 [~ ab4]!2 [~ a4]!2 [~ bb4]!2 + [~ a4]!2 [~ g4]!2 [d4 e4] [f4 gb4] ~!2 + [~ c5]!4 [~ a4]!2 [[c4 ~] [d4 ~]] [[eb4 ~] [e4 ~]] + [~ c5]!4 [~ eb5]!2 [g4*2 [f4 ~]] [[e4 ~] [d4 ~]] + >\`, + // bass + \`< + c3!7 a3 f3!2 + e3!2 ~!4 + c3!7 a3 f3!2 + e3!2 ~!4 + f3!2 e3!2 d3!2 ~!2 + f3!2 e3!2 ab3!2 ~!2 + >\` + .legato(.5) +).fast(2).pianoroll({fold:1,cycles:8,overscan:8})`, ]} /> @@ -150,58 +411,6 @@ s("hh").struct("x!3 ~ x!2 ~ x ~ x!2 ~").speed(.8)
-## Polyrhythms vs Polyphony - - - -## About Me - -
- -- 💻 Studied Computer Science and Media, working as a software developer by day -- 🎺 Trumpet Player, studied Jazz and Popular Music -- 🎤 Dilettante Music Producer of all kinds of genres -- 💿 ocassionally publishes music with Lui Mafuta & Puste -- 🔌 Modular Synth & Electronics Lover, Dilettante DJ .. -- 💌 Coding Blog: [Loophole Letters](https://loophole-letters.vercel.app/) -- ✨ Started live coding music not too long ago - -
- - {/* */} - - - - - {/* */} - {/* - */} -
- -
- -
- - -## How it started - - - - -## Mini Notation - - - - ## Continuous Signals - - - -## From Haskell to Python to JavaScript - -
- -| Project | Language | Description | -| -------------- | ---------- | --------------------------------- | -| Tidal Cycles | Haskell | original haskell implementation | -| Remake | Haskell | Tidal Cycles rewrite from scratch | -| Tidal Vortex | Python | Port of Remake to Python | -| Strudel Cycles | JavaScript | Port of Vortex to Javascript | - -
-
diff --git a/talk/main.jsx b/talk/main.jsx index 391841d17..d361f1b2e 100644 --- a/talk/main.jsx +++ b/talk/main.jsx @@ -6,7 +6,7 @@ import '@strudel.cycles/react/dist/style.css'; ReactDOM.render( -
+
, diff --git a/talk/public/codeandmusic.png b/talk/public/codeandmusic.png new file mode 100644 index 000000000..a30910d8a Binary files /dev/null and b/talk/public/codeandmusic.png differ