merge evaluator and scheduler hooks + use getTime
This commit is contained in:
parent
2172d1a767
commit
9497c99e9e
4 changed files with 57 additions and 63 deletions
|
|
@ -2,10 +2,9 @@ import controls from '@strudel.cycles/core/controls.mjs';
|
||||||
import { evalScope } from '@strudel.cycles/eval';
|
import { evalScope } from '@strudel.cycles/eval';
|
||||||
import { getAudioContext, panic, webaudioOutput } from '@strudel.cycles/webaudio';
|
import { getAudioContext, panic, webaudioOutput } from '@strudel.cycles/webaudio';
|
||||||
import { useCallback, useState } from 'react';
|
import { useCallback, useState } from 'react';
|
||||||
import useScheduler from '../../../src/hooks/useScheduler';
|
|
||||||
import useEvaluator from '../../../src/hooks/useEvaluator';
|
|
||||||
import useKeydown from '../../../src/hooks/useKeydown.mjs';
|
|
||||||
import CodeMirror, { flash } from '../../../src/components/CodeMirror6';
|
import CodeMirror, { flash } from '../../../src/components/CodeMirror6';
|
||||||
|
import useKeydown from '../../../src/hooks/useKeydown.mjs';
|
||||||
|
import useStrudel from '../../../src/hooks/useStrudel';
|
||||||
import './style.css';
|
import './style.css';
|
||||||
// import { prebake } from '../../../../../repl/src/prebake.mjs';
|
// import { prebake } from '../../../../../repl/src/prebake.mjs';
|
||||||
|
|
||||||
|
|
@ -63,16 +62,21 @@ stack(
|
||||||
.echoWith(4,.125,(x,n)=>x.gain(.15*1/(n+1))) // echo notes
|
.echoWith(4,.125,(x,n)=>x.gain(.15*1/(n+1))) // echo notes
|
||||||
//.hush()
|
//.hush()
|
||||||
)
|
)
|
||||||
.cps(2/3)`;
|
.fast(2/3)`;
|
||||||
|
|
||||||
// await prebake();
|
// await prebake();
|
||||||
|
|
||||||
|
const ctx = getAudioContext();
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const [code, setCode] = useState(defaultTune);
|
const [code, setCode] = useState(defaultTune);
|
||||||
const { evaluate, pattern, isDirty, error: evaluatorError } = useEvaluator({ code });
|
const { scheduler, evaluate, schedulerError, evalError, isDirty } = useStrudel({
|
||||||
const { scheduler, error: schedulerError } = useScheduler(pattern, webaudioOutput);
|
code,
|
||||||
|
defaultOutput: webaudioOutput,
|
||||||
|
getTime: () => ctx.currentTime,
|
||||||
|
});
|
||||||
const [view, setView] = useState();
|
const [view, setView] = useState();
|
||||||
const error = evaluatorError || schedulerError;
|
const error = evalError || schedulerError;
|
||||||
useKeydown(
|
useKeydown(
|
||||||
useCallback(
|
useCallback(
|
||||||
(e) => {
|
(e) => {
|
||||||
|
|
@ -105,8 +109,8 @@ function App() {
|
||||||
<nav className="z-[12] w-full flex justify-center absolute bottom-0">
|
<nav className="z-[12] w-full flex justify-center absolute bottom-0">
|
||||||
<div className="bg-slate-500 space-x-2 px-2 rounded-t-md">
|
<div className="bg-slate-500 space-x-2 px-2 rounded-t-md">
|
||||||
<button
|
<button
|
||||||
onClick={() => {
|
onClick={async () => {
|
||||||
getAudioContext().resume();
|
await getAudioContext().resume();
|
||||||
scheduler.start();
|
scheduler.start();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
import { useRef, useState, useCallback, useEffect } from 'react';
|
|
||||||
import { evaluate as _evaluate } from '@strudel.cycles/eval';
|
|
||||||
|
|
||||||
function useEvaluator({ code, evalOnMount = true }) {
|
|
||||||
const [error, setError] = useState();
|
|
||||||
const [activeCode, setActiveCode] = useState(code);
|
|
||||||
const [pattern, setPattern] = useState();
|
|
||||||
const isDirty = code !== activeCode;
|
|
||||||
|
|
||||||
const evaluate = useCallback(async () => {
|
|
||||||
if (!code) {
|
|
||||||
console.log('no code..');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
// TODO: let user inject custom eval function?
|
|
||||||
const { pattern: _pattern } = await _evaluate(code);
|
|
||||||
setActiveCode(code);
|
|
||||||
setPattern(_pattern);
|
|
||||||
setError();
|
|
||||||
} catch (err) {
|
|
||||||
setError(err);
|
|
||||||
console.warn('eval error', err);
|
|
||||||
}
|
|
||||||
}, [code, scheduler]);
|
|
||||||
const inited = useRef();
|
|
||||||
useEffect(() => {
|
|
||||||
if (!inited.current && evalOnMount) {
|
|
||||||
inited.current = true;
|
|
||||||
evaluate();
|
|
||||||
}
|
|
||||||
}, [evaluate, evalOnMount]);
|
|
||||||
return { error, evaluate, activeCode, pattern, isDirty };
|
|
||||||
}
|
|
||||||
|
|
||||||
export default useEvaluator;
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
import { Scheduler } from '@strudel.cycles/core';
|
|
||||||
import { useEffect, useMemo, useState } from 'react';
|
|
||||||
|
|
||||||
function useScheduler(pattern, defaultOutput, interval = 0.1) {
|
|
||||||
const [error, setError] = useState();
|
|
||||||
// TODO: how / when to remove schedulerError?
|
|
||||||
const scheduler = useMemo(
|
|
||||||
() => new Scheduler({ interval, onTrigger: defaultOutput, onError: setError }),
|
|
||||||
[defaultOutput, interval],
|
|
||||||
);
|
|
||||||
useEffect(() => {
|
|
||||||
// console.log('pattern', pattern);
|
|
||||||
pattern && scheduler?.setPattern(pattern);
|
|
||||||
}, [pattern, scheduler]);
|
|
||||||
return { error, scheduler };
|
|
||||||
}
|
|
||||||
|
|
||||||
export default useScheduler;
|
|
||||||
44
packages/react/src/hooks/useStrudel.mjs
Normal file
44
packages/react/src/hooks/useStrudel.mjs
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
import { Scheduler } from '@strudel.cycles/core';
|
||||||
|
import { useRef, useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
|
import { evaluate as _evaluate } from '@strudel.cycles/eval';
|
||||||
|
|
||||||
|
function useStrudel({ defaultOutput, interval, getTime, code, evalOnMount = true }) {
|
||||||
|
// scheduler
|
||||||
|
const [schedulerError, setSchedulerError] = useState();
|
||||||
|
const [evalError, setEvalError] = useState();
|
||||||
|
const [activeCode, setActiveCode] = useState(code);
|
||||||
|
const isDirty = code !== activeCode;
|
||||||
|
// TODO: how / when to remove schedulerError?
|
||||||
|
const scheduler = useMemo(
|
||||||
|
() => new Scheduler({ interval, onTrigger: defaultOutput, onError: setSchedulerError, getTime }),
|
||||||
|
[defaultOutput, interval],
|
||||||
|
);
|
||||||
|
const evaluate = useCallback(async () => {
|
||||||
|
if (!code) {
|
||||||
|
console.log('no code..');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
// TODO: let user inject custom eval function?
|
||||||
|
const { pattern } = await _evaluate(code);
|
||||||
|
setActiveCode(code);
|
||||||
|
scheduler?.setPattern(pattern);
|
||||||
|
setEvalError();
|
||||||
|
} catch (err) {
|
||||||
|
setEvalError(err);
|
||||||
|
console.warn('eval error', err);
|
||||||
|
}
|
||||||
|
}, [code, scheduler]);
|
||||||
|
|
||||||
|
const inited = useRef();
|
||||||
|
useEffect(() => {
|
||||||
|
if (!inited.current && evalOnMount) {
|
||||||
|
inited.current = true;
|
||||||
|
evaluate();
|
||||||
|
}
|
||||||
|
}, [evaluate, evalOnMount]);
|
||||||
|
|
||||||
|
return { schedulerError, scheduler, evalError, evaluate, activeCode, isDirty };
|
||||||
|
}
|
||||||
|
|
||||||
|
export default useStrudel;
|
||||||
Loading…
Add table
Add a link
Reference in a new issue