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:
co-authored by
Claude Opus 5
parent
dc9d1cea85
commit
2f7768136b
@@ -96,8 +96,6 @@ export const icons = {
|
|||||||
* löst keinen Alarm aus. */
|
* löst keinen Alarm aus. */
|
||||||
fahne: rahmen('<path d="M6 21V4"/><path d="M6 4.8h11.6l-2.5 4 2.5 4H6"/>'),
|
fahne: rahmen('<path d="M6 21V4"/><path d="M6 4.8h11.6l-2.5 4 2.5 4H6"/>'),
|
||||||
|
|
||||||
/** Tonversatz — zwei Pfeile, die auseinandergehen. */
|
|
||||||
versatz: rahmen('<path d="M3 12h18"/><path d="M7 8l-4 4 4 4"/><path d="M17 8l4 4-4 4"/>'),
|
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export type IconName = keyof typeof icons;
|
export type IconName = keyof typeof icons;
|
||||||
|
|||||||
+73
-29
@@ -85,13 +85,12 @@ export function geraeteprofil(): {
|
|||||||
/** Wie oft der Stand zum Server geht. */
|
/** Wie oft der Stand zum Server geht. */
|
||||||
const MELDEABSTAND = 10_000;
|
const MELDEABSTAND = 10_000;
|
||||||
|
|
||||||
/** Die Stufen des Tonversatzes in Millisekunden.
|
/** In welchen Schritten der Regler einrastet. */
|
||||||
*
|
const VERSATZSCHRITT = 100;
|
||||||
* **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,
|
/** Wie weit in beide Richtungen. Darüber hinaus ist es kein Versatz mehr,
|
||||||
* was vorkommt — und wer mehr braucht, hat keine Einstellung zu wenig,
|
* sondern eine kaputte Datei. */
|
||||||
* sondern eine kaputte Datei. */
|
const VERSATZGRENZE = 3000;
|
||||||
const VERSAETZE = [-1000, -500, -300, -200, -100, 0, 100, 200, 300, 500, 1000];
|
|
||||||
|
|
||||||
/** Wo gemerkte Tonversätze liegen — je Datei, in diesem Browser.
|
/** 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
|
* 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,
|
* dahinter. Jetzt: Wellenform für den Ton, CC-Kasten für die Untertitel,
|
||||||
* Schieberegler für die Qualität. */
|
* 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 textmenue = menue('untertitel', 'Untertitel');
|
||||||
const stufenmenue = menue('regler', 'Qualität');
|
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');
|
const links = document.createElement('div');
|
||||||
links.className = 'pl-gruppe';
|
links.className = 'pl-gruppe';
|
||||||
@@ -383,8 +430,7 @@ export function spieler(anfrage: Spieleranfrage): void {
|
|||||||
|
|
||||||
const rechts = document.createElement('div');
|
const rechts = document.createElement('div');
|
||||||
rechts.className = 'pl-gruppe';
|
rechts.className = 'pl-gruppe';
|
||||||
rechts.append(
|
rechts.append(rest, tonmenue.knopf, textmenue.knopf, stufenmenue.knopf, vollbild);
|
||||||
rest, tonmenue.knopf, versatzmenue.knopf, textmenue.knopf, stufenmenue.knopf, vollbild);
|
|
||||||
|
|
||||||
const unten = document.createElement('div');
|
const unten = document.createElement('div');
|
||||||
unten.className = 'pl-unten';
|
unten.className = 'pl-unten';
|
||||||
@@ -653,23 +699,9 @@ export function spieler(anfrage: Spieleranfrage): void {
|
|||||||
|
|
||||||
tonmenue.setzen(spuren);
|
tonmenue.setzen(spuren);
|
||||||
|
|
||||||
// **Der Versatz hat ein eigenes Menü.** Er stand vorher unter den
|
// Ohne Tonspur gibt es nichts zu verschieben.
|
||||||
// Tonspuren, und dort las er sich wie eine: „Später (+100 ms)" sah aus
|
tonmenue.fuss.classList.toggle('hidden', toene.length === 0);
|
||||||
// wie der Name einer Spur. Eine Einstellung gehört nicht in eine Liste
|
versatzstand();
|
||||||
// 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());
|
|
||||||
},
|
|
||||||
})));
|
|
||||||
|
|
||||||
const texte = auskunft?.subtitleStreams ?? [];
|
const texte = auskunft?.subtitleStreams ?? [];
|
||||||
textmenue.setzen(
|
textmenue.setzen(
|
||||||
@@ -914,7 +946,7 @@ export function spieler(anfrage: Spieleranfrage): void {
|
|||||||
|
|
||||||
/** Ein kleines Menü, das über der Leiste aufgeht. */
|
/** Ein kleines Menü, das über der Leiste aufgeht. */
|
||||||
function menue(bild: keyof typeof icons, titel: string): {
|
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');
|
const huelle = document.createElement('div');
|
||||||
huelle.className = 'pl-menue';
|
huelle.className = 'pl-menue';
|
||||||
@@ -934,10 +966,20 @@ export function spieler(anfrage: Spieleranfrage): void {
|
|||||||
|
|
||||||
const liste = document.createElement('div');
|
const liste = document.createElement('div');
|
||||||
liste.className = 'pl-liste';
|
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);
|
huelle.append(ausloeser, liste);
|
||||||
|
liste.appendChild(fuss);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
knopf: huelle,
|
knopf: huelle,
|
||||||
|
fuss,
|
||||||
setzen: punkte => {
|
setzen: punkte => {
|
||||||
liste.innerHTML = '';
|
liste.innerHTML = '';
|
||||||
punkte.forEach(p => {
|
punkte.forEach(p => {
|
||||||
@@ -950,6 +992,8 @@ export function spieler(anfrage: Spieleranfrage): void {
|
|||||||
};
|
};
|
||||||
liste.appendChild(b);
|
liste.appendChild(b);
|
||||||
});
|
});
|
||||||
|
// Der Fuss gehört nicht zur Auswahl und wird deshalb wieder angehängt.
|
||||||
|
liste.appendChild(fuss);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -897,6 +897,29 @@ textarea.feld {
|
|||||||
}
|
}
|
||||||
.pl-menue.auf .pl-liste { display: flex; }
|
.pl-menue.auf .pl-liste { display: flex; }
|
||||||
|
|
||||||
|
/* **Der Fuss ist sichtbar etwas anderes als die Liste darüber.**
|
||||||
|
Eine Einstellung zwischen Inhalten sieht aus wie ein Inhalt — der
|
||||||
|
Tonversatz stand als Eintrag zwischen den Sprachen und las sich wie eine.
|
||||||
|
Ein Strich, eine Überschrift, ein Regler: drei Mittel, und jedes einzelne
|
||||||
|
würde es schon sagen. */
|
||||||
|
.pl-fuss {
|
||||||
|
margin-top: 6px; padding: 8px 8px 6px;
|
||||||
|
border-top: 1px solid var(--line);
|
||||||
|
display: flex; flex-direction: column; gap: 6px;
|
||||||
|
}
|
||||||
|
.pl-fusstitel {
|
||||||
|
font-size: 11px; font-weight: 600; letter-spacing: .04em;
|
||||||
|
text-transform: uppercase; color: var(--text-muted);
|
||||||
|
}
|
||||||
|
/* Breiter als der Lautstärkeregler — hier wird genau gezielt, nicht gewischt. */
|
||||||
|
.pl-versatz { width: 100%; }
|
||||||
|
/* Die Mitte markieren: ohne sie trifft man die Null nur durch Zufall. */
|
||||||
|
.pl-versatz::-webkit-slider-runnable-track {
|
||||||
|
background:
|
||||||
|
linear-gradient(rgba(255, 255, 255, .55), rgba(255, 255, 255, .55)) 50% / 2px 10px no-repeat,
|
||||||
|
rgba(255, 255, 255, .28);
|
||||||
|
}
|
||||||
|
|
||||||
.pl-punkt {
|
.pl-punkt {
|
||||||
display: flex; align-items: center; gap: 8px;
|
display: flex; align-items: center; gap: 8px;
|
||||||
background: none; border: 0; color: var(--text);
|
background: none; border: 0; color: var(--text);
|
||||||
|
|||||||
Reference in New Issue
Block a user