Factor5-Sound vollstaendig: Ausklang-Tail im TFMX-Renderer (loop_mode-Stopp + Fade)

Stefans Meldung "Factor5-Zeit zu kurz, Soundfile nicht ganz abgespielt" -- die
Ursache lag im Renderer: real_song_end markiert nur das Ende der TRACK-SEQUENZ
(2.4s), die dann noch klingenden Samples wurden hart abgeschnitten.

- render_tfmx.c: neues optionales 6. CLI-Arg tail_max_seconds. Im Tail-Modus
  wird loop_mode=0 gesetzt -- tfmx.h laesst den Sequencer bei song_end dann
  STEHEN (kein Restart, keine neuen Noten), waehrend die Paula-Voices weiter
  ausklingen. (Erster Versuch ohne loop_mode-Stopp nahm stattdessen die
  naechste Loop-Iteration auf -- per RMS-Selbstaehnlichkeit nachgewiesen.)
  Tail endet bei ~300ms Stille oder tail-Limit; bei Limit-Ende (loopende
  Samples ohne natuerliches Ende) wird ein 600ms-Fade-out angewendet.
- Factor5 ("Brausen") loopt auf Paula-Ebene endlos -> Tail 2.6s => Gesamt
  exakt 5.0s (DOSBox-Messung ~4.8s Screendauer, Stefans "ca. 5 Sekunden"),
  sauber ausgeblendet. Rauser-Sting endet natuerlich bei 2.34s.
- audio.py: tail_seconds-Parameter, Cache-Suffix _tail (alte abgeschnittene
  Caches greifen nicht mehr). intro.py: Jingles mit Tail, Titelmusik bewusst
  ohne (exakter Loop-Punkt-Schnitt fuers nahtlose pygame-Loopen).

Screen haelt weiterhin exakt Songlaenge (jetzt 5.0s), verifiziert: WAV klingt
aus (RMS 2065->261), --once headless exit 0.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
duffyduck
2026-07-24 22:22:31 +02:00
co-authored by Claude Fable 5
parent ccad606a43
commit 949a7eeda2
3 changed files with 114 additions and 19 deletions
+18 -7
View File
@@ -453,7 +453,7 @@ def wait_for_key(clock, draw_fn, fps=30):
clock.tick(fps)
def render_audio_with_loading(clock, container, name, song_index, label):
def render_audio_with_loading(clock, container, name, song_index, label, tail_seconds=None):
'''Rendert einen TFMX-Song per tfmx_audio.render_wav in einem Hintergrund-
Thread, waehrend der Hauptthread weiter Events pumpt und einen simplen
Ladebildschirm zeichnet.
@@ -485,7 +485,8 @@ def render_audio_with_loading(clock, container, name, song_index, label):
def worker():
try:
result['path'] = tfmx_audio.render_wav(container, name, song_index=song_index)
result['path'] = tfmx_audio.render_wav(container, name, song_index=song_index,
tail_seconds=tail_seconds)
except Exception as exc:
result['error'] = exc
@@ -536,15 +537,25 @@ def preload_all_audio(clock, assets):
verfuegbar ist (dann bliebe es sowieso stumm, siehe main()).'''
if not pygame.mixer.get_init():
return {}, False
# Die beiden kurzen Jingles bekommen einen Ausklang-Tail (siehe
# render_wav-Docstring: real_song_end schneidet sonst die noch klingenden
# Samples ab -- Stefans "Factor5-Soundfile ist noch nicht ganz abgespielt").
# Die geloopte Titelmusik bewusst OHNE Tail (exakter Loop-Punkt-Schnitt).
# Factor5-Tail = 2.6s -> Gesamt ~5.0s: das Brausen-Sample loopt endlos
# (kein natuerliches Ende), im Original zeigt die Engine den Screen ~5s
# (DOSBox-Messung ~4.8s; Stefans Erinnerung "ca. 5 Sekunden") und stoppt
# den Sound beim Wechsel. render_tfmx blendet das Ende sauber aus (600ms
# Fade), scene_factor5 haelt den Screen genau Songlaenge.
jobs = [
(('TITEL2', 0), 'Rauser-Sound'),
(('TITEL2', 1), 'Factor5-Sound'),
(('TITEL', None), 'Titelmusik'),
(('TITEL2', 0), 'Rauser-Sound', 5.0),
(('TITEL2', 1), 'Factor5-Sound', 2.6),
(('TITEL', None), 'Titelmusik', None),
]
audio_paths = {}
for key, label in jobs:
for key, label, tail in jobs:
name, song_index = key
path, quit_requested = render_audio_with_loading(clock, assets.container, name, song_index, label)
path, quit_requested = render_audio_with_loading(clock, assets.container, name, song_index,
label, tail_seconds=tail)
audio_paths[key] = path
if quit_requested:
return audio_paths, True