Basic Music Randomizer

Post your example zscripts/ACS scripts/etc here.
Forum rules
The Projects forums are only for projects. If you are asking questions about a project, either find that project's thread, or start a thread in the General section instead.

Got a cool project idea but nothing else? Put it in the project ideas thread instead!

Projects for any Doom-based engine (especially 3DGE) are perfectly acceptable here too.

Please read the full rules for more details.
User avatar
Sir Robin
Posts: 400
Joined: Wed Dec 22, 2021 7:02 pm
Graphics Processor: Intel (Modern GZDoom)
Location: Medellin, Colombia

Basic Music Randomizer

Post by Sir Robin »

There are probably fancier music handler mods out there, but I threw this together to solve one issue - When I'm testing my levels I usually test them in Doom2 as MAP01, and I always hear the same song over and over again. So this code will change to a random level music every time a level is loaded.

It works by first generating a list of available music by iterating levelinfo nodes and then picking one at random.

Here's the code:

Code: Select all

class RandomMusicPlayer : eventhandler
{
    string MusicSelection;

    override void OnRegister()
    {
        ChangeMusicRandom();
    }

    void ChangeMusicRandom()
    {
        if (!MusicSelection) MusicSelection = GetRandomMusicLump();
        if (MusicSelection)
        {
            console.printf("RandomMusicPlayer: Playing music: "..MusicSelection);
            S_ChangeMusic(MusicSelection);
        }
        else
        {
            console.printf("RandomMusicPlayer: No valid music lumps found.");
        }
    }
    
    string GetRandomMusicLump()
    {
        array<string> MusicList;

        int LevelInfosCount=levelinfo.GetLevelInfoCount();
        for (int i = 0; i < LevelInfosCount; i++)
        {
            levelinfo li = levelinfo.GetLevelInfo(i);
            string musicLump=li.music;
            
            // because of a quirk in how Doom/2 music is handled
            if (musicLump.left(1) == "$") musicLump="D_"..stringtable.localize(musicLump);
            
            if (MusicLump && wads.findlump(MusicLump) >= 0)
            {
                //console.printf("Music for level "..li.levelnum..": "..li.music.." = "..MusicLump);//debug
                MusicList.push(musicLump);
            }
        }
        
        if (MusicList.size() > 0)
        {
            return MusicList[random(0,MusicList.size() - 1)];
        }
        else
        {
            return "";
        }
    }
}
 
Last edited by Sir Robin on Sat Jul 02, 2022 1:18 am, edited 1 time in total.
User avatar
Sir Robin
Posts: 400
Joined: Wed Dec 22, 2021 7:02 pm
Graphics Processor: Intel (Modern GZDoom)
Location: Medellin, Colombia

Re: Basic Music Randomizer

Post by Sir Robin »

WorldLoaded() is called only when a fresh map is loaded, not for example when a save game is loaded. Moved the music randomizer from WorldLoaded() on OnRegister() which is called every game start. Updated code in original post.
User avatar
Ozymandias81
Posts: 2052
Joined: Thu Jul 04, 2013 8:01 am
Graphics Processor: nVidia with Vulkan support
Location: Mount Olympus, Mars

Re: Basic Music Randomizer

Post by Ozymandias81 »

While I am not sure if the Wumpus mod has the music randomizer, but it happened a crash while changing the midi device from Fluidsynth to anything, using GZDoom 4.9pre 115. Typing this here in case if this is the "mod" that causes such issue or if it comes from GZDoom itself. Can confirm at least that it doesn't happen with Blade of Agony.

