Better architectural distinction between live coding mode and composition mode
This commit is contained in:
@ -10,11 +10,11 @@
|
||||
import Spectrogram from './lib/components/audio/Spectrogram.svelte';
|
||||
import ConfirmDialog from './lib/components/ui/ConfirmDialog.svelte';
|
||||
import InputDialog from './lib/components/ui/InputDialog.svelte';
|
||||
import { createCsoundDerivedStores, type LogEntry } from './lib/csound';
|
||||
import TemplateDialog from './lib/components/ui/TemplateDialog.svelte';
|
||||
import { createCsoundDerivedStores, type LogEntry, type EvalSource } from './lib/csound';
|
||||
import { type CsoundProject } from './lib/project-system';
|
||||
import { DEFAULT_CSOUND_TEMPLATE, LIVECODING_TEMPLATE } from './lib/config/templates';
|
||||
import { templateRegistry, type CsoundTemplate } from './lib/templates/template-registry';
|
||||
import { createAppContext, setAppContext } from './lib/contexts/app-context';
|
||||
import { createExecutionStrategy, type ExecutionStrategy } from './lib/csound/execution-strategies';
|
||||
import type { ProjectMode } from './lib/project-system/types';
|
||||
import {
|
||||
PanelLeftClose,
|
||||
@ -32,13 +32,11 @@
|
||||
const appContext = createAppContext();
|
||||
setAppContext(appContext);
|
||||
|
||||
const { csound, projectManager, editorSettings, projectEditor, uiState } = appContext;
|
||||
const { csound, projectManager, editorSettings, projectEditor, uiState, executionContext } = appContext;
|
||||
const csoundDerived = createCsoundDerivedStores(csound);
|
||||
|
||||
let analyserNode = $state<AnalyserNode | null>(null);
|
||||
let interpreterLogs = $state<LogEntry[]>([]);
|
||||
let currentStrategy = $state<ExecutionStrategy | null>(null);
|
||||
let currentMode = $state<ProjectMode>('composition');
|
||||
|
||||
let logsUnsubscribe: (() => void) | undefined;
|
||||
|
||||
@ -47,12 +45,16 @@
|
||||
|
||||
const result = await projectManager.getAllProjects();
|
||||
if (result.success && result.data.length === 0) {
|
||||
await projectManager.createProject({
|
||||
title: 'Template',
|
||||
author: 'System',
|
||||
content: DEFAULT_CSOUND_TEMPLATE,
|
||||
tags: []
|
||||
});
|
||||
const classicTemplate = templateRegistry.getById('classic');
|
||||
if (classicTemplate) {
|
||||
await projectManager.createProject({
|
||||
title: 'Welcome',
|
||||
author: 'System',
|
||||
content: classicTemplate.content,
|
||||
tags: [],
|
||||
mode: classicTemplate.mode
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
logsUnsubscribe = csoundDerived.logs.subscribe(logs => {
|
||||
@ -78,9 +80,10 @@
|
||||
projectEditor.setContent(value);
|
||||
}
|
||||
|
||||
function handleNewFile() {
|
||||
function handleNewEmptyFile() {
|
||||
const emptyTemplate = templateRegistry.getEmpty();
|
||||
const result = projectEditor.requestSwitch(
|
||||
() => projectEditor.createNew(DEFAULT_CSOUND_TEMPLATE)
|
||||
() => projectEditor.createNew(emptyTemplate.content)
|
||||
);
|
||||
|
||||
if (result === 'confirm-unsaved') {
|
||||
@ -88,9 +91,15 @@
|
||||
}
|
||||
}
|
||||
|
||||
function handleNewLiveCodingFile() {
|
||||
function handleNewFromTemplate() {
|
||||
uiState.showTemplateDialog();
|
||||
}
|
||||
|
||||
function handleTemplateSelect(template: CsoundTemplate) {
|
||||
uiState.hideTemplateDialog();
|
||||
|
||||
const result = projectEditor.requestSwitch(
|
||||
() => projectEditor.createNew(LIVECODING_TEMPLATE)
|
||||
() => projectEditor.createNew(template.content)
|
||||
);
|
||||
|
||||
if (result === 'confirm-unsaved') {
|
||||
@ -110,14 +119,9 @@
|
||||
}
|
||||
}
|
||||
|
||||
async function handleExecute(code: string, source: 'selection' | 'block' | 'document') {
|
||||
async function handleExecute(code: string, source: EvalSource) {
|
||||
try {
|
||||
if (!currentStrategy) {
|
||||
currentStrategy = createExecutionStrategy(currentMode);
|
||||
}
|
||||
|
||||
const fullContent = projectEditor.content;
|
||||
await currentStrategy.execute(csound, code, fullContent, source);
|
||||
await executionContext.execute(code, source);
|
||||
} catch (error) {
|
||||
console.error('Execution error:', error);
|
||||
}
|
||||
@ -189,28 +193,16 @@
|
||||
|
||||
$effect(() => {
|
||||
const mode = projectEditor.currentProject?.mode || 'composition';
|
||||
const projectId = projectEditor.currentProjectId;
|
||||
|
||||
if (mode !== currentMode) {
|
||||
const oldMode = currentMode;
|
||||
currentMode = mode;
|
||||
if (mode !== executionContext.mode) {
|
||||
executionContext.switchMode(mode).catch(console.error);
|
||||
}
|
||||
|
||||
// IMPORTANT: Only create new strategy if mode actually changed
|
||||
// Reset the old strategy if switching away from livecoding
|
||||
if (oldMode === 'livecoding' && currentStrategy) {
|
||||
const liveCodingStrategy = currentStrategy as any;
|
||||
if (liveCodingStrategy.reset) {
|
||||
liveCodingStrategy.reset();
|
||||
}
|
||||
}
|
||||
executionContext.setContentProvider(() => projectEditor.content);
|
||||
|
||||
currentStrategy = createExecutionStrategy(mode);
|
||||
|
||||
if (mode === 'livecoding' && oldMode === 'composition') {
|
||||
console.log('Switched to live coding mode');
|
||||
} else if (mode === 'composition' && oldMode === 'livecoding') {
|
||||
csound.stop().catch(console.error);
|
||||
console.log('Switched to composition mode');
|
||||
}
|
||||
if (projectId) {
|
||||
executionContext.startSession(projectId).catch(console.error);
|
||||
}
|
||||
});
|
||||
|
||||
@ -236,8 +228,8 @@
|
||||
<FileBrowser
|
||||
{projectManager}
|
||||
onFileSelect={handleFileSelect}
|
||||
onNewFile={handleNewFile}
|
||||
onNewLiveCodingFile={handleNewLiveCodingFile}
|
||||
onNewEmptyFile={handleNewEmptyFile}
|
||||
onNewFromTemplate={handleNewFromTemplate}
|
||||
onMetadataUpdate={handleMetadataUpdate}
|
||||
selectedProjectId={projectEditor.currentProjectId}
|
||||
/>
|
||||
@ -325,7 +317,6 @@
|
||||
onExecute={handleExecute}
|
||||
logs={interpreterLogs}
|
||||
{editorSettings}
|
||||
mode={currentMode}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@ -448,6 +439,12 @@
|
||||
placeholder="Untitled"
|
||||
onConfirm={handleSaveAs}
|
||||
/>
|
||||
|
||||
<TemplateDialog
|
||||
bind:visible={uiState.templateDialogVisible}
|
||||
onSelect={handleTemplateSelect}
|
||||
onCancel={() => uiState.hideTemplateDialog()}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
||||
Reference in New Issue
Block a user