Music Switching

JeanSwamp

Member
Hello,

I'm playing around with music switch between rooms, like from Title Screen to starting off the game, switching to rooms, death room, loading room, and so on.

How do you guys handle all this switches and decide which music to play at a given time? Do you hard code all of this?

Thank you
 

NightFrost

Member
I have an obj_audio that has two chief functions. One is volume control, the other is a state machine for music. States are start, fadein, play, fadeout, silence. Both start and fadein kick off the music play, start just does it at full volume. Play and silence are both just idle states with no code, I separated them so it is clearer for me what is happening. I could have used a single idle state just as well. Then there's a few scripts that activate state changes and supply relevant variables. Pretty much the only thing that currently calls for those is my room transition controller (sends the same fade time to music as it uses for transition fade scripts, so they are in sync).
 

Guitarmike

Member
My approach is similar to NightFrost's although mine is somewhat simpler. I create a persistent obj_music_controller object that includes variables for "current_song" and "volume." From there, depending on when you want the music to change, you can take a few different approaches. If it is just one room, one song, I would just create a ds_map that links rooms to sound resources. If you want more control, i.e. switching songs in the middle of a room, you might want to go with some kind of event system or script that "changes the record" when needed.
 

JeanSwamp

Member
My approach is similar to NightFrost's although mine is somewhat simpler. I create a persistent obj_music_controller object that includes variables for "current_song" and "volume." From there, depending on when you want the music to change, you can take a few different approaches. If it is just one room, one song, I would just create a ds_map that links rooms to sound resources. If you want more control, i.e. switching songs in the middle of a room, you might want to go with some kind of event system or script that "changes the record" when needed.
I'm already doing the variables you mention. Now I really need some good way to handle the switching, fade ins/outs and so on

Hopefully @NightFrost can share a bit more!
 
Last edited:

NightFrost

Member
Well, it is not a complex system since it just switches music. All of the relevant code in obj_audio would be (this is obviously a persistent object):
Code:
// CREATE
enum State_Music {
   Fadein,
   Start,
   Playing,
   Fadeout,
   Silence
}
State = State_Music.Silence;
Music_Current = -1;
Music_Fade_Time = 0;

// STEP
if(State == State_Music.Start){
   if(!audio_is_playing(Music_Current)){
       audio_play_sound(Music_Current, 0, true);
       audio_sound_gain(Music_Current, global.Volume_Music, 0);
   }
   State = State_Music.Playing;
}

else if(State == State_Music.Fadein){
   if(!audio_is_playing(Music_Current)){
       audio_play_sound(Music_Current, 0, true);
       audio_sound_gain(Music_Current, 0, 0);
       audio_sound_gain(Music_Current, global.Volume_Music, Music_Fade_Time);
   }
   State = State_Music.Playing;
}

else if(State == State_Music.Playing){
   // Do nothing for now.
}

else if(State == State_Music.Fadeout){
   if(audio_is_playing(Music_Current)){
       audio_sound_gain(Music_Current, 0, Music_Fade_Time);
   }
   State = State_Music.Silence;
}

else if(State == State_Music.Silence){
   // Do nothing for now. 
}
And the relevant scripts:
Code:
/// @function scr_music_start(music);
/// @description Starts music at full volume.
/// @param music The music to start.
obj_audio.State = State_Music.Start;
obj_audio.Music_Current = argument[0];

/// @function scr_music_fadein(music, speed)
/// @description Fades in given music.
/// @param music The music to fade in.
/// @param speed Fade speed.
obj_audio.State = State_Music.Fadein;
obj_audio.Music_Current = argument[0];
// Speeds coming from room transitioner are in steps, convert to milliseconds.
obj_audio.Music_Fade_Time = argument[1] / 60 * 1000;

/// @function scr_music_fadeout(speed)
/// @description Fade out currently playing music.
/// @param speed Fade speed.
obj_audio.State = State_Music.Fadeout;
// Speeds coming from room transitioner are in steps, convert to milliseconds.
obj_audio.Music_Fade_Time = argument[0] / 60 * 1000;
I could also do all that with just scripts, without the state state machine, but I felt that 1) it is good to be able to recall the state if it becomes necessary and 2) if / when I expand the system, it may be advantageous to be able to run code only in certain states. I'd need to fix the fade states before that though, as you can see the machine spends just a single step in them. I should make it stay in the state until volume fade is finished. That could be accomplished just by using a countdown variable, so the state wouldn't set the sound gain repeatedly.
 

Yal

