diff --git a/tools/tfmx_player/render_tfmx.c b/tools/tfmx_player/render_tfmx.c index 350faf8..f12cbeb 100644 --- a/tools/tfmx_player/render_tfmx.c +++ b/tools/tfmx_player/render_tfmx.c @@ -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./smpl. // 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 #include #include @@ -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 [max_seconds]\n", argv[0]); + fprintf(stderr, "usage: %s [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]");