28 days · 165 commits
February 2026
- Day 307 · 0 commits

- Day 308 · 11 commits

- Audio engine
- 302e919Implemented scale-aware piano key coloring and fold-to-scale mode for the piano roll. Added ScaleSnapManager integration to PianoKeyboardComponent that applies subtle time-of-day tinted highlights to in-scale keys while dimming non-scale keys (25% darker, 70% saturation). Added 'Fold to Scale' toggle option to the scale selector dropdown menu that collapses the piano roll grid and keyboard to show only notes belonging to the current scale. Updated coordinate conversion methods (midiNoteToY, yToMidiNote) in both BasePianoRollComponent and PianoKeyboardComponent to handle fold mode mapping between visible rows and MIDI notes. Wired up ChangeListener callbacks so the UI updates reactively when scale settings change.
- f9518e0Implemented piano roll keybed click and drag to trigger note highlights and audio preview. Added mouse event handlers (mouseDown, mouseDrag, mouseUp) to PianoKeyboardComponent that convert Y position to MIDI notes and trigger preview callbacks. When clicking a key, it highlights cyan and plays the note sound. Dragging across keys stops the previous note and starts the new one, creating a smooth glissando-style interaction. Wired up the callbacks in PianoRollViewport to delegate to BasePianoRollComponent's existing triggerNotePreview/stopNotePreview infrastructure.
- 0523326Added three new sliders to the Timeline Sizing and Color section for fine-tuning clip visuals. Clip Saturation (0.2-0.8, default 0.5) and Clip Brightness (0.3-0.8, default 0.55) control the purple background color of sample clips where waveforms are displayed. Track Label Opacity (0-100%, default 95%) controls the visibility of the greyish highlight overlay behind track name text at the top of each clip - at 0% the overlay is invisible showing pure clip color, at 100% the full highlight is visible for better text readability. All settings persist to the runtime config and take effect immediately when adjusted. Also fixed an issue in TimelineLabelPainter where the brighter() method was stripping alpha values from gradient colors by preserving alpha after brightness adjustments.
- 1301803Implemented time-of-day harmonized visual enhancements for the timeline component to match the sequencer's Living Theme polish. Added horizontal gradient row backgrounds with depth shadows, trackf division lines with gradient fade and glow effects, and playhead rendering with multi-layer bloom, glow, and gradient trail. Enhanced sample clip rendering with harmonized fill colors and gradient overlays, modernized the ruler background with vertical gradient depth and time-aware tick colors. Updated track labels with vertical gradients and bottom shadows for selected rows, added multi-layer glow effects for selection highlighting, and upgraded waveform display with tinted gradients. Improved grid lines to use time-of-day harmonized colors with proper hierarchy, and enhanced drag feedback with glowing trail effects. All enhancements include dark theme fallbacks for compatibility.
- UI / UX
- f3b7ad6Styled note inspector toggle button to match other piano roll selector buttons with time-of-day themed background. Increased height of all corner buttons from 26px to 32px for better text readability.
- e56bd82Added multiple velocity editing for piano roll. Dragging the velocity bar of a selected note now applies the same delta to all other selected notes (relative adjustment). Created PianoRollNoteInspector panel that appears when notes are selected, providing a slider to set absolute velocity for all selected notes at once. The inspector shows selection count and auto-hides when nothing is selected.
- dd7c504Lowered the minimum size thresholds for displaying note name labels in the piano roll so they remain visible at lower zoom levels. The height threshold was reduced from 12px to 9px and width from 30px to 20px, allowing the 11pt caption font labels to display on smaller notes. The tiered zoom-based thresholds for showing all note names (vs just C notes) were also adjusted from 50x16px to 35x12px.
- 814ab04Added a ChordDetector helper class that analyzes selected notes and identifies chord names in real-time. The detector supports 50+ chord patterns including major, minor, diminished, augmented, 7ths, 9ths, 11ths, 13ths, suspended, and altered chords, with intelligent partial voicing recognition that allows identification even when notes like the 5th are omitted. Chord names display in the piano roll window title bar next to the track name (e.g., 'Piano Roll - Seq 1 - Fm7') and update dynamically as the selection changes. Also fixed the title bar layout to use full available width instead of the previous 60% constraint, ensuring chord names always display without truncation.
- 7a7cbf0Added root note visual indicators to the piano keyboard for scale-aware display. Root notes (tonics) of the selected scale now receive a stronger color tint (18% alpha vs 8% for other in-scale notes) to stand out from other scale degrees. Added small colored dots on root note keys using the time-of-day theme color - positioned on the right side for white keys and centered for black keys with brighter appearance for visibility on dark backgrounds. This is for quickly identifying the home note of the current scale.
- 3da0097Fixed session recovery dialog to use time override settings for theme colors. The RecoveryWizardDialog was always using the actual system time to determine its background gradient color, which caused it to display the wrong time-of-day theme when a time override was active. Added getCurrentHour() and getCurrentMinute() methods to CrashRecoveryManager that delegate to the ConditionMonitor to retrieve override-aware time values. Updated the RecoveryWizardDialog constructor and timer callback to fetch time from these new methods instead of directly from juce::Time::getCurrentTime(). The dialog now correctly matches the rest of the application's Living Theme colors when time overrides are set.
- f51c2e2Added user-configurable timeline waveform color settings to the Interface Settings panel. Renamed the 'Timeline Sizing' section to 'Timeline Sizing and Color' and added four new sliders: Waveform Hue Shift (0.0-0.2, default 0.065) controls the color contrast against track backgrounds, Waveform Brightness Min/Max (0.80-0.97) control the brightness range of waveform peaks and valleys, and Track Background Brightness (0.03-0.15, default 0.07) adjusts the darkness of track rows for better waveform visibility. Updated the DesignTokens runtime config system to persist these settings and modified the TimeOfDayColorSystem functions to read from the configurable values instead of hardcoded constants. Changes take effect immediately when adjusting sliders, with the timeline repainting to show the new colors in real-time.
- Day 309 · 5 commits

- Audio engine
- da3e0b5Fixed piano roll MIDI recording which had two critical bugs preventing it from working. The recording state machine never transitioned from Armed to Recording because the transport play state was read from isSequencerPlaying(), which actually returns the BPM clock source setting (useInternalClock) rather than whether the transport is playing. Replaced all three call sites in PianoRollViewport with direct reads of the PID_GLOBAL_PLAY parameter, matching the pattern used by RecordingCoordinator. Also reset wasPlaying_ to false in the arm() method to ensure clean rising-edge detection regardless of prior transport state. The second bug caused a single keypress to create many duplicate notes because processBlock recorded every MIDI event in the merged midiMessages buffer, which included internal playback and audition events fed back through the forwarding queue. Added a dedicated midiExternalRecordQueue_ that only receives hardware controller input from handleIncomingMidiMessage, and changed processBlock to record exclusively from that queue. Additionally added Shift+click support on the piano roll REC button to arm recording and auto-start transport playback simultaneously.
- 50c5adaConnected external MIDI controller input to piano roll key highlighting. Added a dedicated lock-free. SPSC queue (pianoRollMidiInputQueue_) in PluginProcessor to forward MIDI events from the device callback to the UI thread without competing with the step input or recording queues. The PianoRollViewport timer now always polls this queue and calls the existing onExternalMidiNoteOn/Off methods, which feed the PianoRollKeyHighlightManager that was already fully built but never wired up. Piano keys now light up green in real-time when pressed on an external MIDI controller.
- a0384f6Upgraded Piano Roll minimap overview to navigate both horizontally and vertically. Previously clicking or dragging the minimap only adjusted the horizontal scroll position, ignoring the vertical click coordinate entirely. Extended the onNavigate and onViewportDrag callback signatures to include MIDI note information, added vertical drag offset tracking, and wired the PianoRollViewport callbacks to set both X and Y scroll positions using the piano roll's midiNoteToY coordinate conversion.
- 4990c11Added MIDI step input mode to the piano roll. Created a lock-free SPSC ring buffer (StepInputMidiQueue) to route MIDI events from the callback thread to the message thread, and a PianoRollStepInputManager with a state machine handling chord detection via a 15ms window. Incoming MIDI notes are placed at an independent insert cursor (rendered as a dashed cyan line) which advances by the configured step size on key release. Supports 9 step sizes from whole note to triplet sixteenth, rest advancement (Right Arrow), backstep with deletion (Left Arrow/Backspace), and tie extension (T key). Added toggle button and step size combo to the control bar, with I key as the activation shortcut.
- 4cfb55aCompleted batch mute/unmute operations for piano roll notes. Added 'M' keyboard shortcut to toggle mute on selected notes, context menu Mute submenu (Mute Selected, Unmute Selected, Toggle Mute), and batch methods (muteSelectedNotes, unmuteSelectedNotes, toggleMuteSelectedNotes) with undo support and playback engine sync.
- Day 310 · 2 commits

- Audio engine
- e454572Added piano roll Pattern Repeat feature that duplicates selected notes N times with configurable. spacing and velocity variation. The dialog offers four spacing modes (Auto matches selection span, Bars, Beats, and Custom) with real-time info labels showing total span in beats and milliseconds at current BPM. Velocity modes include None, Fade Out, Fade In, Random, and Accent, each controlled by an amount slider. Created PatternRepeatDialog for the UI, PianoRollPatternRepeatAction for full undo/redo support, and wired the menu item into the Timing submenu of the piano roll context menu.
- Other
- 71365c7Replaced piano roll Ctrl+D duplicate handler with a proper implementation that uses the undo system and transfers selection to newly created notes. Previously the shortcut called duplicateSelectedNotes directly without undo support, and the offset calculation was incorrect (used absolute maxEndTime instead of the relative span). Now gathers selected note bounds, computes offset as maxEndTime minus minStartTime so duplicates land immediately after the selection block, performs the operation through PianoRollDuplicatePatternAction for full undo/redo, and selects the duplicated notes so repeated Ctrl+D chains correctly. Added getCreatedNotes getter to PianoRollDuplicatePatternAction to enable reading back assigned note IDs after the action performs.
- Day 311 · 2 commits

- Audio engine
- f545d32Added piano roll time signature support, triplet/dotted grid modes, swing quantize system, and MIDI file import with dialog. Created GridDivision.h with enumeration for grid subdivision types (normal, triplet, dotted, quintuplet) and utility functions. Added grid division dropdown and swing slider (50-75%) to PianoRollControlBar, fixing the layout to flow left-to-right so all controls are visible. Implemented MidiQuantizeHelper quantizeWithSwing() for destructive swing quantization and SwingQuantizeDialog for configuring swing amount and grid size via context menu. Built complete MIDI import pipeline with MidiFileAnalyzer for extracting track info, tempo maps, and time signatures from MIDI files, MidiImportDialog for track selection with merge/replace modes and tempo import option, and PianoRollMidiImportAction for full undo/redo support. Wired 'Import MIDI File...' and 'Quantize with Swing...' menu items to context menu in PianoRollContextMenuHandler. Fixed compilation errors in importMidiFileWithDialog() by using processorRef.getUndoManager() pattern and setting BPM via APVTS parameter.
- Timeline
- c58d676Fix project load hang caused by O(n) XML character scan Remove redundant bracket-counting loop in validateProjectXML() that iterated through every character of the XML string (1.8MB+) to count < and > brackets. This check was unnecessary since JUCE's XML parser already validates well-formedness during parsing.
- Day 312 · 4 commits

- Audio engine
- a13755bAdded pattern duplication feature to piano roll with dialog, full note property preservation, and keyboard shortcut. Enhanced DuplicatedNote struct to carry channel, probability, mute, and MPE expression data. Created PatternDuplicateDialog with offset mode options (auto/bars/beats/custom) and BPM-aware info display. Added addNoteWithProperties method to BasePianoRollComponent for full-fidelity note creation during duplication. Updated collectPatternDuplicateData to deep-copy all note properties including MPE curves. Wired Ctrl+Shift+D keyboard shortcut through both keyPressed handler and PianoRollInteractionHandler callback. Connected context menu 'Duplicate Entire Pattern' to dialog flow with undo/redo support via PianoRollDuplicatePatternAction.
- 5c29c52Added MIDI export feature to piano roll with File dropdown menu in control bar. Created MidiExportDialog with options for export scope (all/selection), track name, tempo, time signature, and MIDI resolution. Implemented exportMidiFileWithDialog in BasePianoRollComponent that builds export summary, shows configuration dialog, opens file chooser, and writes standard MIDI file with tempo/time signature metadata. Wired File menu callbacks through PianoRollViewport to connect Import and Export actions.
- UI / UX
- 9fa7eceAdded batch transpose feature to piano roll with dialog, undo/redo, and keyboard shortcuts
- Other
- 3c74249All debug statements have been removed from. ProcessorState.cpp - Removed all TRACE DBG statements. SequencerState.cpp - Removed all DBG statements from loadState and loadPianoRollData
- Day 313 · 4 commits

