Docs file normalization.

This commit is contained in:
Johannes Findeisen 2026-11-06 15:20:20 +01:00
commit 619c2d0808
46 changed files with 3587 additions and 2579 deletions

View file

@ -1,48 +1,78 @@
# Project Brief: A Modern, Lightweight, energyXT-Inspired DAW
**Document purpose:** This file is the authoritative project brief and implementation guide for an AI coding agent working inside an IDE.
**Document purpose:** This file is the authoritative project brief and
implementation guide for an AI coding agent working inside an IDE.
**Working project name:** `xtc` (temporary; keep the project name configurable and do not hard-code it into public APIs).
**Working project name:** `xtc` (temporary; keep the project name configurable
and do not hard-code it into public APIs).
**Primary goal:** Build a modern, reliable, lightweight digital audio workstation inspired by the workflow and modular philosophy of energyXT. This is a new implementation, not a clone of energyXT's proprietary code or assets.
**Primary goal:** Build a modern, reliable, lightweight digital audio
workstation inspired by the workflow and modular philosophy of energyXT. This is
a new implementation, not a clone of energyXT's proprietary code or assets.
**Architecture decision:** **B — Modular engine first.** The sequencer, instruments, effects, mixers, audio inputs, and outputs are components in one unified processing graph. The default user experience should still be a simple sequencer-first workspace; users can open the modular view when they need to inspect or edit signal flow.
**Architecture decision:** **B — Modular engine first.** The sequencer,
instruments, effects, mixers, audio inputs, and outputs are components in one
unified processing graph. The default user experience should still be a simple
sequencer-first workspace; users can open the modular view when they need to
inspect or edit signal flow.
**Language decision:**
- **100% C for the audio engine and core domain logic.**
- **FLTK with C++ for the graphical user interface only.**
- The GUI talks to the core through a small, documented C API.
- Do not introduce C++ into the audio engine or core library.
- Keep dependencies small, prefer open-source components, and avoid unnecessary frameworks.
- Keep dependencies small, prefer open-source components, and avoid unnecessary
frameworks.
---
## 1. Instructions to the AI coding agent
## 1. Instructions to the AI Coding Agent
Treat this document as the project contract. Follow it in every implementation task.
Treat this document as the project contract. Follow it in every implementation
task.
1. Read this file and the existing project before making changes.
2. Inspect the current build system, source tree, and tests. Do not assume the repository is empty.
3. Implement work in small, buildable increments. Each increment must compile and have relevant tests before proceeding.
4. Prefer complete, coherent file updates over partial snippets. Do not silently remove existing functionality.
5. Before editing, state briefly what you intend to change and which files are affected. Then make the changes.
6. Do not invent APIs, FLTK features, audio backend capabilities, or dependency behavior. Check installed headers and official documentation when uncertain.
7. Keep C source compatible with **C99** initially. Use C11 features only when explicitly justified and supported by the selected compiler/toolchain.
8. Use C snake_case identifiers. Use clear names; avoid cryptic one-letter names except conventional loop counters.
9. Validate external input, lengths, indexes, counts, enum values, and allocation sizes. Handle errors explicitly.
10. Do not hide failures, silently clamp invalid data, or continue with partially initialized objects.
11. Avoid unnecessary dependencies, generated-code systems, global mutable state, and elaborate abstractions.
12. Never perform audio-thread-unsafe operations from the real-time callback. See the real-time rules below.
13. Keep the project usable on Linux first. Do not make Linux-specific details leak into the public core API.
2. Inspect the current build system, source tree, and tests. Do not assume the
repository is empty.
3. Implement work in small, buildable increments. Each increment must compile
and have relevant tests before proceeding.
4. Prefer complete, coherent file updates over partial snippets. Do not silently
remove existing functionality.
5. Before editing, state briefly what you intend to change and which files are
affected. Then make the changes.
6. Do not invent APIs, FLTK features, audio backend capabilities, or dependency
behavior. Check installed headers and official documentation when uncertain.
7. Keep C source compatible with **C99** initially. Use C11 features only when
explicitly justified and supported by the selected compiler/toolchain.
8. Use C snake_case identifiers. Use clear names; avoid cryptic one-letter names
except conventional loop counters.
9. Validate external input, lengths, indexes, counts, enum values, and
allocation sizes. Handle errors explicitly.
10. Do not hide failures, silently clamp invalid data, or continue with
partially initialized objects.
11. Avoid unnecessary dependencies, generated-code systems, global mutable
state, and elaborate abstractions.
12. Never perform audio-thread-unsafe operations from the real-time callback.
See the real-time rules below.
13. Keep the project usable on Linux first. Do not make Linux-specific details
leak into the public core API.
14. Add or update tests and documentation with each feature.
15. At the end of a task, report: files changed, behavior added, build/test commands run, results, known limitations, and the next sensible step.
16. If a requirement is ambiguous, choose the smallest safe implementation consistent with this document and explain the assumption. Ask a question only if the ambiguity blocks safe progress.
17. Do not claim that a feature works unless it has been implemented and tested. Clearly distinguish a prototype, stub, and finished feature.
18. Never copy energyXT source code, proprietary resources, UI artwork, or undocumented internal implementation. Use energyXT only as inspiration for high-level workflow ideas.
15. At the end of a task, report: files changed, behavior added, build/test
commands run, results, known limitations, and the next sensible step.
16. If a requirement is ambiguous, choose the smallest safe implementation
consistent with this document and explain the assumption. Ask a question
only if the ambiguity blocks safe progress.
17. Do not claim that a feature works unless it has been implemented and tested.
Clearly distinguish a prototype, stub, and finished feature.
18. Never copy energyXT source code, proprietary resources, UI artwork, or
undocumented internal implementation. Use energyXT only as inspiration for
high-level workflow ideas.
### Definition of done for every task
A task is complete only when:
- the code builds with warnings enabled;
- relevant tests pass;
- error paths are considered;
@ -53,16 +83,19 @@ A task is complete only when:
---
## 2. Product principles
## 2. Product Principles
The application should feel like a small, responsive music instrument rather than a general-purpose content-creation suite.
The application should feel like a small, responsive music instrument rather
than a general-purpose content-creation suite.
### Core principles
- **Simple by default, powerful when opened up.**
- A single unified component graph underlies the application.
- The sequencer, mixer, instruments, effects, audio I/O, and utility processors use a common node model.
- Common operations should require few clicks and avoid modal dialogs when practical.
- The sequencer, mixer, instruments, effects, audio I/O, and utility processors
use a common node model.
- Common operations should require few clicks and avoid modal dialogs when
practical.
- The modular graph should expose real signal flow, not be a decorative diagram.
- The project must remain understandable to a human developer.
- Audio reliability is more important than visual effects or feature count.
@ -75,6 +108,7 @@ The application should feel like a small, responsive music instrument rather tha
### Explicit non-goals for the first release
Do not initially implement:
- video, notation, collaboration, cloud accounts, or online services;
- an integrated marketplace;
- scripting as a requirement for basic operation;
@ -86,11 +120,12 @@ Do not initially implement:
- automatic online update services;
- a proprietary project format that cannot be inspected or migrated.
These may be considered later, but they must not delay the first reliable recording and playback workflow.
These may be considered later, but they must not delay the first reliable
recording and playback workflow.
---
## 3. High-level architecture
## 3. High-Level Architecture
Use distinct layers with narrow interfaces.
@ -125,7 +160,9 @@ Use distinct layers with narrow interfaces.
+------------------------------------------------------------+
```
The C core and audio engine may be separate libraries or clearly separated modules within one C library. Keep their interfaces explicit even if they initially compile into one library.
The C core and audio engine may be separate libraries or clearly separated
modules within one C library. Keep their interfaces explicit even if they
initially compile into one library.
### Suggested repository layout
@ -179,13 +216,14 @@ xtc/
└── build/ # generated; do not commit
```
Keep C and C++ files clearly separated. C headers exposed to C++ must use `extern "C"` guards.
Keep C and C++ files clearly separated. C headers exposed to C++ must use
`extern "C"` guards.
---
## 4. Language and API boundary
## 4. Language and API Boundary
### C code owns
### C Code owns
- project and track data;
- graph nodes, ports, and connections;
@ -198,7 +236,7 @@ Keep C and C++ files clearly separated. C headers exposed to C++ must use `exter
- backend-independent engine state;
- error codes and diagnostic messages.
### C++/FLTK code owns
### C++/FLTK Code owns
- windows and widgets;
- layout and drawing;
@ -211,15 +249,19 @@ Keep C and C++ files clearly separated. C headers exposed to C++ must use `exter
### Boundary rules
- Public C headers must compile from both C and C++.
- Do not expose C++ classes, STL containers, exceptions, or FLTK types through the C API.
- Do not expose C++ classes, STL containers, exceptions, or FLTK types through
the C API.
- Prefer opaque handles for objects whose internal layout must remain private.
- Use explicit integer error codes and documented output parameters.
- Define ownership for every pointer: borrowed, caller-owned, or transferred.
- Do not return pointers into mutable engine memory unless their lifetime is guaranteed.
- Do not return pointers into mutable engine memory unless their lifetime is
guaranteed.
- Do not let GUI widgets mutate internal engine structures directly.
- Avoid a public API that mirrors every internal struct field. Provide stable operations instead.
- Avoid a public API that mirrors every internal struct field. Provide stable
operations instead.
Example API shape (illustrative only; refine after reviewing the actual codebase):
Example API shape (illustrative only; refine after reviewing the actual
codebase):
```c
#ifndef XTC_H
@ -254,17 +296,21 @@ xtc_result xtc_transport_stop(xtc_app *app);
#endif
```
Do not implement this exact API blindly if the existing design calls for a better interface. Keep it small and consistent.
Do not implement this exact API blindly if the existing design calls for a
better interface. Keep it small and consistent.
---
## 5. Modular processing graph — primary design decision
## 5. Modular Processing Graph — Primary Design Decision
**Decision B: Modular engine first.** The graph is the common representation of signal processing and routing. The sequencer is a source of time-based events and clips, not a separate audio system disconnected from the graph.
**Decision B: Modular engine first.** The graph is the common representation of
signal processing and routing. The sequencer is a source of time-based events
and clips, not a separate audio system disconnected from the graph.
### Node categories
Start with a small set:
- audio input;
- audio output;
- audio clip player;
@ -277,11 +323,13 @@ Start with a small set:
- metering/analyzer;
- utility nodes such as channel mapping.
Do not build every node at once. First prove the graph with a test tone, gain node, and output node.
Do not build every node at once. First prove the graph with a test tone, gain
node, and output node.
### Ports and connections
Each node has a stable identifier, a node type, and declared ports. A port has:
- a unique identifier within its node;
- a direction (input or output);
- a signal/data type (audio, MIDI/event, or control);
@ -289,6 +337,7 @@ Each node has a stable identifier, a node type, and declared ports. A port has:
- a documented sample/block processing contract.
Validate connections before accepting them:
- source and destination exist;
- source port is an output and destination is an input;
- signal types are compatible;
@ -298,13 +347,18 @@ Validate connections before accepting them:
### Cycles and feedback
For the first working engine, reject cycles in the audio-processing graph. A directed acyclic graph is easier to schedule safely and predictably. Report a useful error to the user. Do not silently break a cycle.
For the first working engine, reject cycles in the audio-processing graph. A
directed acyclic graph is easier to schedule safely and predictably. Report a
useful error to the user. Do not silently break a cycle.
Feedback support can be considered later using explicit delay/feedback nodes and a defined block-boundary model. Never introduce arbitrary graph cycles without a correct scheduling design.
Feedback support can be considered later using explicit delay/feedback nodes and
a defined block-boundary model. Never introduce arbitrary graph cycles without a
correct scheduling design.
### Graph compilation
Compile the editable graph into an execution plan outside the real-time thread:
1. validate nodes, ports, and edges;
2. identify source nodes and reachable output nodes;
3. detect cycles;
@ -313,21 +367,31 @@ Compile the editable graph into an execution plan outside the real-time thread:
6. allocate buffers and prepare node state;
7. publish an immutable, ready-to-run plan.
The audio callback processes the prepared plan. It must not perform graph discovery, sorting, dynamic allocation, file loading, or plugin creation.
The audio callback processes the prepared plan. It must not perform graph
discovery, sorting, dynamic allocation, file loading, or plugin creation.
### Graph replacement during playback
The editor must not modify the graph currently being traversed by the audio thread. Prepare a new plan off-thread and publish it through a bounded real-time-safe mechanism. Define how the old plan is retired only after the audio thread can no longer access it. Do not use a naive pointer swap followed by immediate free.
The editor must not modify the graph currently being traversed by the audio
thread. Prepare a new plan off-thread and publish it through a bounded
real-time-safe mechanism. Define how the old plan is retired only after the
audio thread can no longer access it. Do not use a naive pointer swap followed
by immediate free.
Possible approaches include a carefully designed single-producer/single-consumer handoff, epochs, or another proven reclamation scheme. Choose one, document it, and test it under stress. Keep the initial design as simple as safety allows.
Possible approaches include a carefully designed single-producer/single-consumer
handoff, epochs, or another proven reclamation scheme. Choose one, document it,
and test it under stress. Keep the initial design as simple as safety allows.
### Sequencer integration
The sequencer stores timeline content and emits events to the graph at the correct sample positions. A clip player or instrument node consumes those events. The GUI timeline is a view/editor for project data; it is not the audio scheduler.
The sequencer stores timeline content and emits events to the graph at the
correct sample positions. A clip player or instrument node consumes those
events. The GUI timeline is a view/editor for project data; it is not the audio
scheduler.
---
## 6. Real-time audio requirements
## 6. Real-Time Audio Requirements
These rules are mandatory.
@ -354,54 +418,75 @@ These rules are mandatory.
- process silence safely when a source is unavailable;
- handle backend buffer sizes and channel counts within documented limits.
Do not assume all backends use a fixed block size unless the backend contract guarantees it. Establish maximum supported frame/event counts and define what happens when limits are exceeded.
Do not assume all backends use a fixed block size unless the backend contract
guarantees it. Establish maximum supported frame/event counts and define what
happens when limits are exceeded.
### Thread ownership
Document which thread owns each mutable resource:
- GUI thread: widgets and GUI state;
- control/project thread: editable project state, file operations, graph compilation;
- control/project thread: editable project state, file operations, graph
compilation;
- audio thread: active processing plan and real-time DSP state;
- backend callbacks: follow the backend's documented threading model.
Avoid sharing mutable structs across threads without an explicit synchronization strategy. Atomics are not automatically safe for every use: verify that the selected atomic operations are lock-free where required and use correct memory ordering.
Avoid sharing mutable structs across threads without an explicit synchronization
strategy. Atomics are not automatically safe for every use: verify that the
selected atomic operations are lock-free where required and use correct memory
ordering.
### Timing
Use audio sample position as the authoritative playback clock. Represent timeline positions with an integer or rational scheme that avoids accumulated floating-point drift. Convert musical time (bars/beats/ticks) to sample positions using tempo and meter maps. Define behavior at tempo changes before implementing advanced tempo automation.
Use audio sample position as the authoritative playback clock. Represent
timeline positions with an integer or rational scheme that avoids accumulated
floating-point drift. Convert musical time (bars/beats/ticks) to sample
positions using tempo and meter maps. Define behavior at tempo changes before
implementing advanced tempo automation.
---
## 7. Audio backend strategy
## 7. Audio Backend Strategy
Start on Linux and keep the backend replaceable.
1. Define a small backend interface in C.
2. Implement one backend first, selected after checking the target system and installed development packages. JACK-compatible audio is a reasonable first target on Linux.
3. Test device enumeration, start/stop, sample rate, buffer size, channel count, disconnects, and shutdown.
2. Implement one backend first, selected after checking the target system and
installed development packages. JACK-compatible audio is a reasonable first
target on Linux.
3. Test device enumeration, start/stop, sample rate, buffer size, channel count,
disconnects, and shutdown.
4. Keep backend-specific headers out of the public API.
5. Add another backend only after the engine works and tests pass.
Do not assume PipeWire-native, JACK compatibility, ALSA PCM, and desktop audio routing are interchangeable. Document the chosen backend's setup and limitations.
Do not assume PipeWire-native, JACK compatibility, ALSA PCM, and desktop audio
routing are interchangeable. Document the chosen backend's setup and
limitations.
The engine should also have an offline/test mode that processes buffers without physical audio hardware. This makes unit and integration testing repeatable.
The engine should also have an offline/test mode that processes buffers without
physical audio hardware. This makes unit and integration testing repeatable.
---
## 8. MIDI, parameters, automation, and DSP
## 8. MIDI, Parameters, Automation, and DSP
### MIDI/events
### MIDI/Events
- Use a compact, well-defined event representation.
- Store event time relative to a project timeline and convert it to sample offsets for a processing block.
- Store event time relative to a project timeline and convert it to sample
offsets for a processing block.
- Validate event sizes and event counts.
- Handle note-on, note-off, velocity, channel, controller, pitch bend, and tempo/transport events as needed.
- Ensure all held notes can be released on stop, panic, seek, device loss, or project teardown.
- Handle note-on, note-off, velocity, channel, controller, pitch bend, and
tempo/transport events as needed.
- Ensure all held notes can be released on stop, panic, seek, device loss, or
project teardown.
- Avoid unbounded event queues.
### Parameters
Every automatable control should have:
- a stable parameter ID;
- a type and valid range;
- a default value;
@ -409,85 +494,115 @@ Every automatable control should have:
- a safe update mechanism;
- optional automation and MIDI mapping.
Do not silently clamp invalid serialized values. Validate project data and return an error or apply a clearly documented migration rule. UI controls may constrain user input, but core validation must remain authoritative.
Do not silently clamp invalid serialized values. Validate project data and
return an error or apply a clearly documented migration rule. UI controls may
constrain user input, but core validation must remain authoritative.
### Automation
Implement automation only after transport, graph processing, and basic parameter updates work. Define interpolation types explicitly (initially step and linear are enough). Automation evaluation must be deterministic and bounded.
Implement automation only after transport, graph processing, and basic parameter
updates work. Define interpolation types explicitly (initially step and linear
are enough). Automation evaluation must be deterministic and bounded.
### DSP
Start with a few well-tested processors:
- gain;
- pan;
- simple meter/peak detector;
- test oscillator;
- basic delay only after buffer/lifetime handling is sound.
Keep DSP algorithms in C and independently testable. Use appropriate numerical safeguards, including finite-value checks where needed. Avoid premature SIMD optimization until profiling shows a real bottleneck.
Keep DSP algorithms in C and independently testable. Use appropriate numerical
safeguards, including finite-value checks where needed. Avoid premature SIMD
optimization until profiling shows a real bottleneck.
---
## 9. FLTK/C++ GUI guidelines
## 9. FLTK/C++ GUI Guidelines
The GUI is a thin client of the C API, not the owner of the engine.
### Main views
1. **Sequencer:** tracks, audio/MIDI clips, timeline ruler, playhead, selection, zoom and horizontal scrolling.
2. **Mixer:** channels, faders, pan, mute/solo, inserts/sends when supported, and meters.
3. **Modular graph:** nodes, ports, connections, zoom/pan, selection, and connection validation feedback.
4. **Transport:** play, stop, record, tempo, meter, loop range, and current position.
5. **Project/file dialogs:** create, open, save, import audio, and manage missing assets.
1. **Sequencer:** tracks, audio/MIDI clips, timeline ruler, playhead, selection,
zoom and horizontal scrolling.
2. **Mixer:** channels, faders, pan, mute/solo, inserts/sends when supported,
and meters.
3. **Modular graph:** nodes, ports, connections, zoom/pan, selection, and
connection validation feedback.
4. **Transport:** play, stop, record, tempo, meter, loop range, and current
position.
5. **Project/file dialogs:** create, open, save, import audio, and manage
missing assets.
The default workspace should emphasize the sequencer and transport. The graph view is an advanced but first-class view of the same underlying project.
The default workspace should emphasize the sequencer and transport. The graph
view is an advanced but first-class view of the same underlying project.
### GUI implementation
### GUI Implementation
- Use FLTK for conventional widgets and application windows.
- Use custom-drawn widgets for the timeline, piano roll, mixer strips, waveform display, and graph canvas where needed.
- Use custom-drawn widgets for the timeline, piano roll, mixer strips, waveform
display, and graph canvas where needed.
- Keep drawing code separate from project mutation.
- Use GUI timers or the toolkit's appropriate event mechanism for refreshing meters; never poll from the audio callback or block the GUI waiting for audio.
- Use GUI timers or the toolkit's appropriate event mechanism for refreshing
meters; never poll from the audio callback or block the GUI waiting for audio.
- Avoid redrawing the entire application when only a small region changes.
- Support keyboard shortcuts and predictable focus behavior.
- Make selection, dragging, snapping, zooming, and scrolling consistent across editors.
- Make selection, dragging, snapping, zooming, and scrolling consistent across
editors.
- Never call FLTK APIs from the audio thread.
- Do not hold GUI locks while calling potentially blocking engine operations.
- Keep C++ simple: use RAII for GUI resources, clear ownership, and small classes. Do not force the C core into C++ abstractions.
- Keep C++ simple: use RAII for GUI resources, clear ownership, and small
classes. Do not force the C core into C++ abstractions.
### Visual direction
Aim for a compact, dark, high-contrast interface with restrained decoration. Prioritize legible waveforms, clip boundaries, transport state, and meter levels. Avoid excessive gradients, animations, nested panels, and modal configuration windows.
Aim for a compact, dark, high-contrast interface with restrained decoration.
Prioritize legible waveforms, clip boundaries, transport state, and meter
levels. Avoid excessive gradients, animations, nested panels, and modal
configuration windows.
Do not copy energyXT's artwork, exact visual assets, or proprietary UI resources. Recreate the general principles of compactness, direct manipulation, and modular routing in an original design.
Do not copy energyXT's artwork, exact visual assets, or proprietary UI
resources. Recreate the general principles of compactness, direct manipulation,
and modular routing in an original design.
---
## 10. Project format and persistence
## 10. Project Format and Persistence
The project format must be versioned from its first release.
### Requirements
- Include a format version and application version.
- Store stable IDs for tracks, nodes, ports where necessary, clips, parameters, and connections.
- Store stable IDs for tracks, nodes, ports where necessary, clips, parameters,
and connections.
- Save relative asset paths when possible.
- Define behavior for missing audio files.
- Validate every field before allocating large amounts of memory.
- Handle truncated, malformed, unsupported, or corrupted files gracefully.
- Never execute code while loading a project.
- Save atomically: write a temporary file, flush as appropriate, and rename it into place when safe.
- Preserve unknown optional fields when practical, or explicitly document when they are discarded.
- Save atomically: write a temporary file, flush as appropriate, and rename it
into place when safe.
- Preserve unknown optional fields when practical, or explicitly document when
they are discarded.
- Include migration functions when the format changes.
- Keep project serialization outside the real-time thread.
Choose a simple, well-supported format after considering the dependency and robustness trade-offs. A small, documented text format can help inspect projects, but large binary audio data should generally live in separate assets rather than be embedded in a text document. Do not add a serialization dependency without a clear reason.
Choose a simple, well-supported format after considering the dependency and
robustness trade-offs. A small, documented text format can help inspect
projects, but large binary audio data should generally live in separate assets
rather than be embedded in a text document. Do not add a serialization
dependency without a clear reason.
---
## 11. Undo/redo and editing commands
## 11. Undo/Redo and Editing Commands
Use explicit commands for user-visible edits, such as:
- create/delete/move/resize clip;
- create/delete/rename track;
- change parameter;
@ -495,21 +610,28 @@ Use explicit commands for user-visible edits, such as:
- connect/disconnect ports;
- change tempo or meter.
A command should validate its inputs and have a well-defined inverse or stored previous state. Avoid designing a generic event-sourcing framework before it is needed.
A command should validate its inputs and have a well-defined inverse or stored
previous state. Avoid designing a generic event-sourcing framework before it is
needed.
The initial implementation may begin without a complete undo stack, but design edit operations so undo/redo can be added without rewriting all editors. Never make an edit partially visible if it fails validation.
The initial implementation may begin without a complete undo stack, but design
edit operations so undo/redo can be added without rewriting all editors. Never
make an edit partially visible if it fails validation.
---
## 12. Build, coding standards, and dependencies
## 12. Build, Coding Standards, and Dependencies
### Build system
Use a straightforward Makefile unless the existing repository has a sound reason to use another build system.
Use a straightforward Makefile unless the existing repository has a sound reason
to use another build system.
The build must:
- compile C with the selected C standard and warnings enabled;
- compile C++ GUI sources with the standard supported by the chosen FLTK version;
- compile C++ GUI sources with the standard supported by the chosen FLTK
version;
- link the GUI with FLTK and the C core;
- link the required audio backend;
- provide `all`, `clean`, `test`, and a debug build target;
@ -517,9 +639,11 @@ The build must:
- avoid embedding machine-specific paths;
- separate generated objects and binaries into a build directory.
Use `pkg-config` where supported by the installed dependencies. Check actual package names on the target distribution rather than hard-coding unverified names.
Use `pkg-config` where supported by the installed dependencies. Check actual
package names on the target distribution rather than hard-coding unverified
names.
### C style
### C Style
- Use C99 initially.
- Use `snake_case`.
@ -532,7 +656,7 @@ Use `pkg-config` where supported by the installed dependencies. Check actual pac
- Use `const` where appropriate.
- Do not suppress warnings merely to get a clean build.
### C++ GUI style
### C++ GUI Style
- Keep C++ confined to the GUI and any unavoidable C++-only third-party wrapper.
- Prefer small classes with explicit ownership.
@ -544,21 +668,26 @@ Use `pkg-config` where supported by the installed dependencies. Check actual pac
### Dependencies
Before adding a dependency:
1. identify the exact feature it provides;
2. check license and maintenance status;
3. determine whether the existing code can provide the functionality simply and safely;
3. determine whether the existing code can provide the functionality simply and
safely;
4. document the dependency and its version constraints;
5. keep it optional if the feature is optional.
Prefer open-source dependencies with clear licensing. Do not claim the whole application is license-compatible until all direct and bundled dependencies have been reviewed.
Prefer open-source dependencies with clear licensing. Do not claim the whole
application is license-compatible until all direct and bundled dependencies have
been reviewed.
---
## 13. Testing and diagnostics
## 13. Testing and Diagnostics
### Unit tests
Test at least:
- graph validation and topological sorting;
- invalid ports and incompatible connections;
- cycle detection;
@ -573,6 +702,7 @@ Test at least:
### Integration tests
Test:
- test oscillator → gain → output processing;
- offline rendering with deterministic output;
- graph replacement during active processing;
@ -585,6 +715,7 @@ Test:
### Tools
Where available, use:
- compiler warnings;
- AddressSanitizer and UndefinedBehaviorSanitizer in non-real-time test builds;
- static analysis;
@ -592,25 +723,29 @@ Where available, use:
- stress tests for graph edits and shutdown;
- audio loopback or offline render comparisons.
Sanitizers and diagnostic logging should not be enabled in production real-time callbacks unless their real-time implications have been specifically evaluated.
Sanitizers and diagnostic logging should not be enabled in production real-time
callbacks unless their real-time implications have been specifically evaluated.
---
## 14. Development roadmap and acceptance criteria
## 14. Development Roadmap and Acceptance Criteria
Implement these milestones in order. Do not jump ahead merely because a later feature is exciting.
Implement these milestones in order. Do not jump ahead merely because a later
feature is exciting.
### Repository and design baseline
- Inspect the repository and available toolchain.
- Create or update architecture documentation and the Makefile.
- Verify C compiler, C++ compiler, FLTK, audio development headers, and test tools.
- Verify C compiler, C++ compiler, FLTK, audio development headers, and test
tools.
- Record dependency and licensing decisions.
- Add a minimal application that starts and exits cleanly.
**Acceptance:** clean build on the target Linux environment; no audio engine assumptions hidden in GUI code.
**Acceptance:** clean build on the target Linux environment; no audio engine
assumptions hidden in GUI code.
### C core and offline processing
### C Core and offline processing
- Create the C library/API.
- Define node, port, connection, and graph data structures.
@ -619,7 +754,8 @@ Implement these milestones in order. Do not jump ahead merely because a later fe
- Add oscillator, gain, meter, and output test nodes.
- Implement deterministic offline block processing.
**Acceptance:** automated test proves oscillator → gain → meter/output produces expected samples without hardware.
**Acceptance:** automated test proves oscillator → gain → meter/output produces
expected samples without hardware.
### Real-time backend
@ -629,16 +765,18 @@ Implement these milestones in order. Do not jump ahead merely because a later fe
- Add safe control-to-audio communication.
- Stress-test shutdown and graph replacement.
**Acceptance:** stable playback for a sustained test; no known callback allocations or blocking calls; failures are reported clearly.
**Acceptance:** stable playback for a sustained test; no known callback
allocations or blocking calls; failures are reported clearly.
### FLTK shell
### FLTK Shell
- Create main window, menus, transport, status area, and view switching.
- Call the C API through the public header.
- Add an audio engine status indicator.
- Implement clean startup and shutdown.
**Acceptance:** GUI can start/stop the engine, report backend errors, and close without leaks or hangs.
**Acceptance:** GUI can start/stop the engine, report backend errors, and close
without leaks or hangs.
### Modular graph editor
@ -648,16 +786,19 @@ Implement these milestones in order. Do not jump ahead merely because a later fe
- Display invalid connection feedback.
- Submit graph edits through validated C API commands.
**Acceptance:** graph shown by the GUI matches the graph used by the engine; invalid connections are rejected without corrupting active playback.
**Acceptance:** graph shown by the GUI matches the graph used by the engine;
invalid connections are rejected without corrupting active playback.
### Project and sequencer foundation
- Add project persistence and stable IDs.
- Add tracks and clip objects.
- Implement timeline rendering, selection, moving, trimming, zoom, and scrolling.
- Implement timeline rendering, selection, moving, trimming, zoom, and
scrolling.
- Add transport/sample-position synchronization.
**Acceptance:** save/load a project with clips and reproduce the same arrangement.
**Acceptance:** save/load a project with clips and reproduce the same
arrangement.
### Audio clips and recording
@ -666,16 +807,18 @@ Implement these milestones in order. Do not jump ahead merely because a later fe
- Keep file I/O outside the audio callback.
- Add missing-asset reporting.
**Acceptance:** record, save, reopen, and play a basic audio project without callback file I/O.
**Acceptance:** record, save, reopen, and play a basic audio project without
callback file I/O.
### MIDI and a simple instrument
### MIDI And a simple instrument
- Add MIDI input and clip events.
- Add a basic internal synthesizer or test instrument.
- Handle note-off, panic, seeking, and stop correctly.
- Add a minimal piano-roll editor only after event scheduling works.
**Acceptance:** record or draw MIDI notes, play them in time, save the project, and reopen it.
**Acceptance:** record or draw MIDI notes, play them in time, save the project,
and reopen it.
### Mixer, automation, and editing polish
@ -684,7 +827,8 @@ Implement these milestones in order. Do not jump ahead merely because a later fe
- Add a bounded undo/redo system for common edits.
- Improve keyboard interaction and workflow.
**Acceptance:** basic composition and mixing can be completed without editing project files manually.
**Acceptance:** basic composition and mixing can be completed without editing
project files manually.
### Extensibility and release preparation
@ -693,31 +837,40 @@ Implement these milestones in order. Do not jump ahead merely because a later fe
- Review project format migration, crash behavior, performance, and licensing.
- Package the application and document Linux setup.
**Acceptance:** reproducible release build, tested install/uninstall, clear limitations, and complete user/developer documentation.
**Acceptance:** reproducible release build, tested install/uninstall, clear
limitations, and complete user/developer documentation.
---
## 15. Initial implementation task for the agent
## 15. Initial Implementation Task for the Agent
Start with the **repository and design baseline** only.
1. Inspect the current repository and report its state.
2. Identify the available C/C++ compilers, FLTK version, audio backend development packages, `pkg-config`, and test tools.
2. Identify the available C/C++ compilers, FLTK version, audio backend
development packages, `pkg-config`, and test tools.
3. Do not install packages or modify system configuration without permission.
4. Propose the smallest initial source tree compatible with this brief.
5. Add or update the Makefile and documentation only as needed.
6. Create a minimal program that builds and exits cleanly; do not yet implement a full audio engine or GUI.
6. Create a minimal program that builds and exits cleanly; do not yet implement
a full audio engine or GUI.
7. Build it and run its tests.
8. Report exact commands, results, assumptions, and any missing dependencies.
After the baseline is reviewed, continue with the C core and offline processing. Keep each milestone independently buildable and testable.
After the baseline is reviewed, continue with the C core and offline processing.
Keep each milestone independently buildable and testable.
---
## 16. Long-term quality bar
## 16. Long-Term Quality Bar
The project succeeds if a musician can open it quickly, connect components without fighting the interface, record and arrange audio/MIDI, and make music without needing to understand every detail of the engine.
The project succeeds if a musician can open it quickly, connect components
without fighting the interface, record and arrange audio/MIDI, and make music
without needing to understand every detail of the engine.
The implementation succeeds if a developer can read the C code, understand ownership and thread boundaries, test components independently, and add functionality without turning the application into an unmaintainable framework.
The implementation succeeds if a developer can read the C code, understand
ownership and thread boundaries, test components independently, and add
functionality without turning the application into an unmaintainable framework.
**Guiding rule:** build a small, coherent system whose components compose well. Do not build a large DAW and then attempt to simplify it afterward.
**Guiding rule:** build a small, coherent system whose components compose well.
Do not build a large DAW and then attempt to simplify it afterward.