Version: 0.7.0 | Build: 1f4c1117 (Upgraded from e42cb7cf, 23 commits)
1. POLY Step Sequencer Lane (46 Chord Shapes & Voice-Leading Tools)
Commits: 71c32ca0, 1f4c1117
A dedicated POLY lane sits alongside PITCH in the step sequencer (LaneKey::Poly, paint mode 17). It runs on its own clock (linked to PITCH step indices by default), allowing short harmonic loops such as 4-step chord progressions to cycle beneath any TRIG pattern length.
Chord Engine & Root-Top Voicing
- 46 Chord Shapes (
ChordKind): Initially introduced with 21 core intervals/triads/sevenths and expanded by 24 additional voicings in1f4c1117— dyads (M3,m3,4th,tritone),add2/add11,6/9,m6/9,7sus2,maj7sus2,7b5,+7,+maj7,9/maj9/m9/9sus4(no 5th),m11,13shell,maj7#11,7b9,7#9,quintal, and a semitone cluster. Every shape is capped atroot + 3notes. - Step Picker & Scale Awareness: Clicking a
POLYstep opens a six-group chord picker modeled on theCONDpopup.CHORD_POOLis ordered by harmonic complexity; shapes containing tones outside the channel pitch scale are dimmed. Scroll wheel cycles shapes, right-click clears back to a single note, and theRNDhalf selects an in-scale chord dynamically per trigger. - Inversions Keep Top Root Fixed: Chord inversions shift upper intervals downward below the
PITCHnote sostep_pitchstays fixed as the voicing ceiling. Sub-oscillators, noise layers, and pitch-tracking targets continue tracking the pitch shown on thePITCHlane. - Paraphonic Internal DSP (
OSC 1/OSC 2): When a step triggers a chord,render_osc1_coreandrender_osc2_coreswap per-noteOscCorestate copies to render up to four notes per step across everySynthesisTypearm, equal-power summed before shared envelopes, filters, granular processing, and FX.Mesh 2Dand the standaloneGranularengine remain monophonic root-only; steps without chords execute the original path unchanged. - Polyphonic Hosted Instrument Output: Hosted
CLAP,VST3, and.omnipluginsynths receive stacked polyphonic MIDI events (note_onfor the root,note_on_stackedbypassing release-first even in mono mode for upper tones), released together on the subsequent trigger.
POLY Lane Tool Row & Auto-Randomize (engine/sequencer/poly_ops.rs)
- Step & Inversion Transforms:
Shift < >(rotates chord shapes together withRNDflags),+/-(shifts all active chords up or down one inversion),x2,/2,Reverse,Invert(parallel quality toggles: major/minor, sus2/sus4, dim/aug), andClear. - Spring-Back Global Knobs (
spring_knob):Cmp: compresses/expands voicings toward simpler or denser entries inCHORD_POOL.Ofs: shifts each chord up to 12 in-scale steps along the pool.Rnd: replaces a fraction of steps with random in-scale shapes from the AR range window.Slw: applies voice-leading smoothing by picking the inversion closest to the preceding step.
- Auto-Randomize & Serialization:
POLYintegrates directly into the AR Rack (afterPITCH) with dedicated range bounds, Re-roll, Drift/Elastic, Shuffle/Rotate, and Mix-to-Home. Default chordless steps omit the newStepfields so existing patches save and load unchanged.
2. Oscillator Architecture Split, Through-Zero FM (TZ) & Ring Mod Expansion
Commits: 33697702, 250704cd, e11d1371, 810f8660, 29b7e0fd, c0519cd2, d0cda332, 4d737093
Engine + Mod Split (33697702)
The single combined Type menu has been split into two controls mapped bijectively onto the existing synthesis_type storage field (decompose_synth / compose_osc_synth):
EngineSelector:Oscillator,Harmonics,Cluster,Mesh 2D(and legacyGranularwhen opening older projects).ModSwitch (Off/FM/Ring): Preserves the chosen carrier waveform when switching modulation modes. Unsupported engine/mode combinations grey out with an explicit reason instead of silently dropping selection. Colliding carrier labels were disambiguated (Braids SineKick/SqrHats,Plaits VA/Shaper/WTMorph,Morph Wavetable).
FM & Ring Across Plaits, Cluster, Harmonics & Mesh 2D (250704cd, e11d1371)
- Added
SynthesisTypevariantsPlaitsRing,ClusterFm,ClusterRing,HarmonicsFm,HarmonicsRing, andMeshRing. ClusterandHarmonicssupport Linear FM on their internal frequency buffers (add_linear_fm).Plaits,Cluster,Harmonics, andMesh 2Dpickups now share thering_mix_blockdry/ring stage across bothOSC 1andOSC 2. AtAmount = 0, unit tests verify bit-exact parity with plain unmodulated engines.- Under
Mesh 2D, theFM/Ringbox now remains visible above the plate editor, factory plate presets move from dual miniature button rows into a single full-nameFactorycombo box (29b7e0fd), and theGranulatepanel widens belowTimbre | P.Modto226 ptwith all eight knobs (Position..Density,Texture..Reverb) arranged in one row (810f8660).
Through-Zero FM (FmEngine::ThroughZero, c0519cd2) & Modulator Display (4d737093)
- Standard Linear FM clamps a carrier near
0 Hzonce deviation exceeds the carrier frequency (Amtabove ~10% at the FM envelope peak), creating hard waveform stalling. ThroughZerointegrates the linear deviation into a bidirectional phase offset (tz_step, per-voicetz_phase/tz_phase2, reset on trigger) so the carrier reverses direction cleanly through zero phase.- Cycled via the
Engswitch (Lin/Phs/TZ), supported onWave,BraidsFm, andPlaitsFmalgorithms with a phase input; algorithms without a phase input fall back to Linear delay/filter/noise modulation and display anFM: texturebadge in the picker. - For non-standard-wave carriers on
OSC 1, the FM header now surfacesmod [Sin|Tri|Sqr|Saw|Nse](Noisehighlighted) because a hidden Noise modulator raises spectral flatness ~10x compared to Sine (verified via addedfm_spectral diagnostics ind0cda332).
3. Modulate-a-Modulator (1,348 Targets) & Panel Modulation Rings
Commits: 202f780e, c0878d58
Continuous parameters inside modulators can now be modulated by any modulation source:
- Expanded
LfoTarget(models/mod_param_targets_gen.rs): Appended 1,348 generated targets (leaving the original 80 routes intact for saved patches) covering continuous parameters on:- LFO: phase, pulse width, curve, depth, drift, bias, smooth, delay, fade.
- Mod Env: delay, hold, sustain, release, velocity amount, vel-to-attack, sustain fade, depth (with block-rate synchronization for hold/delay/sus-fade/vel>atk).
- All 10 Omni Sources: continuous parameters from
LorenzthroughStep Seq, includingRNDandSEQ.
- Routing UI & Rings: Context menus group targets under
"MOD: <family> <n>"(568 per-slot targets), modulator panel knobs accept drag-and-drop cables viaModParamCtx.slot, and Macro owner groups shifted12 -> 14to resolve a collision withRND'sMOD IN. Channel view evaluatesModParamHighlightsper frame soLFO,ENV,REC, andOmnipanel knobs display animated modulation indicator rings and"modulated by"tooltips matching synthesis knobs.
4. Interactive Filter Graph Dragging & Panel Layout
Commits: eb104db2, f7a0fd6b, 5331a4d3, 63a670c7, d89515b1
- Direct Graph Editing (
f7a0fd6b): Clicking and dragging inside the frequency-response curve in any filter slot (Mix FX 1–8, Master bus, Noise 1, Noise 2) sets cutoff horizontally along the log frequency axis and resonance vertically (normalized to cover Noise slot 1's legacy Q range). HoldsShiftfor fine adjustment, supports double-click reset, and commits one undo action per drag gesture. - Stacked Caption Column & Full-Width Mix FX (
eb104db2,5331a4d3): Filter index, mode, and model stack in a compact left column so the response curve fills the remaining width (560 ptmax across the Mix FX panel; compact column width preserved in Noise layers). - Routing & Tab Removal (
d89515b1,63a670c7): For filter slots2..8(Mix FX and Noise), theSerial/Parallelrouting selector sits in the knob row below the graph in the same position occupied by the drive selector on slot 1. Closing the currently viewed filter slot (e.g.F8) now steps selection to the nearest active neighbor below rather than jumping back toF1.
5. Two-Layer 1:1 Pixel-Grid Lanczos Knobs & Linux Atlas Fix
Commits: 3c6313fe, 4fa68052, 33adf316, 457ce59b
- Linux OpenGL Texture Limit Fix (
3c6313fe): Repacked the legacy100x12800filmstrip into a16x8(1600x800) atlas to prevent first-frame black windows/panics on Linux OpenGL drivers capped at8192 pxmax texture dimension. - Two-Layer Texture Architecture (
4fa68052): Replaced the 128-frame (~5 MB) sprite filmstrip with two lightweight textures — staticknob_base(baked scale and shadow) and rotatingknob_body(12:00 pointer drawn across a240°8:00..4:00travel shared across vector fallback and modulation rings). - 1:1 Per-Pixel-Size Lanczos3 Caching (
33adf316,457ce59b): Removed hardcoded250 pxsource assertions to accept1000 pxsource PNGs and eliminated GPU bilinear mipmap softening. Each rendered diameter (diameter * pixels_per_point) generates and caches a dedicated premultiplied-alpha Lanczos3 texture snapped directly onto the physical pixel grid.
Commit Reference (e42cb7cf..1f4c1117)
1f4c1117 POLY lane: 46 chord shapes and the tool row (shift, +/-, Global knobs, transforms)
71c32ca0 POLY lane: per-step chords on the internal oscillators and hosted synths
457ce59b Knob: per-pixel-size Lanczos textures drawn 1:1 on the pixel grid
33adf316 Knob layers: any PNG size (was a hard 250 px assert that would panic the GUI)
4fa68052 Knob: two-layer texture (static base + rotated body), 240° travel
3c6313fe Knob filmstrip: repack 100x12800 strip into 16x8 atlas (1600x800)
c0878d58 Modulator panels: modulation rings on their own knobs
202f780e Modulate a modulator: every continuous modulator parameter is a target
d89515b1 Filter slots 2-8: Serial/Parallel combo moves to the knob row
63a670c7 Filter tabs: removing the viewed slot steps to its neighbour below, not F1
5331a4d3 Mix FX filter: box spans the panel, graph takes the side margins
c8bd4887 Revert "Filter slots: F1..F8 tabs as a vertical strip beside the box, graph taller"
d273de0c Filter slots: F1..F8 tabs as a vertical strip beside the box, graph taller
f7a0fd6b Filter graph: drag to set cutoff (x) and resonance (y)
eb104db2 Filter face: type/kind stacked under the caption, response graph beside them
4d737093 FM box: show OSC 1's modulator shape for non-standard-wave sources
d0cda332 Ignored FM noise diagnostics: inharmonic share + spectral flatness per source/engine
c0519cd2 FM: through-zero engine (TZ) + "FM: texture" mark in the source picker
29b7e0fd Mesh 2D: factory plates in a combo instead of two button rows
810f8660 Mesh 2D: Granulate box full width, eight knobs in one row
e11d1371 Mesh 2D: Ring modulation + FM/Ring box above the plate box
250704cd Oscillator Mod stage 2: FM/Ring on Plaits, Cluster and Harmonics
33697702 Oscillator: Engine + Mod (Off/FM/Ring) instead of the combined Type list