- Audio engine
- 1e0b4a5Added real-time arpeggiator MIDI effect system with per-track effect chains, toggle-based UI, and ghost note preview. Created MidiEffects infrastructure including MidiEffectProcessor base class, MidiEffectChain per-track container, MidiEffectManager central orchestrator, and ArpeggiatorProcessor with pattern generation supporting Up, Down, UpDown, DownUp, Random, and AsPlayed modes. Integrated MIDI effect processing into PluginProcessor processBlock after PianoRollPlaybackEngine. Modified PianoRollArpeggiatorSelector to toggle real-time arpeggiator on left-click instead of destructive apply, with cyan highlight and bracketed text indicating active state. Added 'Print to Notes' menu option for destructive baking with existing undo support. Implemented ghost note preview in PianoRollPaintManager showing upcoming arpeggiated notes as semi-transparent cyan rectangles. Fixed held note population by extracting note-on/off events from MIDI buffer in MidiEffectChain::processBlock, enabling arpeggiator to capture piano roll notes during playback. Added getTrackIndex accessor to PianoRollViewport and getPatternNoteAt accessor to ArpeggiatorProcessor for UI integration. Forwarded MIDI input note events from MidiInputProcessor to effect chains for external controller latch mode support.
- a51ad9cMIDI Effects Foundation
- 25f9831 Added beat marker support to GpuWaveformRenderer to display tempo-aligned grid lines on waveform displays when GPU rendering is active. The existing WaveformBeatMarkerOverlay component used standard JUCE Graphics painting, but OpenGL composites after all JUCE paint() calls, causing the GPU waveform to render over the beat markers. Fixed by integrating beat marker rendering directly into the OpenGL render pass. Added public API methods setBeatMarkersEnabled(), setMeasureLinesEnabled(), setBeatMarkerColour(), setMeasureLineColour(), setDownbeatColour(), and setBeatMarkerConfig() to GpuWaveformRenderer. Implemented cached BeatGridLine struct with recalculateBeatGridLines() for efficient grid calculation. Beat markers render using OpenGL immediate mode after the waveform but before the playhead, matching the existing playhead rendering pattern. Updated WaveformDisplayComponent to pass beat marker state and timing configuration to the GPU renderer during paint(), including theme-aware downbeat colouring. Lowered minimum spacing thresholds from 4px to 2px for beats and 20px to 8px for measures to ensure visibility when viewing long samples. Fixed beatMarkerConfigDirty flag not being reset on early exit paths, which was causing unnecessary recalculation every frame.
- c0752e1Added bounds validation guards across all piano roll note rectangle construction paths to prevent Direct2D crash. The crash occurred in JUCE's finishFrame() when getNoteBottomY() produced values that created negative or zero-height rectangles, corrupting the D2D device context render state. Added width/height validation at 9 locations in BasePianoRollComponent.cpp covering playback highlights, MPE badge/trail click and hover hit testing, lasso and selection manager rect converters, and note hit testing. Fixed paintRecordingPreview height threshold in PianoRollPaintManager.cpp to account for the 2-pixel inset. Gated all drum mode debug tracing to only fire when drumModeActive is true to reduce log noise. Added debug trace to setDrumModeEnabled and isNoteInViewport culling path for ongoing drum mode diagnosis.
- Day 314 · 9 commits

- Audio engine
- c9e8191Added manual track delay compensation with per-track timing offset and smart lookahead latency. Created TrackDelayBuffer class using juce::dsp::DelayLine with SmoothedValue for click-free delay transitions supporting a bipolar range of -100ms to +100ms per track. Integrated delay buffer into TrackChannel by refactoring the process() method to accumulate all player audio into an internal mix buffer before applying delay and routing to mixer buses. Added smart lookahead calculation in MixerEngine that computes the minimum negative delay across all tracks and shifts all effective delays so the most negative becomes zero, reporting the offset as plugin latency to the host via dynamic setLatencySamples() updates in PluginProcessor. Added delay compensation knob to TrackControlRow as a hidden-by-default column controlled through CollapseStateManager visibility flags, and to MixerChannelStrip as an always-visible rotary knob for regular tracks with automatic hiding on the master strip. Extended CollapseStateManager getWidthForStage() and getVisibilityFlags() to support the new hideDelayComp flag, and wired context menu callbacks for column show/hide toggling.
- 991b905Added dithering options for audio export with triangular, rectangular, and noise-shaped algorithms. Created DitherProcessor class that applies configurable dither noise to float audio buffers before bit-depth reduction to 16-bit or 24-bit integer formats. Integrated dithering into ExportAudioEngine's writeToWavFile pipeline where a copy of the buffer is dithered before writing, preserving the original. Added dither type combo box and amount slider to ExportManagerWindow's. Processing Options section with automatic visibility toggling based on selected bit depth. Extended ConversionSettings and AudioConverter to apply per-chunk dithering during batch file conversion. Added dither type selector to BatchConversionDialog for consistency across both export paths.
- 930cd9dAdded automation point quantize feature with configurable grid resolution and strength. Created AutomationQuantizeDialog providing UI for snapping automation points to musical grid positions with resolution options (bar, beat, 1/2, 1/4, 1/8 beat) and strength settings (100%, 75%, 50%, 25%). Integrated BPM and time signature awareness via processor's getEffectiveBPM() and getBeatsPerBar() accessors. Real-time preview displays affected point count, grid interval in milliseconds, and maximum shift distance. Added 'Quantize Points...' context menu option to both AutomationCurveEditor (standalone) and AutomationMouseHandler (timeline). Full undo/redo support via existing AutomationPointsScaleAction.
- c3de9daAdded parameter copy/paste functionality for mixer sliders with semantic type matching. Created ParameterClipboardHandler class that enables copying slider values with Ctrl+C and pasting to compatible sliders with Ctrl+V. Implemented semantic type inference from parameter IDs allowing paste between same-type parameters across tracks (e.g., any volume to any volume, any pan to any pan). Added parameterID tracking to ModulatableSlider with callback mechanism for components in separate windows. Integrated with ParameterGestureTracker for full undo/redo support. Wired mixer channel strip volume, pan, width, and input gain sliders to the clipboard system. Visual feedback provided via InfoChiron showing copied values and paste confirmations.
- 10e2017Added track duplication feature with dialog, undo support, and full data copying across all grids. Created TrackDuplicator helper class that copies 60+ cell parameters including samples, effects, envelope, reverb, delay, pitch, filter, granular settings, and timeline clips. Implemented DuplicateTrackDialog with destination track selector, clear destination toggle, and name suffix option. Added DuplicateTrackAction for full undo/redo support with ValueTree-based state capture. Wired dialog into both GridContextMenuBuilder for grid track headers and TrackControlStripComponent for mixer track names, replacing the placeholder 'Coming soon' stub.
- UI / UX
- ce711d9Fixed shift+drag resize handle not revealing the delay compensation column. The delay comp visibility was gated by both the collapse stage and a separate hide flag that defaults to true, meaning the stage alone was insufficient to show it. Added delay comp as the third step in the shift+drag pullout chain after width section, following the same reveal/hide pattern. Extended both the right-drag expand chain (stages, width, delay comp) and left-drag collapse chain (delay comp, width, stages) to handle all three levels incrementally. Also fixed a double-hide bug in the left-drag path where both delay comp and width would disappear simultaneously instead of one at a time. Wired the new callback in TrackControlStripComponent to toggle hideDelayCompColumn and synced resize handle state in both the delay comp context menu handler and showAllHiddenControlSets.
- 5e7a686Added automation fade in/out generator with configurable curve shapes and point density. Created AutomationFadeInOutDialog providing UI for generating smooth fade curves on automation lanes with options for direction (fade in/out), start time, duration, start/end values (0-100%), curve shapes (linear, exponential, logarithmic, S-curve), and point density (10-100 points). Integrated into both timeline automation context menu via AutomationMouseHandler and standalone AutomationCurveEditor context menu. Existing points within the fade region are automatically replaced while preserving points outside. Full undo/redo support via AutomationPointsScaleAction.
- 24c3707Added automation point thinning feature with Ramer-Douglas-Peucker algorithm for reducing curve density while preserving shape. Created AutomationThinDialog with configurable tolerance slider (0.1-10%), real-time preview showing point reduction statistics, and full undo/redo support via AutomationPointsScaleAction. Integrated into timeline automation context menu in AutomationMouseHandler with 'Thin Points...' option that enables when curves have more than 2 points. Algorithm preserves first/last points and Step curve types which represent intentional hard transitions. Also added optional processor reference to AutomationCurveEditor and AutomationCurvePanel constructors for standalone curve editor support.
- 4e63c03Added batch quantize dialog for sequencer patterns with full undo support. Created BatchQuantizeDialog providing UI for scope selection (all tracks/selected track), target selection (timing/gate/both), quantize strength (100%/75%/50%/25%), gate length targets, and swing-aware option. Implemented SequencerQuantizeAction wrapping the existing quantizeActivePattern functionality with proper undo/redo through the backup/restore mechanism. Added 'Quantize Pattern...' menu item to sequencer grid context menu. Dialog loads current settings from SequencerState and displays real-time preview of configuration.
- Day 315 · 7 commits

- Audio engine
- 292e9ffAdded expandable Variation Curve Editor panel (Phase A), Semantic Condition Mapping system (Phase D), and Range Slider interpolation (Phase B) to the Duplicate with Variations dialog. Phase B adds start/end range sliders with four interpolation modes (Linear, Exponential, S-Curve, Random) for pitch, volume, pan, and filter cutoff parameters, with gradient coloring in the grid preview for ranged targets. Phase D introduces a semantic condition mapping system with 9 axes (time brightness/energy/calm, weather wetness/intensity/clarity, season warmth/lushness/melancholy), 12 presets across Time/Weather/Season grids, and an intensity slider that modulates condition-aware parameter curves evaluated at each destination cell's actual condition index. Phase A adds a disclosure-toggled curve editor panel with stacked parameter lanes showing draggable per-condition points, smooth interpolation (Linear/Hermite/Step), abbreviated condition header labels with interval thinning, and factory-created lanes for pitch, volume, pan, and filter cutoff. Curve overrides are the highest priority layer in the delta merge chain (preset → range → semantic → manual → curve). Fixed a construction-order crash where PresetsTab constructor called updatePreviewSummary() before parametersTab_ was initialized by adding null guards. New files: SemanticConditionMapping.h/.cpp, SemanticMappingPanel.h/.cpp, VariationConditionLabels.h, VariationCurveData.h, VariationCurveLaneComponent.h/.cpp, VariationCurveEditorPanel.h/.cpp.
- 7599675Updated DuplicateWithVariationsDialog and VariationGridPreview to use full DesignTokens theme-aware color system. Replaced all hardcoded hex colors and juce::Colours constants with getThemeAwareSurface(), getThemeAwareTextPrimary(), getThemeAwareTextSecondary(), getThemeAwareColor(), getThemeAwareBorder(), and getThemeAwareButtonColor() calls that respect Living theme time-of-day interpolation and Dark theme modes. Enlarged dialog from 900x700 to 920x800 and increased row heights from 24px to 28px in ParametersTab to give controls adequate room. Converted six hardcoded paint()-time section headers (PITCH, VOLUME/PAN, FILTER, ENVELOPE, PLAYBACK, GRANULAR) to juce::Label components positioned in resized() for correct alignment with the new row sizing. Increased preset card height from 56px to 66px, filter/option rows from 28px to 32px, and footer button width from 130px to 160px. Added processorRef_ to VariationGridPreview for ConditionMonitor access, and getHour()/getMinute() helpers to the dialog for passing theme state to PresetCardComponent and tab constructors. Applied DesignTokens::runtimeConfig font sizes (caption, small, body, heading) throughout all tabs replacing hardcoded pixel values.
- 2e0333eFixed source cell parameter values being stale when copied to variation destinations. The envelope tab UI writes vol/pan/ADSR changes to APVTS via Attachments but not to celloBridge, while copyCellDataCrossCondition and the preset generator sourceData struct both read from celloBridge. Added syncAPVTSToSampleCellWrapper for the source cell at the top of generate() so that current UI-edited values are available before any cross-condition copies or preset delta calculations occur.
- 372d6c1Fixed Duplicate with Variations parameter overrides (pan, volume, ADSR) not applying to duplicated copies. The variation engine wrote parameter deltas to celloBridge via SampleDataManager setters, but the audio thread reads these values from APVTS cached atomic pointers, which were never updated. Added syncSampleCellWrapperToAPVTS calls in DuplicateWithVariationsAction for both perform and undo paths, pushing celloBridge values into APVTS so the audio thread picks up the correct parameters for all affected cells.
- 44bc619Removed legacy sampleLists dual-store from SampleDataManager, eliminating the dead gridData->sampleLists storage that previously caused confusion and a runtime bug where sample path writes went to the wrong store. Added insertSamplePath and moveSamplePath methods to SampleCellWrapper to support the redirected operations. Rewrote removeSampleFromCell, insertSampleInCell, moveSampleInCell, and setSampleListForCell to route through celloBridge instead of the removed legacy arrays. Fixed swapCellData which previously swapped only the dead store without updating celloBridge. Removed the sampleLists member from ConditionGridData, its resize lambda, and its initialization and clear logic. Cleaned up sample paths sync blocks from synchronizeToLegacyArrays, synchronizeFromLegacyArrays, and validateSynchronization in SampleDataManagerIntegration, and removed stale dual-store comments from VariationGenerationEngine and DuplicateWithVariationsAction.
- 9cb5d41Added Duplicate with Variations feature for generating sample variations across empty grid cells. Created VariationPresetDefinitions.h with 12 built-in musical presets (Octave Layers, Harmonic Intervals, Detuned Doubles, Pitch Spread, Reversed Ghost, Granular Texture, Time Stretch Versions, Stutter Chop, Velocity Layers, Envelope Shapes, Filter Sweep, Dark/Bright Pair) organized by category with configurable sub-options. Built VariationGenerationEngine for target cell discovery using outward-walk algorithm and cross-condition cell copying with full parameter delta application. Implemented tabbed DuplicateWithVariationsDialog (Presets, Parameters, Destination, Templates) with category filtering, manual parameter overrides, and VariationGridPreview mini-grid visualization showing source, target, occupied, and empty cells. Added DuplicateWithVariationsAction for single Ctrl+Z undo of entire batch operations. Wired into context menu system through GridCommand, GridContextMenuCallback, GridContextMenuBuilder (both tooltip and non-tooltip paths), GridSampleOperationsHandler, and BaseGridComponent. Fixed celloBridge data store mismatch where setSampleListForCell wrote to dead legacy storage by using addSampleToCell for forward path and setSamplePath for undo restore.
- UI / UX
- 53042c9Applied EphemeraLookAndFeel to DuplicateWithVariationsDialog so all controls render with the app's custom styling instead of default JUCE appearance. Added a dedicated EphemeraLookAndFeel instance owned by the dialog with time-of-day override since the detached DialogWindow cannot inherit the editor's LookAndFeel through JUCE's parent hierarchy. Set the LookAndFeel on the dialog component before child construction so all filter buttons, preset cards, Apply/Cancel buttons, parameter sliders, combo boxes, toggle buttons, scrollbars, and tab bar styling are inherited automatically. Added destructor to clear LookAndFeel references on all tab components before the owned instance is destroyed, preventing dangling pointers. Follows the same pattern established by PluginSettingsWindow.
- Day 316 · 9 commits