šŸ§ *penguin noises*
GMC Elder
I do this in every game I make:
Code:
///bgm(sfx)
if(global.current_bgm <> NONE){
    if(audio_is_playing(global.current_bgm)){
        if(global.current_bgm == argument0){
            exit
        }
        audio_stop_sound(global.current_bgm)
    }
}
global.current_bgm = argument0
if(argument0 <> NONE){
    audio_play_sound(argument0,1000,true)
    audio_sound_gain(argument0,1,0)
}
You just init the current_bgm variable before you call bgm for the first time, and bam, done. bgm(NONE) turns the music off, and you won't restart the same song that's already playing. I usually stuff this script in the room creation code rather than having a music object.
 

JeanSwamp

Member
Well, it is not a complex system since it just switches music. All of the relevant code in obj_audio would be (this is obviously a persistent object):
Code:
// CREATE
enum State_Music {
   Fadein,
   Start,
   Playing,
   Fadeout,
   Silence
}
State = State_Music.Silence;
Music_Current = -1;
Music_Fade_Time = 0;

// STEP
if(State == State_Music.Start){
   if(!audio_is_playing(Music_Current)){
       audio_play_sound(Music_Current, 0, true);
       audio_sound_gain(Music_Current, global.Volume_Music, 0);
   }
   State = State_Music.Playing;
}

else if(State == State_Music.Fadein){
   if(!audio_is_playing(Music_Current)){
       audio_play_sound(Music_Current, 0, true);
       audio_sound_gain(Music_Current, 0, 0);
       audio_sound_gain(Music_Current, global.Volume_Music, Music_Fade_Time);
   }
   State = State_Music.Playing;
}

else if(State == State_Music.Playing){
   // Do nothing for now.
}

else if(State == State_Music.Fadeout){
   if(audio_is_playing(Music_Current)){
       audio_sound_gain(Music_Current, 0, Music_Fade_Time);
   }
   State = State_Music.Silence;
}

else if(State == State_Music.Silence){
   // Do nothing for now.
}
And the relevant scripts:
Code:
/// @function scr_music_start(music);
/// @description Starts music at full volume.
/// @param music The music to start.
obj_audio.State = State_Music.Start;
obj_audio.Music_Current = argument[0];

/// @function scr_music_fadein(music, speed)
/// @description Fades in given music.
/// @param music The music to fade in.
/// @param speed Fade speed.
obj_audio.State = State_Music.Fadein;
obj_audio.Music_Current = argument[0];
// Speeds coming from room transitioner are in steps, convert to milliseconds.
obj_audio.Music_Fade_Time = argument[1] / 60 * 1000;

/// @function scr_music_fadeout(speed)
/// @description Fade out currently playing music.
/// @param speed Fade speed.
obj_audio.State = State_Music.Fadeout;
// Speeds coming from room transitioner are in steps, convert to milliseconds.
obj_audio.Music_Fade_Time = argument[0] / 60 * 1000;
I could also do all that with just scripts, without the state state machine, but I felt that 1) it is good to be able to recall the state if it becomes necessary and 2) if / when I expand the system, it may be advantageous to be able to run code only in certain states. I'd need to fix the fade states before that though, as you can see the machine spends just a single step in them. I should make it stay in the state until volume fade is finished. That could be accomplished just by using a countdown variable, so the state wouldn't set the sound gain repeatedly.
Thanks! I was more interesting on how you call out this stuff, room starts? room creation code? etc
 

NightFrost

Member
Thanks! I was more interesting on how you call out this stuff, room starts? room creation code? etc
I've built this thing only recently so I haven't used it beyond small titleroom-gameroom-gameoverroom cycles. The initial titlescreen music kicks off in my init room where obj_audio calls scr_music_start in its own create. Thereafter everything is pretty much invoked by room transitioner. Whenever a room transition starts, it calls for music fadeout with appropriate speed. Then I have two scripts, scr_game_start and scr_game_over that are used to initialize or reset some appropriate variables at these events (like current score). The room transitioner has a feature that can run a script at room switch, and I give it the gamestart script when I transition from title to game, and gameover script when I transition from gameover screen to title. Both of these scripts include a music fadein call with the appropriate music and speed which is read from room transitioner's settings.

(The room transitioner is a state machine that runs through a fadeout - room change - script execute - fadein step cycle. It simply uses a black box with variable alpha to perform fades.)

As such this is not suitable for music transitions that would occur in a room, as the fades are not aware of each other. The system would need to be reworked slightly to a form where you can command it to run through the entire cycle on its own, but still retain the capability to simply fade in a tune, and to fade into silence (no music).
 

JeanSwamp

Member
I'm having issues with the fadein/out. Basically on how do I call a music stop after the fade so a fadein can come in place.
 

Yal

šŸ§ *penguin noises*
GMC Elder
I'm having issues with the fadein/out. Basically on how do I call a music stop after the fade so a fadein can come in place.
You could have a persistent "musicStopper" object... set an alarm, give it a variable to keep track of which sound to stop, when the alarm happens stop it. Since it's persistent, it'll trigger even if you change rooms, so it works for stuff like crossfading area tracks on room transitions.
 
Top