import { controls, evalScope } from '@strudel.cycles/core'; import { CodeMirror, useHighlighting, useKeydown, useStrudel, flash } from '@strudel.cycles/react'; import { getAudioContext, initAudioOnFirstClick, panic, webaudioOutput } from '@strudel.cycles/webaudio'; import { useCallback, useState } from 'react'; import './style.css'; // import { prebake } from '../../../../../repl/src/prebake.mjs'; initAudioOnFirstClick(); // TODO: only import stuff when play is pressed? evalScope( controls, import('@strudel.cycles/core'), import('@strudel.cycles/tonal'), import('@strudel.cycles/mini'), import('@strudel.cycles/xen'), import('@strudel.cycles/webaudio'), import('@strudel.cycles/osc'), ); const defaultTune = `samples({ bd: ['bd/BT0AADA.wav','bd/BT0AAD0.wav','bd/BT0A0DA.wav','bd/BT0A0D3.wav','bd/BT0A0D0.wav','bd/BT0A0A7.wav'], sd: ['sd/rytm-01-classic.wav','sd/rytm-00-hard.wav'], hh: ['hh27/000_hh27closedhh.wav','hh/000_hh3closedhh.wav'], }, 'github:tidalcycles/Dirt-Samples/master/'); stack( s("bd,[~ ],hh*8") // drums .speed(perlin.range(.7,.9)) // random sample speed variation //.hush() ,"" // bassline .off(1/8,x=>x.add(12).degradeBy(.5)) // random octave jumps .add(perlin.range(0,.5)) // random pitch variation .superimpose(add(.05)) // add second, slightly detuned voice .n() // wrap in "n" .decay(.15).sustain(0) // make each note of equal length .s('sawtooth') // waveform .gain(.4) // turn down .cutoff(sine.slow(7).range(300,5000)) // automate cutoff //.hush() ,">".voicings('lefthand') // chords .superimpose(x=>x.add(.04)) // add second, slightly detuned voice .add(perlin.range(0,.5)) // random pitch variation .n() // wrap in "n" .s('square') // waveform .gain(.16) // turn down .cutoff(500) // fixed cutoff .attack(1) // slowly fade in //.hush() ,"a4 c5 ".struct("x(5,8)") .superimpose(x=>x.add(.04)) // add second, slightly detuned voice .add(perlin.range(0,.5)) // random pitch variation .n() // wrap in "n" .decay(.1).sustain(0) // make notes short .s('triangle') // waveform .degradeBy(perlin.range(0,.5)) // randomly controlled random removal :) .echoWith(4,.125,(x,n)=>x.gain(.15*1/(n+1))) // echo notes //.hush() ) .fast(2/3)`; // await prebake(); const ctx = getAudioContext(); const getTime = () => ctx.currentTime; function App() { const [code, setCode] = useState(defaultTune); const [view, setView] = useState(); // const [code, setCode] = useState(`"c3".note().slow(2)`); const { scheduler, evaluate, schedulerError, evalError, isDirty, activeCode, pattern, started } = useStrudel({ code, defaultOutput: webaudioOutput, getTime, }); useHighlighting({ view, pattern, active: started && !activeCode?.includes('strudel disable-highlighting'), getTime: () => scheduler.now(), }); const error = evalError || schedulerError; useKeydown( useCallback( async (e) => { if (e.ctrlKey || e.altKey) { if (e.code === 'Enter') { e.preventDefault(); flash(view); await evaluate(code); if (e.shiftKey) { panic(); scheduler.stop(); scheduler.start(); } if (!scheduler.started) { scheduler.start(); } } else if (e.code === 'Period') { scheduler.stop(); panic(); e.preventDefault(); } } }, [scheduler, evaluate, view], ), ); return (
); } export default App;