灵符lingfu

ling-station-x

↓ 0 downloads

LingStationX: a DAW in Ling with a piano roll, arranger, performance view, theory-aware score fixing, Qwen instrument choice, Prism / Growl / Synth X / Membrane instruments and Ling-design-system effect windows

Linux · x86-64Web · WASM
Keywords daw, music, midi, synth, sequencer, ling
lingfu install ling-station-x
LicenseApache-2.0 OR MIT
Authorsling-lin
READMECode / FilesVersionsDependency GraphDependentsSecurityBuildsSettings

Code / Files (853)

README.md
# LingStationX

A digital audio workstation **written in [Ling](../ling)** — the arranger, piano roll, mixer, node editor,
performance launcher, file browser, dialogs and every instrument are `.ling` programs. It is a port of
[LingStation](../[LingStation]) (same layout, same ROYGBIV palette, same panels) that swaps the egui/VST host
for Ling's own runtime and audio crates.

```
LingStationX/
  ling/            the application (main.ling + modules)          <- the DAW itself
  instruments/     instrument "plugins": plain .ling patch files    <- edit / write your own
  assets/          font, project templates (Ambient Pads, EDM Starter, Hip Hop)
  tools/           patch/template generators, screenshot test harness
  docs/            DEV_NOTES.md (language gotchas, API, testing)
```

The audio engine is the native `ling-daw` crate in the Ling repo (`../ling/crates/ling-daw`), exposed to
scripts as `daw_*` builtins; a handful of `px_*` / `st_*` / `fs_*` / `dlg_*` builtins give the UI fast pixel
drawing, a shared state store, file browsing and native dialogs.

## Build & run

Needs a checkout of the Ling repo next to this folder (`../ling`, branch `lingstationx`) and Rust.

```powershell
cd ..\ling
cargo build --release --bin ling      # once (add --bin ling only; ~10 min)
cd ..\LingStationX
.\run.bat                             # or: ../ling/target/release/ling run --interp ling/main.ling
```

`run.bat` prefers the release build and falls back to the debug build.

## What is in it

* **Arranger** — timeline with ruler, loop region, tracks, clips (MIDI note previews, audio waveforms), Draw / Select
  (marquee) / Move / Slice tools, grid snap, zoom, copy-drag, drag files in from the sidebar, expandable
  **automation lanes** (level, pan, any instrument/effect parameter) with point editing and automation recording.
* **Piano roll & Parameters** — draw/select/move/resize notes, snap and note-length, velocity / pan / cutoff /
  resonance lanes per note, quantize / humanize / transpose; the Parameters tab adds the instrument's knobs,
  presets, patch load/save and (for drums) a 4x4 pad grid.
* **Instruments** — *Ling Synth X* (subtractive + additive + FM in one voice), *Ling Membrane* (physical-modeling
  drums), **Ling Growl** (monophonic dubstep / electro bass and lead: wavetable stack, FM, vowel filter, four drawable
  16-point modulation lanes and a 7x10 mod matrix, 8 presets in `instruments/Growl/`) and **Ling Voice** (a formant singer
  driven by IPA lyrics, 7 singers in `instruments/Voice/`). Patches are text files in `instruments/`. The instrument
  panels are drawn in the Ling design system (outline + crosshatch, tile lettering, ROYGBIV meanings; `ling/ds.ling`).
* **Ling Prism** - a 16-voice analog-style synth for big electronic sounds (`ling-daw/src/dsp/prism.rs`): two morphing wavetable oscillators
  (sine / tri / saw / square / pulse / organ / bell / spectral) with 1-7 unison voices and phase warp, six ways for A and B to interact (add, ring,
  phase-mod, hard sync, xor, min), sub, noise, an analog *hum* drone and voice drift, a stereo multimode filter plus a note-tuned comb, eight
  multi-point envelopes (draw / drag / add / remove breakpoints) and two LFOs that reach 20 destinations through a 13 x 20 modulation matrix,
  and a harmonizer, phaser, ensemble chorus, ping-pong delay and reverb. **Microtonal**: 19 / 22 / 24 / 31 / 17 / 53 EDO, just intonation,
  Pythagorean, meantone, Bohlen-Pierce, slendro, pelog, harmonic series, whole tone, octave stretch, or twelve hand-tuned notes. The dice
  randomize the sound, the modulation, the effects or all of it, and *mut* wanders away from the current patch. 281 presets in `instruments/Prism/`
  (trance, deep house, disco, witch house, hyperpop, microtonal, ambient, plus a bank of sounds named after and imitating FL Studio's Sytrus and Harmor
  factory presets - pads, hoovers, donk and wobble basses, arps, keys, bells, kicks, FX) from `tools/gen_prism.py` and `tools/gen_prism_fl.py`.