- Audio engine
- a35ef2fAdded audio device loss handling system for graceful recovery from device disconnection. Created AudioDeviceLossHandler class that detects device loss through JUCE lifecycle callbacks (prepareToPlay/releaseResources), automatically pauses playback and safely stops recording to preserve data, notifies users via dialog when device is lost, and tracks device state for automatic recovery. Integrated handler with PluginProcessor lifecycle methods and connected it to AudioRecorder for safe abort on disconnection. Added getEditorPlayState() accessor to PluginProcessor for thread-safe play state queries. Uses JUCE's RT-safe millisecond counter for timing and AsyncUpdater pattern for thread-safe UI notifications.
- f0caedaAdded AudioBufferSafetyGuard system for comprehensive buffer safety hardening. Created Source/AudioBufferSafetyGuard.h with safe copy/add operations featuring automatic bounds clamping (SAFE_BUFFER_COPY, SAFE_BUFFER_ADD, SAFE_BUFFER_ADD_RAMP macros), debug-mode canary values to detect buffer overwrites post-hoc via CanaryGuard RAII class, SIMD alignment validation utilities, and thread-safe metrics tracking. Integrated with highest-risk audio paths: MixerEngine::processGlobalEffects (reverb/delay mixback), SamplePlayer::processAdding (granular output), ReverbScJuceProcessor/EphemeralDelayProcessor (pre-delay buffer access with extra bounds checks), and TrackChannel::process (sequencer routing, player pool mixing, effect sends). Added DEBUG_BUFFER_SAFETY_ENABLED flag to DebugConfig.h (default off for performance). All safety operations are real-time safe (no allocations, no locks, inline functions) with zero overhead when debug mode is disabled.
- 24ab5e3Added MIDI buffer overflow prevention system to protect against high-density MIDI streams from DAW hosts. Created MidiBufferManager class with lock-free circular buffer, priority-based message filtering (note events never dropped, lower-priority CC/SysEx filtered first), and configurable thresholds (768 warning, 896 critical, 1024 max events per block). Implementation uses pre-allocated scratch buffer for RT-safe filtering without audio thread allocations. Integrated into PluginProcessor.processBlock() after MIDI forwarding merge, with deferred overflow warning logging via handleAsyncUpdate(). Added DEBUG_MIDI flag to DebugConfig.h for diagnostic output. Exposed getMidiBufferMetrics() and resetMidiBufferMetrics() accessors for UI monitoring of overflow statistics including total messages received/dropped, overflow event count, and peak buffer usage.
- c0fa5b8Added parameter smoothing to ReverbScJuceProcessor and EphemeralDelayProcessor to eliminate zipper noise and clicks during automation playback. Reverb processor now smooths feedback (10ms), LP frequency (10ms at block rate), and mix (5ms per-sample) using juce::SmoothedValue. Delay processor smooths feedback and mix (5ms per-sample) and damping cutoff (10ms at block rate). Delay time is intentionally left unsmoothed as abrupt changes create useful pitch artifacts for creative effects. Follows the same pattern established in SoftClipperProcessor with midpoint sampling for smoother transitions across audio block boundaries.
- d614096Added envelope looping mode to ADSR envelope generator with three modes: Off (standard ADSR), Sustain Loop (oscillates between loop start and sustain level during sustain phase using smooth sine interpolation), and Full Loop (restarts entire ADSR cycle continuously). Registered six new APVTS parameters (Env1/Env2_LoopMode, LoopStart, LoopEnd) in ParameterHelpersEffects.cpp with 0-100% normalized ranges. Extended ADSREnvelope class with loop parameter caching, processLoopLogic() for timing calculations, and calculateLoopValue() for smooth amplitude interpolation. Added loop mode combo box and conditional loop start/end sliders to EnvelopeControlPanel that show/hide based on selected mode. Updated EnvelopeVisualizer to display loop regions with gold-highlighted sustain loop indicators and curved return arrows for full loop mode. Fixed envelope panel height clipping in ModulationRoutingRowComponent by adding getTotalRequiredHeight() method to EnvelopeControlPanel and replacing hardcoded 140px with dynamic height calculation (~270-310px depending on loop visibility), with onHeightChanged callback to update parent layout when loop mode toggles.
- fa37573Added tanh-based soft clipper/saturator effect to the master bus with configurable drive (0-24dB), knee shape, and output ceiling parameters. Created SoftClipperProcessor DSP class with RT-safe per-sample processing, smoothed parameter transitions, and atomic gain reduction metering. Placed soft clipper controls (drive knob + bypass toggle) in the master channel strip's delay compensation slot, fixing the vertical alignment mismatch between master and numbered tracks by always allocating 44px for that layout region. Added right-click context menu on the drive knob for knee and ceiling presets. Bypass defaults to ON so existing projects are unaffected. New files: SoftClipperProcessor.h/.cpp.
- UI / UX
- 64de680Added undo stack overflow protection with configurable limits in Advanced settings. Created UndoStackLimiter class wrapping JUCE's setMaxNumberOfStoredUnits() to manage undo history size. Added Memory Management section to Advanced settings tab with dropdown for selecting limit presets (25, 50, 100, 200, 300 actions). Integrated with UIPreferencesManager for persistence across sessions. Status label displays real-time usage and shows orange warning when approaching 80% of limit. Oldest actions are automatically pruned when limit is reached.
- e845b2cFixed crash in EnvelopeVisualizer::drawLoopRegion() that occurred when dragging the loop end slider below the loop start value. The issue was caused by a negative height being passed to g.fillRect() when loopEnd < loopStart resulted in a negative calculation for the rectangle dimensions. Added proper value ordering using juce::jmin/jmax to ensure loopStartVal is always the smaller value and loopEndVal is always the larger, and added minimum height validation (1.0f) to prevent zero or negative dimensions in graphics operations.
- 1698df7Added per-routing-slot environmental modulation smoothing to prevent abrupt parameter jumps when condition sources (Time of Day, Weather, Season, Location, Moon Phase, Wind Speed) change. Registered 32 ModSmooth_N APVTS parameters (0–30s range, 0.3 skew, 2s default) and implemented a one-pole exponential lowpass filter in ModulationEngine that runs at block rate, applied only to environmental sources while LFOs and envelopes pass through unsmoothed. Each routing slot gets its own independent smoothing time so the same source routed to different destinations can glide at different rates. Added a 'Smooth:' slider to ModulationRoutingRowComponent that appears automatically when an environmental source is selected and hides for non-environmental sources, with value display formatting (Off / ms / s). Inactive slots reset their smoothing state to zero to prevent stale glides on reuse. Excluded ModSmooth_ parameters from the modulation destination list to prevent circular routing.
- Day 317 · 9 commits

- Audio engine
- 79613f6Added MidiMapping module with MidiMappingTypes.h defining core data structures including 64-byte cache-aligned slots for audio thread safety, MidiMappingProcessor.h/cpp implementing double-buffered lock-free CC processing with 20ms value smoothing to prevent zipper noise, and MidiMappingManager.h/cpp providing CRUD operations, auto-detect learn mode state machine, factory presets (Default, Mix Controls, Transport), user preset management, and import/export to .ephemera-midi XML files. Integrated MidiMappingProcessor into PluginProcessor processBlock for real-time CC handling and wired MidiMappingManager initialization. Added ValueTree persistence to ProcessorState with saveMidiMappingsToState and loadMidiMappingsFromState methods. Connected existing MIDI Learn UI in PluginMidiTabComponent to MidiMappingManager, wrapping callbacks in MessageManager::callAsync to prevent threading crashes from MIDI thread UI updates. Supports linear and logarithmic scaling modes, relative encoder protocols (SignedBit, BinaryOffset, TwosComplement), and per-mapping channel filtering
- ab759aaAdded Project Consolidation feature that gathers all external audio assets into a portable project folder. Created Consolidation module with ProjectConsolidationManager for background file operations, ProjectAssetCollector for scanning grid samples and timeline clips across all condition types, ProjectConsolidationDialog with time-of-day theming showing file list with status icons and details panel, and ConsolidationHelper utilities for file copying with CRC32 verification. Integrated consolidation status display and button into File Settings tab that updates automatically via DocumentManager change listener when projects are saved or loaded. Dialog displays destination folder path, external file count with sizes, and available disk space. Supports optional ZIP archive creation after consolidation. Fixed crash during path updates by ensuring SampleDataManager always receives absolute paths rather than relative paths which juce::File cannot parse.
- e7b1773Implemented Project Consolidation feature for packaging all project assets into a portable folder structure. Created ConsolidationTypes.h defining AssetInfo, AssetCategory, AssetStatus, ConsolidationOptions, ConsolidationProgress, ConsolidationResult, and SpaceAnalysis data structures. Implemented ConsolidationHelper with static utility methods for file copying with CRC32 verification, unique filename generation, path validation, byte size formatting, and condition name lookups. Built ProjectAssetCollector that scans all five condition grids (Time, Weather, Season, Location, MoonPhase), multi-sample cell lists, timeline clips, and unassigned samples while detecting duplicates and categorizing files as external, local, missing, or large. Created ProjectConsolidationManager with background thread worker for file operations, AsyncUpdater pattern for thread-safe progress callbacks, automatic pre-consolidation backup creation, optional ZIP archive generation, and path update orchestration. Designed ProjectConsolidationDialog with time-of-day theming, scrollable asset list showing status icons and file sizes, details panel for selected assets, space analysis summary, toggle options for path updates and ZIP creation, progress bar with phase and file count indicators, and results display with error reporting. Integrated consolidation UI into PluginFileTabComponent File Settings tab with status label showing external asset count and size, and Consolidate button that launches the dialog. Added all nine new source files to TimeSampler.jucer build configuration.
- bb99902Created SampleSearcher utility that searches parent folders, project Samples directories, user-specified paths, and platform-specific default locations (Music folder, Native Instruments, Splice) for missing audio files. Implemented RelocationHistoryManager that persists individual file relocations and folder-level mappings to XML in the Ephemera app data directory, automatically applying known relocations on future project loads. Built MissingSampleRelinkDialog component with list view showing all missing samples with resolved/missing status indicators, Locate button for manual file browsing, Auto-Search for automatic discovery, and Batch Relink for handling moved folders. Updated StateLoadApplicator to show the dialog instead of just an InfoChiron notification when missing files are detected after project load. Added RelocationHistoryManager member to PluginProcessor for session-wide relocation tracking. Dialog uses time-of-day theming consistent with Ephemera's design language and reports relink results to InfoChiron upon completion.
- Effects
- 850bc81Added atomic file write operations to prevent project corruption during saves. Created AtomicFileWriter helper class that implements the write-to-temp-then-rename pattern, ensuring the original file remains intact if a crash or power failure occurs mid-write. Integrated atomic writes into AutoSaveManager::performAutoSave() and EditorPanelManager::performStateSave(). Added optional InterProcessLock support to prevent concurrent writes from multiple plugin instances accessing the same project file.
- UI / UX
- 4bb16feFixed thread cleanup crash when closing the consolidation dialog by properly stopping the worker thread before destruction. Updated ProjectConsolidationManager destructor to signal thread exit and wait up to 10 seconds before using stopThread as a last resort to prevent destroying a running thread. Added signalThreadShouldExit call to cancelConsolidation method for faster cancellation response. Replaced blocking Thread::sleep calls in the consolidation thread with interruptible loops that check the cancel flag every 10ms, allowing the thread to respond to cancellation requests promptly. Updated dialog destructor to explicitly reset the manager ensuring proper thread cleanup order during destruction.
- 73b4c31Added CRC32 checksum validation to auto-save and backup file operations for corruption detection. Created FileIntegrityValidator utility class with checksum calculation and validation methods. Updated EditorPanelManager to write checksums during save and validate them during load, showing a warning dialog if mismatch is detected with option to load anyway or cancel. Updated AutoSaveManager to include checksum and data size in auto-save file format with static validation method. Added post-copy integrity verification to BackupManager that deletes corrupted backups. Extended CrashRecoveryManager RecoveryFile struct with IntegrityStatus enum and validation during recovery file list generation. Updated RecoveryWizardDialog to display integrity status with color coding (green=verified, orange=legacy, red=corrupted), disable restore for corrupted files, and show warning indicators in file list. All changes are backwards compatible with existing files that lack checksums.
- b82718cAdded auto-save first-run dialog and changed default to ON for better user protection. Created AutoSaveFirstRunDialog component that shows on first standalone launch, explaining auto-save benefits and allowing users to configure interval (1-60 min) and max backups (1-20). Dialog uses time-of-day theming and requires explicit user choice between 'Enable Auto-Save 'Recommended' and 'Don't Enable'. Changed autoSaveEnabled default from false to true in both AutoSaveManager and PluginFileTabComponent. Integrated first-run check into EphemeraStandaloneApplication startup flow after crash recovery but before session restore. Added gentle reminder dialog when users disable auto-save in File Settings, encouraging manual saves.
- Other
- 10c3b64Global Smoothing Coverage
- Day 318 · 14 commits

