Lulada is a Linux Digital Audio Workstation built on a winelib runtime. It combines DAW sequencing, recording, automation, JACK-native audio/MIDI, and in-process Windows VST2, VST3, and CLAP plugins in one Linux application.
Lulada is the Wine-NSPA DAW application. Its core application model is a modular music-production environment: clip launching, linear arrangement, multi-track recording, tracker sequencing, piano-roll editing, sample playback, automation, JACK routing, and plugin processing are all part of the same session graph.
The Windows-plugin path is an implementation capability inside that DAW. VST2, VST3, and CLAP plugins are loaded in-process through JUCE-NSPA and Wine-NSPA, so plugin DSP, plugin editors, JACK graph routing, and the DAW transport all share one Linux process.
| Surface | Current implementation |
|---|---|
| Session View | clip grid, scenes, per-column track strips, scene launch, scene tempo/time-signature override, follow actions, stop buttons, and sample-accurate audio-thread launch scheduling |
| Arrangement / Timeline | audio and MIDI lanes, region move/resize/split/snap, looped regions, clip gain, Bezier fade curves, marker track, ruler interaction, and disk-streamed audio record/playback |
| Multi-track recording | track-oriented audio recording through disk-streaming services, with graph auto-wiring for the multi-track patchbay |
| Tracker | vendored VHT-style tracker engine, pattern grid, QWERTY note entry, per-cell FX columns, multi-pattern sequencing, per-row delay/probability/range, row-per-beat control, mute/solo, and MIDI recording |
| Piano-roll | MIDI note regions, viewport/zoom/tools, velocity lane, snap divisions, ruler, playhead, Alt-copy, axis lock, edge resize, clipboard, quantize, humanize, and scale-snap with live preview |
| MIDI clips | first-class sources shared by Session View and Arrangement, backed by copy-on-write MIDI note region data |
| Sampler | FT2-style mixer DSP, multi-instrument bank/slot workflow, volume/pan envelopes, voice-level FX, pitch/mod-wheel routing, four stereo bus outputs, AVX2 mix path, and session-global sample pool |
| Automation | copy-on-write automation point/region/track model, curve math, sample-accurate MIDI CC dispatch, touch-record FIFO, mute table, and session XML round-trip |
| Modular graph | audio, MIDI, JACK ports, sequencers, samplers, internal processors, and Windows plugins are routable nodes in the same graph |
| Plugin processing | in-process Windows VST2, VST3, and CLAP nodes run beside native DAW processors |
Lulada separates DAW ownership from runtime substrate ownership. The DAW owns the session model, graph topology, timeline, clip launching, MIDI editors, sampler, automation, JACK policy, plugin scan policy, and UI presentation. JUCE-NSPA and Wine-NSPA provide the Windows-plugin and native-peer substrate used by that application.
| Layer | Responsibility |
|---|---|
| Lulada application shell | main window, view switching, session/document commands, graph UI, plugin manager, internal dialogs, and visual identity |
| Composition model | Session View cells/scenes plus Arrangement/Timeline lanes and regions |
| Authoring engines | tracker, piano-roll, sampler, automation, MIDI source/region services |
| Graph engine | audio/MIDI routing, internal processors, Windows plugin nodes, nested subgraphs, multi-track patchbay wiring |
| JACK engine | audio period boundary, native audio ports, native MIDI ports, same-period MIDI ingress/egress |
| JUCE-NSPA | winelib build support, Windows VST2/VST3/CLAP plugin formats, WineHWNDEmbedComponent, Wayland peer support, async plugin-load helper path |
| Wine-NSPA | Win32 loader/runtime, wineserver, Wine thread state, X11/Wayland embed protocol, Win32 priority mapping |
The important boundary is that plugin execution is one subsystem inside the DAW. It does not define the whole application model.
Lulada has both live clip-launching and a linear arrangement model. Session View is organized around cells, scenes, per-column track strips, follow actions, scene-level tempo/time-signature overrides, and sample-accurate launch scheduling on the audio thread. Arrangement/Timeline provides audio and MIDI lanes with region authoring, marker navigation, loop ranges, clip gain, fade curves, and disk-streamed audio playback/recording.
The two surfaces share clip data instead of acting as unrelated modes. MIDI clips are first-class sources that can appear in Session View and Arrangement, and the timeline services keep source/region/lane ownership explicit.
Lulada has two main MIDI composition surfaces.
| Surface | Role |
|---|---|
| Tracker | pattern-first MIDI sequencing with QWERTY entry, per-cell FX columns, block editing, multi-pattern sequences, row-level timing/probability/range controls, track loop controls, and mute/solo |
| Piano-roll | note-region editing with velocity lane, snap divisions, ruler/playhead, drag/trim/copy gestures, clipboard, quantize, humanize, scale-snap, and live preview |
Both editors feed the same MIDI source/region infrastructure. That matters for the DAW model: tracker phrases, piano-roll clips, Session View cells, and Arrangement MIDI regions are not separate plugin-host side channels. They are composition data inside the project.
The sampler is an internal DAW instrument, not an external dependency. It uses an FT2-style mixer core with multi-instrument bank/slot workflow, volume and pan envelopes, voice-level FX, pitch/mod-wheel routing, four stereo bus outputs, and an AVX2 SIMD mix kernel. The session-global sample pool exposes 128 banks with 32 slots per bank, and sample-bank state round-trips through the session.
Automation is also internal to the engine. The current implementation uses a copy-on-write automation model with point, region, and track objects, curve math, target dispatch, sample-accurate MIDI CC output, a touch-record FIFO, and session XML round-trip.
The Linux build is JACK-first. JACK is the audio transport, MIDI transport, and the timing boundary for realtime graph execution. ALSA-seq is disabled in this build.
Current inbound MIDI path:
JackAudioIODevice::process() reads each enabled midi_in_N port with
jack_midi_event_get().currentPeriodMidiInput for graph-wide MIDI input
and currentPeriodMidiInputPerPort[N] for explicit per-port nodes.AudioEngine, MidiEngine, and JackMidiInputNode consume those buffers
during the same period.Current outbound MIDI path:
midi_out_N buffers before the
graph rendersJackMidiOutputNode and JackMidiOutputAllNode write directly through
writeJackMidiOutput()jack_midi_event_write() receives the caller’s sample offset for the
current periodThe graph exposes JACK MIDI as topology: combined input, per-port input nodes, per-port output nodes, and broadcast output nodes are explicit graph surfaces.
Windows plugin support is integrated into the DAW process through JUCE-NSPA and Wine-NSPA.
| Surface | Current behavior |
|---|---|
| VST2 | enabled through the system Steinberg VST2 SDK 2.4 |
| VST3 | enabled for Windows VST3 modules loaded through the winelib runtime |
| CLAP | enabled under __WINE__ through JUCE-NSPA CLAPPluginFormat for Windows .clap PE DLLs |
| LV2 / LADSPA / AU | not registered in the winelib configuration |
| Built-in nodes | sampler, tracker, MIDI tools, audio FX, and internal processors remain native Lulada nodes |
The scan surface is limited to 64-bit Windows-plugin directories inside the
active WINEPREFIX:
drive_c/Program Files/Common Files/VST2drive_c/Program Files/Steinberg/VstPluginsdrive_c/Program Files/Common Files/VSTdrive_c/Program Files/Common Files/VST3drive_c/Program Files/Common Files/CLAPdrive_c/users/<user>/AppData/Local/Programs/Common/CLAPProgram Files (x86) is intentionally excluded because the host is x86_64
winelib and cannot load 32-bit plugin DLLs.
Interactive plugin add uses an asynchronous creation path. Lulada requests
node creation, JUCE-NSPA performs plugin instantiation on a winelib
CreateThread worker, then completion returns to the message thread for node
attachment and UI update. Large plugin descriptors and port lists therefore do
not block the DAW shell while they are materialized.
Lulada uses JUCE-NSPA’s embedded Win32 editor layer for plugin UI surfaces. Plugin editors are Wine HWND-backed windows embedded under the DAW’s native Linux window tree.
| Surface | Owner | Current behavior |
|---|---|---|
| Main DAW shell | Lulada | GL-backed native application window, Session View, Arrangement, graph, mixer/channel surfaces, plugin manager, and internal dialogs |
| X11 plugin embed | JUCE-NSPA + Wine-NSPA | WineHWNDEmbedComponent creates the Win32 editor HWND and Wine-NSPA embeds the native X11 child under the host peer |
| Wayland plugin embed | JUCE-NSPA + Wine-NSPA | JUCE-NSPA owns the host wl_display; Wine creates a child wl_surface and installs it as a subsurface of the JUCE peer |
| Message pump | JUCE-NSPA | whole-thread queue pumping, input-first passes, and bounded general drain |
| Dialog policy | Lulada | Open Session, Save As, Import Graph, and Export Graph use JUCE internal choosers parented on the main content component |
The UI layer also uses a type-color system so graph blocks, wires, and channel strips identify Audio I/O, JACK MIDI, VST2, VST3, CLAP, and internal nodes without relying on plugin names.
| Boundary | Current behavior |
|---|---|
| Application type | Linux x86_64 Digital Audio Workstation |
| Runtime model | winelib application using Wine-NSPA for Win32 plugin execution |
| Window system | Wayland when available, X11 fallback |
| Audio/MIDI backend | JACK |
| Windows plugin formats | VST2, VST3, CLAP |
| Linux-native external plugin formats | excluded in the winelib configuration |
| Built-in processors | native Lulada graph nodes |
| Project model | session graph with clip, arrangement, tracker, piano-roll, sampler, automation, plugin, and routing state |
Startup prepares Wine state before plugin code executes: the host ensures a
wineserver socket exists, promotes the process with
SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS), and calls
OleInitialize(nullptr) before plugin initialization reaches static
constructor-heavy code paths.
src/main.ccsrc/pluginmanager.cppsrc/pluginprocessor.cppsrc/plugineditor.cppsrc/engine/graphmanager.cppsrc/engine/jack.hppsrc/engine/jack.cppsrc/engine/clapprovider.cppsrc/ui/sessionview.hppsrc/ui/sessionview.cppsrc/ui/arrangementview.hppsrc/ui/arrangementview.cppsrc/ui/pianoroll/pianoroll_view.cppsrc/ui/pianoroll/pianoroll_grid.cppsrc/ui/pianoroll/quantize_dialog.cppsrc/ui/pluginwindow.cppsrc/ui/pluginmanagercomponent.cppsrc/ui/mainwindow.cppsrc/ui/style_v1.cppsrc/nodes/tracker.hppsrc/nodes/tracker.cppsrc/nodes/trackereditor.cppsrc/nodes/sampler.hppsrc/nodes/sampler.cppsrc/nodes/midiplayer.cppsrc/nodes/audioclip.cppsrc/nodes/jackmidiinputnode.hppsrc/nodes/jackmidioutputnode.hppsrc/nodes/jackmidiinputallnode.hppsrc/nodes/jackmidioutputallnode.hppsrc/services/timeline/lane.hppsrc/services/timeline/playlist.hppsrc/services/timeline/midi_note_region.hppsrc/services/audiostreaming/disk_stream.cppsrc/services/audiostreaming/playback_ds.cppsrc/services/audiostreaming/record_ds.cppsrc/services/automation/automation_engine.cppsrc/dsp/automation/automation_track.hppsrc/dsp/automation/automation_region.hppsrc/services/samplebankpool.cppsrc/services/arrangementtracksservice.cppCMakeLists.txt