Here you are a screenshot using Developer 8 command (or was 7? Can't remember atm), also I will post here the report for devs in case.
CrashReport.zip
You do not have the required permissions to view the files attached to this post.
User avatar
Sir Robin
Posts: 400
Joined: Wed Dec 22, 2021 7:02 pm
Graphics Processor: Intel (Modern GZDoom)
Location: Medellin, Colombia

Re: Basic Music Randomizer

Post by Sir Robin »

Ozymandias81 wrote:While I am not sure if the Wumpus mod has the music randomizer, but it happened a crash while changing the midi device from Fluidsynth to anything, using GZDoom 4.9pre 115. Typing this here in case if this is the "mod" that causes such issue or if it comes from GZDoom itself. Can confirm at least that it doesn't happen with Blade of Agony.

Here you are a screenshot using Developer 8 command (or was 7? Can't remember atm), also I will post here the report for devs in case.
CrashReport.zip
I haven't tried that version but I don't think my mod could be doing anything like that. It doesn't even load until you load a level, and the screenshot shows you still at the titlescreen
thugsta
Posts: 140
Joined: Mon Jan 21, 2019 10:10 am

Re: Basic Music Randomizer

Post by thugsta »

So how do you go about writing the music lumps to read the music?
User avatar
Sir Robin
Posts: 400
Joined: Wed Dec 22, 2021 7:02 pm
Graphics Processor: Intel (Modern GZDoom)
Location: Medellin, Colombia

Re: Basic Music Randomizer

Post by Sir Robin »

thugsta wrote: Tue Sep 20, 2022 7:47 pm So how do you go about writing the music lumps to read the music?
It's really simple. If you look at the GetRandomMusicLump function, you see that it basically:
  1. Iterates the levelinfos
  2. Gets the specified music lump from each level
  3. Validates the lump (uses wads.findlump())
  4. Pushes the validated lump into a list
  5. At the end, picks a random entry from the validated list and returns it to the calling function
  6. The calling function plays it with a call to S_ChangeMusic
User avatar
wildweasel
Moderator Team Lead
Posts: 21510
Joined: Tue Jul 15, 2003 7:33 pm
Preferred Pronouns: He/Him
Operating System Version (Optional): Windows 10, 21H1
Graphics Processor: nVidia with Vulkan support

Re: Basic Music Randomizer

Post by wildweasel »

Ozymandias81 wrote: Tue Jul 19, 2022 8:51 am While I am not sure if the Wumpus mod has the music randomizer, but it happened a crash while changing the midi device from Fluidsynth to anything, using GZDoom 4.9pre 115. Typing this here in case if this is the "mod" that causes such issue or if it comes from GZDoom itself. Can confirm at least that it doesn't happen with Blade of Agony.
This seems like specifically a problem with your hardware config and GZDoom, and not the mod. The only reason it won't happen in Blade of Agony is because that is not playing any MIDI music and won't be trying to initialize a MIDI device while you're switching them. You should probably post a Bugs thread about it.
thugsta
Posts: 140
Joined: Mon Jan 21, 2019 10:10 am

Re: Basic Music Randomizer

Post by thugsta »

Sir Robin wrote: Fri Sep 23, 2022 4:35 pm
thugsta wrote: Tue Sep 20, 2022 7:47 pm So how do you go about writing the music lumps to read the music?
It's really simple. If you look at the GetRandomMusicLump function, you see that it basically:
  1. Iterates the levelinfos
  2. Gets the specified music lump from each level
  3. Validates the lump (uses wads.findlump())
  4. Pushes the validated lump into a list
  5. At the end, picks a random entry from the validated list and returns it to the calling function
  6. The calling function plays it with a call to S_ChangeMusic
Oh so it's only for midi's. My bad, i was trying to find to randomize ogg files
User avatar
Sir Robin
Posts: 400
Joined: Wed Dec 22, 2021 7:02 pm
Graphics Processor: Intel (Modern GZDoom)
Location: Medellin, Colombia

Re: Basic Music Randomizer

Post by Sir Robin »

thugsta wrote: Sun Sep 25, 2022 9:30 am Oh so it's only for midi's. My bad, i was trying to find to randomize ogg files
I wrote and tested it using the stock doom2.wad and Doom Metal vol5 which uses ogg files. The script picks a random lump from levelinfos and passes it to S_ChangeMusic, so whatever formats that function accepts will be played - including mid, ogg, mp3, etc. The script doesn't filter by type or even bother to look at the type.

If you can describe your setup and the issues you're getting, maybe we can help you figure out what you're doing wrong.
thugsta
Posts: 140
Joined: Mon Jan 21, 2019 10:10 am

Re: Basic Music Randomizer

Post by thugsta »

Sir Robin wrote: Mon Sep 26, 2022 8:00 am
thugsta wrote: Sun Sep 25, 2022 9:30 am Oh so it's only for midi's. My bad, i was trying to find to randomize ogg files
I wrote and tested it using the stock doom2.wad and Doom Metal vol5 which uses ogg files. The script picks a random lump from levelinfos and passes it to S_ChangeMusic, so whatever formats that function accepts will be played - including mid, ogg, mp3, etc. The script doesn't filter by type or even bother to look at the type.

If you can describe your setup and the issues you're getting, maybe we can help you figure out what you're doing wrong.
Basically to just grab a few ambient music replacers, gutting the acs randmus, have all the music in a single folder and have it then to be randomized between all soundtracks
User avatar
Sir Robin
Posts: 400
Joined: Wed Dec 22, 2021 7:02 pm
Graphics Processor: Intel (Modern GZDoom)
Location: Medellin, Colombia

Re: Basic Music Randomizer

Post by Sir Robin »

thugsta wrote: Wed Sep 28, 2022 8:10 pm Basically to just grab a few ambient music replacers, gutting the acs randmus, have all the music in a single folder and have it then to be randomized between all soundtracks
I haven't looked at any other mods so I don't know how they work. This one gets a list of music lumps from the levelinfo entries, then picks a random one from that list and plays it. So if the music mods are putting their music into the levelinfos then this script should pick it up. If they are doing something else, you'd have to add some logic to the script to pick up the lump list from where else they are putting it.
thugsta
Posts: 140
Joined: Mon Jan 21, 2019 10:10 am

Re: Basic Music Randomizer

Post by thugsta »

Sir Robin wrote: Mon Oct 03, 2022 3:47 pm
thugsta wrote: Wed Sep 28, 2022 8:10 pm Basically to just grab a few ambient music replacers, gutting the acs randmus, have all the music in a single folder and have it then to be randomized between all soundtracks
I haven't looked at any other mods so I don't know how they work. This one gets a list of music lumps from the levelinfo entries, then picks a random one from that list and plays it. So if the music mods are putting their music into the levelinfos then this script should pick it up. If they are doing something else, you'd have to add some logic to the script to pick up the lump list from where else they are putting it.
Well can you make a levelinfo with the default and DoomMetal Vol5 mixed in so i can see your example being used and i can hopefully take it from there.

Thanks for your help thus far, i appreciate it.
User avatar
Sir Robin
Posts: 400
Joined: Wed Dec 22, 2021 7:02 pm
Graphics Processor: Intel (Modern GZDoom)
Location: Medellin, Colombia

Re: Basic Music Randomizer

Post by Sir Robin »

thugsta wrote: Mon Oct 03, 2022 9:00 pm Well can you make a levelinfo with the default and DoomMetal Vol5 mixed in so i can see your example being used and i can hopefully take it from there.

Thanks for your help thus far, i appreciate it.
DoomMetal doesn't change levelinfos or anything else, it just provides lumps with the same names as the stock lumps to override them. If you want to know the stock names that get put into the levelinfos, look inside gzdoom.pk3, in the mapinfo folder. There is a text file there for each game, these are the MapInfo files. This is the data that gets pulled into the levelinfos in the game.

Look at for example Heretic and you'll see that the music lump is specified directly, like this:

Code: Select all

map E1M1 lookup "HHUSTR_E1M1"
{
	next = "E1M2"
	secretnext = "E1M9"
	sky1 = "SKY1"
	cluster = 1
	music = "MUS_E1M1"
}
So the music lump for E1M1 is MUS_E1M1

But Doom does it with a language lump lookup, the dollar sign signals this:

Code: Select all

map MAP01 lookup "HUSTR_1"
{
	titlepatch = "CWILV00"
	next = "MAP02"
	secretnext = "MAP02"
	sky1 = "SKY1"
	cluster = 5
	par = 30
	music = "$MUSIC_RUNNIN"
}
The music string is "$MUSIC_RUNNIN" but that's not the actual name of the music lump. The dollar sign means you have to look it up in the language file.
So look at Language.def file in the root of gzdoom.pk3 and find this line:

Code: Select all

MUSIC_RUNNIN = "runnin";
so the lookup for "$MUSIC_RUNNIN" is "runnin" but there is another quirk - when doom looks up a music lump it also inserts "d_" at the beginning of the name.
So the proper name for the lump of music in MAP01 is "d_runnin"

Look in the DoomMetal wad file and you see a lump named D_RUNNIN and it is an Ogg Vorbis file. This the is file that will be played when Doom2 Map01 is loaded.

If you look at my code:

Code: Select all

            levelinfo li = levelinfo.GetLevelInfo(i);
            string musicLump=li.music;
I get the music string from the level info from levelinfo.GetLevelInfo(i).music

Code: Select all

            // because of a quirk in how Doom/2 music is handled
            if (musicLump.left(1) == "$") musicLump="D_"..stringtable.localize(musicLump);
I check to see if it starts with a "$" and if so I look it up with the stringtable.localize() function and prepend it with a "D_"

Code: Select all

            if (MusicLump && wads.findlump(MusicLump) >= 0)
            {
                //console.printf("Music for level "..li.levelnum..": "..li.music.." = "..MusicLump);//debug
                MusicList.push(musicLump);
            }
I now have the complete lump name and check to see if a lump with that name exists using the wads.FindLump() function and push it to the MusicList

At the end of all that MusicList should have a list of all valid music lumps from the level info data.

Return to “Script Library”