- Audio engine
- bcfd208Added editorChromeVisible flag to WaveformDisplayComponent enabling marker overlay rendering without toolbar and overview strip chrome. Gated editor toolbar and overview strip visibility behind the chrome flag in setEditorModeActive and resized, while keeping marker overlay always visible in editor mode regardless of chrome setting. Configured SampleEditingTabComponent's compact waveform display with chrome-free editor mode activation in updateWaveformDisplay, providing 1:1 visual parity of trim handles, loop markers, and fade curves between the main waveform display and the sample settings panel. Both displays now stay synchronized in realtime through the existing 20Hz SampleDataManager polling timer.
- a11c0ebAdded realtime SampleDataManager polling during waveform editor mode using a 20Hz Timer that syncs trim, loop, and fade marker positions with changes made in the Sample Settings Panel. Fixed marker overlay invisibility caused by OpenGL z-order by hiding the GPU renderer when entering editor mode, falling back to CPU waveform rendering so software-rendered overlays paint on top. Synced displayTrimStartNormalized and displayTrimEndNormalized from SampleDataManager in updateMarkerOverlayFromCellData so CPU waveform shading matches marker overlay positions. Disabled CPU renderer trim handle drawing when editor mode is active to prevent double-rendering. Added auto-enable behavior for Loop tool that enables loop with default 0-1 range when selected, and Fade tool that seeds 2% duration default fades when both are zero. Redesigned loop markers with triangular grip tabs at the bottom of each boundary line for visual distinction from top-positioned trim handle grips, with boosted alpha values. Added change detection to all WaveformMarkerOverlay setters to avoid unnecessary repaints from timer polling. Moved pixelXToNormalized and normalizedToPixelX to public interface for external coordinate conversion by WaveformInteractionHandler.
- 3363398Added waveform editor Phase 1 with per-cell non-destructive fade-in/fade-out, independent loop points, and normalize gain data model and audio processing. Created WaveformEditTypes.h defining FadeCurveType enum(Linear, Logarithmic, SCurve, EqualPower) with inline computeFadeCurve function. Added 9 atomic members and setters to SamplePlayer with fade envelope application and normalize gain integration into processAdding() gain chain, plus independent loop boundary support separate from trim points. Added 9 Cello::Value properties to SampleCellWrapper for auto-serializing grid cell data. Extended SampleDataManager UnassignedSampleData with 9 fields, 18 getter/setter implementations, and conditional non-default-value XML serialization. Wired all parameters through TrackChannel configurePoolPlayer using pre-loaded map pattern matching existing granular/filter wiring. Connected SampleEditingTabComponent placeholder fade and loop sliders to real SampleDataManager data with save-on-change and triggerAsyncConditionUpdate, updated fade slider range to 30000ms, and added loop start/end constraint enforcement
- 5aae40aFix data loss on project load caused by apvts.replaceState() discarding non-APVTS child nodes before subsystems could read them. Moved all remaining load calls that use getChildWithName() to before replaceState(), matching the pattern previously applied to stepSequencer and celloBridge. Affected subsystems: sequencerState, timeline markers, tempo map, reverb presets, MIDI mappings, zoom presets, GridRegistry, trackDataManager, grid mute/solo, grid volume/pan, all sampleBrowserPersistence loads, UIPreferencesManager, uiStateTree extraction, collectUnknownNodes, and GridTrackOrderManager. Also added three load calls that were missing entirely from the successful load path but present in the error reset paths: loadGridHeaderNamesFromState, loadLFOVisualizerHeightsFromState, and loadTimelineOrderFromState.
- 299a79eAdded step sequencer modulation source with 16-step BPM-synced pattern editor, configurable resolution and interpolation modes, and preset patterns. Created StepSequencerModSource with lock-free atomic step values, host transport-synced stepping via ppqPosition, and Hold/Ramp interpolation. Created StepSequencerControlPanel with interactive click-drag bar visualizer, 30Hz GridTimerManager-driven step highlight animation, and six preset patterns (All Max, All Zero, Random, Ramp Up, Ramp Down, Alternating). Registered StepSeq1 in ModulationSourceManager and added Step Seq 1 option to ModulationRoutingRowComponent source selector with inline control panel display. Added three APVTS parameters for step count, resolution, and interpolation mode. Added ValueTree-based step pattern persistence in ProcessorState with save/load before apvts.replaceState to prevent loss of non-APVTS child nodes. Fixed modulation routing source, destination, and via-source selections not restoring on load by moving celloBridge.loadFromValueTree call before apvts.replaceState, which was discarding the ModulationMatrixNode child before the Cello bridge could read it.
- 4d2eeb9Added view transition animation system with snapshot-based crossfade, directional slide, and scale-fade effects for smooth view switching. Created ViewTransitionTypes.h defining TransitionType, TransitionContext enums and TransitionConfig with per-context defaults. Created ViewTransitionOverlay as lightweight rendering component with four transition painters using AnimationUtils easing functions and threshold-based repaint guards. Created ViewTransitionManager orchestrating transition lifecycle through GridTimerManager at Critical priority with adaptive quality degradation that halves duration after three consecutive slow frames and cancels outright under sustained load, plus half-resolution snapshot capture for 4K displays exceeding 8MP. Integrated transition interception into EditorViewManager updateViewVisibility with state tracking to detect grid tab switches, grid mode switches, and major mode switches, capturing outgoing snapshots before visibility changes and executing animations after layout completes. Added ViewTransitionManager ownership to PluginEditor with overlay as child component, proper destruction ordering, and public accessor. Extended UIPreferencesManager with viewTransitionsEnabled and viewTransitionSpeedMultiplier preferences including ValueTree serialization. Added toggle and speed slider controls to PluginInterfaceTabComponent Appearance section wired through to both UIPreferencesManager persistence and live ViewTransitionManager updates. Moved EditorPanelManager setGpuRendererHiddenForOverlay to public interface for GPU renderer hiding during major mode switch transitions.
- 50297edAdded stereo correlation meter to mixer master channel strip with click-to-expand goniometer popup. Created GoniometerRingBuffer with lock-free 4096-sample ring buffer using atomic release/acquire semantics for audio-to-UI data transport. Integrated Pearson correlation coefficient computation into MixerEngine updateFinalOutputMetering combined with existing peak/RMS loop to avoid a second buffer pass, with EMA smoothing at 300ms time constant and min-hold tracking decaying at 0.67 units/second. Created StereoCorrelationRenderer static drawing class with compact correlation bar, goniometer XY scope using M/S coordinate transform for 45-degree rotated Lissajous display with 8-frame phosphor decay history, detailed correlation bar with min-hold triangle marker, and L/R balance indicator. Created StereoCorrelationBarComponent as 22px compact bar positioned below the master fader and StereoCorrelationPopup as 240x280 floating overlay dismissed on focus loss. Added thin accessor delegations through PluginProcessor to MixerEngine correlation data. Integrated Living Theme color forwarding through MixerPanel updateThemeBaseColor.
- c7759e7Added parameter gesture tracking for undo support to TrackControlRow, EnvelopeControlPanel, and LFOControlPanel. Extended TrackControlRow with Slider::Listener interface to track drag gestures on volume, pan, reverb send, delay send, delay comp, and input trim knobs, wired via setProcessorForGestureTracking called from TrackControlStripComponent during construction. Added sliderDragStarted and sliderDragEnded overrides to EnvelopeControlPanel covering attack, decay, sustain, release, loop start, and loop end sliders with cached parameter IDs for env1/env2 variants. Added matching gesture callbacks to LFOControlPanel for rate and phase sliders with cached parameter IDs for LFO1/LFO2 variants. All three follow the established MixerChannelStripGestureHandler pattern of capturing normalized parameter values at drag boundaries and delegating to ParameterGestureTracker for smart grouping and undo action creation. Moved CTRL-002 feature to bottom of implementation order in features.yaml and updated status to in_progress with notes reflecting completed coverage areas.
- Timeline
- 3455888Waveform Display: Added Loop section display, and fade display, synced trim between waveformdisplay and samplesettingspanel
- 4061f4dWaveform Display: Trim markers fixed
- UI / UX
- c2f8e2eAdded right-click context menu on fade curves in editor mode that displays the four available curve types (Linear, Logarithmic, S-Curve, Equal Power) with the current selection ticked. Intercepted right-click in WaveformInteractionHandler before the standard context menu when the mouse is over a fade curve, querying the current curve type from WaveformMarkerOverlay via new getFadeInCurve and getFadeOutCurve getters. Wired the async menu selection through a new onFadeCurveTypeChangedCallback to update SampleDataManager and refresh the marker overlay immediately
- 8b4f391Added waveform editor inline expansion UI with toolbar, marker overlay, and handle dragging (Phase 2). Created WaveformEditorToolbar with Trim/Loop/Fade tool selection radio buttons, Snap:ZX and Grid toggles, and Normalize/A-B/Collapse operation buttons using FlexBox layout with time-of-day themed background. Created WaveformMarkerOverlay rendering orange trim handles with triangular grip tabs, skyblue loop markers with bracket indicators and LOOP label, and limegreen/orangered fade curves using computeFadeCurve paths, all with 8px hit-zone detection and hover highlighting. Created WaveformOverviewStrip as 12px minimap showing simplified waveform thumbnail with white viewport rectangle supporting click-to-pan and drag-to-scroll. Modified WaveformDisplayComponent to own three new child components hidden by default, with setEditorModeActive toggling visibility and resized calculating editor layout (12px overview, dynamic canvas, 32px toolbar), plus zoom-synced view range propagation to overlay and overview strip. Modified WaveformDisplayManager with WaveformMode enum, Compact/Editor mode transitions with hysteresis threshold detection (enter at 250px, exit at 270px), raised max height to 700px for editor mode, and pre-expansion height restoration on collapse. Modified WaveformInteractionHandler with editor mode awareness checking marker hit targets before playhead interaction, tool-filtered handle dragging via callbacks to SampleDataManager trim/loop/fade setters, and cursor change to left-right resize on relevant handle hover. Added Expand/Collapse Waveform Editor toggle to WaveformContextMenu with dynamic label based on current mode. Added waveform editor state persistence to UIPreferencesManager for mode, height, pre-expansion height, and snap toggles.
- 1e98b61Added modulation depth visualization system showing theoretical min/max range arcs on all modulated controls. Created ModulationRangeRenderer with static drawing methods for rotary knobs (semi-transparent arc with endpoint dots and current position indicator), horizontal sliders (range bar with bracket ticks), and vertical faders (bracket bar left of groove). Extended EphemeraKnob and ModulatableSlider with setModulationRange and setModulationAmount methods using atomic storage with threshold-based repaint guards. Added Colors::Modulation namespace to DesignTokens with complementary hue-shifted range color (withRotatedHue 0.33f) for Living theme and Medium Slate Blue fallback for Dark theme. Integrated range rendering into RotarySliderRenderer drawPremiumRotarySlider between track and value arcs, FaderSliderRenderer drawIntegratedMeterFader after groove draw, and drawTimeOfDayHorizontalSlider between track and fill. Expanded PluginEditor updateComponentModulationVisuals from single-parameter to multi-parameter with three-phase approach computing theoretical ranges from routing config and depth params on UI thread, reading per-slot current offsets from ModulationVisualizationBridge atomics, and distributing to all track control knobs via distributeModulationToControls helper. Added getModulationVisualizationBridge accessor to PluginProcessor and getTrackRow accessor to TrackControlStripComponent for editor wiring. Moved getRangeColor implementation from DesignTokens.h inline to DesignTokens.cpp to resolve forward declaration dependency on ThemeState. Added ModulationRangeRenderer source files to TimeSampler.jucer UI group.
- Other
- 5404694Replaced endpoint-only fade handle hit testing with full curve proximity detection that checks if the mouse is within 4px of any point along the fade curve path using the same computeFadeCurve math as rendering. Added hover highlight that thickens the fade curve stroke from 1.5px to 3px and brightens alpha from 0.5 to 0.85 when the mouse is near the curve. Implemented delta-based drag offset in WaveformInteractionHandler that stores the gap between the click position and the actual fade boundary on mouse down, preventing the fade endpoint from jumping when initiating a drag from the middle of the curve.
- Day 319 · 8 commits

- Audio engine
- 5a66d6bRedesigned aux return vertical layout to dynamically fill available mixer height. Changed from fixed 140px strips with 60px faders to dynamic calculation that gives faders the majority of each strip's space, resulting in ~87-112px faders depending on mixer height. Moved M/S buttons from beside fader to bottom row with pan/mix/HPF knobs, allowing fader width to increase from ~42px to ~88px. Added color-coded shape indicators (square, circle, triangle, hexagon) matching aux send visual language. Increased component width from 82px to 100px for better control sizing. Controls now arranged as top row (shape + number + effect dropdown), middle row (wide fader + meter), and bottom row (M/S buttons + three knobs + HPF bypass).
- c14e8b7 Redesigned aux return UI from bottom dock to vertical strip next to master track. Added LayoutMode enum to AuxReturnChannelComponent supporting both Horizontal and Vertical orientations, with compact vertical layout (82px wide) stacking 4 aux return strips vertically with abbreviated controls. Updated MixerPanel to position aux returns between master track and channel strip viewport for both left and right dock positions, eliminating the previous bottom placement that created asymmetric empty space. Added RTN toggle button to mixer header allowing users to show/hide aux returns on demand, with button highlight indicating visibility state. Implemented separate layout and paint methods for each orientation mode with appropriate sizing constants for compact vertical display
- d08a97aChanged effect processors in PoolPlayerInfo from direct struct members to unique_ptr with lazy initialization, deferring ~500KB+ of memory allocation per idle player. Previously all 160 pool players (10 per track × 16 tracks) eagerly allocated ReverbSc (386KB inline aux buffer), SignalsmithPitchShifter (~100KB+ FIFO/stretch buffers), and EphemeralDelayProcessor (~20KB delay lines) in initializePoolPlayerInfo regardless of whether the player was active. Added ensureEffectProcessorsPrepared() which creates and prepares processors on-demand when configurePoolPlayer assigns a cell for playback, and releaseEffectProcessors() which destroys them when players go idle via releaseResources, hardResetAllPlayersInPool, and forceReleaseClipPlayer. Updated all effect processor accesses from dot to arrow notation throughout the audio processing loop and parameter update paths, with null checks on the audio thread to safely skip processing for players whose effect processors haven't been created yet.
- b0172e3Changed effect processors in PoolPlayerInfo from direct struct members to unique_ptr with lazy initialization, deferring ~500KB+ of memory allocation per idle player. Previously all 160 pool players (10 per track × 16 tracks) eagerly allocated ReverbSc (386KB inline aux buffer), SignalsmithPitchShifter (~100KB+ FIFO/stretch buffers), and EphemeralDelayProcessor (~20KB delay lines) in initializePoolPlayerInfo regardless of whether the player was active. Added ensureEffectProcessorsPrepared() which creates and prepares processors on-demand when configurePoolPlayer assigns a cell for playback, and releaseEffectProcessors() which destroys them when players go idle via releaseResources, hardResetAllPlayersInPool, and forceReleaseClipPlayer. Updated all effect processor accesses from dot to arrow notation throughout the audio processing loop and parameter update paths, with null checks on the audio thread to safely skip processing for players whose effect processors haven't been created yet
- 3a1247bAdded MIDI recording UI controls and input monitoring to the piano roll control bar. When record is armed, new count-in toggle with 1/2/4 bar selector and input quantize toggle now appear alongside the existing mode combo, all wiring through to PianoRollMidiRecordManager's existing setPreRollBars and setInputQuantizeEnabled APIs. Implemented a flashing record indicator that renders a red dot next to the Rec label — steady dim when armed, pulsing bright/dim at 400ms intervals when actively recording — driven by a Timer on the control bar and updated from PianoRollViewport's polling loop via the new updateRecordingIndicator method. Added input monitoring so incoming MIDI from a controller auditions through the piano roll's sound engine while in the Armed state before transport starts, by calling triggerNotePreview/stopNotePreview from BasePianoRollComponent::onExternalMidiNoteOn/Off when the record manager is armed
- 80832f7Added sample key detection display to the sample browser with a new 'Key' column that shows detected musical keys (e.g., 'Cmaj', 'Am') using an FFT-based chromagram and multi-profile Krumhansl-Schmuckler algorithm. Created AudioKeyDetector as a static utility with spectral whitening and percussive frame gating, SampleKeyManager for lock-free state storage, and SampleKeyAnalysisManager for background ThreadPool-based analysis with a global JSON cache persisted to ~/Documents/Ephemera/Cache/sample_keys.json. Wired key data through SampleBrowserDataManager, SampleBrowserFacade, and SampleBrowserStatePersistence with full ValueTree serialization across all four ProcessorState load/save paths. Added a key filter ComboBox to the search row in both horizontal and vertical layouts supporting individual key selection and Camelot-compatible filtering via the '+ Compatible' mode. Extended SampleBrowserSearchEngine with key: search syntax supporting display names, Camelot codes, and OR operators. Rendered major keys in warm gold and minor keys in cool blue with dimmed alpha for low-confidence results, and implemented Camelot wheel-based column sorting with undetected keys sorted last
- UI / UX
- a7e3c48Redesigned aux return vertical layout to side-by-side arrangement. Increased width from 100px to 140px, moving controls to a column right of the fader instead of cramped bottom row. Enlarged knobs from 22px to 32px for better usability. Fader now extends full strip height with meter positioned adjacent.
- 349b697Fixed indefinite spinner when loading folders by removing the completed DirectoryScannerJob from the TimeSliceThread after scanning finishes. The useTimeSlice() method previously returned 0 on completion which JUCE interprets as 'call again immediately,' creating an infinite loop that flooded the message thread with triggerAsyncUpdate calls and repeated applyFilterAndRefreshTable rebuilds, starving paint events and making the UI appear frozen. Added a cleanupCompletedScanJob() method called from handleAsyncUpdate when scanning completes, a scanFinished_ guard flag in the job to return a 5-second sleep instead of re-running completion logic between the finish signal and cleanup, and spinner hiding for the empty-paths early-return edge case in scanAndDisplayFiles
- Day 320 · 2 commits

