diff --git a/packages/codemirror/codemirror.mjs b/packages/codemirror/codemirror.mjs index acc53f521..4ede65869 100644 --- a/packages/codemirror/codemirror.mjs +++ b/packages/codemirror/codemirror.mjs @@ -270,7 +270,7 @@ export class StrudelMirror { } async exportAudio(begin, end) { await this.repl.evaluate(this.code, false) - this.repl.exportAudio(begin, end); + await this.repl.exportAudio(begin, end); this.repl.scheduler.stop(); } diff --git a/packages/core/repl.mjs b/packages/core/repl.mjs index d0cb1e19f..47527c334 100644 --- a/packages/core/repl.mjs +++ b/packages/core/repl.mjs @@ -91,7 +91,7 @@ export function repl({ const stop = () => scheduler.stop(); const start = () => scheduler.start(); - const exportAudio = (begin, end) => scheduler.exportAudio(begin, end); + const exportAudio = async (begin, end) => await scheduler.exportAudio(begin, end); const pause = () => scheduler.pause(); const toggle = () => scheduler.toggle(); const setCps = (cps) => { diff --git a/packages/webaudio/webaudio.mjs b/packages/webaudio/webaudio.mjs index f9b030fdb..cbc5e791c 100644 --- a/packages/webaudio/webaudio.mjs +++ b/packages/webaudio/webaudio.mjs @@ -63,7 +63,7 @@ export async function renderPatternAudio(pattern, cps, begin, end) { } }) - context.startRendering().then(async (renderedBuffer) => { + return context.startRendering().then(async (renderedBuffer) => { console.log(renderedBuffer) const wavBuffer = audioBufferToWav(renderedBuffer); const blob = new Blob([wavBuffer], { type: 'audio/wav' }); diff --git a/website/src/repl/components/ExportModal.jsx b/website/src/repl/components/ExportModal.jsx new file mode 100644 index 000000000..dd207a47c --- /dev/null +++ b/website/src/repl/components/ExportModal.jsx @@ -0,0 +1,127 @@ +import PlayCircleIcon from '@heroicons/react/20/solid/PlayCircleIcon'; +import cx from '@src/cx.mjs'; +import NumberInput from './NumberInput'; +import { useState } from 'react'; +import { Textbox } from './textbox/Textbox'; +import { setMultiChannelOrbits as setStrudelMultiChannelOrbits, setMaxPolyphony as setStrudelMaxPolyphony } from '@strudel/webaudio'; +function Checkbox({ label, value, onChange, disabled = false }) { + return ( + + ); +} +export default function ExportModal(Props) { + const { started, isEmbedded, handleExport } = Props; + + const [startCycle, setStartCycle] = useState(0) // TODO: make a form? + const [endCycle, setEndCycle] = useState(0) + const [multiChannelOrbits, setMultiChannelOrbits] = useState(true) + const [maxPolyphony, setMaxPolyphony] = useState(1024) + const [exporting, setExporting] = useState(false) + return ( + <> + + + +
+

Start cycle

+ { + let v = parseInt(e.target.value); + console.log(v) + v = isNaN(v) ? 0 : Math.max(1, v); + setStartCycle(v); + }} + onChange={v => { + v = parseInt(v) + setStartCycle(v); + }} + type="number" + placeholder="" + value={startCycle ?? ''} + /> +
+
+

End cycle

+ { + let v = parseInt(e.target.value); + v = isNaN(v) ? Math.max(startCycle + 1, parseInt(v)) : v; + setEndCycle(v); + }} + onChange={(v) => { + v = parseInt(v) + setEndCycle(v); + }} + type="number" + placeholder="" + value={endCycle ?? ''} + /> +
+
+

Maximum polyphony

+ { + let v = parseInt(e.target.value); + v = isNaN(v) ? Math.max(1, parseInt(v)) : v; + setMaxPolyphony(v); + }} + onChange={(v) => { + v = Math.max(1, parseInt(v)); + setMaxPolyphony(v); + }} + type="number" + placeholder="" + value={maxPolyphony ?? ''} + /> +
+
+ { + const val = cbEvent.target.checked; + setMultiChannelOrbits(val) + }} + value={multiChannelOrbits} + /> +
+ +
+ + ); +} diff --git a/website/src/repl/components/Header.jsx b/website/src/repl/components/Header.jsx index 91e942d39..d5d8b5f75 100644 --- a/website/src/repl/components/Header.jsx +++ b/website/src/repl/components/Header.jsx @@ -3,6 +3,7 @@ import StopCircleIcon from '@heroicons/react/20/solid/StopCircleIcon'; import cx from '@src/cx.mjs'; import { useSettings, setIsZen } from '../../settings.mjs'; import '../Repl.css'; +import ExportModal from './ExportModal'; const { BASE_URL } = import.meta.env; const baseNoTrailing = BASE_URL.endsWith('/') ? BASE_URL.slice(0, -1) : BASE_URL; @@ -93,18 +94,7 @@ export function Header({ context, embedded = false }) { > {!isEmbedded && update} - + {/* !isEmbedded && (