diff --git a/src/p_setup.c b/src/p_setup.c index 40a68144a..8da76e19e 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -8564,6 +8564,9 @@ boolean P_MultiSetupWadFiles(boolean fullsetup) if (partadd_stage < 0) { + // possible future work: only do this if musicdefs/map headers changed + S_PopulateSoundTestSequence(); + partadd_important = false; partadd_earliestfile = UINT16_MAX; return true; diff --git a/src/s_sound.c b/src/s_sound.c index fa6bf53be..8792f25a4 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -1362,37 +1362,164 @@ musicdef_t *musicdefstart = NULL; struct cursongcredit cursongcredit; // Currently displayed song credit info struct soundtest soundtest; // Sound Test (sound test) +static void S_InsertMapIntoSoundTestSequence(UINT16 map, musicdef_t ***tail) +{ + UINT8 i, j; + (void)tail; + + for (i = 0; i < mapheaderinfo[map]->musname_size; i++) + { + musicdef_t *def = S_FindMusicDef(mapheaderinfo[map]->musname[i], &j); + + if (def == NULL) + continue; + + if (def->sequence.id == soundtest.sequence.id) + continue; + + def->sequence.id = soundtest.sequence.id; + def->sequence.map = map; + + // So what we're doing here is to avoid iterating + // for every insertion, we dereference the pointer + // to get **tail from S_PopulateSoundTestSequence, + // then dereference that to get the musicdef_t *. + // We do it this way so that soundtest.sequence.next + // can be handled natively without special cases. + // I have officially lost my MIND. ~toast 270323 + *(*tail) = def; + *tail = &def->sequence.next; + } +} + +void S_PopulateSoundTestSequence(void) +{ + UINT16 i; + musicdef_t **tail; + + // First, increment the sequence and wipe the HEAD. + // This invalidates all existing musicdefs without us + // having to iterate through everything all the time, + // and offers a very convenient checking mechanism. + // ...preventing id 0 protects against inconsistencies + // caused by newly Calloc'd music definitions. + soundtest.sequence.id = (soundtest.sequence.id + 1) & 255; + if (soundtest.sequence.id == 0) + soundtest.sequence.id = 1; + + soundtest.sequence.next = NULL; + + tail = &soundtest.sequence.next; + + // We iterate over all cups. + { + cupheader_t *cup; + for (cup = kartcupheaders; cup; cup = cup->next) + { + for (i = 0; i < CUPCACHE_MAX; i++) + { + if (cup->cachedlevels[i] >= nummapheaders) + continue; + + if (!mapheaderinfo[cup->cachedlevels[i]]) + continue; + + if (mapheaderinfo[cup->cachedlevels[i]]->cup != cup) + continue; + + S_InsertMapIntoSoundTestSequence(cup->cachedlevels[i], &tail); + } + } + } + + // Then, we iterate over all non-cupped maps. + for (i = 0; i < nummapheaders; i++) + { + if (!mapheaderinfo[i]) + continue; + + if (mapheaderinfo[i]->cup != NULL) + continue; + + S_InsertMapIntoSoundTestSequence(i, &tail); + } + + // Finally, we insert all other musicdefstart at the head. + // It's being added to the sequence in reverse order... + // but because musicdefstart is ALSO populated in reverse, + // the reverse of the reverse is the right way around! + { + musicdef_t *def; + + for (def = musicdefstart; def; def = def->next) + { + if (def->sequence.id == soundtest.sequence.id) + continue; + + def->sequence.id = soundtest.sequence.id; + def->sequence.map = NEXTMAP_INVALID; + + def->sequence.next = soundtest.sequence.next; + soundtest.sequence.next = def; + } + } +} + +static boolean S_SoundTestDefLocked(musicdef_t *def) +{ + // temporary - i'd like to find a way to conditionally hide + // specific musicdefs that don't have any map associated. + if (def->sequence.map >= nummapheaders) + return false; + + return M_MapLocked(def->sequence.map+1); +} + void S_UpdateSoundTestDef(boolean reverse, boolean skipnull) { musicdef_t *newdef; // Naive implementation for now. - newdef = (soundtest.current != NULL - && (skipnull == false || soundtest.current->next != NULL)) - ? soundtest.current->next - : musicdefstart; + newdef = NULL; if (reverse == false) { - // Due to how musicdefs are populated, we have to traverse backwards when attempting forwards. - musicdef_t *def; - - if (soundtest.current == musicdefstart) + newdef = (soundtest.current != NULL) + ? soundtest.current->sequence.next + : soundtest.sequence.next; + while (newdef != NULL && S_SoundTestDefLocked(newdef)) + newdef = newdef->sequence.next; + if (newdef == NULL && skipnull == false) { - newdef = NULL; - if (skipnull == false) - { - goto conclusion; - } + newdef = soundtest.sequence.next; + while (newdef != NULL && S_SoundTestDefLocked(newdef)) + newdef = newdef->sequence.next; + } + } + else + { + musicdef_t *def, *lastdef = NULL; + + if (soundtest.current == soundtest.sequence.next + && skipnull == false) + { + goto conclusion; } - for (def = musicdefstart; def; def = def->next) + for (def = soundtest.sequence.next; def; def = def->sequence.next) { - if (def->next != soundtest.current) - continue; + if (!S_SoundTestDefLocked(def)) + { + lastdef = def; + } - newdef = def; + if (def->sequence.next != soundtest.current) + { + continue; + } + + newdef = lastdef; break; } } @@ -1736,6 +1863,7 @@ void S_InitMusicDefs(void) UINT16 i; for (i = 0; i < numwadfiles; i++) S_LoadMusicDefs(i); + S_PopulateSoundTestSequence(); } // diff --git a/src/s_sound.h b/src/s_sound.h index 3936e83ae..b8a20ced3 100644 --- a/src/s_sound.h +++ b/src/s_sound.h @@ -176,6 +176,13 @@ boolean S_SpeedMusic(float speed); #define MAXDEFTRACKS 3 +struct soundtestsequence_t +{ + UINT8 id; + UINT16 map; + musicdef_t *next; +}; + // Music credits struct musicdef_t { @@ -188,6 +195,7 @@ struct musicdef_t char *composers; int volume; musicdef_t *next; + soundtestsequence_t sequence; }; extern struct cursongcredit @@ -202,12 +210,14 @@ extern struct cursongcredit extern struct soundtest { - boolean playing; // Music is playing? - boolean privilegedrequest; // Overrides S_PlaysimMusicDisabled w/o changing every function signature - musicdef_t *current; // Current selected music definition - SINT8 currenttrack; // Current selected music track for definition + boolean playing; // Music is playing? + boolean privilegedrequest; // Overrides S_PlaysimMusicDisabled w/o changing every function signature + musicdef_t *current; // Current selected music definition + SINT8 currenttrack; // Current selected music track for definition + soundtestsequence_t sequence; // Sequence head } soundtest; +void S_PopulateSoundTestSequence(void); void S_UpdateSoundTestDef(boolean reverse, boolean skipnull); void S_SoundTestPlay(void); void S_SoundTestStop(boolean pause); diff --git a/src/typedef.h b/src/typedef.h index 0615e7034..04298277c 100644 --- a/src/typedef.h +++ b/src/typedef.h @@ -388,6 +388,7 @@ TYPEDEF (listener_t); TYPEDEF (channel_t); TYPEDEF (caption_t); TYPEDEF (musicdef_t); +TYPEDEF (soundtestsequence_t); TYPEDEF (musicstack_t); // screen.h