* **Electronic GM** - `instruments/Electronic GM/` is a second 128-patch General MIDI bank (e-pianos, house organs, acid / sub /
  wobble / reese / neuro basses, supersaw pads and strings, stabs, sync / laser / vowel leads, risers and FX).
  `tools/gen_gm_electronic.py` + `cargo run --release -p ling-daw --example gm_electronic`.
* **Sidechain duck** - Edit > Sidechain Duck... (or the Duck button in the arranger toolbar): pick a track, say the drum kit, choose what triggers it (the kick only, the snare, every hit...) and the tracks that should get out of its way. Each gets a Ducker effect (depth, attack, hold, release, curve; the dip is drawn as you set it) triggered from the kick's notes, so only the kick ducks, it is exact to the sample, and it works even with the drums muted. Ducks show in the Node Editor and the effect list.
* **Tracker import** - File > Import MIDI / FL Studio / Tracker... reads ProTracker `.mod`, ScreamTracker `.s3m`, FastTracker `.xm`, Impulse Tracker `.it` and OpenMPT `.mptm` modules (compressed IT samples too; `.mo3` is not supported - save as `.it`/`.xm` in OpenMPT). Every module instrument becomes a track playing the module's real samples (written as a SoundFont with loops, panning, fine tune and fade-out), the patterns are played through in song order (jumps and breaks followed) into notes with their volumes, pans, lengths and note cuts, and speed/tempo changes become the tempo map. Vibrato, slides, arpeggios and sample offsets are not modelled.
* **Tracker tab** (F4, between Node Editor and Performance) - the arrangement as patterns and pages like OpenMPT: rows down, channels across (a track gets one channel per note that sounds at once, up to 8, so chords read across), an order list of pages, note / instrument / volume cells, hold and note-off marks, the playhead row (Follow keeps it in view), rows per beat 1-8, page size 16-128, hex or decimal row numbers. Click a cell and type notes on the keyboard (Z S X D C V G B H N J M / Q 2 W 3 E R 5 T 6 Y 7 U I), Delete clears, arrows move, [ ] shorten / lengthen the note, Esc leaves the grid. The Font switch draws the grid in the normal English font, Daemon or Chesilin (Chesilin has no - # = so those use the normal font).
* **Sampler** (a new plugin; Parameters tab) - zones of audio files with root note, key / velocity range, fine tune, volume, pan, pitch tracking, forward / ping-pong loops (draggable markers, Auto loop), trim, reverse, one-shot; amplitude ADSR or a full multi-point envelope with sustain / loop points and fade-out, plus panning, pitch and filter envelopes, a resonant low-pass (cutoff, resonance) and random variation per note (volume, pan, cutoff, resonance, like OpenMPT's swings); WAV / FLAC / OGG / MP3, WavPack (via ffmpeg) and Ogg-in-WAV files. Saved with the project (samples are copied into `<project>/samples`).
* **Tracker import** now plays the module's own samples through Samplers: arpeggios become notes, pitch slides / portamento / vibrato become pitch-bend lanes, volume slides / tremolo / retrigger become volume lanes and notes, Zxx filter changes become cutoff / resonance lanes, pattern loops and delays are followed, XM / IT volume, panning and pitch / filter envelopes, fade-outs, instrument cutoff / resonance and global volumes come across. Channels that use these effects get their own track with their lanes. Checked against libopenmpt renders: pitch correlation 0.96-0.99, durations within 0.05 %, level within 1.5 dB. In the import dialog each part can use its original samples, go to a shared percussion kit (one Sampler track), or use a drum sample found in your sample folders by name ("Splash Cymbal" -> a splash sample); **Ask Qwen** gives percussion parts search words and the importer falls back to the module's own sample when nothing is found. Sample folders searched: `[LingStation]` next to the programs folder, `library/samples`, `assets/samples` and Settings > sample_roots.
* **Export Karaoke** (File menu) - subtitles `.ass` (per-syllable karaoke, count-in dots), `.srt` (lines and a progressive-colour version), `.lrc` (word level), a self-contained **HTML player** (cursor: sweep / pop / bouncing ball / underline / block / arrow; pitch ribbon of the melody; every look option live in a panel) and an **MP4** through ffmpeg, with the backing audio (instrumental = lyric tracks muted). Look options: font (default, Daemon, Chesilin or any font file), size, text / sung / outline / cursor colours, outline thickness and opacity, text opacity, shadow, background, lines on screen, colour by pitch, resolution.
* **Transcribe Vocals** (File menu) - speech to text with faster-whisper running on this computer (GPU when available): picks a model from your Hugging Face cache, writes `.srt` (cues from the word timings, broken at sentences and pauses) and `.txt`, and can fit the words to a MIDI clip's notes. ling-lang itself has the same thing as `stt_*` builtins (`stt_start`, `stt_poll`, `stt_segments`, `stt_words`, `stt_srt` ...; see `ling/stt/README.md` and `ling/examples/stt_demo.ling`). Setup once with `ling/stt/setup_windows.ps1` (an isolated venv, nothing goes into your normal Python).
* **Export Sheet Music** (File menu) - the notes as a colour-coded schematic instead of a staff: time on a bar / beat grid, height = pitch (black-key rows shaded), tile colour = pitch class (twelve colours on a circle of fifths), letters in English, Daemon or Chesilin, width = length, brightness = loudness, octave numbers, chord stems, drum symbols, lyrics under the notes, tempo marks, a legend page. SVG pages and a printable HTML (fonts embedded).
* **Vocal to MIDI + Vocal Tuner** (Piano Roll > Vocal to MIDI, Edit menu) - an audio clip with a voice becomes a MIDI clip of the notes that were sung, linked to the recording. Edit the notes in the piano roll (move, stretch, quantize), snap them to a scale, then Render: the recording is re-sung through the notes (pitch-synchronous resynthesis, the formants stay) with retune speed, timing fit, vibrato, tremolo, fades and a temperament (equal, just, Pythagorean, meantone, Werckmeister). The tuned voice lands on a paired track and the original is muted.
* **Scripts** (Edit > Scripts) - Ling files in `scripts/` that the program loads while it runs (save a file and it reloads): note scripts (`arp`, `humanize`, `reverse`, `euclid`) and **custom plugins written in LingDSP**, a small sample-by-sample language returned by `<name>_dsp()`: effects (`tubedrive`, `bitcrush`, `ringmod`, `pingecho`) and instruments (`fmbell`, `supersaw`, `karplus`) with their own knobs, filters, delays, oscillators and envelopes; every copy of a plugin updates when its script is saved. See `scripts/*.ling`.
* **Vocoder** (effect) - the track's own sound is the carrier; the modulator is another track routed to it (Node Editor kind MODULATOR, or the picker in its window) or the built-in talker (vowels, robot, whisper, gate). 8-32 bands, formant shift, hiss for consonants, 14 presets.
* **Ringstorm** (effect) - modular pedals, amps and racks you wire up in a pedalboard window: 20 pedal kinds (gate, compressor, boost, overdrive, distortion, fuzz, amp, cab, EQ, wah, chorus, flanger, phaser, tremolo, vibrato, delay, reverb, octaver, volume, slicer), serial chains, splits and parallel lanes, 20 rig presets.
* **Ling Pluck** (instrument) - physical-modelling strings: guitar, harp, koto, shamisen, sitar (jawari buzz and sympathetic strings), oud, banjo, kalimba and more; 26 presets.
* **Prism genre banks** - 104 new presets (HyperPop, Deep House, Disco, Dance, EDM, Industrial, Atmos & Space, Synthwave, Lo-Fi) made by `tools/gen_prism_genre.py`; every instrument's preset chooser has [<] [>] to step, [@] for a random one, and opens a categorized browser that highlights (and remembers) the current preset.
* **AI Mix & Master** (Edit menu) - every track is rendered alone and measured (loudness, peaks, dynamics, spectrum, width); a plan names each track's role, sets levels, pans crowded instruments, cuts low-end and mud, compresses what is too dynamic and aims the master at a loudness (-14 LUFS by default), each move with its reason and a tick to leave it out; Qwen can correct roles and pick the style. One Undo.
* **Score view + MusicXML** - the piano roll has a Score face: the clip on a staff (grand staff when it spans the keyboard) where you click to add notes, drag to change pitch and place, Delete to remove; Export Sheet Music can also write a MusicXML score for MuseScore, Sibelius, Dorico or Finale.
* **Glue phrases** (Arranger button, or Edit > Glue Clips Into Phrases) - the reverse of Slice: clips that touch (or are at most a chosen rest apart) on the same instrument join into one phrase clip, up to a phrase limit of 4 / 8 / 16 bars or none; a run of identical bars folds into one clip that loops its bar. Per instrument or just the selected track, with a preview of every clip count before anything changes, and one Undo.
* **Export Tracker (PDF)** (File menu) - the Tracker tab as printed pages, like OpenMPT: one page per pattern (rows down, channels across; a wider song continues on more pages of the same pattern), cells `C-5 01 v32` (note, instrument = track number in hex, volume 0-64), `|` held, `===` note ends, bar and beat rows tinted. English, Daemon or Chesilin font, 1-8 rows per beat, 16-128 rows per page, hex or decimal row numbers, light or dark page, portrait or landscape, a range of patterns. Writes an HTML and a PDF (printed by Edge / Chrome / Chromium).
* The **Ling Design System** now also covers the Mixer, Sidebar, Arranger and Piano Roll through the shared buttons, chips, tabs and checkboxes (line work, brackets, crosshatch for "on"), hatched clip headers and outlined notes.
* **Node Editor** is now a round signal table (Reactable style): the master in the middle, every track a puck on the ring with its effects on the spoke toward the centre, master effects orbiting the master; dots travel along the lines faster with the level, each track puck shows its level arc and the notes of the current bar with a hand sweeping at the playhead. Sends / sidechains / ducks are made by dragging from a puck's out port. **Performance** and both views use the Ling design system (line work, crosshatch, brackets, tile lettering, colour keys).
* **Export stems bundle** - File > Render Audio... > tick *Bundle for other DAWs*: a folder with one WAV stem per track (all starting together, so drop them at bar 1), `midi/` (project.mid with the tempo map + one file per track), `instruments/` (soundfonts and Ling patches), `params.json` (levels, pans, instrument state, effect chains and parameters, automation, routing), `project.dawproject` (the open DAWproject format for Bitwig, Studio One, Cubase 14: stems as audio tracks plus muted note tracks) and a README with steps for FL Studio / Ableton / Bitwig.
* **Match key** - `Match key` in the arranger toolbar (or Edit > Match Tracks To Song Key) finds the song's key from the notes and the audio, then matches the ticked tracks to it: MIDI clips in another key are transposed and stray notes snapped onto the scale; melodic audio (a voice, a lead) is tuned onto the scale with Bezier-eased glides from note to note (strength, glide time and curve are yours); loops and mixes are moved to the key.
* **Fit lyrics** - in the Piano Roll's lyrics strip, `Fit...` takes a song's words (paste them in any language; labels, chords and (x2) are removed), splits them into syllables (Qwen can do it, or the built-in splitter) and spreads them over the notes: syllables land on strong beats and long notes, extra notes sustain, short notes hold the syllable before them, a chord carries one sustained syllable, and the lyrics can loop. Ling Voice follows chords legato.
* **Colour-coded icons** for every instrument and effect (Add Effect is now a card picker with a short description of each), and two arranger ticks: **Follow playhead** and **Loop at last clip** (the song loops at the end of its last clip).
* **Automate parameters** - under a track's automation lanes, `Automate...` writes lanes for **this track's parameters, a random handful, or every parameter of every melodic track**, with an optional prompt ("tense build into a drop", "slow ambient drift", "glitchy and wild"). Qwen knows what each parameter does and picks common articulations (wobble, pump, stutter, sweep, riser, per-note plucks and swells ...) that lock to the bars and the notes; without a model the built-in chooser reads your words instead. Lanes you drew yourself are never replaced, and Ctrl+Z undoes it all.
* **Singing** - give a Ling Voice track notes, open the Piano Roll and type lyrics into the strip under the grid:
  `[so-fa]-[rei][to][mi-do]` (`[..]` = one note, `-` inside = several syllables on one note, `-` between notes = slur / sustain the
  vowel, `[-]` = hold). Syllables can be IPA, plain letters read phonetically, pinyin, Hanzi, Hangul, kana or Thai script and are
  converted to IPA (`ling-daw/src/lyrics.rs`). Native script is pasted (Ctrl+V / Paste), IPA symbols have a palette.
* **SoundFonts** - `assets/soundfonts/Ling.sf2` (the Majora's Mask N64 set) is used by MIDI import when present: bank select +
  program change pick the preset, unmatched parts fall back to the built-in GM sounds. Add a soundfont instrument from the Plugin
  Picker (browse / audition with a search box); Settings > MIDI chooses the import soundfont. Loops, envelopes, filter, LFOs,
  layers, velocity/key ranges and exclusive classes are supported; SF2 modulators and effect sends are not.
* **MIDI import extras** - tempo changes become a tempo map (the toolbar shows "N changes", click to clear), pitch bend becomes a
  `bend` automation lane (RPN 0 sets the range), bank select, volume/expression/pan lanes and the sustain pedal are honoured.
* **Mastering & safety** - master limiter (mixer checkbox, on by default), audio test tone + limiter meter in Settings > Audio,
  stem export (Render > one file per track), A/B compare for instrument settings, left-edge clip trimming, double-click slider
  reset, and crash/close recovery (an unsaved session is offered back on the next start).
* **Drum kits** — Ling Membrane has 16 parameters per piece (tune, decay, tension, hardness, body, click, tone, damp, purity, sweep,
  drive, gate, analog, swell, pan, level) and every GM key has its own voicing (six tom pitches, side stick, cowbell, congas, ...).
  Stock kits: Kit_Jazz, Kit_Rock, Kit_Metal, Kit_Funk, Kit_Electro_808, Kit_House_909, Kit_New_Wave, Kit_LoFi (`tools/gen_kits.py`).
* **GM sounds** — `instruments/GM/` holds 128 General MIDI patches (`tools/gen_gm.py` + the `gm_normalize` example).
* **Mixer** — strips with level/pan/mute/solo, meters, per-track FX chains (EQ, Compressor, Drive, Delay, Reverb),
  master strip with compressor, sends and sidechain routing.
* **Node Editor** — graph of tracks → effects → master with draggable send and sidechain routes.
* **Performance** — session/clip launcher: scenes × tracks, quantized launch, Song Play / Session Only, auto-slicing
  the arrangement into scenes, record launched clips back into the arrangement.
* **Audio** — import WAV/FLAC/OGG/MP3, warp clips to the project tempo and transpose them independently
  (WSOLA time-stretch), record audio from an input device, MIDI keyboard input and recording, MIDI export.
* **FL Studio import** - File > Import MIDI / FL Studio... (or drop an `.flp` in the browser) reads the channel rack, pattern notes, playlist
  arrangement, tempo and audio clips of an FL Studio 20/21 project (`ling-daw/src/flp_import.rs`, layout verified against real projects).
  Each channel becomes a part in the same dialog as MIDI import, so any plugin / patch can be chosen per channel; drum channels merge into
  one Drums part on GM keys, sample channels become audio clips, plugins are matched to a suitable sound by name. Automation clips, mixer
  effects, plugin settings and presets are not converted.
* **Ask Qwen to choose instruments** - the import dialog's *Ask Qwen to choose* button describes every part (register, polyphony, note length, GM program) to a
  small Qwen3 model that runs inside the program through ling's own `ling-ai` crate (GGUF via candle, no server, nothing sent anywhere). The model only
  names a *role* for each part ("rolling bass", "warm pad", ...); `ling-daw/src/ai_import.rs` maps roles to real plugins and patches, repairs or ignores bad
  JSON, caps any one role at a third of the parts, and fills in anything the model skipped, so every part always gets a valid choice. Build ling with
  `--features llm,llm-cuda` (or just `llm` for CPU), put a Qwen3 GGUF and its `tokenizer.json` in `assets/models/` (Qwen3-1.7B-Q8_0 is the default, about
  2 GB and ~5-10 s per file; Qwen3-4B-Q4_K_M is a bit better) or pick one in Settings > AI. `tools/ai_eval.ling` compares models on real files.
* **Saving** - Save / Save As ask for a name, create `projects/<name>/` first and write `<name>/<name>.json` there (a name that is already taken becomes `<name> 2`);
  the project is renamed to match and its Metadata (title, genre, a short description of the music) is filled in. The Render dialog always starts from the
  current project's name in `<project folder>/renders/` with a free file name and asks before replacing an existing file. Piano roll: click or drag the ruler
  to set the playhead (double-click plays from there); wheel = keys, Shift+wheel / wheel over the ruler or lanes / a tilt wheel = along the beats, Ctrl+wheel = zoom.
  The **+** next to every preset chooser saves the current sound as a user preset (`instruments/User/`), listed as "User: name" for that instrument.
* **Fix all scores** (button at the top of the Arranger) - opens a sidebar where you choose what to fix, with live counts: pull notes into the key (the tuning of
  every melodic MIDI note), resolve clashes with the chord, straighten passing notes, snap timing, remove doubled notes - and for the arrangement: line clip
  starts up on the grid, round clip durations (never cutting notes), trim overlaps, close gaps. *Fix everything* repeats over every clip until a pass finds
  nothing left (up to 8 passes) and lists what changed per clip; Ctrl+Z undoes all of it. *Suggest sections* reads how busy each bar is and proposes intro /
  verse / build / chorus or drop / bridge or breakdown / fill / outro; click a tag to change it, *Apply tags* draws them on the ruler.
* **Order vs chaos, and repetition** (Fix all scores) - the *Chaos <-> Order* slider (presets *Jazz / Breakcore*, *Balanced*, *Strict*) sets how forgiving the fixer is: low
  leaves colour tones, tension and off-grid swing alone, high pulls everything in. The key and chords for a region come from a **majority vote across the instruments**
  (a loud single-note line counts for more, harmony supports it). Two repetition options conform the arrangement "page by page, book by book": *Backing parts: one
  repeating page* turns a long chord / pad / bass clip into one 1-8 bar page that repeats, with a small turn every 4th and 8th time; *Loud riffs: stated twice, up to 32
  bars* trims or extends a prominent riff to whole 8-bar phrases and states it a second time in the next chorus / drop.
* **How the fixer decides a note is wrong** - it reads the key and chords once, from the score as it was (not again after each pass), smooths away key sections shorter than 5 bars,
  and only changes a note when there is evidence: a long note outside the key that no triad of its neighbours explains, or a note that grinds (half step / major seventh within
  about an octave) against another instrument. Short ornaments, trills, leading tones, arpeggiated chromatic chords and ordinary suspensions are left alone; "resolve clashes with the
  chord" and "straighten passing notes" only act at Strict order, and a fix is never allowed to create a new clash. Fixes are limited to pitches in the key.
* **Slice long clips into patterns** (Fix all scores, before the arrangement is lined up) - a clip of 8 bars or more that is one solid block (an imported 128-bar channel) is cut into
  patterns: silence is dropped, a run of identical 1 / 2 / 4 / 8-bar pages becomes ONE clip holding a single page with its loop length set, material that does not repeat becomes 4-bar
  phrases, and the same pattern coming back later gets the same letter ([A], [B] ...).
* **Rainbow Hypergrowl** (+ Add FX) - the digital harmonic growl of a resampled-wavetable bass (the Au5 "HyperGrowl" family), as a deep chain with 44 knobs and 8 presets
  (Hypergrowl, Yoi Bass, Digital Chop, Granular Cloud, Octave Shatter, Comb Scream, Vowel Melt, Sub Rattler): **drive** (gain, bias, tanh -> sine fold, ring modulator, bit and rate
  crusher) -> a 24-band **wavetable filter** that crossfades two of 12 spectral tables (vowel, comb, harmonic, hollow, rainbow, digital, tilt, bell, yoi, ripple, notches, stairs),
  with position, resonance, shift in octaves, rainbow spread (detunes the bands and runs the right channel's motion late), tilt and *body* (keeps the clean low end) -> a tuned
  feedback **comb** -> a **grain delay** (up to 32 grains: delay, size, density, spray, pitch +-24 st, random pitch, reverse chance, feedback, stereo spread) -> a 2048-point **spectral**
  stage (compress every harmonic toward the local average, bin shifter, weak-bin gate, blur, tilt) -> width, level, soft limiter, mix. **Motion** drives it: an LFO (sine / tri / saw /
  square / sample & hold) with optional stepping, an envelope follower, a slow random drift and a second LFO that wobbles the shift, the comb and the grain pitch. Every knob can be
  automated. It has 2048 samples (about 43 ms) of latency; the dry signal is delayed to match.
* **Hypergrowl sample section** - load a WAV / FLAC / OGG (or use the built-in sung-vowel sweep) as a spectral source: *sample table* (`smix`) lets its spectrum, band by band, replace the
  wavetable in the filter bank, *spos* / *sscan* choose and scan the reading position, *xsyn* lays its spectral envelope over your sound (a vocoder: the bass speaks in the sample's
  voice), *gsrc* makes grains read the sample (a granular sampler), and *freeze* holds the spectrum as a pad. The file is saved with the project. New presets: Vocoder Bass, Sample Cloud,
  Sample Scan, Freeze Pad.
* **Ling Growl: Talk and Sync, and 34 new presets** - *Talk* is a 16-step, tempo-synced vowel sequencer (draw A..U on the bars) feeding a formant filter that blends over the sound, with
  step rate, glide, step count, formant resonance and shift: the bass talks. *Sync* hard-syncs oscillator A (the neuro screech); lane 3 sweeps the ratio. Presets (Parameters tab):
  talkbox, robot vowels, formant bass, yoi talk, alien talk, vox pad, choir stack, glitch talk, screech, neuro sync, hard lead, sync sweep, sync pluck, tear out, dub wobble, half-time wob,
  triplet wob, riddim, riddim 2, minimal wub, mid growl, rasp, gnarl, future bass, supersaw, detune lead, fm bell, pluck bass, sub drop, 808 growl, acid squeal, chirp, swarm, wide stab.
* **Effect windows** (double-click an effect in the mixer) are in the Ling design system for every effect: framed sections, hatched knobs with readouts in real units, tile selectors,
  on / init / rand switches, presets where an effect has them, and for the growl a live display of the filter bank, the motion and the grains.
* **Right-click any knob** (synth or effect) - *Automate* (creates the lane), *Program shape* (writes a sine / triangle / ramp / pulse / staircase / random-hold LFO into the lane
  for the whole song, around the knob or over the full range), *Reset to default*, *Set exact value*, minimum / centre / maximum / randomize, copy / paste value. Effects on the
  master can be automated too (their lanes are programmed from the knob menu; the Arranger shows lanes of tracks).
* **Add harmonized part** (Piano Roll > Compose > Harmony) - select notes (or none for the whole clip), optionally say how ("thirds above", "choir", "jazz stack", "counter melody",
  "soft", "held"), pick the track whose chords to build it off (or all the other tracks) and where to put it (a new track with the same sound, or an existing one). Voices
  stay in key, follow the chords, and avoid a minor second / major seventh against the melody.
* **Vocal tuning** (Piano Roll > Compose with an audio clip selected) - tunes a recorded vocal to the notes of a MIDI track under it: the pitch is tracked, each
  moment is pulled toward the score's note (octave-folded, with strength and retune speed), sung starts are moved onto the beat (within a window you set), and the
  long notes can get vibrato (depth and rate). It re-synthesises with PSOLA so the voice keeps its formants, and writes the tuned take next to the project.
* **Vocal effects** (add them from a track's + Add FX): **Vox Filter** - a 12 / 24 / 48 dB high-pass and low-pass with a resonant corner, a spectral tilt and a *dynamic*
  high-pass that climbs when the voice is quiet (cleans breaths and room noise between phrases); **Vox Reverb** - an 8-line modulated FDN with pre-delay, early
  reflections, a low cut and high cut on the wet signal only, width, and a **duck** that lowers the reverb while the voice sings and blooms it back in the gaps;
  **Vocal Halo** - makes a voice pop in stereo: a mono-safe decorrelated "halo" of the top end (it cancels exactly in mono), a wandering artificial double, a harmonic
  presence exciter, an air shelf, a de-esser, a transient shaper, bass-centred width and a ducked bloom.
* **Batch import** (`tools/batch_list.py`, `tools/batch_run.py`, `tools/batch_import.ling`) - turns a pile of FL Studio projects and MIDI files into LingStation projects:
  for each file Qwen first names the genre, then chooses an instrument for every part knowing the genre, the FL plugin that played it (Sytrus and Harmor suit Prism,
  3x Osc suits Ling Synth X ...) and what each LingStation plugin is; the import is saved to `originals/`, the score and arrangement are fixed and tagged and saved
  to `production/`, and a MIDI file plus a 24-bit stereo 48 kHz WAV go to `renders/` under short names. It runs in small chunks, skips what is already done and
  carries on after a bad file. Every new or imported track starts with a gentle compressor and the master with a glue compressor.
* **Menus** taller than the window scroll (the automation parameter list); in the piano roll, dragging the end of one of several selected notes stretches the whole
  selection (hold Alt to lengthen every note by the same amount instead) and Shift+drag copies the notes to follow the cursor.
* **Solo** - any number of tracks can be soloed together; clicking a soloed track's S clears every solo.
* **Timeline and ranges** - the ruler of the Arranger and the Piano Roll share one set of controls: click or drag = playhead; **double-click then drag** (or Shift+drag)
  = select a time range (the clips or notes inside it get selected too); Ctrl+drag, or the **Loop** chip that appears on a selected range (Ctrl+L), = loop it;
  drag a loop edge to resize the loop; Esc clears the range. Bar / beat numbers thin out as you zoom out and fade away when they would not fit. In the roll,
  Shift- or Ctrl-drag on a selected note drags a copy of the selection; Ctrl+B duplicates it; right-click deletes; arrows nudge (Shift = bar / octave).
* **Pattern tab** (piano roll > Compose) - for a drum track: a rhythm generator (four on the floor, house, techno, trance, disco, breakbeat, trap, drum and bass,
  half-time, boom bap, one drop, euclidean) with density, swing and fills. For a melodic track: *turn chords into arpeggios* (order, rate, octaves, gate and a
  rhythm mask such as off-beat, gallop or euclidean hits/steps/turn) or write an arpeggio over the project's chords. Both write into the selected range
  (replacing only that stretch), at the playhead, or over the whole clip; press again for a variation.
* **Derive** - the **~** next to every preset chooser (and *derive* in Prism's header, *Derive a similar sound* in the Parameters panel) describes up to 24 of the
  sound's parameters to Qwen with a request ("darker and more movement") and applies its "similar but different" version; Ctrl+Z gives the old sound back. Without
  a model it drifts the parameters randomly instead.
* **Theory assistant (piano roll)** - the roll shows the key (and key changes), a chord lane with Roman numerals, and a phrase lane (repeated progressions,
  cadences, motifs, sequences, runs, arpeggios). Notes are coloured by what they are against the key and the chords: chord tone, scale tone, chromatic
  passing, clash, out of key (hover a wrong note for the fix). The detection is deterministic code (`ling-daw/src/theory.rs`), so it is instant and
  never guesses. Chords come from the other tracks when the clip is a melody, else from the clip itself.
* **Compose tab** (piano roll, next to Tools) - *Write*: type "8 bars sparse trance melody in F# minor, i VI III VII" and press Write it (keywords) or
  Ask Qwen to write (the model only fills a small spec: style, density, contour, feel; the notes come from `compose.rs`, so they are always in key and on
  the chords - by default over the chords already in your project). *Fix*: **Auto-correct** pulls out-of-key notes into the key, resolves clashes with the
  chord, snaps slightly-off timing and removes doubled notes in one undo step, with a preview count; *Move to another key* retunes a melody keeping its scale
  degrees. Also shows chords that work next (click one to add it).
* **Style thumbprint** - the project is described as a short story ("A driving trance piece in A minor at 128 BPM, over the progression i VI VII v. Bass plays
  rolling eighth notes...") plus a field list, saved in the project and refreshed on save. Tick *In my style* in Write to compose with it, or scan
  `library/midi/` (drop your MIDI / FLP files there) and borrow another file's style: its feel in your key over your chords.

* **MIDI import** — a dialog lets you pick the instrument for every part (soundfont / General MIDI, the Electronic GM bank, Growl, Voice
  or any patch file); every MIDI track/channel becomes its own arranger track; the GM program picks a matching Ling Synth X
  patch (128 GM names, one voice per instrument family), channel 10 becomes the Ling Membrane drum kit (GM percussion map).
  Imports set the project tempo when the project is still empty; tempo changes inside the file are not followed.
* **Audio/MIDI settings** — Settings > Audio: output device, device buffer size, safety buffer (render-ahead, the main dropout
  control), engine sample rate, live CPU load / latency / dropout counter. MIDI: input device (remembered), channel filter. Audio In:
  recording device. Audio is rendered on its own thread into a ring buffer; the device callback only copies frames.
* **Parallel rendering** - tracks that do not feed each other (sends / sidechains) render side by side on a pool of DSP threads,
  and stem export renders several stems at once. The audio is bit-identical to rendering one track after another.
* **Window** — resizable and maximizable (title-bar button / double-click); the UI re-lays out to the new size.
* **Project** — *Save* puts a new project in `./projects/<name>/` next to the program (no dialog; *Save As* picks another
  folder). The folder is self-contained: `project.json` (notes, lyrics, automation, effects, routing, scenes, instrument
  state), `audio/` (recordings and imported audio, copied in), `soundfonts/`, plus `midi/` (one standard MIDI file per
  track and `project.mid`) and `patches/` (each track's instrument as a `.ling` patch) for other programs. Writes are atomic.
  Undo/redo, autosave, recent projects, templates, render to WAV / FLAC / OGG (in the background, with a progress bar and cancel).

### Keys (FL Studio style - Help > Shortcuts shows them all)
Space play/pause · Enter play from start · Home/End rewind / jump to end · R record · L loop · F5-F8 Arranger / Parameters /
Piano Roll / Node Editor · F9 mixer · F10 settings · F11 Performance · F12 sidebar · Tab next view · F2 rename · Esc deselect ·
+/- zoom · , . grid snap · Ctrl+Z/Y undo/redo · Ctrl+S/O/N · Ctrl+R render · Ctrl+I import · Ctrl+C/X/V · Ctrl+A · Ctrl+B duplicate
selection · Ctrl+D duplicate track · Shift+M / Shift+S mute / solo track.
Arranger: P draw · E select · Y move · S slice · Up/Down track · Left/Right nudge. Piano roll: P/E tools · Q quantize ·
Shift+Q humanize · [ ] note length · Up/Down semitone (Shift = octave). Parameters: PageUp/PageDown presets.
**Caps Lock** turns the typing keyboard into a piano (A W S E D F T G Y H U J K, Z/X octave); with it off the letters are tools.

## Instrument patches

```text
# Ling Synth X patch
name = "Sub Bass"
type = synth                     # synth | drums
wave=0.66 sub=1.0 cutoff=0.3 reso=0.4 detune=0.1 attack=0.05 release=0.16
fx Delay time=0.2 feedback=0.35 mix=0.25
```

Values are normalised 0..1. Drum kits use `<piece>.<param>` keys (`snare.tune=0.4`). Load one from the
Parameters tab, from *Mixer > + > Plugin Picker*, or write a new one and drop it into `instruments/`.
`tools/make_patches.ling` regenerates the stock set.

## Development

`docs/DEV_NOTES.md` documents Ling's quirks and the full `daw_*` API. UI changes can be checked headlessly:

```powershell
python tools/shot.py out.png -- --shot 30 --tab 3 --drive "10,400,300,0;11,400,300,1;12,400,300,0"
```

## UI toolkit

The interface is drawn by Ling itself: `px_*` primitives and vector text (fast, clip-aware, alpha-blended) for the
egui-style chrome, plus **ling-ui's `ui_*` vector controls** (rings, sliders, toggles, checkboxes, tabs) where they fit
- knob arcs, the master level slider, Settings tabs/toggles and the Record-mode checkboxes. ling-ui's Rust-only types
(`MenuBar`, `ShortcutRegistry`...) are not reachable from scripts, so menus and shortcuts are implemented in Ling.

## Known limitations

* VST3 / CLAP hosting and the online licence/activation are not part of this port (Ling instruments replace plug-ins).
* Run with `--interp` (the launcher does): Ling's default JIT backend currently panics compiling this program.
  The tree-walking interpreter runs the UI at roughly 30-60 fps depending on the project.
* The window close button cannot be intercepted by scripts, so there is no "unsaved changes" prompt on exit
  (File > Quit has one; an autosave is written next to the project, or to `autosave_untitled.json`).
* The engine renders at 44.1/48 kHz and resamples (linear) to the device rate, so 96/192 kHz interfaces cost no extra DSP.
* Warp / transpose use a WSOLA stretcher (good for rhythmic and simple material, not Rubber Band quality).
* MIDI hardware input and audio-input recording use the OS default devices and were not exercised on real hardware here.
* The Performance launcher copies clips into scenes; there is no drag-and-drop from the arranger (use a pad's right-click
  menu > *Copy Selected Arrangement Clip Here*).

## Tests

```powershell
cd ..\ling ; cargo test -p ling-daw      # audio engine: DSP, sequencing, routing, launcher, export, hostile-input robustness
cd ..\LingStationX ; python tools\smoke.py   # opens every tab / dialog / menu in the real app
```

← Back to index