View Issue Details

IDProjectCategoryView StatusLast Update
0006647The Dark ModSoundpublic13.12.2025 23:45
ReporterAmadeus Assigned Tostgatilov  
PrioritynormalSeveritynormalReproducibilityalways
Status resolvedResolutionfixed 
Product VersionTDM 2.13 
Target VersionTDM 2.14Fixed in VersionTDM 2.14 
Summary0006647: In-game main menu music doesn't loop when "leadin" value is applied to custom soundshader.
DescriptionIf a custom sound shader using a "leadin" sound file is used for the main menu, then the game ignores the "loop" sound file once it is supposed to play.

This works perfectly only when first starting up The Dark Mod game itself. However, when in-game and after quitting the mission to return to the main menu again, the game only plays the 'leadin" sound, ignoring the loop sound entirely. This causes a very abrupt stop in the soundshader being played, and there is only silence afterward.

In short, the soundshader works correctly when:

- The game is first loaded and when viewing the text briefing

It does not work when:
- escaping from in-game to the main menu
- after quitting the mission and returning to the main menu
Additional InformationThis bug seems like it might be related to FrostSalamander's bug report: 0006532
Tagssound

Relationships

has duplicate 0006532 closedstgatilov Custom main menu music doesn't always play if sound shader has 'leadin' property 

Activities

stgatilov

stgatilov

13.12.2025 18:41

administrator   ~0017089

Interestingly, I also see this warning spammed nonstop after the sound ends:
  Called idSampleDecoderLocal::DecodeOGG() on idSoundSample '%s' without nonCacheData
stgatilov

stgatilov

13.12.2025 18:44

administrator   ~0017090

There is also explanation BTW:

            // assert( false ); // this should never happen
            
            /* DG: turned this assertion into a warning, because this can happen, at least with
             * the Classic Doom3 mod (when starting a new game). There idSoundCache::EndLevelLoad()
             * purges (with idSoundSample::PurgeSoundSample()) sound/music/cdoomtheme.ogg
             * (the music running in the main menu), which free()s nonCacheData.
             * But afterwards (still during loading) idSoundSystemLocal::currentSoundWorld
             * is set back to menuSoundWorld, which still tries to play that sample,
             * which brings us here. Shortly afterwards the sound world is set to
             * the game soundworld (sw) and that sample is not referenced anymore
             * (until opening the menu again, when that sample is apparently properly reloaded)
             * see also https://github.com/dhewm/dhewm3/issues/461 */
stgatilov

stgatilov

13.12.2025 18:52

administrator   ~0017091

I think this is a consequence of the typical Doom 3 level load logic.

During level load, we preload all assets (sounds / images / etc.) which are referenced in map and decl files.
We also mark them as "levelLoadReferenced = true".
When level load ends, we go through all loaded assets, and purge the ones which are not "levelLoadReferenced".
Because they are supposed to be leftovers from the previous map/mission.

So I guess the problem here is that main menu sound is not used/referenced anywhere in the map/decl, hence it is unloaded too...
stgatilov

stgatilov

13.12.2025 19:33

administrator   ~0017092

The question however is: why leadin sound plays?
It is also not referenced in the mission (in fact, both leadin and looping sounds are referenced only by the same sound shader).

The answer is that it gets reloaded here:
  idSoundWorldLocal::PlayShaderDirectly
  idSoundEmitterLocal::StartSound

    // if the sample is onDemand (voice mails, etc), load it now
    if ( chan->leadinSample->purged ) {
        int start = Sys_Milliseconds();
        chan->leadinSample->Load();
        int end = Sys_Milliseconds();
        session->TimeHitch( end - start );
        // recalculate start44kHz, because loading may have taken a fair amount of time
        if ( !soundWorld->fpa[0] ) {
            start44kHz = soundSystemLocal.GetCurrent44kHzTime() + MIXBUFFER_SAMPLES;
        }
    }
stgatilov

stgatilov

13.12.2025 19:43

administrator   ~0017093

As far as I understand, this bug should apply to all sounds which:
  1) are not referenced in the map/level AND
  2) are played dynamically via "music" or "play" or "localSound" in GUI, or "startMusic" script event, or "testSound" console command

Recall that sound loading consists of two parts:
  1) loading data from the file/disk (into nonCacheData)
  2) decompressing OGG format
It seems that p.1 is done during level load and when PlayShaderDirectly is called (by only for leadin).
On the other hand, p.2 is done on async/sound thread, which is called "realtime decoding".

The problem right now is that looping sounds are not loaded from disk (p.1).
I can either add their loading inside PlayShaderDirectly, increasing potential latency for looping sounds when they are first played.
Or I can try to load the looping files on async thread in idSoundChannel::GatherChannelSamples... which I don't like for a variety of reasons.
stgatilov

stgatilov

13.12.2025 23:44

administrator   ~0017094

Fixed this in svn rev 11032.

I decided to simple include the sound sample of loop body in the loading logic inside PlayShaderDirectly, so that it gets loaded along with leadin/first sample.
Works fine for me.

Note: as far as I see in the code, looping sounds are expected to have only one loop body sound.
The loading logic only loads the first sound sample from the list of alternatives.

Issue History

Date Modified Username Field Change
11.12.2025 19:55 Amadeus New Issue
11.12.2025 19:55 Amadeus Tag Attached: sound
11.12.2025 19:55 Amadeus Relationship added related to 0006532
13.12.2025 18:41 stgatilov Note Added: 0017089
13.12.2025 18:44 stgatilov Note Added: 0017090
13.12.2025 18:52 stgatilov Note Added: 0017091
13.12.2025 19:33 stgatilov Note Added: 0017092
13.12.2025 19:43 stgatilov Note Added: 0017093
13.12.2025 23:44 stgatilov Note Added: 0017094
13.12.2025 23:45 stgatilov Assigned To => stgatilov
13.12.2025 23:45 stgatilov Status new => resolved
13.12.2025 23:45 stgatilov Resolution open => fixed
13.12.2025 23:45 stgatilov Fixed in Version => TDM 2.14
13.12.2025 23:45 stgatilov Relationship replaced has duplicate 0006532