Skip to main content

songbird-state

Pure data layer for the Songbird DAW. Defines the project data model, entity types, channel-aligned state slices, and persistence. This crate has no business logic, no I/O beyond persistence, and no engine dependencies.

Architecture

songbird-state/src/
├── ids.rs              Strongly-typed entity IDs (TrackId, ClipId, etc.)
├── map.rs              Map<K, V> — ordered collection with dirty tracking
├── entities/           Domain entity structs (atoms)
├── slices/             Channel-aligned slice structs (molecules)
├── state_manager.rs    StateManager — root state container (organism)
├── store/              StateStore — change tracking, undo/redo, listeners
└── persistence/        File I/O: bird text, session autosave, git history

Layer Hierarchy

StateManager           ← single root, composes all slices
  └── 10 Slices        ← one per sync engine channel
       └── Entities    ← individual domain types
            └── IDs    ← strongly-typed keys

Entities

Domain types with Serialize + Deserialize. No business logic beyond constructors and accessors.
EntityFileDescription
Trackentities/track.rsAudio/MIDI track metadata
Clipentities/clip.rsAudio or MIDI clip content
MixerStateentities/mixer.rsPer-track mix state (gain, pan, mute, solo)
PluginInstanceentities/plugin.rsPlugin instance with saved parameter state
AutomationLaneentities/automation.rsParameter automation breakpoints
Sectionentities/section.rsArrangement section
SongMetadataentities/song.rsBPM, key, time signature
ProjectMetadataentities/project.rsProject name, ID, sample rate
LoopStateentities/transport.rsLoop region and enable state
MetronomeStateentities/transport.rsClick track settings
ArmStateentities/recording.rsPer-track record arm and input routing
Marker / Regionentities/marker.rsTimeline markers, regions, tempo/key markers
ChatStoreentities/chat.rsAI chat history and model config
GenerationStoreentities/generation.rsAI generation job history
UserSettingsentities/settings.rsGlobal user preferences

Slices

Channel-aligned structs that group related entities. Each slice maps 1:1 to a sync engine channel and a persistence file.
SliceChannelPersistence fileContents
SongSlicetrack.*, section.*{name}.birdtracks, sections, tempo/key markers
ClipSlicetrack.*{name}.birdclips
AutomationSlicetrack.*{name}.birdautomation lanes
ProjectSliceproject.*daw.state.jsonmetadata, markers, regions, engine config
TransportSlicetransport.*daw.state.jsonloop state, metronome
RecordingSlicerecording.*daw.state.jsonper-track arm state
MixerSlicemixer.*daw.mixer.jsonper-track mix, sends, returns, master bus
PluginSliceplugin.*daw.plugins.jsonplugin instances
AiSliceai.*daw.ai.jsonchat, generation
SettingsSlicesettings.*settings.jsonuser preferences (global)

StateManager

The root state container. One StateManager per open project.
pub struct StateManager {
    pub song:       SongSlice,
    pub clip:       ClipSlice,
    pub automation: AutomationSlice,
    pub project:    ProjectSlice,
    pub transport:  TransportSlice,
    pub recording:  RecordingSlice,
    pub mixer:      MixerSlice,
    pub plugin:     PluginSlice,
    pub ai:         AiSlice,
    pub settings:   SettingsSlice,
}
Key property: because each field is a separate struct, Rust allows simultaneous &mut borrows of different slices — e.g., a mixer command can mutate state.mixer while a transport command reads state.transport.

StateStore

Wraps StateManager with:
  • Undo/redo — snapshots before each mutation
  • Change listeners — notify subscribers on mutation
  • Dirty tracking — which slices changed since last persist
  • Git persistence — commit state to git-backed project history

Persistence

ModulePurpose
persistence/bird_io.rs.bird text format read/write
persistence/session.rsCrash-recovery autosave + recent project list
persistence/project_history.rsGit-based commit history
CrateRelationship
songbird-syncImports entities/slices for command dispatch. Also hosts generation_state and bridge_layer runtime services.
songbird-filesFilesystem services (samples, presets, loops, templates). No dependency on state.
songbird-typesShared low-level types (TimeStretchMode, ARA traits). State depends on this.