{% extends "basis.html" %}{% set seiten_module = ("dig",) %}{% block titel %}{{ d.titel or (t.blatt.ohne_titel if d.interpret else t.blatt.ohne_namen) }} – Timbre{% endblock %}{% block weich %} data-weich{% endblock %}{% block inhalt %} {% set b = t.blatt %}{% set m = d.merkmale %}{% set sig = m.signal or {} %}{% set abg = m.abgeleitet or {} %} {% macro punkt(art) %}{% set erkl = t.herkunft[art][1] %}{% endmacro %} {% macro dez(x, n) %}{% set s = ('%.' ~ n ~ 'f') | format(x) %}{{ s | dezimal(sprache) }}{% endmacro %} {# Die Sicherheit der gemessenen Tonart steht immer in einer eigenen Zeile (ohne Trennpunkt): neben „gemessen 4m“ passt sie in keiner Breite. #} {# Tonart-Codes kommen intern als 1A–12B und werden nur zur Anzeige nach Open Key (1m–12d) umgerechnet; data-tonart trägt den internen Code für titelblatt.js. #} {# Tag-Werte (BPM, Tonart) stehen ohne Herkunftspunkt mit „(Tags)“, gemessene Werte mit Punkt. Ungültige Werte gelten als fehlend. #} {% set cam = abg.camelot if abg.camelot | camelot_stil else none %} {% set gem = sig.camelot_gemessen if sig.camelot_gemessen | camelot_stil else none %} {% set sicher = sig.camelot_gemessen_sicherheit if sig.camelot_gemessen_sicherheit is number else none %} {# Energie nur als Stufe o · + · ++ · +++ (energie.py), nie die Feinstufe #}{% set e_stufe = abg.energiestufe | energie_stufe %} {% set sek = (d.dauer_s | int) if d.dauer_s is number and d.dauer_s >= 0 else none %} {% if demo and not demo_angemeldet %}{% include "demo_band.html" %}{% endif %}
{# Cover „A+“ (24.10.2026): static/cover.js setzt das Bild aus den Tags (oder das Muster) und die Herkunft; ohne Skript bleibt es weg #}
{{ b.eyebrow }}
{# ohne Titel und ohne Artist: ein „Ohne Namen“ statt zweier Platzhalter #} {% set namenlos = not d.titel and not d.interpret %} {{ d.titel or (b.ohne_namen if namenlos else b.ohne_titel) }}

{{ [none if namenlos else (d.interpret or b.ohne_interpret), d.album, d.jahr] | select | join(' · ') }}

{# Live-Demo: Namensnennung je Track – „Titel – Artist · Lizenz · Quelle“ (demo_credits.json) #} {% if demo_credit %}{% set c = demo_credit %}

{{ t.demo.credit_zeile }} {{ c.titel }} – {{ c.artist }} · {{ c.lizenz }} · {{ t.demo.credits_quelle }}

{% endif %} {# Tag List (Paket 2): Knopf +/✓ und Taste T im Blattkopf; ohne Skript bleibt der Knopf verborgen #} {# „Passt als Nächstes“ (22.10.2026): der Knopf klappt den Abschnitt in der Tiefe auf und springt hin (Booth, mobil); ohne Skript verborgen #}
{# Ort der Datei in Worten; titelblatt.js setzt Symbol und – wenn die Datei im Onlinespeicher liegt – den Abspielknopf davor. #} {% if (d.ort and status_speicher) or d.herkunft %}
{% if d.ort and status_speicher %}{{ t.ort[d.ort] }}{% endif %}
{% endif %}
{# Tempo-Feld (24.10.2026, Variante A „Spiegel der Tonart“): eigene Vorlage, damit die fünf Fälle einzeln prüfbar sind #} {% include "kz_tempo.html" %} {#- Tonart nach der Vorgabe aus quelle.py (31.10.2026): Tags, sonst Rekordbox-Import, sonst gemessen – Quelle als Symbol am Wert (wq.html). Weichen Rekordbox und Messung ab, führt „anders“ zur Uneinigkeit. #} {%- from "wq.html" import wq -%} {#- Quellen je Feld (31.10.2026): mit Konto nach dessen Anzeige-Reihenfolge (quelle.titel_anzeige), sonst die Vorgabe -#} {%- set tq = qa.tonart if qa is defined and qa else tonart_quelle(abg.camelot, d.rekordbox.tonart if d.rekordbox else none, gem) -%} {%- set wahl = tq[0] if tq[1] in ('tags', 'rekordbox') else none %} {#- Tonart-Schreibweise (07.11.2026): der große Wert ist antippbar und klappt „Schreibweise: [7A] [12m] [Dm]“ auf (static/tonart.js) #}
{% if wahl %}{{ wq(tq[1], 'tonart', t.wertquelle) }} {{ b.kz.tonart_tags if tq[1] == 'tags' else b.kz.tonart }} {%- if gem %}{{ wq('gemessen', 'tonart', t.wertquelle) }} {{ gem | tonart }}{% if tq[1] == 'rekordbox' and gem != wahl %} {{ b.kz.urteil.anders }}{% endif %}{% if sicher is not none %}{{ b.kz.sicherheit }} {{ dez(sicher, 2) }}{% endif %}{% endif %} {%- elif gem %}{{ wq('gemessen', 'tonart', t.wertquelle) }} {{ b.kz.tonart_gemessen }}{% if sicher is not none %}{{ b.kz.sicherheit }} {{ dez(sicher, 2) }}{% endif %} {%- else %}–{{ b.kz.tonart }}{% endif %} {#- Doppel-Tonart aus den Tags („9A/8A“, Mixed In Key, 07.11.2026): die erste gilt, die zweite steht als Uneinigkeit daneben -#} {%- set tdm = d.tags_datei if d.tags_datei is mapping else none %} {%- set zweit = tdm.tonart2 if (tdm and wahl and tq[1] == 'tags' and tdm.tonart == wahl) else (d.rekordbox.tonart2 if (d.rekordbox and wahl and tq[1] == 'rekordbox') else none) %} {%- if zweit %}{{ b.kz.mik.zweite | replace('{k}', zweit | tonart) }}{% endif %} {#- Rekordbox UND Tags (07.11.2026): widersprechen sich die Quellen, bleiben beide sichtbar – nichts wird still überschrieben; nur mit erkannter Quelle (ohne Rekordbox-Import oder ohne Tag-Tonart steht hier nichts) -#} {%- set rb_ton = d.rekordbox.tonart if d.rekordbox else none %} {%- set tag_ton = tdm.tonart if tdm else none %} {%- set andere = rb_ton if (tq[1] == 'tags' and rb_ton and rb_ton != wahl) else (tag_ton if (tq[1] == 'rekordbox' and tag_ton and tag_ton != wahl) else none) %} {%- if andere %}{{ (b.kz.mik.laut_rb if tq[1] == 'tags' else b.kz.mik.laut_tags) | replace('{k}', andere | tonart) }}{% endif %}
{% if e_stufe is not none %}{{ abg.energiestufe | energie_plus }}{{ punkt('abgeleitet') }} {{ b.kz.energie }}{{ energie_felder(abg.energiestufe, t) }} {%- else %}–{{ b.kz.energie }}{% endif %} {#- Energie 1–10 von Mixed In Key aus den Tags (07.11.2026): eigener Herkunftswert, nie als o/+/++/+++ -#} {%- if tdm and tdm.energie %}{{ b.kz.mik.energie | replace('{n}', tdm.energie | string) }}{% endif %}
{% if sek is not none %}{{ '%d:%02d' | format(sek // 60, sek % 60) }}{% else %}–{% endif %}{{ b.kz.laenge }}
{# Hüllen für titelblatt.js (data-ub: die Stellen, die TimbreTitelblatt.ueberblick füllt – dieselbe Funktion wie im Fly-in der Bibliothek). Ohne JavaScript (oder wenn das Skript scheitert) bleiben sie unsichtbar; dann stehen darunter die Rohwerte. #} {# Rückfall: sichtbar, bis titelblatt.js die Diagramme gezeichnet hat. #}
{% set quelle = {'signal': 'gemessen', 'abgeleitet': 'abgeleitet', 'semantik': 'modell', 'dj': 'modell', 'genre': 'modell'} %}
{% for art, werte in m.items() if art != 'kurve' %} {# Genre: ganze Prozent aus kompakt.genre_prozente (genre_prozent, von der Route gerechnet) – dieselbe Rechnung wie in Liste, Mischbalken und Export. Ein Genre mit Wert, das dort fehlt, liegt unter einem halben Prozent. #}

{{ art }}

{% for k, v in werte.items() if not (art == 'signal' and k in ('camelot_gemessen_sicherheit', 'camelot_gemessen_version')) %}{% set e_roh = art == 'abgeleitet' and k == 'energiestufe' %}{% set name = t.energie if e_roh else (t.merkmal_namen[art ~ '|' ~ k] or k) %}
{% if art in quelle %}{{ punkt(quelle[art]) }} {% endif %}{{ name }}
{%- set cam_stil = v | camelot_stil if (art == 'abgeleitet' and k == 'camelot') or (art == 'signal' and k == 'camelot_gemessen') else '' %}
{% if cam_stil %}{{ v | tonart }}{% elif v is none %}–{% elif e_roh %}{{ energie_felder(v, t) or '–' }}{% elif art == 'genre' and v is number and v > 0 and genre_prozent %}{% set proz = genre_prozent[k] | default(0) %}{{ '< 1' if proz == 0 else proz }} %{% else %}{{ v }}{% endif %}{% if art == 'signal' and k == 'camelot_gemessen' and werte.camelot_gemessen_sicherheit is number %} {{ t.sicherheit }} {{ dez(werte.camelot_gemessen_sicherheit, 2) }}{% endif %}
{% endfor %}
{% else %}

{{ b.keine_rohwerte }}

{% endfor %} {% if m %}

{% for art in ('gemessen', 'abgeleitet', 'modell') %}{{ t.herkunft[art][0] }}: {{ t.herkunft[art][1] }}{% endfor %}

{% endif %}
{# Rekordbox-Import (23.10.2026): Cue-Streifen, Knopfreihe und Werte aus Rekordbox – nur, wenn es welche gibt. Cues im Konto (24.10.2026): Mit den Tabellen (d.cues nicht null) übernimmt cues.js Streifen und Knopfreihe, rekordbox_seite.js zeigt dann nur die persönlichen Werte. rekordbox.js liefert beiden die Rechnung (Fahnen, Pad-Buchstaben). #} {% if d.rekordbox %}{% endif %} {% if d.cues is not none %}{% endif %} {% if d.rekordbox or d.cues is not none %}{% endif %} {% if d.rekordbox %}{% endif %} {% if d.cues is not none %}{% endif %} {% endblock %}