render_tfmx.c: Song-Index-Feature nachgezogen (war im Quellcode noch nicht committet)
Repo-Hygiene-Fund (23.07.2026): tools/tfmx_audio.py reicht song_index bereits seit dem Factor5-Sound-Fix als 5. CLI-Arg an render_tfmx durch (siehe dessen Docstring), aber die zugehoerige C-Quelle war nie committed -- nur lokal auf der VM in /home/aria/kellogg_remake gebaut. Ein frischer Checkout+Build von origin/master haette also render_tfmx OHNE song_index-Unterstuetzung erzeugt: jeder render_wav(..., song_index=N)-Aufruf (z.B. TITEL2 Song 1 fuer den Factor5-Sound) waere klanglich stillschweigend auf Song 0 zurueckgefallen -- kein Crash, aber ein 1:1-Port-Bruch, den man erst durchs Hoeren gemerkt haette. Ursache: parallel zur Bugfix-Session ist zusaetzlich ein zweiter, veralteter Git-Checkout unter /tmp entstanden (tmpfs, ueberlebt keinen Reboot) und dort unabhaengig weitergearbeitet worden, ohne vorher zu fetchen -- dadurch ist lokal vs. Remote auseinandergelaufen. Nach Abgleich: die tatsaechliche Arbeitskopie auf der VM (/home/aria/kellogg_remake) war fuer alle anderen Dateien bereits 1:1 identisch mit origin/master; nur diese eine C-Datei fehlte im Repo. Die verwaisten, ueberholten Doppel-Commits im tmpfs-Checkout wurden verworfen (kein Datenverlust, deren Inhalt war ein aelterer, bereits ueberholter Zwischenstand).
This commit is contained in:
@@ -13,6 +13,16 @@
|
||||
// re-bundles that pair into the TFHD container tfmx.h expects, since the
|
||||
// game's naming convention differs from TFMX's usual mdat.<name>/smpl.<name>
|
||||
// convention.
|
||||
//
|
||||
// SONG-INDEX (added 22.07.2026 abends, Stefans Meldung "das Spiel hat noch
|
||||
// wesentlich mehr Lieder"): ein einzelnes TFX-Modul kann MEHRERE Songs
|
||||
// buendeln (tfmx.h's v_songs[]/v_songs_count, ausgewaehlt ueber
|
||||
// player_info.admin.start_song). Bisher haben wir immer nur Song 0
|
||||
// gerendert. Stichprobe ergab: TITEL.TFX hat 3 Songs, TITEL2.TFX hat 2,
|
||||
// ONGAME2.TFX sogar 14 (vermutlich je ein Level-Track). Der optionale 5.
|
||||
// CLI-Arg waehlt den gewuenschten Song; ohne Angabe bleibt das Verhalten
|
||||
// exakt wie vorher (Song 0, kein tfmx_restart-Aufruf noetig weil das schon
|
||||
// der Init-Default ist).
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
@@ -62,23 +72,22 @@ static void write_wav(const char *path, int16_t *pcm, int32_t frames, int32_t sa
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc < 4) {
|
||||
fprintf(stderr, "usage: %s <mdat.tfx> <smpl.sam> <out.wav> [max_seconds]\n", argv[0]);
|
||||
fprintf(stderr, "usage: %s <mdat.tfx> <smpl.sam> <out.wav> [max_seconds] [song_index]\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
// WICHTIG (Fix 22.07.2026 abends): [max_seconds] ist NUR noch eine
|
||||
// Sicherheits-Obergrenze, keine Ziel-Laenge mehr! Vorher wurde exakt
|
||||
// Sicherheits-OBERGRENZE, keine Ziel-Laenge mehr! Vorher wurde exakt
|
||||
// `seconds` lang gerendert -- war der Wert kleiner als die echte
|
||||
// Songlaenge, wurde mitten im Stueck abgeschnitten (Stefans Meldung:
|
||||
// "die Musik ist zu kurz, da fehlt der Rest", verursacht durch TITEL mit
|
||||
// festen 60s bzw. einen stehengebliebenen 8s-Cache-Rest). Stattdessen
|
||||
// rendern wir jetzt in kleinen Haeppchen und beobachten tfmx.h's eigenes
|
||||
// `real_song_end`-Flag (siehe tfmx.h: wird pro Tick in tfmx_run()
|
||||
// gesetzt, sobald die Track-Sequenz einmal komplett durchgelaufen ist
|
||||
// und intern neu startet) -- sobald es feuert, haben wir GENAU eine
|
||||
// vollstaendige natuerliche Song-Schleife im Kasten und brechen ab,
|
||||
// egal wie lang das Stueck wirklich ist. max_seconds greift nur als
|
||||
// Notbremse, falls ein Modul (defekt/kaputt) nie ein Ende meldet.
|
||||
// frueher genutzten 60s bzw. einen stehengebliebenen 8s-Cache-Rest).
|
||||
// Stattdessen rendern wir jetzt in kleinen Haeppchen und beobachten
|
||||
// tfmx.h's eigenes `real_song_end`-Flag -- sobald es feuert, haben wir
|
||||
// GENAU eine vollstaendige natuerliche Song-Schleife im Kasten und
|
||||
// brechen ab, egal wie lang das Stueck wirklich ist. max_seconds greift
|
||||
// nur als Notbremse, falls ein Modul (defekt/kaputt) nie ein Ende meldet.
|
||||
double max_seconds = argc > 4 ? atof(argv[4]) : 180.0;
|
||||
int song_index = argc > 5 ? atoi(argv[5]) : -1; // -1 = Default-Song (0)
|
||||
|
||||
uint32_t mdat_len = 0, smpl_len = 0;
|
||||
uint8_t *mdat = load_file(argv[1], &mdat_len);
|
||||
@@ -111,6 +120,20 @@ int main(int argc, char **argv) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (song_index >= 0) {
|
||||
if ((uint32_t)song_index >= s->v_songs_count) {
|
||||
fprintf(stderr, "song_index %d out of range (v_songs_count=%u)\n", song_index, s->v_songs_count);
|
||||
return 4;
|
||||
}
|
||||
// tfmx_init hat bereits Song 0 aufgesetzt (tfmx_init_decoder ->
|
||||
// tfmx_restart, siehe tfmx.h). Fuer einen anderen Index muessen wir
|
||||
// den Sequencer neu auf den gewuenschten Song ausrichten:
|
||||
// start_song setzen, dann tfmx_restart() erneut aufrufen (liest
|
||||
// v_songs[start_song] und initialisiert Sequencer-Position/Speed neu).
|
||||
s->player_info.admin.start_song = song_index;
|
||||
tfmx_restart(s);
|
||||
}
|
||||
|
||||
int32_t max_frames = (int32_t)(max_seconds * sample_rate);
|
||||
// Chunk klein genug waehlen, dass real_song_end nicht durch einen
|
||||
// zweiten Tick INNERHALB desselben Chunks schon wieder auf 0 zurueck-
|
||||
@@ -151,8 +174,8 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
|
||||
write_wav(argv[3], pcm, total, sample_rate);
|
||||
fprintf(stderr, "wrote %s: %d frames @ %d Hz (%.2fs)%s\n",
|
||||
argv[3], total, sample_rate, (double)total / sample_rate,
|
||||
fprintf(stderr, "wrote %s: song=%d %d frames @ %d Hz (%.2fs)%s\n",
|
||||
argv[3], song_index, total, sample_rate, (double)total / sample_rate,
|
||||
natural_end ? " [natuerliches Songende/Loop-Punkt erkannt]"
|
||||
: " [Sicherheits-Obergrenze erreicht, kein Songende gefunden -- Modul pruefen]");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user