Let's fucking go

This commit is contained in:
2025-10-14 23:21:00 +02:00
parent cec7ed8bd4
commit 267323abf2
10 changed files with 994 additions and 45 deletions

View File

@ -3,6 +3,7 @@ import { Csound } from '@csound/browser';
export interface CsoundEngineOptions {
onMessage?: (message: string) => void;
onError?: (error: string) => void;
onPerformanceEnd?: () => void;
}
export class CsoundEngine {
@ -10,6 +11,9 @@ export class CsoundEngine {
private initialized = false;
private running = false;
private options: CsoundEngineOptions;
private scopeNode: AnalyserNode | null = null;
private audioNode: AudioNode | null = null;
private audioContext: AudioContext | null = null;
constructor(options: CsoundEngineOptions = {}) {
this.options = options;
@ -18,26 +22,12 @@ export class CsoundEngine {
async init(): Promise<void> {
if (this.initialized) return;
try {
this.csound = await Csound();
this.csound.on('message', (message: string) => {
this.options.onMessage?.(message);
});
await this.csound.setOption('-odac');
this.initialized = true;
this.log('Csound initialized successfully');
} catch (error) {
const errorMsg = error instanceof Error ? error.message : 'Failed to initialize Csound';
this.error(errorMsg);
throw error;
}
this.initialized = true;
this.log('Csound ready');
}
async evaluateCode(code: string): Promise<void> {
if (!this.initialized || !this.csound) {
if (!this.initialized) {
throw new Error('Csound not initialized. Call init() first.');
}
@ -46,8 +36,29 @@ export class CsoundEngine {
await this.stop();
}
this.log('Resetting Csound...');
await this.csound.reset();
this.scopeNode = null;
this.log('Creating new Csound instance...');
this.csound = await Csound();
this.csound.on('message', (message: string) => {
this.options.onMessage?.(message);
});
this.csound.on('onAudioNodeCreated', (node: AudioNode) => {
this.audioNode = node;
this.audioContext = node.context as AudioContext;
this.log('Audio node created and captured');
});
this.csound.on('realtimePerformanceEnded', async () => {
try {
await this.csound?.cleanup();
} catch {}
this.running = false;
this.log('Performance complete');
this.options.onPerformanceEnd?.();
});
this.log('Setting audio output...');
await this.csound.setOption('-odac');
@ -63,22 +74,28 @@ export class CsoundEngine {
const sco = scoMatch[1].trim();
this.log('Compiling orchestra...');
await this.csound.compileOrc(orc);
const compileResult = await this.csound.compileOrc(orc);
if (compileResult !== 0) {
throw new Error('Failed to compile orchestra');
}
this.log('Reading score...');
await this.csound.readScore(sco);
this.log('Starting...');
this.log('Starting performance...');
this.running = true;
await this.csound.start();
this.log('Performing...');
this.running = true;
await this.csound.perform();
this.setupAnalyser();
this.log('Performance complete');
this.running = false;
} catch (error) {
this.running = false;
if (this.csound) {
try {
await this.csound.cleanup();
} catch {}
}
const errorMsg = error instanceof Error ? error.message : 'Evaluation failed';
this.error(errorMsg);
throw error;
@ -89,8 +106,9 @@ export class CsoundEngine {
if (!this.csound || !this.running) return;
try {
this.log('Stopping...');
await this.csound.stop();
await this.csound.reset();
await this.csound.cleanup();
this.running = false;
this.log('Stopped');
} catch (error) {
@ -107,6 +125,36 @@ export class CsoundEngine {
return this.initialized;
}
getAudioContext(): AudioContext | null {
return this.audioContext;
}
private setupAnalyser(): void {
if (!this.audioNode || !this.audioContext) {
this.log('Warning: Audio node not available yet');
return;
}
try {
this.scopeNode = this.audioContext.createAnalyser();
this.scopeNode.fftSize = 2048;
this.scopeNode.smoothingTimeConstant = 0.3;
this.audioNode.disconnect();
this.audioNode.connect(this.scopeNode);
this.scopeNode.connect(this.audioContext.destination);
this.log('Analyser node created and connected');
} catch (error) {
console.error('Failed to setup analyser:', error);
this.log('Error setting up analyser: ' + error);
}
}
getAnalyserNode(): AnalyserNode | null {
return this.scopeNode;
}
private log(message: string): void {
this.options.onMessage?.(message);
}