Der Tonversatz ist ein Regler, abgetrennt unter den Spuren

Drei Anläufe, und du hattest jedes Mal recht.

**Er gehört ins Tonmenü** — aber sichtbar nicht zu den Spuren. Jetzt
trennt ihn ein Strich ab, darüber steht „TONVERSATZ — Ohne Versatz" als
Überschrift, darunter ein Regler. Drei Mittel, und jedes einzelne würde
schon sagen, dass das keine Sprache ist.

**Ein Regler statt Auswahlpunkten.** Feste Stufen hiessen: für jeden Wert
ein Eintrag, und die standen zwischen den Sprachen wie weitere Sprachen.
Gezogen wird von −3 bis +3 Sekunden in Hundertern; die Mitte ist als
Strich markiert, sonst trifft man die Null nur zufällig. Gerechnet wird
erst beim Loslassen, nicht beim Ziehen — jede Änderung baut den Strom neu
auf, und das tut man nicht zwanzigmal beim Hinschieben. Daneben
„Zurücksetzen", sobald etwas eingestellt ist.

**Und der Lautsprecher ist zurück.** Hier stand ein eigenes Zeichen, damit
er nicht zweimal in der Leiste auftaucht — links Stummschalten, rechts die
Tonspur. Die Wellenform erkannte aber niemand als „Ton". Zwei Lautsprecher
sind das kleinere Übel, zumal der linke beim Stummschalten
durchgestrichen wird und damit anders aussieht.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-10-07 20:42:50 +02:00
co-authored by Claude Opus 5
parent dc9d1cea85
commit 2f7768136b
3 changed files with 96 additions and 31 deletions
+73 -29
View File
@@ -85,13 +85,12 @@ export function geraeteprofil(): {
/** Wie oft der Stand zum Server geht. */
const MELDEABSTAND = 10_000;
/** Die Stufen des Tonversatzes in Millisekunden.
*
* **Nicht jeder Hunderter von −5000 bis +5000.** Das wären einhunderteins
* Einträge für etwas, das man im Jahr dreimal braucht. Diese elf decken ab,
* was vorkommt — und wer mehr braucht, hat keine Einstellung zu wenig,
* sondern eine kaputte Datei. */
const VERSAETZE = [-1000, -500, -300, -200, -100, 0, 100, 200, 300, 500, 1000];
/** In welchen Schritten der Regler einrastet. */
const VERSATZSCHRITT = 100;
/** Wie weit in beide Richtungen. Darüber hinaus ist es kein Versatz mehr,
* sondern eine kaputte Datei. */
const VERSATZGRENZE = 3000;
/** Wo gemerkte Tonversätze liegen — je Datei, in diesem Browser.
*
@@ -372,10 +371,58 @@ export function spieler(anfrage: Spieleranfrage): void {
* acht Strahlen sah aus wie eine Sonne — niemand vermutete die Bildqualität
* dahinter. Jetzt: Wellenform für den Ton, CC-Kasten für die Untertitel,
* Schieberegler für die Qualität. */
const tonmenue = menue('tonspur', 'Tonspur');
// **Der Lautsprecher, nicht die Wellenform.** Hier stand einmal ein eigenes
// Zeichen, damit er nicht zweimal in der Leiste auftaucht — links für
// Stummschalten, rechts für die Tonspur. Die Wellenform erkannte aber
// niemand als „Ton"; zwei Lautsprecher sind das kleinere Übel, zumal der
// linke beim Stummschalten durchgestrichen wird und damit anders aussieht.
const tonmenue = menue('ton', 'Ton');
const textmenue = menue('untertitel', 'Untertitel');
const stufenmenue = menue('regler', 'Qualität');
const versatzmenue = menue('versatz', 'Tonversatz');
/* ---------- Der Tonversatz, abgetrennt im Tonmenü ---------- */
// **Ein Regler, keine Liste.** Feste Stufen hiessen: für jeden Wert ein
// Eintrag, und die standen zwischen den Sprachen wie weitere Sprachen.
// Hier wird gezogen, und zwar erst beim Loslassen — jede Änderung baut den
// Strom neu auf, und das tut man nicht zwanzigmal beim Hinschieben.
const versatzkopf = document.createElement('div');
versatzkopf.className = 'pl-fusstitel';
const versatzregler = document.createElement('input');
versatzregler.type = 'range';
versatzregler.className = 'pl-laut pl-versatz';
versatzregler.min = String(-VERSATZGRENZE);
versatzregler.max = String(VERSATZGRENZE);
versatzregler.step = String(VERSATZSCHRITT);
versatzregler.setAttribute('aria-label', 'Tonversatz in Millisekunden');
const versatzzurueck = knopf('Zurücksetzen', 'pl-punkt');
function versatzstand(): void {
versatzkopf.textContent = `Tonversatz — ${versatzWort(tonversatz)}`;
versatzregler.value = String(tonversatz);
versatzregler.setAttribute('aria-valuetext', versatzWort(tonversatz));
versatzzurueck.classList.toggle('hidden', tonversatz === 0);
}
function versatzSetzen(ms: number): void {
tonversatz = Math.max(-VERSATZGRENZE, Math.min(VERSATZGRENZE, Math.round(ms / VERSATZSCHRITT) * VERSATZSCHRITT));
versatzMerken(anfrage.dateiId, tonversatz);
versatzstand();
void stromAufbauen(filmzeit());
}
// Beim Ziehen nur die Zahl mitlaufen lassen, beim Loslassen rechnen.
versatzregler.oninput = () => {
versatzkopf.textContent = `Tonversatz — ${versatzWort(Number(versatzregler.value))}`;
};
versatzregler.onchange = () => versatzSetzen(Number(versatzregler.value));
versatzregler.onclick = e => e.stopPropagation();
versatzzurueck.onclick = e => { e.stopPropagation(); versatzSetzen(0); };
tonmenue.fuss.append(versatzkopf, versatzregler, versatzzurueck);
const links = document.createElement('div');
links.className = 'pl-gruppe';
@@ -383,8 +430,7 @@ export function spieler(anfrage: Spieleranfrage): void {
const rechts = document.createElement('div');
rechts.className = 'pl-gruppe';
rechts.append(
rest, tonmenue.knopf, versatzmenue.knopf, textmenue.knopf, stufenmenue.knopf, vollbild);
rechts.append(rest, tonmenue.knopf, textmenue.knopf, stufenmenue.knopf, vollbild);
const unten = document.createElement('div');
unten.className = 'pl-unten';
@@ -653,23 +699,9 @@ export function spieler(anfrage: Spieleranfrage): void {
tonmenue.setzen(spuren);
// **Der Versatz hat ein eigenes Menü.** Er stand vorher unter den
// Tonspuren, und dort las er sich wie eine: „Später (+100 ms)" sah aus
// wie der Name einer Spur. Eine Einstellung gehört nicht in eine Liste
// von Inhalten.
//
// Feste Stufen statt zweier Tasten, wie bei der Qualität: so zeigt der
// Haken, wo man steht, und man trifft einen Wert, statt sich
// hinzutasten — jeder Schritt baut den Strom neu auf.
versatzmenue.setzen(VERSAETZE.map(ms => ({
text: versatzWort(ms),
gewaehlt: ms === tonversatz,
tun: () => {
tonversatz = ms;
versatzMerken(anfrage.dateiId, ms);
void stromAufbauen(filmzeit());
},
})));
// Ohne Tonspur gibt es nichts zu verschieben.
tonmenue.fuss.classList.toggle('hidden', toene.length === 0);
versatzstand();
const texte = auskunft?.subtitleStreams ?? [];
textmenue.setzen(
@@ -914,7 +946,7 @@ export function spieler(anfrage: Spieleranfrage): void {
/** Ein kleines Menü, das über der Leiste aufgeht. */
function menue(bild: keyof typeof icons, titel: string): {
knopf: HTMLElement; setzen: (punkte: Wahl[]) => void;
knopf: HTMLElement; fuss: HTMLElement; setzen: (punkte: Wahl[]) => void;
} {
const huelle = document.createElement('div');
huelle.className = 'pl-menue';
@@ -934,10 +966,20 @@ export function spieler(anfrage: Spieleranfrage): void {
const liste = document.createElement('div');
liste.className = 'pl-liste';
// **Ein abgetrennter Fuss für das, was keine Auswahl ist.**
// Eine Einstellung zwischen Inhalten sieht aus wie ein Inhalt — der
// Tonversatz stand als „Später (+100 ms)" zwischen den Sprachen und las
// sich wie eine. Hier ist er durch einen Strich und eine Überschrift
// sichtbar etwas anderes.
const fuss = document.createElement('div');
fuss.className = 'pl-fuss hidden';
huelle.append(ausloeser, liste);
liste.appendChild(fuss);
return {
knopf: huelle,
fuss,
setzen: punkte => {
liste.innerHTML = '';
punkte.forEach(p => {
@@ -950,6 +992,8 @@ export function spieler(anfrage: Spieleranfrage): void {
};
liste.appendChild(b);
});
// Der Fuss gehört nicht zur Auswahl und wird deshalb wieder angehängt.
liste.appendChild(fuss);
},
};
}