Skip to main content

Songbird C++ Backend (app/)

The C++ backend is a standalone JUCE desktop application that hosts a Tracktion Engine audio engine and communicates with a React-based UI through a WebView bridge.

Architecture Overview

┌──────────────────────────────────────────────────────────────────┐
│  React UI (WebView)                                              │
│  Zustand stores ←→ juceBridge (StateStorage) ←→ native functions │
└──────────────────┬───────────────────────────────────────────────┘
                   │ JS ↔ C++ via JUCE WebBrowserComponent
┌──────────────────▼───────────────────────────────────────────────┐
│  SongbirdEditor (Main Component)                                  │
│  ├─ WebViewBridge    — JS↔C++ native function dispatch            │
│  ├─ StateSync        — Zustand store ↔ engine state sync          │
│  ├─ PlaybackInfo     — Real-time meters, transport position, FFT  │
│  ├─ ProjectState     — Git-based undo/redo (libgit2)              │
│  ├─ BirdLoader       — .bird file parser → Tracktion Edit         │
│  ├─ PluginManager    — Plugin window management, plugin swap      │  
│  ├─ MacroMapper      — Macro parameter mapping for channel strips │
│  ├─ LyriaManager     — AI music generation (Lyria/Magenta)        │
│  ├─ MidiRecorder     — Real-time MIDI recording                   │
│  ├─ AudioRecorder    — Real-time audio recording                  │
│  └─ MidiToBird       — MIDI clip → .bird file serialization       │
│                                                                    │
│  Tracktion Engine (Audio Engine)                                   │
│  └─ te::Edit → Tracks → Plugins → Audio/MIDI Clips                │
└────────────────────────────────────────────────────────────────────┘

Key Classes

SongbirdEditor (SongbirdEditor.h/.cpp)

The main application component. Owns the Tracktion Engine, the WebView, and orchestrates all subsystems. Inherits from juce::Component, juce::Timer, and juce::AudioProcessorListener. Responsibilities:
  • Application lifecycle (constructor, destructor, timer loop)
  • Bird file loading and reloading
  • Plugin state tracking (audio thread → UI sync)
  • Undo/redo orchestration
  • Export (stems, master, sheet music)
  • MIDI editing helpers (piano roll → bird file round-trip)

WebViewBridge (WebViewBridge.cpp)

Implements createWebViewOptions() which registers all JS↔C++ native function handlers. This is the sole communication layer between React and C++. Handler domains:
  • StateloadState, updateState, resetState, reactReady, getHistory
  • TransporttransportPlay/Pause/Stop/Seek, setLoopRange, setBpm, setProjectScale
  • PluginsopenPlugin, changePlugin, getPluginParams, setPluginParam, getAvailablePlugins
  • MixersetTrackMixer, setMixerParamRT, setSidechainSource
  • Bird FilesreadBird, loadBird, updateBird, writeBirdUser, saveBird
  • ExportexportSheetMusic, exportStems, exportMaster
  • MIDIlistMidiInputs, setMidiInput, sendKeyboardMidi, recording controls
  • SettingsgetApiKey, setApiKey, getSystemTheme, setZoom, uiReady
  • AIaddGeneratedTrack, removeGeneratedTrack, Lyria config/prompts

StateSync (StateSync.cpp)

Bidirectional state synchronization between Zustand stores (React) and the Tracktion Engine:
  • handleStateUpdate() — dispatches incoming Zustand state to engine (transport, mixer)
  • applyTransportState() — maps transport store → te::TransportControl
  • applyMixerState() — maps mixer store → track volume/pan/mute/solo
  • createTrackWatchers() — per-track ValueTree listeners for C++ → React push

BirdLoader (BirdLoader.h/.cpp)

Parser for the .bird music notation format. Converts .bird text files into Tracktion Engine edits. Pipeline: .bird text → parse()BirdParseResultpopulateEdit()te::Edit

ProjectState (ProjectState.h/.cpp)

Git-based undo/redo system using libgit2. Manages an in-process git repository for the project directory. Key operations: commit(), undo(), redo(), revertLastLLM(), getHistory()

PlaybackInfo (PlaybackInfo.h/.cpp)

Real-time audio analysis and transport position tracking. Runs on a 30Hz timer, processes the master audio buffer for level meters, spectrum analysis, stereo width, and phase correlation.

MidiRecorder / AudioRecorder

Real-time recording systems that capture MIDI/audio input and write to Tracktion clips.

MacroMapper (MacroMapper.h/.cpp)

Maps high-level macro parameters (e.g., “drive”, “warmth”) to specific plugin parameters on channel strips like Console 1.

Data Flow

Bird File Loading

User opens .bird file
  → BirdLoader::parse() on background thread
  → BirdParseResult (tracks, sections, notes, plugins)
  → BirdLoader::populateEdit() on message thread
  → Tracktion Engine creates tracks, loads plugins, inserts MIDI clips
  → emitTrackState() pushes JSON to React via WebView event
  → React Zustand stores update → UI renders

State Synchronization

React slider drag
  → setMixerParamRT native function (real-time, no state persist)
  → C++ sets engine volume/pan directly

React slider release
  → Zustand persist → updateState native function
  → C++ handleStateUpdate() → applyMixerState()
  → ProjectState::commit() (git snapshot)

C++ engine change (e.g., plugin parameter tweak)
  → TrackStateWatcher ValueTree callback
  → pushMixerStateToReact() → WebView event
  → React Zustand store update

Build

cmake -B build -G Ninja
cmake --build build
The build produces SongbirdPlayer.app in build/SongbirdPlayer_artefacts/.