Add real-time audio spectrum test for audio sources and templates

- Add WebSocket endpoints for live audio spectrum streaming at ~20Hz
- Audio source test: resolves device/channel, shares stream via ref-counting
- Audio template test: includes device picker dropdown for selecting input
- Canvas-based 64-band spectrum visualizer with falling peaks and beat flash
- Channel-aware: mono sources show left/right/mixed spectrum correctly

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-26 14:19:41 +03:00
parent 4806f5020c
commit 147ef3b4eb
12 changed files with 725 additions and 6 deletions

View File

@@ -122,7 +122,9 @@
{% include 'modals/pp-template.html' %}
{% include 'modals/profile-editor.html' %}
{% include 'modals/audio-source-editor.html' %}
{% include 'modals/test-audio-source.html' %}
{% include 'modals/audio-template.html' %}
{% include 'modals/test-audio-template.html' %}
{% include 'modals/value-source-editor.html' %}
{% include 'partials/tutorial-overlay.html' %}

View File

@@ -0,0 +1,27 @@
<!-- Test Audio Source Modal -->
<div id="test-audio-source-modal" class="modal" role="dialog" aria-modal="true" aria-labelledby="test-audio-source-modal-title">
<div class="modal-content">
<div class="modal-header">
<h2 id="test-audio-source-modal-title" data-i18n="audio_source.test.title">Test Audio Source</h2>
<button class="modal-close-btn" onclick="closeTestAudioSourceModal()" title="Close" data-i18n-aria-label="aria.close">&#x2715;</button>
</div>
<div class="modal-body">
<canvas id="audio-test-canvas" class="audio-test-canvas"></canvas>
<div class="audio-test-stats">
<span class="audio-test-stat">
<span class="audio-test-stat-label" data-i18n="audio_source.test.rms">RMS</span>
<span class="audio-test-stat-value" id="audio-test-rms">---</span>
</span>
<span class="audio-test-stat">
<span class="audio-test-stat-label" data-i18n="audio_source.test.peak">Peak</span>
<span class="audio-test-stat-value" id="audio-test-peak">---</span>
</span>
<span class="audio-test-stat">
<span id="audio-test-beat-dot" class="audio-test-beat-dot"></span>
<span class="audio-test-stat-label" data-i18n="audio_source.test.beat">Beat</span>
</span>
</div>
<div id="audio-test-status" class="audio-test-status" data-i18n="audio_source.test.connecting">Connecting...</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,40 @@
<!-- Test Audio Template Modal -->
<div id="test-audio-template-modal" class="modal" role="dialog" aria-modal="true" aria-labelledby="test-audio-template-modal-title">
<div class="modal-content">
<div class="modal-header">
<h2 id="test-audio-template-modal-title" data-i18n="audio_template.test.title">Test Audio Template</h2>
<button class="modal-close-btn" onclick="closeTestAudioTemplateModal()" title="Close" data-i18n-aria-label="aria.close">&#x2715;</button>
</div>
<div class="modal-body">
<div class="form-group">
<div class="label-row">
<label for="test-audio-template-device" data-i18n="audio_template.test.device">Audio Device:</label>
<button type="button" class="hint-toggle" onclick="toggleHint(this)" title="?">?</button>
</div>
<small class="input-hint" style="display:none" data-i18n="audio_template.test.device.hint">Select which audio device to capture from during the test</small>
<select id="test-audio-template-device"></select>
</div>
<button type="button" id="test-audio-template-start-btn" class="btn btn-primary" onclick="startAudioTemplateTest()" style="margin-top: 8px;">
<span data-i18n="audio_template.test.run">🧪 Run</span>
</button>
<canvas id="audio-template-test-canvas" class="audio-test-canvas" style="display:none; margin-top: 12px;"></canvas>
<div id="audio-template-test-stats" class="audio-test-stats" style="display:none;">
<span class="audio-test-stat">
<span class="audio-test-stat-label" data-i18n="audio_source.test.rms">RMS</span>
<span class="audio-test-stat-value" id="audio-template-test-rms">---</span>
</span>
<span class="audio-test-stat">
<span class="audio-test-stat-label" data-i18n="audio_source.test.peak">Peak</span>
<span class="audio-test-stat-value" id="audio-template-test-peak">---</span>
</span>
<span class="audio-test-stat">
<span id="audio-template-test-beat-dot" class="audio-test-beat-dot"></span>
<span class="audio-test-stat-label" data-i18n="audio_source.test.beat">Beat</span>
</span>
</div>
<div id="audio-template-test-status" class="audio-test-status" style="display:none;"></div>
</div>
</div>
</div>