Add audio-reactive color strip sources, improve delete error messages
Add new "audio" color strip source type with three visualization modes (spectrum analyzer, beat pulse, VU meter) supporting WASAPI loopback and microphone input via PyAudioWPatch. Includes shared audio capture with ref counting, real-time FFT spectrum analysis, and beat detection. Improve all referential integrity 409 error messages across delete endpoints to include specific names of referencing entities instead of generic "one or more" messages. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -27,6 +27,7 @@
|
||||
<option value="color_cycle" data-i18n="color_strip.type.color_cycle">Color Cycle</option>
|
||||
<option value="effect" data-i18n="color_strip.type.effect">Procedural Effect</option>
|
||||
<option value="composite" data-i18n="color_strip.type.composite">Composite</option>
|
||||
<option value="audio" data-i18n="color_strip.type.audio">Audio Reactive</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
@@ -315,6 +316,107 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Audio-reactive fields -->
|
||||
<div id="css-editor-audio-section" style="display:none">
|
||||
<div class="form-group">
|
||||
<div class="label-row">
|
||||
<label for="css-editor-audio-viz" data-i18n="color_strip.audio.visualization">Visualization:</label>
|
||||
<button type="button" class="hint-toggle" onclick="toggleHint(this)" title="?" data-i18n-aria-label="aria.hint">?</button>
|
||||
</div>
|
||||
<small class="input-hint" style="display:none" data-i18n="color_strip.audio.visualization.hint">How audio data is rendered to LEDs.</small>
|
||||
<select id="css-editor-audio-viz" onchange="onAudioVizChange()">
|
||||
<option value="spectrum" data-i18n="color_strip.audio.viz.spectrum">Spectrum Analyzer</option>
|
||||
<option value="beat_pulse" data-i18n="color_strip.audio.viz.beat_pulse">Beat Pulse</option>
|
||||
<option value="vu_meter" data-i18n="color_strip.audio.viz.vu_meter">VU Meter</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="label-row">
|
||||
<label for="css-editor-audio-device" data-i18n="color_strip.audio.device">Audio Device:</label>
|
||||
<button type="button" class="hint-toggle" onclick="toggleHint(this)" title="?" data-i18n-aria-label="aria.hint">?</button>
|
||||
</div>
|
||||
<small class="input-hint" style="display:none" data-i18n="color_strip.audio.device.hint">Audio input source. Loopback devices capture system audio output; input devices capture microphone or line-in.</small>
|
||||
<select id="css-editor-audio-device">
|
||||
<!-- populated dynamically from /api/v1/audio-devices -->
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="label-row">
|
||||
<label for="css-editor-audio-sensitivity">
|
||||
<span data-i18n="color_strip.audio.sensitivity">Sensitivity:</span>
|
||||
<span id="css-editor-audio-sensitivity-val">1.0</span>
|
||||
</label>
|
||||
<button type="button" class="hint-toggle" onclick="toggleHint(this)" title="?" data-i18n-aria-label="aria.hint">?</button>
|
||||
</div>
|
||||
<small class="input-hint" style="display:none" data-i18n="color_strip.audio.sensitivity.hint">Gain multiplier for audio levels. Higher values make LEDs react to quieter sounds.</small>
|
||||
<input type="range" id="css-editor-audio-sensitivity" min="0.1" max="5.0" step="0.1" value="1.0"
|
||||
oninput="document.getElementById('css-editor-audio-sensitivity-val').textContent = parseFloat(this.value).toFixed(1)">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="label-row">
|
||||
<label for="css-editor-audio-smoothing">
|
||||
<span data-i18n="color_strip.audio.smoothing">Smoothing:</span>
|
||||
<span id="css-editor-audio-smoothing-val">0.30</span>
|
||||
</label>
|
||||
<button type="button" class="hint-toggle" onclick="toggleHint(this)" title="?" data-i18n-aria-label="aria.hint">?</button>
|
||||
</div>
|
||||
<small class="input-hint" style="display:none" data-i18n="color_strip.audio.smoothing.hint">Temporal smoothing between frames. Higher values produce smoother but slower-reacting visuals.</small>
|
||||
<input type="range" id="css-editor-audio-smoothing" min="0.0" max="1.0" step="0.05" value="0.3"
|
||||
oninput="document.getElementById('css-editor-audio-smoothing-val').textContent = parseFloat(this.value).toFixed(2)">
|
||||
</div>
|
||||
|
||||
<div id="css-editor-audio-palette-group" class="form-group">
|
||||
<div class="label-row">
|
||||
<label for="css-editor-audio-palette" data-i18n="color_strip.audio.palette">Palette:</label>
|
||||
<button type="button" class="hint-toggle" onclick="toggleHint(this)" title="?" data-i18n-aria-label="aria.hint">?</button>
|
||||
</div>
|
||||
<small class="input-hint" style="display:none" data-i18n="color_strip.audio.palette.hint">Color palette used for spectrum bars or beat pulse coloring.</small>
|
||||
<select id="css-editor-audio-palette">
|
||||
<option value="rainbow" data-i18n="color_strip.palette.rainbow">Rainbow</option>
|
||||
<option value="fire" data-i18n="color_strip.palette.fire">Fire</option>
|
||||
<option value="ocean" data-i18n="color_strip.palette.ocean">Ocean</option>
|
||||
<option value="lava" data-i18n="color_strip.palette.lava">Lava</option>
|
||||
<option value="forest" data-i18n="color_strip.palette.forest">Forest</option>
|
||||
<option value="aurora" data-i18n="color_strip.palette.aurora">Aurora</option>
|
||||
<option value="sunset" data-i18n="color_strip.palette.sunset">Sunset</option>
|
||||
<option value="ice" data-i18n="color_strip.palette.ice">Ice</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div id="css-editor-audio-color-group" class="form-group" style="display:none">
|
||||
<div class="label-row">
|
||||
<label for="css-editor-audio-color" data-i18n="color_strip.audio.color">Base Color:</label>
|
||||
<button type="button" class="hint-toggle" onclick="toggleHint(this)" title="?" data-i18n-aria-label="aria.hint">?</button>
|
||||
</div>
|
||||
<small class="input-hint" style="display:none" data-i18n="color_strip.audio.color.hint">Low-level color for VU meter bar.</small>
|
||||
<input type="color" id="css-editor-audio-color" value="#00ff00">
|
||||
</div>
|
||||
|
||||
<div id="css-editor-audio-color-peak-group" class="form-group" style="display:none">
|
||||
<div class="label-row">
|
||||
<label for="css-editor-audio-color-peak" data-i18n="color_strip.audio.color_peak">Peak Color:</label>
|
||||
<button type="button" class="hint-toggle" onclick="toggleHint(this)" title="?" data-i18n-aria-label="aria.hint">?</button>
|
||||
</div>
|
||||
<small class="input-hint" style="display:none" data-i18n="color_strip.audio.color_peak.hint">High-level color at the top of the VU meter bar.</small>
|
||||
<input type="color" id="css-editor-audio-color-peak" value="#ff0000">
|
||||
</div>
|
||||
|
||||
<div id="css-editor-audio-mirror-group" class="form-group" style="display:none">
|
||||
<div class="label-row">
|
||||
<label for="css-editor-audio-mirror" data-i18n="color_strip.audio.mirror">Mirror:</label>
|
||||
<button type="button" class="hint-toggle" onclick="toggleHint(this)" title="?" data-i18n-aria-label="aria.hint">?</button>
|
||||
</div>
|
||||
<small class="input-hint" style="display:none" data-i18n="color_strip.audio.mirror.hint">Mirror spectrum from center outward: bass in the middle, treble at the edges.</small>
|
||||
<label class="settings-toggle">
|
||||
<input type="checkbox" id="css-editor-audio-mirror">
|
||||
<span class="settings-toggle-slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Shared LED count field -->
|
||||
<div id="css-editor-led-count-group" class="form-group">
|
||||
<div class="label-row">
|
||||
|
||||
Reference in New Issue
Block a user