- Audio engine
- 3f6e7edImplemented complete compressor system with both global and per-cell modes. Added CompressorTab to GlobalEffectsSettingsComponent with compression curve visualization, gain reduction metering, and full parameter controls including algorithm selection (VCA, FET, Optical, Variable-Mu, Digital). Converted CompressorSettingsPanelComponent to use Cello reactive bindings for per-cell compressor settings with automatic UI synchronization. Added 14 compressor properties to SampleCellWrapper (threshold, ratio, attack, release, knee, gains, dry/wet, lookahead, auto-makeup, algorithm) and corresponding getter/setter methods to SampleDataManager. Integrated CompressorProcessor into TrackChannel effect chain with lazy initialization and cached enable flags for real-time safe processing. Per-cell mode supports VCA and Digital algorithms while global mode supports all five.
- b6f9595Added professional-quality global compressor processor with VCA and Digital (look-ahead) algorithms. Implemented CompressorProcessor with branchless soft-knee compression using smoothstep interpolation, stereo-linked peak envelope detection, and 5ms look-ahead ring buffer for transient handling. Integrated compressor into MixerEngine processing chain between reverb/delay returns and pitch shifter. Added 15 APVTS parameters with full DAW automation support. Connected existing CompressorSettingsPanelComponent UI to backend via APVTS attachments with real-time gain reduction metering from processor. Extended OptimizedParameterCache with compressor parameter caching for efficient audio-thread access.
- Day 321 · 6 commits

- Audio engine
- ace9658Fixed global compressor parameters not affecting audio due to dirty-flag race condition in MixerEngine. The parameter cache's updateDirtyParameters() was consuming dirty flags before MixerEngine could check them, causing hasAnyCompressorParamDirty() to return false and skip all parameter updates to the CompressorProcessor. Removed the broken dirty-flag optimization and simplified to always update compressor parameters from the cache, which is correctly synchronized. Input gain, output gain, and dry/wet mix now properly affect the audio signal.
- 68ebf00Optimized global compressor DSP performance and improved parameter ranges. Eliminated unnecessary dB conversions in the per-sample audio loop by pre-converting auto-makeup gain to linear domain once per block and working directly with linear gain multipliers instead of round-tripping through dB conversion. Changed makeup gain smoothing from 5ms to 20ms to match other block-rate parameters and prevent audible stepping artifacts. Raised attack time minimum from 0.1ms to 1.0ms to prevent distortion on low frequencies caused by tracking individual waveform cycles. Lowered release time minimum from 10ms to 5ms to enable fast 'breathing' compression styles.
- 5701362Fixed three compressor parameters that were defined in UI but not implemented in DSP. Auto-makeup percentage was hardcoded to 70% and now correctly reads the user's 50-100% setting, with maximum compensation increased from 12dB to 18dB. Lookahead time was hardcoded to 5ms and now reads from the user parameter with dynamic updates each audio block for real-time changes. Hold time had no implementation and now properly delays the release phase by maintaining envelope level for the specified duration before allowing gain reduction to decay, with hold counter reset on each new peak detection.
- d4adf7fFixed per-cell compressor metering to read from correct processor instance and enhanced global compressor curve display with full interactivity. Added getCompressorMeteringForCondition() method to TrackChannel and getPerCellCompressorMetering() helper to PluginProcessor, enabling the per-cell compressor settings panel to display actual per-cell metering values instead of incorrectly showing global compressor activity. Per-cell panels now show zeros/silence when disabled or using global mode. Upgraded the global compressor CompressionCurveDisplay with mouse interaction for dragging threshold and knee parameters, cyan input level indicator line, hover tooltips showing input/output/gain reduction at cursor position, knee region visualization with highlighting, and double-click to reset defaults.
- 88b7467Improved global compressor with soft-knee bug fix, performance optimization, and new parameters. Fixed visualization mismatch between UI and DSP by creating shared CompressionMathHelpers.h using smoothstep interpolation. Added dirty-flag optimization to MixerEngine reducing parameter updates to only when changed. Added input/output level meters to global CompressorTab. Marked FET, Optical, and Variable-Mu algorithms as 'Coming Soon' with selection prevention. Increased metering refresh rate from 30Hz to 60Hz. Added three new parameters: Hold Time (0-500ms), Lookahead Time (0-20ms), and Auto-Makeup Percentage (50-100%) with full APVTS integration and UI controls.
- 70a4816Added APVTS parameter listeners for all 14 global compressor parameters in PluginProcessor constructor and destructor. The compressor UI controls were not updating the OptimizedParameterCache because the parameterChanged callback was never invoked for compressor parameters, leaving cached enable/bypass values at their struct defaults of false. This caused the processing condition to always evaluate false, preventing processBlock from being called and metering from updating. Registered listeners for enable, bypass, threshold, ratio, attack, release, knee, input gain, output gain, makeup gain, dry/wet, lookahead, auto makeup, and algorithm parameters to ensure cache dirty flags are properly set when UI controls change.
- Day 322 · 7 commits

- Audio engine
- 0ab39faAdded Sample Browser filter panel with duration, channels, sample rate, and file type filters. Created FilenameTagParser utility for extracting tags from sample filenames using delimiter tokenization (underscores, dashes, CamelCase) and known sample term matching. Added auto-tag context menu items for single and batch tagging operations. Integrated filter panel into SampleBrowserLayoutManager for both horizontal and vertical modes with toggle button in search row. Added matchesFilterCriteria() to SampleBrowserSearchEngine for filter state evaluation. Browser to timeline drag-drop was already functional via existing GridDragDropHandler infrastructure.
- 920c668Extended MixerEQProcessor from 6 to 8 bands with dedicated HPF (40Hz) and LPF (18kHz) filter bands alongside Low Shelf, 4 Parametric Peak bands, and High Shelf. Added dual FFT spectrum visualization showing pre-EQ input (blue) and post-EQ output (green) at 30Hz refresh rate by capturing samples before processing and extending SpectralDataBuffer with dual spectrum support. Created EqPresetManager with 6 factory presets: Flat, Vocal Presence, Drum Punch, Bass Enhancement, De-essing, and Telephone. Updated EqCurveComponent with interactive 8-band control points supporting click-drag frequency/gain adjustment, mouse wheel Q control, double-click reset, shift+drag fine mode, and alt+drag frequency lock. Converted context menu to JUCE 8 async PopupMenu API. Updated EqWindowComponent, EqBandTabStrip, and APVTS parameter creation to support 8 bands with HighPass/LowPass filter types.
- 3948b5aFixed parameter gesture tracking and undo support across multiple systems. Added JUCE native beginChangeGesture/endChangeGesture calls to ParameterGestureTracker for proper host automation recording during slider drags. Wrapped manual parameter changes in TimelineUnifiedOverrideComponent, TrackControlStripComponent, and EditorNavigationManager with gesture calls for proper undo grouping. Implemented proper undo closures for all 12 GridViewModel methods that previously had TODO stubs, now capturing old values before operations to enable full undo/redo support for cell sample paths, custom names, volume, pan, display modes, playback modes, and ADSR settings. Created SequencerShiftAction UndoableAction class and integrated it with SequencerShiftContextMenu to make pattern shift operations undoable using the existing backup/restore mechanism.
- Timeline
- 6bb7857Fixed timeline override undo by using ParameterGestureTracker instead of JUCE native gesture calls. The JUCE beginChangeGesture/endChangeGesture methods only notify host DAWs for automation recording but don't create undo actions. Updated TimelineUnifiedOverrideComponent, TrackControlStripComponent, and EditorNavigationManager to use the ParameterGestureTracker which properly creates undoable actions for parameter changes.
- UI / UX
- f1af6a1Fixed performance regression from unconditional DEBUG_UNDO_ALWAYS logging during parameter gestures. Changed the macro to be conditional on DEBUG_UNDO_ENABLED flag (currently disabled), eliminating DBG output overhead on every slider drag, button click, and knob turn that was blocking the UI/message thread.
- 0288a83Added notifyHost parameter to ParameterGestureTracker::gestureStarted() and gestureEnded() to prevent double beginChangeGesture() calls that crashed when dragging sliders with SliderAttachments. Updated all slider listener callbacks in EqWindowComponent, MixerChannelStripGestureHandler, TrackControlRow, EnvelopeControlPanel, and LFOControlPanel to pass notifyHost=false since SliderAttachment already handles host gesture notification. Fixed shutdown crash in AuxReturnChannelComponent by calling setLookAndFeel(nullptr) on level sliders before the BusSliderLookAndFeel instances are destroyed, preventing use-after-free when sliders try to access their LookAndFeel during destruction.
- 82c5c6cReplaced direct this capture in the showMenuAsync callback with a juce::Component::SafePointer<EqCurveComponent> to prevent use-after-free crash when the application closes while a context menu callback is pending. The SafePointer automatically becomes nullptr when the component is destroyed, allowing the callback to safely bail out instead of accessing a dangling pointer.
- Day 323 · 4 commits
- UI / UX
- 377ac98Added custom folder management and duplicate detection to Plugin Browser. Fixed scanner finding 0 plugins by replacing dynamic path construction with hardcoded Windows VST3 directories that don't require existence checks. Added Add Folder and Remove Folder toolbar buttons with async FileChooser and PopupMenu dialogs for managing custom search paths. Custom paths persist to EphemeraPluginSettings.xml separate from the plugin cache. Implemented duplicate detection using PluginDescription::createIdentifierString() to skip redundant plugin entries during scanning. Status label now displays duplicate count when plugins are skipped (e.g., 42 plugins (3 duplicates
- c2fdddbAdded search and filter functionality to Plugin Browser with real-time text search across plugin name, manufacturer, and category fields. Implemented type filter dropdown (All/Instruments/Effects) and dynamically-populated category filter dropdown. Created PluginBrowserSearchEngine with static filter methods following the SampleBrowserSearchEngine pattern. Status label now shows filtered count (e.g. '5 of 42 plugins') when filters are active. Added auto-detection of newly installed plugins on startup using needsRescan() which compares VST3 directory modification times against cache timestamp, displaying 'New plugins detected, rescan recommended' when appropriate.
- c66b71fAdded Phase 2 Plugin Browser features: XML cache persistence, async background scanning, and progress dialog. Created PluginCacheManager for saving/loading plugin list to EphemeraPluginCache.xml in AppData with cache validation and modification time tracking. Created PluginScanProgressDialog as modal overlay with progress bar, status label, and cancel button using Timer-based UI updates. Extended PluginScannerManager with AsyncUpdater base class, ThreadPool-based background scanning via ScanJob inner class, progress callbacks, and cancellation support. Updated PluginBrowserComponent to load from cache on init for instant startup, show progress dialog during scans, and added Clear Cache button. Added PluginBrowserWindow::deleteInstance() calls to EphemeraStandaloneApplication and PluginEditor destructors to fix shutdown crash caused by singleton window outliving JUCE infrastructure.
- 646e61eAdded VST3 Plugin Browser with scan functionality and TableListBox display. Created PluginBrowser module with PluginInfo struct for plugin metadata, PluginScannerManager wrapping juce::KnownPluginList and AudioPluginFormatManager with platform-specific VST3 path discovery, PluginBrowserTableModel implementing TableListBoxModel with sortable columns (Name, Manufacturer, Category, Type, Format), PluginBrowserComponent as the main panel with scan button and status display, and PluginBrowserWindow as singleton DocumentWindow following PoolManagerWindow pattern with custom title bar and state persistence. Added VST button to BottomBarComponent with left-click to toggle browser window and right-click context menu for 'Scan For VST Plugins' and 'Open Plugin Browser' options. Phase 1 foundation for plugin management - Phase 2 will add XML caching, background scanning with progress dialog.
- Day 324 · 7 commits

