Game Development Community

Menu Music And Interface Audio

by Steve Acaster · in Torque 3D Professional · 06/19/2012 (5:40 am) · 5 replies

Thread created primarily to work out best solution for T3D CE.

--------------------------------------------------------------

To get audio to play in a menu (before the server is created) you need to load the datablocks in art/client/init.cs rather than in art/datablocks/audioProfiles.cs.

//at the bottom of init.cs
new SFXProfile(mainMenuTheme)
{
   filename = "art/sound/music/my_tune.ogg";
   description = "AudioMusicLoop2D";
   preload = false;
};

And then at the bottom of art/gui/MainMenu.gui.
function MainMenuGui::onWake(%this)
{
   ...

   //yorks	 
   $maintheme1=sfxCreateSource("mainMenuTheme");
   $maintheme1.play();
   echo("Start Main Menu Theme");
}

function MainMenuGui::onSleep(%this)
{
   //yorks
   $maintheme1.stop();
   echo("Stop Main Menu Theme");
}

Et voila, main menu music that can be controlled from the music volume options in audio options.

Now let's get buttons to click.
You'll need to create a new description for GUI audio in core/scripts/client/audioDescription.cs.
//yorks added!
singleton SFXDescription( InterFace2D : AudioGui )
{
   isLooping         = false;
};

And then back in mainmenu.gui add:
datablock SFXProfile("custom_button_click")
{
   filename = "art/sound/hvystep_mono01.ogg";
   description = "Interface2D";
   preload = true;
};

We need to use mainMenu.gui rather than init.cs to avoid console spam about the GUI/Interface audio not being initialized yet - it works anyway because the audio channel is loaded next, it's just that it gives you 3 lines of console complaint.

Finally, we need to go back and add the command to play the audio to our button. Name the button and then create a function based on an action. As we'll test this with the "select level" button, find the button in mainMenu.gui with the command line:
Command = "Canvas.pushDialog(ChooseLevelDlg);";

And name it: mm_chooseLevel
new GuiButtonCtrl(mm_chooseLevel) {
         canSaveDynamicFields = "0";
         Enabled = "1";
         isContainer = "0";
         Profile = "GuiMenuButtonProfile";
         HorizSizing = "relative";
         VertSizing = "bottom";
         Position = "9 114";
         Extent = "289 75";
         MinExtent = "8 8";
         canSave = "1";
         isDecoy = "0";
         Visible = "1";
         Command = "Canvas.pushDialog(ChooseLevelDlg);";
         tooltipprofile = "GuiToolTipProfile";
         hovertime = "1000";
         text = "Play";
         groupNum = "-1";
         buttonType = "PushButton";
         useMouseEvents = "1";
      };

Then create the function.
function mm_chooseLevel::onClick(%this)
{
   sfxPlayOnce("custom_button_click");
   echo("Choose Level Button Clicked");
}

Stock Problem:
Now there is a problem with this - and that is when you've loaded a level and then quit back to mainMenu, the Interface Audio Channel gets disabled again. Music works fine, but interface/gui audio is switched off. So this needs fixing.

Remember: 2D audio should be stereo, 3D audio should be Mono!

#1
06/19/2012 (10:49 am)
I moved client-side UI audio into a file called guiAudio.cs located in "scripts/gui" and is executed just after the call to SFXStartup() in "scripts/main".

You don't need a function in order to play button sounds, Gui Profiles already support buttonOver and buttonDown sounds.

Here is my portion of guiAudio.cs that relates to buttons sounds:
// Sound Profiles must exist before the Gui Profiles that want to use them.

new SFXProfile(AudioButtonOver)
{
   filename = "art/sound/gui/buttonOver";
   description = "AudioGui";
   preload = true;
};

new SFXProfile(AudioButtonDown)
{
   filename = "art/sound/gui/buttonDown";
   description = "AudioGui";
   preload = true;
};

singleton GuiControlProfile(GuiMenuButtonAudibleProfile : GuiMenuButtonProfile)
{
   soundButtonDown = "AudioButtonDown";
   soundButtonOver = "AudioButtonOver";
};
Then, in the mainMenuGui.gui I changed all profile references for the buttons from GuiMenuButtonProfile to GuiMenuButtonAudibleProfile. You can hear this in action in r65.

Due to the cluttered and unorganized execution of things in the Template scripts, this file location and execution order won't work for the MainMenu music.

In the new Template I'm working on, this wont be an issue :)

Oh, and my last comment on Ticket#29 was that the actual resolution that closed the ticket had issues... I just held off on re-opening the ticket since I'm hoping to kill off the old Templates anyway.
#2
06/19/2012 (11:02 am)
A couple of notes:

SFXPlayOnce shouldn't be used for sounds that are played more than once. The startup sound is a good example of a one-shot sound that you don't need to waste a datablock on.

You can add sounds to GuiProfiles from within the GUI Editor, instead of hand scripting them like I did, but you'll have to relocate the saved Profiles in order to actually make use of the sounds.
#3
06/19/2012 (6:53 pm)
That's weird. I haven't been having that issue, Steve. I can run a game, load a level, play it, exit back to the main menu and all of my button sounds still work fine - along with my menu music.

If you drop me an email at vegassparkyrich@gmail.com I'll send you my svn info so you can see it in action. CAVEAT: T3D 1.1, but the 1.2 executable performs the same way (until you try to load a level without reverting the "deathball" back to a standard RigidShape that is).

I just realized that you're playing the sound in the onClick() handler - I set my gui sounds in profiles instead.
#4
06/19/2012 (7:08 pm)
To clarify, in scripts/client/AudioProfiles.cs I have the following:

new SFXProfile(AudioButtonDown)
{
   filename = "art/sound/gui/buttondown.ogg";
   description = "AudioGui";
   preload = false;
};

new SFXProfile(AudioButtonOver)
{
   filename = "art/sound/gui/buttonover.ogg";
   description = "AudioGui";
   preload = false;
};

Then in art/gui/defaultGameProfiles.cs at the top of the file I dropped this:

GuiButtonProfile.soundButtonOver = "AudioButtonOver";
GuiButtonProfile.soundButtonDown = "AudioButtonDown";

GuiMenuButtonProfile.soundButtonOver = "AudioButtonOver";
GuiMenuButtonProfile.soundButtonDown = "AudioButtonDown";

I do recall that I did it this way because when I put that directly into the profiles it didn't like it - never looked for why.
#5
06/19/2012 (7:12 pm)
Wow, Mike - I totally did not read your post before dropping that - and now that I've read your post I think I know why putting those soundButton* definitions in the profiles didn't work. Must be the loading order. Thanks man!