feat: Enhance Supertonic voice mixer controls with range inputs and display labels

This commit is contained in:
JB
2025-12-20 07:36:34 -08:00
parent 9a72c209b3
commit eabfe87ffb
3 changed files with 38 additions and 6 deletions
+5
View File
@@ -262,6 +262,11 @@ body {
display: none !important; display: none !important;
} }
/* Ensure the HTML hidden attribute always wins over component display rules. */
[hidden] {
display: none !important;
}
.modal__overlay { .modal__overlay {
position: absolute; position: absolute;
inset: 0; inset: 0;
+27
View File
@@ -31,6 +31,8 @@ const setupVoiceMixer = () => {
const supertonicVoiceSelect = app.querySelector('[data-role="supertonic-voice"]'); const supertonicVoiceSelect = app.querySelector('[data-role="supertonic-voice"]');
const supertonicStepsInput = app.querySelector('[data-role="supertonic-steps"]'); const supertonicStepsInput = app.querySelector('[data-role="supertonic-steps"]');
const supertonicSpeedInput = app.querySelector('[data-role="supertonic-speed"]'); const supertonicSpeedInput = app.querySelector('[data-role="supertonic-speed"]');
const supertonicStepsLabel = app.querySelector('[data-role="supertonic-steps-display"]');
const supertonicSpeedLabel = app.querySelector('[data-role="supertonic-speed-display"]');
const speedInput = document.getElementById("preview-speed"); const speedInput = document.getElementById("preview-speed");
const importInput = document.getElementById("voice-import-input"); const importInput = document.getElementById("voice-import-input");
const headerActions = document.querySelector(".voice-mixer__header-actions"); const headerActions = document.querySelector(".voice-mixer__header-actions");
@@ -290,6 +292,7 @@ const setupVoiceMixer = () => {
const desired = Number(state.draft.supertonic?.speed ?? 1.0); const desired = Number(state.draft.supertonic?.speed ?? 1.0);
if (!Number.isNaN(desired)) { if (!Number.isNaN(desired)) {
speedInput.value = String(desired); speedInput.value = String(desired);
setRangeFill(speedInput);
} }
} }
}; };
@@ -591,9 +594,18 @@ const setupVoiceMixer = () => {
} }
if (supertonicStepsInput) { if (supertonicStepsInput) {
supertonicStepsInput.value = String(state.draft.supertonic?.total_steps ?? 5); supertonicStepsInput.value = String(state.draft.supertonic?.total_steps ?? 5);
setRangeFill(supertonicStepsInput);
} }
if (supertonicSpeedInput) { if (supertonicSpeedInput) {
supertonicSpeedInput.value = String(state.draft.supertonic?.speed ?? 1.0); supertonicSpeedInput.value = String(state.draft.supertonic?.speed ?? 1.0);
setRangeFill(supertonicSpeedInput);
}
if (supertonicStepsLabel) {
supertonicStepsLabel.textContent = String(state.draft.supertonic?.total_steps ?? 5);
}
if (supertonicSpeedLabel) {
const speed = Number(state.draft.supertonic?.speed ?? 1.0);
supertonicSpeedLabel.textContent = `${(Number.isFinite(speed) ? speed : 1.0).toFixed(2)}×`;
} }
applyProviderToUI(); applyProviderToUI();
renderSelectedVoices(); renderSelectedVoices();
@@ -1016,8 +1028,13 @@ const setupVoiceMixer = () => {
const value = Number(supertonicStepsInput.value || "5"); const value = Number(supertonicStepsInput.value || "5");
state.draft.supertonic.total_steps = clamp(value, 2, 15); state.draft.supertonic.total_steps = clamp(value, 2, 15);
supertonicStepsInput.value = String(Math.round(state.draft.supertonic.total_steps)); supertonicStepsInput.value = String(Math.round(state.draft.supertonic.total_steps));
if (supertonicStepsLabel) {
supertonicStepsLabel.textContent = supertonicStepsInput.value;
}
setRangeFill(supertonicStepsInput);
markDirty(); markDirty();
}); });
setRangeFill(supertonicStepsInput);
} }
if (supertonicSpeedInput) { if (supertonicSpeedInput) {
@@ -1026,11 +1043,17 @@ const setupVoiceMixer = () => {
const normalized = clamp(value, 0.7, 2.0); const normalized = clamp(value, 0.7, 2.0);
state.draft.supertonic.speed = normalized; state.draft.supertonic.speed = normalized;
supertonicSpeedInput.value = normalized.toFixed(2); supertonicSpeedInput.value = normalized.toFixed(2);
if (supertonicSpeedLabel) {
supertonicSpeedLabel.textContent = `${normalized.toFixed(2)}×`;
}
setRangeFill(supertonicSpeedInput);
if (speedInput) { if (speedInput) {
speedInput.value = String(normalized); speedInput.value = String(normalized);
setRangeFill(speedInput);
} }
markDirty(); markDirty();
}); });
setRangeFill(supertonicSpeedInput);
} }
if (voiceFilterSelect) { if (voiceFilterSelect) {
@@ -1052,6 +1075,10 @@ const setupVoiceMixer = () => {
state.draft.supertonic.speed = clamp(speed, 0.7, 2.0); state.draft.supertonic.speed = clamp(speed, 0.7, 2.0);
if (supertonicSpeedInput) { if (supertonicSpeedInput) {
supertonicSpeedInput.value = state.draft.supertonic.speed.toFixed(2); supertonicSpeedInput.value = state.draft.supertonic.speed.toFixed(2);
setRangeFill(supertonicSpeedInput);
}
if (supertonicSpeedLabel) {
supertonicSpeedLabel.textContent = `${state.draft.supertonic.speed.toFixed(2)}×`;
} }
} }
}; };
+6 -6
View File
@@ -73,14 +73,14 @@
{% endfor %} {% endfor %}
</select> </select>
</div> </div>
<div class="field"> <div class="field field--slider">
<label for="supertonic-quality">Supertonic quality (total steps)</label> <label for="supertonic-quality">Supertonic quality (total steps) <span class="tag" data-role="supertonic-steps-display">5</span></label>
<input type="number" id="supertonic-quality" data-role="supertonic-steps" min="2" max="15" value="5"> <input type="range" id="supertonic-quality" data-role="supertonic-steps" min="2" max="15" step="1" value="5">
<p class="hint">2 = fastest/lowest quality, 15 = slowest/highest quality.</p> <p class="hint">2 = fastest/lowest quality, 15 = slowest/highest quality.</p>
</div> </div>
<div class="field"> <div class="field field--slider">
<label for="supertonic-speaker-speed">Supertonic speed</label> <label for="supertonic-speaker-speed">Supertonic speed <span class="tag" data-role="supertonic-speed-display">1.00×</span></label>
<input type="number" id="supertonic-speaker-speed" data-role="supertonic-speed" min="0.7" max="2.0" step="0.05" value="1.0"> <input type="range" id="supertonic-speaker-speed" data-role="supertonic-speed" min="0.7" max="2.0" step="0.05" value="1.0">
</div> </div>
<p class="hint">Supertonic voice mixing is not implemented yet. Stub target: <a href="https://github.com/Topping1/Supertonic-Voice-Mixer" target="_blank" rel="noreferrer">Supertonic-Voice-Mixer</a>.</p> <p class="hint">Supertonic voice mixing is not implemented yet. Stub target: <a href="https://github.com/Topping1/Supertonic-Voice-Mixer" target="_blank" rel="noreferrer">Supertonic-Voice-Mixer</a>.</p>
</div> </div>