- Audio engine
- 2772850Added VST3 plugin assignment to mixer effects rack insert slots. Restructured the empty slot popup menu into organized Stock Effects and VST3 Plugins sections, with VST3 plugins grouped by manufacturer into submenus. Implemented lazy-loading of scanned plugin list from XML cache via getAvailableVST3Plugins() on PluginProcessor, using std::vector<PluginInfo> to avoid juce::Array trivial-relocatability constraints. Added loadVST3Plugin() for async plugin instantiation through PluginInstanceManager with automatic InsertChainProcessor slot assignment and editor window opening via onPluginEditorRequested callback chain. Added removeVST3Plugin() with audio-safe deletion that clears the InsertChainProcessor slot before removing the instance. Extended MixerEffectSlot with VST3 state tracking (isVST3Plugin, vstInstanceId) and updated synchronizeSlotsWithEffectChain() with a two-pass approach to handle mixed stock and VST3 effects. Wired onPluginEditorRequested callback in PluginEditor constructor for opening plugin editor windows from rack slot interactions.
- 17aee09Added VST insert chain audio routing with pre/post fader support. Created InsertChainProcessor class with 17 locations (16 mixer tracks + master bus), 8 slots each (0-3 pre-fader, 4-7 post-fader), using atomic slot state for lock-free audio thread reads. Split MixerTrackManager's monolithic gain+pan+sum loop into three phases: smoothed gain applied in-place, post-fader inserts, then pan+sum to output. Wired InsertChainProcessor into PluginProcessor lifecycle (constructor, prepareToPlay, releaseResources, destructor) and added master bus insert call between master EQ and master volume in processBlock. Uncommented PluginInstanceEntry routing metadata fields (assignedTrackIndex, insertSlotIndex, bypassed) for future UI binding.
- Effects
- d1f8aaeAdded VST3 plugin state persistence diagnostics and fixed effects rack change detection for hosted plugins. Registered 'PluginHosting' as a known node type in ProcessorState::isKnownNodeType() to prevent the forward-compatibility system from treating it as an unknown tag and triggering spurious newer-version warnings. Added comprehensive DBG logging throughout the save/load chain in PluginProcessor::savePluginHostingState(), loadPluginHostingState(), PluginInstanceManager::saveState(), loadState(), InsertChainProcessor::saveState(), and loadState() to trace instance counts, node presence, descriptor XML availability, plugin state blob sizes, and slot restoration counts. Extended EffectsRackComponent::hasEffectChainChanged() to also compare InsertChainProcessor VST3 slot instance IDs against a tracked lastKnownVSTSlots array, ensuring the timer-driven auto-sync detects restored or newly-assigned VST3 plugins that were previously invisible to the stock-effects-only change detection. Updated synchronizeSlotsWithEffectChain() to record current VST3 slot state after each sync pass.
- 60b5dfcFixed VST3 plugin scanner crash caused by JUCE_ASSERT_MESSAGE_THREAD requiring code to run on the actual message thread rather than merely holding a MessageManagerLock. Replaced the MessageManagerLock approach in ScanJob::runJob() with callFunctionOnMessageThread() which dispatches each scanNextFile() call to the real message thread while keeping the orchestration loop on the ThreadPool for progress tracking and cancellation. Added ScanNextFileArgs struct for parameter passing through the C callback interface, sehScanNextFile() SEH wrapper to catch hardware exceptions from misbehaving plugins like Wurli V2.vst3, and scanNextFileOnMessageThread() as the dispatch callback. Scanner now survives anti-debugger plugins and plugins returning garbage bus info data, logging crashes and continuing to the next plugin.
- e2611deFixed VST2 SDK compile error (C1083) by setting JUCE_PLUGINHOST_VST to disabled in .jucer JUCEOPTIONS. Projucer was generating JUCE_PLUGINHOST_VST=1 in the .vcxproj preprocessor definitions, causing juce_VSTPluginFormat.cpp to include pluginterfaces/vst2.x/aeffect.h which is not bundled with JUCE 8. VST3 plugin hosting (JUCE_PLUGINHOST_VST3=1) remains enabled for the Plugin Browser scanner.
- UI / UX
- c6e4ae9Routed VST3 effect slot clicks to the native plugin editor window instead of the stock effect chain panel. Added an early check in EffectsRackComponent::handleEffectNameClick() that detects VST3 slots via getIsVST3Plugin() and getVSTInstanceId(), then delegates to the existing processorRef.onPluginEditorRequested callback which routes through PluginEditor's PluginEditorWindowManager to create or focus the plugin's native DocumentWindow. Stock effect slots continue to toggle the EffectChainPanelComponent as before.
- 14fd713Implemented the complete pipeline from Plugin Browser double-click to opening a hosted plugin's native editor GUI. Created PluginInstanceManager for async plugin loading with shutdown safety, PluginEditorWindow as a DocumentWindow hosting native plugin editors, and PluginEditorWindowManager to track open windows. Wired the callback chain through PluginBrowserWindow (static callback pattern for lazy singleton) to PluginEditor. Fixed VST3 loading failure by adding lossless PluginDescription XML round-trip via descriptorXml field in PluginInfo, preserving uniqueId/deprecatedUid that JUCE's VST3 format requires for component class lookup.
- Day 325 · 3 commits

- Audio engine
- e06b7d3Added Living Theme support to mixer effects rack popup menus. Integrated ThemedPopupMenuLookAndFeel into EffectsRackComponent for the Stock Effects and VST3 Plugins menus, using ConditionMonitor time for consistent theming with the rest of the UI. Added clarifying documentation to PopupMenuRenderer and ThemedPopupMenuLookAndFeel headers explaining the architecture: PopupMenuRenderer provides global Dark Theme defaults via EphemeraLookAndFeel, while ThemedPopupMenuLookAndFeel provides per-component overrides with full Living and Dark Theme support.
- 20e3d5cImplemented VST3 plugin delay compensation (PDC) for mixer insert chains. Added latency query methods to InsertChainProcessor for summing slot latencies per location, including getMaxTrackLatency() and getMasterLatency() for PDC calculations. Added refreshAllLatencies() to PluginInstanceManager for detecting runtime latency changes from plugins enabling/disabling lookahead. Extended MixerTrackManager with per-track TrackDelayBuffer arrays that apply compensation delays after insert processing but before master summing, aligning all tracks to the highest-latency track. Updated MixerEngine to track and expose cachedInsertChainLatency_ for host PDC reporting. Modified PluginProcessor's processBlock to call updateDelayCompensation() each block, refresh plugin latencies dynamically, and include total insert chain latency (max track + master) in the host-reported latency value.
- Other
- a811622Fix standalone app crash on shutdown in Desktop::~Desktop(). Add setVisible(false) and removeFromDesktop() calls to MainWindow destructor before destroying content. This ensures the window is properly unregistered from JUCE's Desktop singleton before shutdown, preventing the crash caused by dangling focus listener references.
- Day 326 · 2 commits

- Audio engine
- 7c11320Clear VST plugin instances and insert chain routing on New Project. Previously, clicking 'New Project' would reset samples, track names, sequencer state, and APVTS parameters, but VST plugin instances in the mixer effects rack persisted across project resets. Added plugin clearing to handleNewProject() by closing all open plugin editor windows and calling loadPluginHostingState with empty state. Fixed loadPluginHostingState to properly clear instances when called with no PluginHosting node instead of silently returning. Also fixed EffectsRackComponent change detection to track VST3 slot assignments so the UI updates when plugins are added or removed externally.
- f5358a1Fixed VST3 plugin crash when loading FabFilter Pro-Q 3 and other plugins with sidechain inputs into the mixer effect rack. The crash occurred because VST3 plugins with sidechains expect more channels (e.g., 4 for stereo main + stereo sidechain) than our 2-channel mixer track buffers provide. Added configurePluginBusLayout() helper in PluginInstanceManager that properly configures plugin bus layouts by preserving the plugin's bus count structure, setting main buses to stereo, and disabling sidechain/aux buses. Applied this configuration in loadPluginAsync(), loadState(), and prepareAllInstances(). Also added a defensive safety check in InsertChainProcessor::processSlotRange() to skip processing if a channel mismatch is still detected, preventing crashes as a fallback.
- Day 327 · 9 commits

- Audio engine
- 853c8f8Added Track Freeze/Render system for CPU-heavy projects. Created TrackFreezeManager to orchestrate per-cell offline rendering of sample+effects chains to 32-bit float WAV files, with TrackFreezeRenderer handling the actual offline render loop and FrozenCellPlayer providing RT-safe playback of pre-rendered audio. Frozen tracks bypass normal TrackChannel processing in MixerEngine and instead route through FrozenCellPlayer, which swaps between pre-rendered cells as conditions change (time, weather, season, etc.) without CPU cost. Added TrackFreezeDialog with cost analysis confirmation and progress view. Integrated freeze/unfreeze context menu items in both TimelineActiveSourcesColumn and GridContextMenuBuilder track menus, with blue 'F' badge indicators on frozen track labels and subtle blue tint overlay on frozen MixerChannelStrips updated via the MixerPanel 30Hz timer. Wired state persistence through ProcessorState using ValueTree with relative file paths for project portability.
- 89134fcWired metering system right-click context menus to visible mixer UI components. Added mouse listeners on the volume fader and meter overlay components in MixerChannelStrip so right-clicking the fader area shows meter configuration menus. Master channel strip shows LUFS meter toggle, spectral meter toggle, peak hold settings, LUFS target selection, and integrated LUFS reset. Regular track strips show pre-fader/post-fader metering toggle with per-track override or global default option. Connected menu callbacks to MixerPanel toggle methods and MeterPreferencesManager for state persistence.
- 3313d38Added Living Theme support to VST3 plugin editor header bar preset ComboBox and save dialog. Applied ThemedPopupMenuLookAndFeel to the preset dropdown ComboBox so its popup menu follows time-of-day colors, with updates wired through setProcessor() and timerCallback() to stay in sync as time changes. Themed the save preset AlertWindow with time-of-day background, text, and outline colors in Living mode and dark theme colors in Dark mode. Also added ThemedPopupMenuLookAndFeel to the mixer effects rack popup menus in showAddEffectMenu() and handleEmptySlotClick() for consistent themed styling across all plugin-related popup menus.
- UI / UX
- ed2c293Optimized BaseGridComponent repaint scope in three areas. Guarded updateThemeBaseColor() to only call repaint() when the grid is visible, preventing unnecessary repaints on the 4 hidden grid tabs while still keeping the cached color up to date. Scoped breathing animation repaints from the full component down to just the header region, since breathing only visually affects header gradients and colors. Added getWarpRepaintBounds() helper that calculates a mouse-position-plus-radius bounding rectangle clipped to the grid content area, replacing full grid content area repaints across all 4 warp effect sites (mouseMove, mouseEnter, mouseExit, timerCallback ripple) with targeted repaints, and tracking previousWarpMousePos to properly clear old warp positions on mouse move.
- 7aef606Added keyboard shortcut customization system with searchable UI in Controls tab. Created ShortcutRegistry on PluginProcessor with ~100 registered shortcuts across 19 categories and 7 contexts, supporting click-to-rebind, same-context conflict detection, and Reset All. Migrated all 9 handler classes (EditorKeyboardShortcutHandler, TimelineKeyboardHandler, TimelineSelectionShortcuts, TimelineSelectionNavigator, GridInteractionHandler, PianoRollInteractionHandler, MixerUIManager, NavigationManager, KeyboardShortcutManager) from hardcoded KeyPress comparisons to registry.matchesAction() lookups. User-modified bindings persist via ProcessorState ValueTree serialization, with old project files loading cleanly on factory defaults.
- 58a7c6bAdded Living Theme support to VST3 plugin editor header bar buttons, ComboBox, and label. Created updateControlColors() helper that applies theme-aware colours to all header bar controls using DesignTokens time-of-day functions: prev/next/save/load TextButtons use getThemeAwareButtonColor() for backgrounds, the bypass ToggleButton tick uses time-of-day accent in Living mode, the preset ComboBox uses getThemeAwareSurface() and getThemeAwareBorder() for its background and outline, and the plugin name label follows getThemeAwareTextPrimary(). Colors update automatically via the existing 1-second timer when ConditionMonitor time changes.
- 29841fdFixed VST3 plugin editor window crash and sizing when using custom title bar. Added paint() override to skip DocumentWindow's broken title bar drawing that computed negative height (0 - 2px border = -2) with setTitleBarHeight(0). Removed childBoundsChanged override that caused a shrink feedback loop by not accounting for non-native window border insets, letting JUCE's default ResizableWindow implementation handle content-to-window sizing correctly.
- 6a83440Fixed VST3 plugin editor window crash and sizing when using custom title bar. Added paint() override to skip DocumentWindow's broken title bar drawing that computed negative height (0 - 2px border = -2) with setTitleBarHeight(0). Removed childBoundsChanged override that caused a shrink feedback loop by not accounting for non-native window border insets, letting JUCE's default ResizableWindow implementation handle content-to-window sizing correctly.
- 7fe93e0VST3 plugin editor custom header bar with preset management. Added PluginPresetManager for per-plugin factory preset enumeration and user preset save/load as .ephPreset files. Created PluginEditorHeaderBar with themed 32px strip containing preset dropdown, prev/next navigation, save/load buttons, and bypass toggle wired to InsertChainProcessor. Wrapped plugin editors in PluginEditorHostComponent that handles dynamic resize propagation between the header bar and native plugin editor.
- Day 328 · 6 commits

