Trying to do better but it's hard

This commit is contained in:
2025-10-15 12:42:56 +02:00
parent 1dc9d1114e
commit ea8ecd4b2a
9 changed files with 200 additions and 163 deletions

View File

@ -1,13 +1,10 @@
import { Csound } from '@csound/browser';
export type InstanceMode = 'persistent' | 'ephemeral';
export interface CsoundEngineOptions {
onMessage?: (message: string) => void;
onError?: (error: string) => void;
onPerformanceEnd?: () => void;
onAnalyserNodeCreated?: (node: AnalyserNode) => void;
instanceMode?: InstanceMode;
}
export interface PerformanceMetrics {
@ -30,16 +27,15 @@ export class CsoundEngine {
private scopeNode: AnalyserNode | null = null;
private audioNode: AudioNode | null = null;
private audioContext: AudioContext | null = null;
private instanceMode: InstanceMode;
constructor(options: CsoundEngineOptions = {}) {
this.options = options;
this.instanceMode = options.instanceMode ?? 'ephemeral';
}
async init(): Promise<void> {
if (this.initialized) return;
await this.ensureCsoundInstance();
this.initialized = true;
this.log('Csound ready');
}
@ -49,10 +45,51 @@ export class CsoundEngine {
this.log('Creating Csound instance...');
this.csound = await Csound();
this.setupCallbacks();
await this.csound.setOption('-odac');
}
}
async restart(): Promise<void> {
this.log('Restarting Csound...');
if (this.running) {
await this.stop();
}
if (this.csound) {
try {
await this.csound.reset();
} catch (error) {
this.log('Reset failed, creating new instance...');
await this.cleanupInstance();
await this.ensureCsoundInstance();
}
} else {
await this.ensureCsoundInstance();
}
await this.csound!.setOption('-m0');
await this.csound!.setOption('-odac');
await this.csound!.setOption('-+msg_color=false');
await this.csound!.setOption('--daemon');
const ac = await this.csound!.getAudioContext();
const sampleRate = ac?.sampleRate || 48000;
const header = `sr = ${sampleRate}\nksmps = 32\n0dbfs = 1\nnchnls = 2\nnchnls_i = 1`;
const compileResult = await this.csound!.compileOrc(header);
if (compileResult !== 0) {
throw new Error('Failed to compile base header');
}
await this.csound!.start();
this.compiled = true;
this.running = true;
this.setupAnalyser();
this.log('Csound restarted and ready');
}
private setupCallbacks(): void {
if (!this.csound) return;
@ -78,11 +115,13 @@ export class CsoundEngine {
throw new Error('Csound not initialized. Call init() first.');
}
try {
await this.ensureCsoundInstance();
if (!this.csound) {
throw new Error('No Csound instance available');
}
try {
this.log('Compiling orchestra...');
const result = await this.csound!.compileOrc(orchestra);
const result = await this.csound.compileOrc(orchestra);
if (result !== 0) {
const errorMsg = 'Orchestra compilation failed';
@ -135,7 +174,7 @@ export class CsoundEngine {
await this.csound!.readScore(event);
}
async evaluateCode(code: string, forceNewInstance = false): Promise<void> {
async evaluateCode(code: string): Promise<void> {
if (!this.initialized) {
throw new Error('Csound not initialized. Call init() first.');
}
@ -145,22 +184,10 @@ export class CsoundEngine {
await this.stop();
}
const needsNewInstance = forceNewInstance ||
this.instanceMode === 'ephemeral' ||
!this.csound;
if (needsNewInstance && this.csound) {
this.log('Destroying existing instance...');
await this.cleanupInstance();
} else if (this.csound && this.compiled) {
this.log('Resetting Csound for new performance...');
await this.resetForNewPerformance();
}
await this.restart();
this.scopeNode = null;
await this.ensureCsoundInstance();
const orcMatch = code.match(/<CsInstruments>([\s\S]*?)<\/CsInstruments>/);
const scoMatch = code.match(/<CsScore>([\s\S]*?)<\/CsScore>/);
@ -171,13 +198,12 @@ export class CsoundEngine {
const orc = orcMatch[1].trim();
const sco = scoMatch[1].trim();
const compileResult = await this.compileOrchestra(orc);
if (!compileResult.success) {
throw new Error(compileResult.errorMessage || 'Compilation failed');
}
await this.csound!.compileOrc(orc);
this.compiled = true;
await this.readScore(sco);
await this.startPerformance();
if (sco) {
await this.readScore(sco);
}
} catch (error) {
this.running = false;
@ -298,31 +324,6 @@ export class CsoundEngine {
}
}
async reset(): Promise<void> {
this.log('Resetting Csound...');
await this.stop();
await this.cleanupInstance();
this.compiled = false;
await this.ensureCsoundInstance();
this.log('Reset complete');
}
private async resetForNewPerformance(): Promise<void> {
if (!this.csound) return;
try {
await this.csound.reset();
await this.csound.setOption('-odac');
this.compiled = false;
this.running = false;
this.audioNode = null;
this.audioContext = null;
this.scopeNode = null;
} catch (error) {
this.log('Reset failed, creating new instance...');
await this.cleanupInstance();
}
}
private async cleanupInstance(): Promise<void> {
if (!this.csound) return;