Fix worklets not loading

This commit is contained in:
Nikita 2025-10-19 19:44:53 +03:00
parent 920776fdfe
commit 908c0e44ff
6 changed files with 28 additions and 23 deletions

View file

@ -269,8 +269,10 @@ export class StrudelMirror {
await this.repl.evaluate(this.code); await this.repl.evaluate(this.code);
} }
async exportAudio(begin, end) { async exportAudio(begin, end) {
// await this.repl.evaluate(this.code, false) await this.repl.evaluate(this.code, false)
this.repl.exportAudio(begin, end); this.repl.exportAudio(begin, end);
this.repl.scheduler.stop();
} }
async stop() { async stop() {
this.repl.scheduler.stop(); this.repl.scheduler.stop();

View file

@ -348,7 +348,7 @@ export function applyFM(param, value, begin) {
duration, duration,
} = value; } = value;
let modulator; let modulator;
let stop = () => {}; let stop = () => { };
if (fmModulationIndex) { if (fmModulationIndex) {
const ac = getAudioContext(); const ac = getAudioContext();

View file

@ -208,11 +208,11 @@ export function registerWorklet(url) {
} }
let workletsLoading; let workletsLoading;
function loadWorklets() { export function loadWorklets() {
if (!workletsLoading) { if (!workletsLoading) {
const audioCtx = getAudioContext(); const audioCtx = getAudioContext();
const allWorkletURLs = externalWorklets.concat([workletsUrl]); const allWorkletURLs = externalWorklets.concat([workletsUrl]);
workletsLoading = Promise.all(allWorkletURLs.map((workletURL) => audioCtx.audioWorklet.addModule(workletURL))); workletsLoading = Promise.all(allWorkletURLs.map((workletURL) => audioCtx.audioWorklet.addModule(workletURL))).then(() => workletsLoading = undefined);
} }
return workletsLoading; return workletsLoading;

View file

@ -5,9 +5,10 @@ This program is free software: you can redistribute it and/or modify it under th
*/ */
import * as strudel from '@strudel/core'; import * as strudel from '@strudel/core';
import { superdough, getAudioContext, setLogger, doughTrigger, registerWorklet, setAudioContext, getSampleBufferSource, loadBuffer, getSampleInfo, getSound, initAudio, setSuperdoughAudioController } from 'superdough'; import { superdough, getAudioContext, setLogger, doughTrigger, registerWorklet, setAudioContext, getSampleBufferSource, loadBuffer, getSampleInfo, getSound, initAudio, setSuperdoughAudioController, loadWorklets, setMaxPolyphony, setMultiChannelOrbits } from 'superdough';
import './supradough.mjs'; import './supradough.mjs';
import { workletUrl } from 'supradough'; import { workletUrl } from 'supradough';
import { SuperdoughAudioController } from 'superdough/superdoughoutput.mjs';
registerWorklet(workletUrl); registerWorklet(workletUrl);
@ -27,16 +28,16 @@ export const webaudioOutput = (hap, _deadline, hapDuration, cps, t) => {
}; };
export async function renderPatternAudio(pattern, cps, begin, end) { export async function renderPatternAudio(pattern, cps, begin, end) {
const oldAudioCtx = getAudioContext()
await oldAudioCtx.close()
let audioContext = new OfflineAudioContext(2, (end - begin) / cps * 48000, 48000); let audioContext = new OfflineAudioContext(2, (end - begin) / cps * 48000, 48000);
setAudioContext(audioContext) setAudioContext(audioContext)
setSuperdoughAudioController(null) let context = getAudioContext()
await initAudio({ setSuperdoughAudioController(new SuperdoughAudioController(context))
maxPolyphony: 1024, setMaxPolyphony(1024)
multiChannelOrbits: true setMultiChannelOrbits(true)
await loadWorklets()
})
logger('[webaudio] start rendering'); logger('[webaudio] start rendering');
console.log(audioContext)
let haps = pattern.queryArc(begin, end, { _cps: cps }) let haps = pattern.queryArc(begin, end, { _cps: cps })
Promise.all(haps.map(async h => { Promise.all(haps.map(async h => {
@ -48,11 +49,11 @@ export async function renderPatternAudio(pattern, cps, begin, end) {
else { else {
s = h.value.s s = h.value.s
} }
} let bank = getSound(s).data.samples
let bank = getSound(s).data.samples if (bank) {
if (bank) { let { url: sampleUrl, label } = getSampleInfo(h.value, bank);
let { url: sampleUrl, label } = getSampleInfo(h.value, bank); await loadBuffer(sampleUrl, context, label)
await loadBuffer(sampleUrl, audioContext, label) }
} }
})) }))
haps.forEach(async (hap) => { haps.forEach(async (hap) => {
@ -62,9 +63,8 @@ export async function renderPatternAudio(pattern, cps, begin, end) {
} }
}) })
let context = getAudioContext() context.startRendering().then(async (renderedBuffer) => {
context.startRendering().then((renderedBuffer) => { console.log(renderedBuffer)
// console.log(renderedBuffer)
const wavBuffer = audioBufferToWav(renderedBuffer); const wavBuffer = audioBufferToWav(renderedBuffer);
const blob = new Blob([wavBuffer], { type: 'audio/wav' }); const blob = new Blob([wavBuffer], { type: 'audio/wav' });
let downloadName = '' let downloadName = ''
@ -82,9 +82,10 @@ export async function renderPatternAudio(pattern, cps, begin, end) {
a.click(); a.click();
document.body.removeChild(a); document.body.removeChild(a);
URL.revokeObjectURL(url); URL.revokeObjectURL(url);
await context.close()
setAudioContext(null) setAudioContext(null)
setSuperdoughAudioController(null) setSuperdoughAudioController(null)
initAudio() await initAudio()
}); });
} }

View file

@ -94,11 +94,13 @@ export function Header({ context, embedded = false }) {
{!isEmbedded && <span>update</span>} {!isEmbedded && <span>update</span>}
</button> </button>
<button <button
onClick={() => handleExport(1, 16)} onClick={() => !started && handleExport(0, 16)}
title="export" title="export"
className={cx( className={cx(
'flex items-center space-x-1', 'flex items-center space-x-1',
!isEmbedded ? 'p-2' : 'px-2', !isEmbedded ? 'p-2' : 'px-2',
started ? 'opacity-50' : 'hover:opacity-50',
)} )}
> >
{!isEmbedded && <span>export</span>} {!isEmbedded && <span>export</span>}

View file

@ -114,7 +114,7 @@ export function SettingsTab({ started }) {
isMultiCursorEnabled, isMultiCursorEnabled,
} = useSettings(); } = useSettings();
const shouldAlwaysSync = isUdels(); const shouldAlwaysSync = isUdels();
const canChangeAudioDevice = BaseAudioContext.prototype.setSinkId != null; const canChangeAudioDevice = AudioContext.prototype.setSinkId != null;
return ( return (
<div className="text-foreground p-4 space-y-4 w-full" style={{ fontFamily }}> <div className="text-foreground p-4 space-y-4 w-full" style={{ fontFamily }}>
{canChangeAudioDevice && ( {canChangeAudioDevice && (