support multiple repls on same page
This commit is contained in:
parent
3f051cdd8d
commit
a05757f8d6
4 changed files with 36 additions and 4 deletions
|
|
@ -9,3 +9,7 @@ hello!!!!
|
||||||
blablalba
|
blablalba
|
||||||
|
|
||||||
<MiniRepl tune="C3.m" />
|
<MiniRepl tune="C3.m" />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<MiniRepl tune="'C3 G3'.m" />
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
import { useEffect, useRef, useState } from 'react';
|
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import type { ToneEventCallback } from 'tone';
|
import type { ToneEventCallback } from 'tone';
|
||||||
import * as Tone from 'tone';
|
import * as Tone from 'tone';
|
||||||
import { TimeSpan } from '../../strudel.mjs';
|
import { TimeSpan } from '../../strudel.mjs';
|
||||||
import type { Hap } from './types';
|
import type { Hap } from './types';
|
||||||
|
import usePostMessage from './usePostMessage';
|
||||||
|
|
||||||
export declare interface UseCycleProps {
|
export declare interface UseCycleProps {
|
||||||
onEvent: ToneEventCallback<any>;
|
onEvent: ToneEventCallback<any>;
|
||||||
|
|
@ -61,7 +62,6 @@ function useCycle(props: UseCycleProps) {
|
||||||
}, [onEvent, onSchedule, onQuery, ready]);
|
}, [onEvent, onSchedule, onQuery, ready]);
|
||||||
|
|
||||||
const start = async () => {
|
const start = async () => {
|
||||||
console.log('start');
|
|
||||||
setStarted(true);
|
setStarted(true);
|
||||||
await Tone.start();
|
await Tone.start();
|
||||||
Tone.Transport.start('+0.1');
|
Tone.Transport.start('+0.1');
|
||||||
|
|
@ -72,7 +72,7 @@ function useCycle(props: UseCycleProps) {
|
||||||
Tone.Transport.pause();
|
Tone.Transport.pause();
|
||||||
};
|
};
|
||||||
const toggle = () => (started ? stop() : start());
|
const toggle = () => (started ? stop() : start());
|
||||||
return { start, stop, onEvent, started, toggle, query, activeCycle };
|
return { start, stop, setStarted, onEvent, started, toggle, query, activeCycle };
|
||||||
}
|
}
|
||||||
|
|
||||||
export default useCycle;
|
export default useCycle;
|
||||||
|
|
|
||||||
11
repl/src/usePostMessage.ts
Normal file
11
repl/src/usePostMessage.ts
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
|
function usePostMessage(listener) {
|
||||||
|
useEffect(() => {
|
||||||
|
window.addEventListener('message', listener);
|
||||||
|
return () => window.removeEventListener('message', listener);
|
||||||
|
}, [listener]);
|
||||||
|
return (data) => window.postMessage(data, '*');
|
||||||
|
}
|
||||||
|
|
||||||
|
export default usePostMessage;
|
||||||
|
|
@ -1,11 +1,19 @@
|
||||||
import { useCallback, useLayoutEffect, useRef, useState } from 'react';
|
import { useCallback, useLayoutEffect, useState, useMemo, useEffect } from 'react';
|
||||||
import { isNote } from 'tone';
|
import { isNote } from 'tone';
|
||||||
import { evaluate } from './evaluate';
|
import { evaluate } from './evaluate';
|
||||||
import { useWebMidi } from './midi';
|
import { useWebMidi } from './midi';
|
||||||
import type { Pattern } from './types';
|
import type { Pattern } from './types';
|
||||||
import useCycle from './useCycle';
|
import useCycle from './useCycle';
|
||||||
|
import usePostMessage from './usePostMessage';
|
||||||
|
|
||||||
|
let s4 = () => {
|
||||||
|
return Math.floor((1 + Math.random()) * 0x10000)
|
||||||
|
.toString(16)
|
||||||
|
.substring(1);
|
||||||
|
};
|
||||||
|
|
||||||
function useRepl({ tune, defaultSynth }) {
|
function useRepl({ tune, defaultSynth }) {
|
||||||
|
const id = useMemo(() => s4(), []);
|
||||||
const [code, setCode] = useState<string>(tune);
|
const [code, setCode] = useState<string>(tune);
|
||||||
const [activeCode, setActiveCode] = useState<string>();
|
const [activeCode, setActiveCode] = useState<string>();
|
||||||
const [log, setLog] = useState('');
|
const [log, setLog] = useState('');
|
||||||
|
|
@ -14,6 +22,7 @@ function useRepl({ tune, defaultSynth }) {
|
||||||
const dirty = code !== activeCode;
|
const dirty = code !== activeCode;
|
||||||
const activateCode = (_code = code) => {
|
const activateCode = (_code = code) => {
|
||||||
!cycle.started && cycle.start();
|
!cycle.started && cycle.start();
|
||||||
|
broadcast({ type: 'start', from: id });
|
||||||
if (activeCode && !dirty) {
|
if (activeCode && !dirty) {
|
||||||
setError(undefined);
|
setError(undefined);
|
||||||
return;
|
return;
|
||||||
|
|
@ -76,6 +85,14 @@ function useRepl({ tune, defaultSynth }) {
|
||||||
ready: !!pattern,
|
ready: !!pattern,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const broadcast = usePostMessage(({ data: { from, type } }) => {
|
||||||
|
if (type === 'start' && from !== id) {
|
||||||
|
// console.log('message', from, type);
|
||||||
|
cycle.setStarted(false);
|
||||||
|
setActiveCode(undefined);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// set active pattern on ctrl+enter
|
// set active pattern on ctrl+enter
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
const handleKeyPress = (e: any) => {
|
const handleKeyPress = (e: any) => {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue