# GUI guidelines Use FLTK/C++ for windows, menus, dialogs, and the event loop. Keep all audio engine and project-domain logic in C. Main views: - Sequencer: tracks, clips, ruler, playhead, selection, zoom and scrolling. - Mixer: channels, faders, pan, mute/solo and meters. - Modular graph: nodes, ports, connections, validation feedback. - Transport: play/stop/record, tempo, meter, loop and position. Use custom-drawn widgets where ordinary controls are not a good fit: timeline, waveforms, piano roll, mixer strips and graph canvas. Keep drawing separate from project mutation. Never call FLTK from the audio thread. Visual direction: compact, high-contrast, restrained dark interface. Avoid excessive animation and modal configuration. Recreate broad usability ideas, not energyXT's exact artwork or proprietary resources. ## Phase 3 shell The shell opens JACK on startup through `xtc_backend.h`. It never accesses backend structures, processes samples, or calls JACK itself. Graph domain data is owned by opaque C objects, manipulated only through the C API. All backend control calls run on the GUI thread; FLTK is never called from an audio callback. No server is started and no audio ports are connected by the GUI. The initially empty graph produces silence. - **Play / F5:** start the engine. **Stop / F8:** deactivate it. **Pause / F7:** hold playback. **Space:** toggle Play/Stop. **To start / Home:** stop and seek to zero. Pause/Home are disabled while recording. These advance/pause the sample-counted playhead; imported audio clips play through their graph source. - **Reconnect / F6:** close the old client and open a fresh stopped client. Use this after server loss or sample-rate changes. A failed close preserves the handle and reports the failure instead of opening another client. - **View menu / Ctrl+1, Ctrl+2, Ctrl+3:** switch between sequencer, mixer and modular graph. Tabs provide the same view switching. Mixer, graph and sequencer editors are described below. - **File / Quit / Ctrl+Q** or the window close button: close the backend and synchronize audio callbacks before hiding/destroying widgets. A failed close leaves the window open for a retry. New/Open/Save actions are described below. About identifies the development milestone and version. The indicator shows disconnected, ready, running, server lost, format changed or process-error states. The status line shows rate, actual block size, mono layout, processed block count, xruns and process result. Command errors remain visible until a successful control action; periodic refresh does not erase them. A GUI-owned 100 ms timer reads atomic snapshots and collects retired plans. Label text changes only when needed. The timer is removed before successful close and again by the window destructor. No GUI locks are held across control calls. Operations such as opening JACK can briefly block the GUI; there is no worker/control-thread framework in this initial shell. MainWindow owns the backend handle and FLTK owns the window's children. The destructor also attempts cleanup on exceptional event-loop exit; if JACK close itself fails then, it reports to stderr and retains the callback context until process exit. Normal close/reconnect paths permit retry and release ownership only after successful close. The entry point catches C++ exceptions before process exit. Backend operations return C error codes throughout. Tests: `make test-gui` runs real widgets/callbacks/timers against a fake C backend under Xvfb, including control errors, startup without JACK, partially initialized handles, server/format notifications, view switching, retrying close, and timer removal. `make test-gui-jack` additionally requires a running JACK-compatible server, tests repeated start/stop, reconnect and active-client close, and creates no routes. Physical playback is outside this shell. See BUILD.md and the integration test README for sanitizer limitations and keyboard smoke results. ## Phase 4 modular editor Open **Modular Graph** or press **Ctrl+3**. Add oscillator (440 Hz), gain (0.10), pass-through meter or output nodes with the toolbar. Their parameters are fixed presets in this milestone and are drawn on each node; parameter editing and live meter display are not implemented. Connect oscillator → gain → meter → output for a simple test chain. No sound reaches hardware until ports are explicitly connected outside the GUI. Output nodes are required to render; isolated sources and an empty graph produce silence. Drag a node body/title to move it. Drag a circular output port to an input port to connect. Click a node or wire to select it (yellow outline/wire), then press Delete/Backspace or **Delete selection**. Deleting a node deletes its incident wires. Escape cancels a drag preview. Canvas scrollbars pan the view; positions are retained across edits/reconnect but not across application restart. There is no graph zoom, multiselection, undo or external routing UI yet. The editor supports 64 nodes on a fixed 2000x4000 canvas. Every semantic action becomes a C graph command. The window owns a C project containing the graph handle and publishes the C-created candidate through the backend. Cycle, invalid-direction, duplicate connection, missing-port, capacity and backend failures are shown below the canvas; failed edits leave the graph unchanged. Capacity feedback distinguishes the possible node limit/pending edit condition and allows retry. Editing while stopped replaces the prepared plan without starting playback. Editing with a disconnected startup backend stays local until reconnect. A lost or changed live backend requires reconnect before further semantic edits. Moving/selecting nodes does not touch the engine. The graph state line distinguishes offline, prepared, queued and active states. Queued explicitly means the drawing represents the next submitted graph while the engine finishes the previous plan. The 100 ms GUI timer observes audio adoption revisions and then shows active. Graphs are not edited in place on the audio thread. There is no automatic retry/hidden edit queue; users retry a rejected capacity edit. Plan replacement can reset oscillator phase and is not crossfaded. Render validation and active replacement tests are described in tests/integration/README.md. ## Phase 5 projects and sequencer File/New (Ctrl+N), Open (Ctrl+O), Save (Ctrl+S), and Save As (Ctrl+Shift+S) use native file dialogs and the C persistence API. New/Open/Quit offer Cancel/Discard when semantic edits are unsaved; save first to retain them. Save As confirms overwrites. The title marks unsaved changes. Failed loads and backend submissions retain the old document. Loading parses before stopping audio; installing a valid candidate stops and resets transport before compiling and submitting. A later failure can leave the retained document stopped at zero. Opening/New resets graph layout; graph positions are not saved. See PROJECT_FORMAT.md. Sequencer offers Add track, Add region, Delete region/track, Zoom +/-. Select a track header to add a one-bar region there at the cursor. Select a region to delete it; deleting a selected track cascades to its regions. Delete also works with canvas focus. Drag a region body to move it in time or between tracks; drag either edge to trim within its original source bounds. Edits commit on release with 1/16-note snapping; Escape cancels. There is no drag preview, undo, multiselection, rename or tempo editor yet. Overlapping regions are permitted. The scrollable canvas expands to cover the arrangement plus a margin; zoom ranges from 24 to 384 pixels/quarter. Names, tempo and 4/4 meter are drawn. A ruler click seeks while stopped (or positions the cursor when disconnected). The 100 ms GUI refresh converts the backend's actual sample counter to ticks; it never integrates wall-clock time. Play resumes and Stop pauses. Reconnect, New and Open reset position. Add region creates silent metadata; imported WAV clips play through the audio source node (Phase 6 below). MIDI clips and notes are described below. The C model supports a constant tempo; a tempo map and scheduler are future work. Tests cover C-model/persistence boundaries, GUI move/trim gestures and zoom, save/reopen, failed load/submission rollback, sample-derived cursor updates, and live JACK playhead advance/pause. ## Phase 6 audio workflow Use File/Import WAV (Ctrl+I) to add an audio clip at the playhead on the selected track, or on a new Audio track. Record (Shift+F5) chooses a WAV destination and captures JACK input until Stop finalizes and adds the take. No input routes are created automatically. Save after Stop; the project references the external WAV. Import creates an Audio clips graph source and output route if the source is absent. Modular Graph offers Add audio source for explicit routing through gain or meter nodes. All tracks currently share one mono timeline mix. Arrangement edits stop playback; graph edits remain live outside recording. During recording, edits, file actions, reconnect and close require Stop first. Open/Play reports missing, unreadable or unsupported assets, preserving their regions as silence. The backend status shows the unique issue count. Select a clip and use File/Relink selected audio to choose another path; Play validates the replacement. Playback uses preloaded immutable samples; imports and loads can block the GUI while reading, but never the audio callback. See AUDIO_FILES.md for supported WAV formats, memory limits, musical placement, recording overflow/partial-take recovery, external asset portability and the software-only acceptance tests. Waveform drawing, input monitoring, recording latency compensation and per-track graph inserts are not implemented. Per-track gain/pan/mute/solo is available in Phase 8 below. ## Phase 7 piano roll Add MIDI clip creates a one-bar clip on the selected/first existing track at the cursor. Select it and choose Piano roll (View/Piano roll, Ctrl+4). Click to draw, drag a body to move pitch/time, drag its right edge to resize, and right-click or Delete to remove. Notes use source ticks with 1/16 snapping; trimmed source content is retained. Edits stop transport and are blocked during audio recording. Panic/F9 silences held notes; Record continues to mean WAV audio capture. Modular Graph offers Add instrument for explicit routing. Status includes MIDI drops. See MIDI.md for voice limits, unsupported messages and live input routing. ## Phase 8 mixer and editing Mixer (Ctrl+2) now has a selectable track strip, gain/pan controls, mute/solo, Output L/R peaks and editable gain/pan automation lanes. Mixer edits stop playback. Click the lane to add/replace points, right-click near a point to remove, and change First tick to navigate. Ctrl+Z, Ctrl+Shift+Z and Ctrl+Y undo and redo up to 32 project edits; New/Open resets history. M/S and arrow keys provide mixer shortcuts. See MIXER.md for exact controls, history rollback, stereo port routing, automation semantics and prototype limits. ## Phase 11 minimal composition workflow [WORKFLOW.md](WORKFLOW.md) walks through creating, arranging, saving, closing, reopening and playing MIDI/audio with the GUI. New/Open select Sequencer; Ctrl+3 still opens the modular graph. Stop retains its established position-hold behavior and finalizes recording; explicit Pause retains position without finalizing a take (and is refused during recording). Home stops and returns to zero. Failed candidate installation now refreshes the actual backend state even when the previous document is retained. `make test-workflow` uses a live JACK-compatible backend and Xvfb, with exact stereo render comparisons across destruction/recreation of the GUI and live playhead/meter/transport checks. `test-gui` covers stop/seek failure and recording guards. No project files need manual editing for this workflow.