- Audio engine
- f0db89eAdded UI visual polish ('dazzle') micro-interactions and depth effects across buttons, grid cells, mixer strips, and bottom bar. Implemented elastic bounce-back animation on button release using exponential decay with cosine damping over 300ms, and added a subtle white shimmer sweep that travels across hovered buttons on a 2-second cycle. Enhanced grid cell selection rendering with a 2px inset shadow at the top edge for depth, a breathing outer glow ring that pulses via sine-modulated alpha, and an expanding/contracting focus glow ring on focused cells. Added 1px top-edge inner shadow on hovered grid cells. Increased MixerChannelStripPainter gradient contrast from 0.03 to 0.07 and added 1px white bevel highlight at top and black shadow at bottom of each strip. Tagged transport buttons (Play, Stop, Rec) as bottomBarButton with currentHour/currentMinute properties so they now receive time-of-day themed styling consistent with the other bottom bar buttons. Added a 1px bottom shadow line to the bottom bar paint method. Enhanced the recording button pulse animation with a harmonic overtone at double frequency for a more urgent, complex pulsing effect during active recording
- 0b3b0d7Updated Audio/MIDI Settings window to use time-of-day themed styling for all child components. Changed SettingsWindowLookAndFeel to inherit from EphemeraLookAndFeel instead of juce::LookAndFeel_V4, so buttons, combo boxes, toggle switches, group component outlines, sliders, scrollbars, and text editors within the settings window now render with the correct Ephemera time-of-day colors instead of default JUCE V4 styling. Added setCurrentTimeOverride calls in the constructor and 30Hz timer callback to keep the LookAndFeel's time context synchronized with the processor's ConditionMonitor, since the settings window is a separate top-level window outside the main editor hierarchy.
- 1b84316Added per-track timeline recording system (Phase 1). Created TrackRecordArmManager with atomic bitfield for RT-safe per-track arm state, input assignment routing, and ValueTree persistence. Created RecordingWaveformBuilder using AbstractFifo lock-free ring buffer for audio-thread-to-UI peak data transfer. Created TimelineRecordingOverlay as transparent child component of TimelineGridComponent that draws a growing red-tinted clip region with live waveform peaks, pulsing border, and duration counter during recording at 30Hz. Extended RecordingViewModel with multi-arm API, per-track arm observable properties, track-based filename generation, and Recordings/ subfolder organization. Added arm button UI to TimelineActiveSourcesColumn with filled/hollow red circle indicators, click-to-toggle, right-click input routing menu, and context menu integration. Modified RecordingCoordinator to check TrackRecordArmManager for armed tracks, push peaks to RecordingWaveformBuilder during processBlock, and trigger overlay start/stop callbacks through the editor. Wired TrackRecordArmManager into PluginProcessor with ProcessorState save/load persistence, and updated BottomBarButtonHandler to prefer per-track arm path when tracks are armed with fallback to existing global arm behavior.
- Timeline
- 90dea82Fixed timeline clip drag-to-empty-lane snap-back bug by rewriting the display-list branch of TimelineGeometryManager::rebuildRowHeightCache() to iterate rows in ascending rowIndex order instead of display-list encounter order. Previously, tracks were compacted together by display-list position, so a clip dragged to rowIndex 8 (the 4th track in display order) would get Y position 3*H instead of 8*H, causing it to visually snap back on release. The new approach walks the display list once to map group headers to the rowIndex of their first child track, then sequentially iterates all rows 0 to numTotalRows-1, inserting group headers at the correct positions and placing empty rows in their proper vertical space. All downstream consumers (getRowYPosition, getRowIndexAtY, getTotalContentHeight, getGroupIdAtY) read from the same cache arrays and auto-correct without changes.
- 0c84481Fixed timeline clip vertical drag to use free lane placement instead of insertion reorder. Removed applyInsertionReorder() logic that was incorrectly displacing unrelated clips when dragging a track to a new lane — now only the dragged clip's rowIndex changes, allowing clips to stack freely on the same lane. Fixed z-order painting in TimelineGridPainter by sorting the paint order by startTimeSec so later clips render on top of earlier clips when stacked, with the actively dragged clip always painting last. Updated hit-testing in TimelineSampleInteractionHandler::getSampleInfoAtPosition() to return the clip with the latest startTimeSec at a given position, matching the visual z-order so the topmost visible clip receives clicks and drag events. Removed redundant rowIndex update from TimelineDragDropHandler::itemDragMove() to prevent double-update conflicts with the mouseDrag() path, and reverted persistence to only save the dragged clip's lane rather than all clips.
- UI / UX
- bb3b9b0Extended record arm buttons to all timeline track rows including empty ones. Rewrote paintRecordArmButtons to iterate via forEachRow helper instead of activeSamples, ensuring hollow red circles appear on every row regardless of whether it has clips. Updated mouseDown arm button hit-testing to use row geometry directly from getRowYPosition and getTrackHeight rather than searching activeSamples, so clicking arm buttons on empty tracks works correctly.
- Day 329 · 1 commit

- UI / UX
- afcc05aTake lane system improvement: Fixed Y-position mismatch in paintTakeLaneRows by replacing global getTrackHeight() with per-track getIndividualItemHeight() lookup, eliminating vertical misalignment when tracks have different height multipliers. Replaced hardcoded 40px take lane height with proportional sizing (60% of parent track height, clamped 30-80px) via new shared TakeLaneConstants.h used by both TimelineGeometryManager and TimelineGridComponent. Connected TakeLaneManager::Listener to TimelineGridComponent so expand/collapse, comp region edits, and group changes now trigger geometry rebuilds and repaints automatically. Added waveform rendering in take lanes by passing ActiveSampleInfo to TakeLanePainter which draws AudioThumbnail data with proper trim range mapping beneath comp region overlays. Added take lane labels to TimelineActiveSourcesColumn with indented styling and matching Y-position calculations. Implemented click interaction for take lanes in both the grid and sources column: left-click selects a take as active comp, right-click shows context menu with Select for Comp, Mute/Unmute, and Remove from Group options.
- Day 330 · 0 commits

- Day 331 · 7 commits

- Audio engine
- e2b8a6aAdded 5 low-effort high-impact UI/UX polish improvements. Introduced spring physics easing functions (easeOutSpring, easeOutBounce) to AnimationUtils and applied spring easing to mixer panel transitions, view slide/crossfade transitions, and transport button glow decay for punchier motion feel. Created MicroFeedbackOverlay as a backward-compatible replacement for UndoRedoFlashOverlay with additional flash types for save success, export complete, and playback start events. Added skeleton shimmer loading effect to grid cells in both Time and Weather grids that shows placeholder shapes with a sweeping gradient band while samples load. Added magnetic snap radial pulse rendering to TimelineGridComponent that draws an expanding ring and flash dot at non-edge grid snap points. Added track state halos to TimelineActiveSourcesColumn that paint subtle red left-edge gradient glows for record-armed tracks and blue glows for frozen tracks.
- Timeline
- 1ff2d7fFixed take lane void/blank space below expanded take lanes by resolving a first-match vs last-match disagreement between the geometry cache and paint code. When a take group has multiple clips on the same track, assignEffectiveLanes gives each clip its own rowIndex, but paintTakeLaneRows uses the first activeSample match to determine the parent row while rebuildRowHeightCache's trackToRow mapping was using the last match. This caused the geometry to reserve take lane space after the wrong row, leaving an orphaned row between the painted take lanes and the next track. Changed trackToRow to use first-match (consistent with all paint code paths), and added logic to collapse non-primary rows for tracks with expanded take lanes to zero height, eliminating the extra row entirely.
- UI / UX
- 6534248Hardened take lane system for 1.0 release after comprehensive audit. Added takeIndex validation in setCompRegion to reject operations referencing non-existent takes. Added group existence guards in all three undo action classes (CompRegionSetAction, TakeMuteAction, TakeLabelRenameAction) so undo/redo gracefully no-ops if a take group was dissolved. Wired undoManager through to RecordingCoordinator take group creation and TimelineKeyboardHandler create/dissolve shortcuts so those operations are now undoable. Added Escape key handler to TakeLaneHeaderComponent label editing so users can cancel a rename without saving. Added null guard on takeLanePainter_ before paintTakeLaneRow call. Added normalizeCompRegions call in validateClipIDs after removing orphaned takes to ensure clean merged state on project load.
- cb36c4dFixed take lane waveform rendering and sync alignment after track reorder. The RecordingCoordinator was using integer string IDs from addUnassignedSample as clipIDs for take groups, but ActiveSampleInfo used UUID-based IDs from TimelineClip.getClipID(), causing waveform lookups to always fail for both takes. Changed RecordingCoordinator to create a proper TimelineClip via addClip after recording and use its UUID-based clipID for take group creation, and to look up existing unassigned clips by their actual TimelineClip IDs instead of integer IDs. Fixed rebuildTakeLaneThumbnailCache to search all condition indices instead of only index 0, so clips at non-zero condition values are found. Fixed take lane header desync after drag-based track reorder by adding rebuildGroupDisplayList and Active Sources Column refresh calls to TimelineMouseDragHelper::handleMouseUpSample. Fixed keyboard-based track reorder sync by replacing manual geometry rebuilds with a full updateActiveSamples call in EditorTrackOrderController to ensure row indices are fresh before rebuilding the display list.
- 15d6831Implemented take lane system completion phases 5-12. Wired up CompSelectionHandler for drag-paint and boundary-drag comp selection with Comp tool smart-split support and cursor feedback. Added composite waveform overlay that dims non-active comp regions on the main track row with semi-transparent dark overlay. Added muted take visual rendering with diagonal stripes, dimmed labels, and 'M' suffix indicator. Integrated orphaned TakeLaneHeaderComponent into TimelineActiveSourcesColumn with Solo/Mute buttons and double-click-to-rename on take lane rows. Consolidated duplicated take lane context menus into shared TakeLaneContextMenu class used by both TimelineGridComponent and TimelineActiveSourcesColumn. Added keyboard shortcuts for create take group (Ctrl+Alt+G) and dissolve take group (Ctrl+Alt+Shift+G) in TimelineKeyboardHandler. Added undo/redo support for comp region edits, take mute toggles, and take label renames via new TakeLaneUndoActions. Added load-time validation in ProcessorState that removes orphaned take references when clip IDs no longer exist in SampleDataManager.
- 6829842Updated take lane colors to derive from the time-of-day theme system. Passed baseThemeColour through to TakeLanePainter and replaced hardcoded hex values in paintTakeLaneLabels and paintHoverState with HSB-derived colors that shift naturally with the living theme.
- 8967b48Fixed take lane left-click selection and added collapse option to take lane context menus. The selectEntireTake method in TakeLaneManager was a stub that only cleared comp regions without creating a replacement, making left-clicks on take lanes appear to do nothing. Updated it to create a single CompRegion spanning the full timeline range with the selected takeIndex, so clicking a take lane now actively selects that take as the comp. Added 'Hide Take Lanes' option with separator to both the grid and active sources column right-click context menus on take lane rows, calling setExpanded(false) to collapse the take lanes directly from within them rather than requiring navigation to the parent track's Take Lanes submenu.
- Day 332 · 8 commits
- Audio engine
- 13aab3cBPM Detection Improvement, Whack a Mole, Snake Rain
- c3dfc27BPM Detector, Snake Game v2, and fixed filter button in Sample browser not follow time of day/living theme.
- 51d6e9dAdded per-track input monitoring with three modes (Auto/In/Off) and a direct monitor toggle for bypassing track EQ. Created InputMonitorManager that provides RT-safe state queries via cached APVTS atomic pointers and input level metering atomics written by the audio thread. Implemented processInputMonitoring() in PluginProcessor that captures input audio at the start of processBlock into a pre-allocated buffer, then mixes monitored input into the output after track processing with constant-power panning and optional EQ routing. Added monitor mode and direct monitor parameters to the per-track parameter registration loop. Added monitor button UI to TimelineActiveSourcesColumn with color-coded state indicators (amber=Auto, green=In, grey=Off), left-click cycling, right-click context menu with mode selection and direct monitor toggle, and horizontal input level meter bars at the bottom of monitored rows.
- 1e5602bAdded CycleRecordingMode enum (NewTake, Replace, MidiOverdub) and APVTS choice parameter with cached pointer in PluginProcessor. Added cycle mode ComboBox to BottomBarComponent transport bar between Record and Metronome buttons with APVTS binding and Overdub greyed out. Added onLoopWrapDuringRecording callback to EditorPlaybackController that fires when the loop wraps during active recording, wired through BottomBarComponent to RecordingCoordinator. Implemented handleCyclePassCompleted which stops the current AudioRecorder, finalizes the completed pass as a timeline clip, manages take groups (NewTake mode) or removes previous passes (Replace mode with WAV cleanup), then starts a new recording with a fresh file for the next pass. Modified handleRecordingCompleted to detect cycle sessions and finalize the last pass through the cycle path. Added getCurrentOutputFile accessor to AudioRecorder and generateCyclePassFilename helper for pass-numbered filenames.
- 51f7a2eImplement per-row view morph transition for Grid <-> Timeline switches. Replaces the monolithic ScaleFade transition with a staggered per-row morph animation where individual track rows animate from grid positions to timeline positions with a waterfall effect (20ms stagger, 250ms per row, spring easing). Includes header crossfade with position interpolation. Fixed viewport coordinate issues: saves absolute viewport position during prepare() to handle currentGridDisplayArea shifting between modes (track control strip width changes), applies correct X/Y offsets for Active Sources column and timeline toolbar/ruler, and renders all strips at natural pixel dimensions via drawImageAt to prevent content stretching.
- UI / UX
- 20ff54bAdded punch region creation via Shift+right-click drag on the timeline ruler and pre/post-roll configuration menu via right-click on the Punch button. The ruler drag creates punch markers with triangular drag handles at the boundaries, auto-enables the punch parameter, and supports grid snapping. Added hover cursor feedback (resize cursor) when mousing over punch boundary edges so they're clearly interactive. The punch button context menu provides pre-roll (off/1/2/4 bars) and post-roll (off/1/2 bars) duration settings routed to PunchRegionManager, plus a clear punch region option. Fixed the punch button missing addMouseListener which was preventing right-click events from reaching the parent component's context menu routing.
- dfb194fFixed playhead snap-back bug when releasing drag outside ruler area. The mouseUp handler was only computing the final time position when the mouse was within the ruler bounds, causing the playhead to revert to its original position if the user released the drag in the grid area below. Changed the final position calculation to always derive time from the clamped X coordinate regardless of Y position, matching the behavior already used during the drag itself.
- 82205a5Added progressive timeline element reveal during Grid-to-Timeline morph transition. Brought Active Sources column, toolbar, ruler, scrollbar, and zoom label to front of the morph overlay so they appear immediately rather than popping in after the animation completes. Drew the incoming timeline snapshot as a fading background (0-50% opacity) behind the morph strips to progressively reveal grid lines, playhead, and grid background during the transition. Fixed viewport offset calculation by saving absolute viewport coordinates during prepare() and computing overlay-relative offsets in execute(), resolving content misalignment caused by currentGridDisplayArea shifting when the track control strip changes width between grid and timeline modes. Changed all row strip rendering from drawImage with stretchToFit to drawImageAt for natural pixel dimensions, and added smooth position interpolation to both header and row strips to eliminate leftward drift during the morph.
- Day 333 · 14 commits

