import React, { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react'; import logo from './logo.svg'; import * as strudel from '../../strudel.mjs'; import cx from './cx'; import * as Tone from 'tone'; import useCycle from './useCycle'; import type { Hap, Pattern } from './types'; import { tetris } from './tunes'; const { Fraction, TimeSpan } = strudel; const fr = (v: number) => new Fraction(v); const ts = (start: number, end: number) => new TimeSpan(fr(start), fr(end)); const parse = (code: string): Pattern => { const { sequence, pure, reify, slowcat, fastcat, cat, stack, silence } = strudel; // make available to eval return eval(code); }; const synth = new Tone.PolySynth().toDestination(); synth.set({ oscillator: { type: 'triangle' }, envelope: { release: 0.01, }, }); function App() { const [code, setCode] = useState(tetris); const [log, setLog] = useState(''); const logBox = useRef(); const [error, setError] = useState(); const [pattern, setPattern] = useState(); // logs events of cycle const logCycle = (_events: any, cycle: any) => { if (_events.length) { setLog((log) => log + `${log ? '\n\n' : ''}# cycle ${cycle}\n` + _events.map((e: any) => e.show()).join('\n')); } }; // cycle hook to control scheduling const cycle = useCycle({ onEvent: useCallback((time, event) => { // console.log('event', event, time); synth.triggerAttackRelease(event.value, event.duration, time); }, []), onQuery: useCallback( (span) => { try { return pattern?.query(span) || []; } catch (err: any) { setError(err); return []; } }, [pattern] ), onSchedule: useCallback( (_events, cycle) => { // console.log('schedule', _events, cycle); logCycle(_events, cycle); }, [pattern] ), ready: !!pattern, }); // parse pattern when code changes useEffect(() => { try { const _pattern = parse(code); setPattern(_pattern); // cycle.query(cycle.activeCycle()); // reschedule active cycle setError(undefined); } catch (err: any) { setError(err); } }, [code]); // scroll log box to bottom when log changes useLayoutEffect(() => { logBox.current.scrollTop = logBox.current?.scrollHeight; }, [log]); return (
logo

Strudel REPL

{error?.message}