- Audio engine
- 0b3582cAdded timeline piano roll clips with a ClipType enum, TimelinePianoRollClipManager for persistence, TimelinePianoRollComponent for note editing, teal MIDI clip rendering with mini note-bar previews, and double-click-to-open piano roll windows with toggle-close behavior, plus wired audio-to-MIDI conversion to create PianoRoll clips with detected notes imported automatically. Added punch/locator keyboard shortcuts (I/O set punch in/out, Alt+I/O jump to positions, Ctrl+Shift+P from selection, Alt+P clear), an orange punch locator display in the transport bar with click-to-jump, and a 'Set Punch Region from Selection' context menu item in the timeline ruler. Added a 'Go To' toolbar button between the snap selector and follow controls for discoverability of the Ctrl+G Go To Position feature. Added Autumnris hidden mini-game to the Season Grid with falling-leaves catcher gameplay, acceleration-based basket physics, combo multipliers, scaling difficulty, wind gusts, and bezier-curve leaf rendering, plus Lunar Lander to the Moon Phase grid with three difficulty levels, gravity physics, terrain generation, collision detection, and four particle types.
- e1546e4Fixed arranger pattern blocks appearing white from 6pm to 8am. ---- Wired global master mono sum audio processing to the existing MixerMasterMonoSum APVTS parameter that previously had no audio code behind it. Cached the parameter pointer in prepareToPlay and added a 13-line L+R mono sum block in processBlock after the soft clipper, gated by an atomic offline rendering flag. Made both per-track and global mono monitoring-only by adding an isOfflineRendering atomic bool to PluginProcessor and MixerTrackManager, propagated via setOfflineRendering
- 25b2602Updated arranger pattern blocks to use time-of-day themed colors in living theme mode, replacing the static 9-color palette with dynamic hues from getPatternColorForTimeOfDay() that shift through warm, cool, dusk, and night spectrums based on the current hour. Added vertical gradient fills for a subtle glass effect and updated suggestNextColour() to match the themed palette when creating new sections. ---- Added audio-to-MIDI conversion feature with two detection modes: YIN pitch detection for monophonic melodies and multi-band spectral flux onset detection for percussion. Created seven new files following the existing BPM detector and analysis manager patterns ---- Wired up the per-track stereo width backend to make the existing mixer width knob functional.
- 26b62e0Softened sequencer grid visuals across five areas for a cleaner, more immersive aesthetic. Reduced grid line alpha values in getSequencerGridLineColor() from 0.55/0.40/0.25 to 0.30/0.20/0.12 to eliminate the cage effect while preserving measure>beat>subdivision hierarchy. Removed the entire bevel effect block from drawStepCell() in SequencerPaintingHelper and reduced drop shadow, gradient contrast, and border alphas for flatter note blocks. Restyled parameter lane velocity and nudge bars to use centered 60%-width thin bars with rounded corners and a simpler two-color gradient, replacing full-width blocks with heavy multi-stop gradients and glow effects, and reduced default lane height from 80 to 60. Replaced the opaque gradient toolbar container in SequencerButtonRowComponent with a semi-transparent glass panel (indigo-tinted at 0.55 alpha, white highlight and border) and converted all sequencer buttons to pill-shaped semi-transparent controls with accent glow borders when toggled on. Applied matching color treatment to SequencerTopRowComponent buttons and made the pattern length label background translucent with no outline. Exposed the existing AuditionManager tempo-matched audition backend to the UI by adding toggleTempoMatchAudition/isTempoMatchAuditionEnabled accessors on PluginProcessor, a ToggleTempoMatchAuditionCommand grid command, and context menu items with checkmark state across BaseGridComponent, EndlessScrollGridComponent, SampleBrowserTableModel, and WaveformContextMenu, plus tooltip entries in ContextMenuTooltips. ---- Fixed Desktop shutdown crash by adding missing GridManagerWindow::deleteInstance()
- 43d9113Overhauled timeline grid visuals for a glassmorphic, premium DAW aesthetic. Softened all horizontal track dividers and sources column grid lines to uniform low-alpha white (0.12f tracks, 0.08f automation) replacing bright themed gradients and glow effects. Brightened ruler text by switching dark theme labels from secondary to primary color at 0.85f alpha, increased living theme text brightness to 1.4f, reduced text shadow alpha from 0.3f to 0.12f, and enhanced tick hierarchy with thicker major ticks (2.0f) and thinner minor ticks (0.6f). Reduced audio clip background opacity from 0.9f to 0.50f so the starry background shows through, replaced the heavy 40%-height white overlay with a thin 5% glass edge highlight, and introduced lilac-to-purple waveform gradients in both themes via new createTimelineClipGlassGradient() and createTimelineWaveformLilacGradient() helpers in TimeOfDayColorSystem.h. Added a dark header band (black at 0.30f alpha) behind clip names and removed the harsh 0.7f black text shadow, shrinking the name area proportion from 35% to 20% to give more space to waveforms. Replaced flat grey track selection fills with a gradient that fades from 15% accent alpha on the left to transparent on the right plus a 3px vibrant accent line on the left edge. Redesigned record arm and monitor buttons from tiny 10px circles to 22x14 pill-shaped controls positioned in the lower half of each track row, with LED glow effects for active states (neon crimson for armed, icy cyan for auto-monitor, electric green for input-monitor) and nearly invisible pills when off, expanding hit areas from 3px to 5px. Moved track names to the upper half of rows with bold font. Brightened inactive toolbar icons by using primary text color at 0.55f alpha instead of secondary, reduced inactive button background alpha from 0.3f to 0.15f, and redesigned active tool state with neon purple outer glow and lilac 0xFFCC88FF icon color. ---- Overhauled Settings Interface tab UI styling across six renderer files. Fixed 'Interfac' tab text truncation by reducing drawTabButton horizontal padding and adding a getTabButtonBestWidth override that measures with bold font to prevent clipping on selected tabs. Removed the vertical center indicator line from horizontal slider thumbs and increased track fill opacity from 0.8 to 0.9 for better visibility. Strengthened GroupComponent section headers with semibold weight (up from medium) and brighter desaturated text colors so they stand out against setting labels. Modernized toggle switch colors from hardcoded green/darkgrey to theme-aware accent colors derived from time-of-day in living mode and DarkTheme accent in dark mode, with a dim grey OFF state that recedes visually. Flattened all combo box styling globally by replacing the ColourGradient background and 3D top highlight with a flat translucent fill, simplifying the outline to a single 1px white border, and swapping the filled triangle dropdown arrow for a stroked chevron path. ---- Fixed Minesweeper difficulty selection buttons and post-game overlay rendering in the header area instead of the grid cell area. Replaced getLocalBounds() centering with getCellBoundsFunc-derived grid area centering so the MINESWEEPER title, Easy/Medium/Hard buttons, and win/loss overlays now appear centered within the actual playable cell grid below the header row and right of the track labels.
- c7089d8Added Arranger Track feature for defining named song sections (Intro, Verse, Chorus, Bridge, Outro) as colored regions in a dedicated 24px half-height track between the Tempo Track and first audio track. Created ArrangerSection data struct with UUID identification, time bounds, and ValueTree serialization. Created ArrangerTrackManager with thread-safe CRUD operations, auto-suggested names and colors, and ChangeBroadcaster notification. Created ArrangerTrackComponent with full mouse interaction including double-click to create sections, body drag to move, edge drag to resize, and right-click context menus for rename, colour change, duplicate, and delete. Added ArrangerSectionAction undo support for all operations. Wired into EditorLayoutManager for positioning, TimelineActiveSourcesColumn for header label, TimelineInteractionHandler for view and playhead sync, and ProcessorState for project persistence. Registered Ctrl+Shift+A keyboard shortcut to toggle arranger track visibility.---- Dimmed track control row visuals at rest and added interaction-driven brightening. Flattened EphemeraKnob backgrounds to near-invisible dark circles with desaturated value arcs that become vivid on hover/drag via a unified interactionAmount. Replaced mute/solo button gradients with ghost dark pills in off-state and theme-colored glow pills in on-state, with dimmed icons at rest. Added 8px group padding between functional control clusters (name, M/S, vol/pan, sends, meter) and increased track name font to 11px with left inset. Reduced grid line opacity to 8% white for barely-visible row separators. ----Snake game: add weather-aware Rain Mode with falling teardrop obstacles, sequencer integration, and separate score tracking
- Timeline
- 1c4cb5aDouble-click on the ruler now clears both the yellow time selection and the grey loop region
- UI / UX
- fa6283bAdded punch/locator keyboard shortcuts, transport position display, and set-punch-from-selection context menu to complete the locator workflow gaps. ----'Fixed piano roll clip creation failing silently by adding the required addUnassignedSample call before addClip in the context menu handler. ---- Autumnris option appears inside the standard themed context menu alongside all the normal header options
- 4b9512cFixed Desktop shutdown crash by adding missing GridManagerWindow -- deleteInstance to both the editor destructor and standalone app shutdown, which left 1 component and 1 peer alive on the Desktop during destruction. Changed four dialog shutdown methods RecoveryWizardDialog, AutoSaveFirstRunDialog, ProjectConsolidationDialog, MissingSampleRelinkDialog from async exitModalState 0 to synchronous deletion since the event loop is already stopped by shutdown time. Added missing ProjectConsolidationDialog andMissingSampleRelinkDialog shutdown calls to standalone app shutdown.
- 44e0ca7Modernized track control row visuals: dimmed knobs/buttons at rest with interaction-driven brightening, pill-shaped knob backgrounds for text breathing room, transparent mute/solo icons colored by theme accent when active, group padding between control clusters, and subtle 8% opacity grid separators. Overrode drawLabel in EphemeraLookAndFeel to remove JUCE's default border rect that caused underlines on editable track name labels.Renamed the 'Shaders' button in the bottom bar to 'Player' and added the missing time-of-day color properties so it now matches the theme-aware coloring of all other bottom bar buttons. Also simplified the auto-commit-message Stop hook to always fire without git dependency, removing the git diff check that was timing out on the large working tree.Added missing bottom margin spacing after the Appearance theme group in PluginInterfaceTabComponent's calculateContentHeight(), which was the only section not followed by the standard DesignTokens::Spacing::md that every other group had. This caused the content height to be 16px short, preventing the scrollbar from reaching the time of day theme settings at the bottom of the Interface settings tab.
- f9192a7Added global time-of-day theming to all popup menus and combo box dropdowns by introducing updatePopupMenuColorsForTime() on EphemeraLookAndFeel. Called it from the editor constructor for immediate startup theming and from the timer on each hour change so colors stay in sync. Also wired it into setCurrentTimeOverride() so external windows like Settings and Piano Roll get themed popups automatically. This single method propagates the immersive HSV-derived environmental colors to all 147+ combo boxes and popup menus across the entire application without requiring per-file changes.
- d6db1aaOverengineered Whack-a-Mole mole with full procedural anatomy, expressive animations, and cinematic hit/miss reactions. Extracted mole visuals into MoleAnimator (8-phase state machine with PreSpawn dirt burst, Peeking, Rising with easeOutBack bounce, Idle with breathing/blinking/whisker twitches, HitReact squash-and-stretch with orbiting dizzy stars, comedic wobble-sink, ExpireTaunt arm wave, and smooth confident descent) and MoleRenderer (pear-shaped Path body with ColourGradient, belly, fur texture, tapered snout, pink nose with specular highlight, 3-per-side whiskers, expression-driven eyes including spiral dizzy eyes and serene closed regal eyes, animated eyelids for blinking and half-lidded confidence, 7 mouth variants from smug smirk to nervous wavy line to surprised O, buck teeth, pink-inner ears with wiggle, hole-gripping paws with claws). Golden mole gets a 3-pointed crown with gem dots and bob animation, cycling rainbow HSV shimmer overlay, and orbiting sparkle stars. Bomb mole gets radial gradient sphere body with metallic highlight arc, curved fuse with shrinking length and pulsing orange-yellow-white spark, menacing slant-browed glowing eyes, tick wobble, and sweat drops when fuse runs low. Expression auto-selection transitions from Confident to Neutral to Nervous as timer depletes, with Regal override for golden and Menacing for bomb. Fixed-size std::array<MoleVisualState, 8> pool for zero heap allocation during gameplay. Three-tier LOD system skips fur texture and extra detail below 45px cell width. Emergence clipping via reduceClipRegion creates mole-rising-from-hole illusion with hole drawn on top of clipped body and paws gripping the rim. ---- Modernized track control row visuals: dimmed knobs/buttons at rest with interaction-driven brightening, pill-shaped knob backgrounds for text breathing room, transparent mute/solo icons colored by theme accent when active, group padding between control clusters, and subtle 8% opacity grid separators. Overrode drawLabel in EphemeraLookAndFeel to remove JUCE's default border rect that caused underlines on editable track name labels.
- e82ede2Modernized track control row visuals: dimmed knobs/buttons at rest with interaction-driven brightening, pill-shaped knob backgrounds for text breathing room, transparent mute/solo icons colored by theme accent when active, group padding between control clusters, bolder track labels without underlines, and subtle 8% opacity grid separators.
- 06bf364Dimmed track control row visuals at rest and added interaction-driven brightening. Flattened EphemeraKnob backgrounds from circles to pill-shaped rounded rectangles so wide negative values have breathing room, with desaturated value arcs that become vivid on hover/drag via a unified interactionAmount. Removed mute/solo button backgrounds entirely for transparent bare icons that use the theme accent color when toggled on and dim grey with row-hover-aware brightening when off. Added 8px group padding between functional control clusters, increased track name font to 11px bold, removed editable label underlines, and reduced grid line opacity to 8% white for barely-visible row separators. ---- Updated popup menu styling to use immersive time-of-day theming instead of generic grey backgrounds. Replaced darker() color derivation with direct HSV construction that preserves the environmental hue at a perceivable saturation and brightness level with 90% opacity for subtle translucency. Changed hover highlights from a simple brighter-background to a vibrant semi-transparent accent color matching the time-of-day palette. Softened menu borders to blend with the environment and added rounded inset rectangles for polished item hover states.
- Day 334 · 5 commits

- Audio engine
- 1a4c019Phase Invert: master channel processing fix + per-sample phase invert with UI. ---- Changed auxReturnsVisible default from true to false in MixerPanel.h:243. The RTN/Return panel will now be closed by default when the mixer opens
- a606d2eDouble-click on the ruler now clears both the yellow time selection and the grey loop region ---- Added MIDI clip resize, auto-resize, and assign-to-grid support to complete the timeline piano roll clips Phase 2 workflow ----
- Timeline
- d5bee3bTimelineRulerComponent::setPlayheadPosition() now immediately forwards the new position to the event handler via eventHandler->setPlayheadPosition(). Previously, the event handler's cached currentPlayheadPosSec only got updated during syncEventHandlerState() (called on view/zoom changes and in the constructor), so it stayed at 0 until one of those triggers happened. Now it stays in sync every time the timer updates the playhead
- UI / UX
- 0a43e86Added Clear Punch Region option to timeline ruler right click context menu, enabbled when clicking an existing punch region
- be5b770Added normalize-to--3dBFS menu item to the waveform right-click context menu and wired the existing but previously unconnected toolbar Normalize button, both calling SamplePlayer::normalizeSample with success/failure feedback via InfoChiron.