Author Topic: FMod features in SGDK2  (Read 7353 times)

Vincent

  • SGDK2 Addict
  • Expert
  • Fanatic
  • *****
  • Posts: 601
  • Legacy of Kain: Revival is completed!!!
    • View Profile
    • Chivalrous Games
    • Email
FMod features in SGDK2
« on: 2010-01-11, 12:48:14 PM »
Hi guys!  :)

I started integrating music in my game.  I'm using FMod, since it is pretty much the easiest way to do it.  I think it's great stuff.  Although there are some little things that I felt were lacking, I add them as I go and it really is going fine.

If I understand correctly, FMod provides the dll and FMod.cs.  I suppose bluemonkmn developped FModBase.cs to "wrap" the "wrapper".  It certainly works well and it is very easy to use.  LoadSound, PlaySound, StopSound and UnloadSound are simple enough.

For the music in my game, I wanted to make smooth transitions between each music.  So I added a system to manage the music, making sure that only one music plays at a time and, if there is a music change, the system does a fade-out of the previous music and a fade-in of the new music simultaneously.  I think it is less of a shock for the ears when you change a level or go into the menu.  I didn't implement this system for sound effects.

I'm also thinking to add controls in the options window to manage to SFX volume and music volume.

If anyone is interested in this, please let me know.  I'll send you my code.

Also, bluemonkmn, do you think it would be a good idea to implement these changes into a new version of FModBase.cs?  Or do you prefer to keep it as it is?

See ya!  ;D
Legacy of Kain: Revival completed!
http://lokrevival.webs.com

See also my company website:
http://chivalrousgames.com

bluemonkmn

  • SGDK Author
  • Administrator
  • Fanatic
  • *****
  • Posts: 2733
    • ICQ Messenger - 2678251
    • MSN Messenger - BlueMonkMN@gmail.com
    • View Profile
    • http://sgdk2.sf.net/
    • Email
Re: FMod features in SGDK2
« Reply #1 on: 2010-01-12, 05:52:54 AM »
It would be a nice feature if it doesn't interfere with the existing operation and is included only as an option to the user.  In SGDK 1, the problem was that all music and sound effects would be forced to fade out when they wanted to stop and you had to do something complicated to make them stop abruptly, which seems wrong.  Did you simply add new functions and leave the existing functions as they were?   I suspect that your enhancements would be good to include in the standard fmodbase.cs.

Vincent

  • SGDK2 Addict
  • Expert
  • Fanatic
  • *****
  • Posts: 601
  • Legacy of Kain: Revival is completed!!!
    • View Profile
    • Chivalrous Games
    • Email
Re: FMod features in SGDK2
« Reply #2 on: 2010-01-12, 08:36:17 AM »
Cool!

I didn't need to modify the existing FModBase functions.  I'll finish what I'm working on right now, then I'll extract the code and post it here.  It's not 100% clean, but I guess you can sort it out and take what you want.
Legacy of Kain: Revival completed!
http://lokrevival.webs.com

See also my company website:
http://chivalrousgames.com

Vincent

  • SGDK2 Addict
  • Expert
  • Fanatic
  • *****
  • Posts: 601
  • Legacy of Kain: Revival is completed!!!
    • View Profile
    • Chivalrous Games
    • Email
Re: FMod features in SGDK2
« Reply #3 on: 2010-01-12, 11:42:29 AM »
Okay, here's some of the stuff that I've done.

I added this in the GameForm.cs so when the game loses focus, the music stops playing:
Code: [Select]
//this part in the run function of GameForm:
            // Display is minimized or inactive, wait until it is restored
            Application.DoEvents();
            if (GameDisplay != null)
               GameDisplay.SwapBuffers();
//was replaced by:
            // Display is minimized or inactive, wait until it is restored
            Application.DoEvents();
            if (GameDisplay != null)
               GameDisplay.SwapBuffers();
            //don't play music if the game is paused
            if(CurrentMusic != null)
               CustomObjects.FMODBase.StopSound(CurrentMusic);           
            if(NextMusic != null)
               CustomObjects.FMODBase.StopSound(NextMusic);
            System.Threading.Thread.Sleep(0);
            continue;

//this part:
   OutputDebugInfo();

//was replaced by:
   CurrentFadeTime = ManageMusic(CurrentFadeTime);
   OutputDebugInfo();


I could not add the previous code in a another file (partial class) but the next code I added in another file using the partial class, so this still goes into GameForm.cs

Code: [Select]
public partial class GameForm : Form
{
   #region music extra stuff

   public const int FadeDuration = 120; //in frames
   public int CurrentFadeTime = FadeDuration;
   public const float MaxVolume = 0.60f;
   public CustomObjects.FMODBase CurrentMusic;
   public CustomObjects.FMODBase NextMusic;

   //this part is useful for my project only
   //It could be replaced by another function or completely dropped
   public CustomObjects.FMODBase GetMusicToPlay()
   {
      //Verify if music is forced
      if (Counter.ForceMusic.CurrentValue != 0)
      {
         switch(Counter.ForceMusic.CurrentValue)
         {
            case 1:
               return TermogentSwampsNormal.Value;
            case 2:
               return ElderGodLairNormal.Value;
            case 3:
               return VoradorMansionNormal.Value;
            case 4:
               return HumanCityNormal.Value;
            case 5:
               return VampireCitadelNormal.Value;
            case 6:
               return HyldenDimensionNormal.Value;
            case 7:
               return PillarsNosgothNormal.Value;
            case 8:
               return HyldenFortressNormal.Value;
            case 9:
               return MenuNormal.Value;
            case 10:
               return BossNormal.Value;
            case 11:
               return ElderGodNormal.Value;
            case 12:
               return IntroNormal.Value;
            default:
               return NoMusic.Value;
         }
      }
      else
      {
         //verify if in any menu
         if(OverlayMap is MiniMap_Map)
         {
            //not in menu so play level music
            switch(CurrentMap.GetType().Name.Substring(0, 2).ToUpper())
            {
               case "VM":
                  return VoradorMansionNormal.Value;
               case "TS":
                  return TermogentSwampsNormal.Value;
               case "EL":
                  return ElderGodLairNormal.Value;
               case "HC":
                  return HumanCityNormal.Value;
               case "HD":
                  return HyldenDimensionNormal.Value;
               case "VC":
                  return VampireCitadelNormal.Value;
               case "PN":
                  return PillarsNosgothNormal.Value;
               case "HF":
                  return HyldenFortressNormal.Value;
               default:
                  return null;
            }
         }
         else
         {
            //in menu so play menu music
            return MenuNormal.Value;
         }
      }
   }


   //this is the important part.  Plays the music and manages the fades
   public int ManageMusic(int CurrentFadeTime)
   {
      //Find the music to play
      CustomObjects.FMODBase Music = GetMusicToPlay();  //this part could be dropped and a custom function added to change the music or to pass it to this function
      if(Music != CurrentMusic && CurrentFadeTime == FadeDuration) //don't want to manage multiple fades at once
      {
         if(CurrentMusic == null)
            CurrentMusic = Music;
         else
            NextMusic = Music;
      }

      if(CurrentMusic != null)
      {
         //Assess music situation
         if((NextMusic != null) && (CurrentMusic != NextMusic) && (CurrentFadeTime == FadeDuration))
         {
            //we are changing the music
            CurrentFadeTime = 0;
         }

         //Assess fade situation
         if(CurrentFadeTime == FadeDuration)
         {
            //No fading right now, keep playing current music at full volume
            CurrentMusic.Volume = MaxVolume;
            FMODBase.PlaySound(CurrentMusic, SoundReplay.Continue);
         }
         else if(CurrentFadeTime == FadeDuration - 1)
         {
            //The fading is finishing, switch the musics and play the new current music at full volume
            FMODBase.StopSound(CurrentMusic);
            CurrentMusic = NextMusic;
            CurrentMusic.Volume = MaxVolume;
            FMODBase.PlaySound(CurrentMusic, SoundReplay.Continue);
            CurrentFadeTime++;
            NextMusic = null;
         }
         else
         {
            //A fading occurs
            //calculate the volume
            float FadeAmount = (MaxVolume * CurrentFadeTime) / FadeDuration;
            CurrentMusic.Volume = MaxVolume - FadeAmount;
            NextMusic.Volume = FadeAmount;
            FMODBase.PlaySound(CurrentMusic, SoundReplay.Continue);
            FMODBase.PlaySound(NextMusic, SoundReplay.Continue);
            CurrentFadeTime++;
         }
      }
      return CurrentFadeTime;
   }
}


I also added a field in fmodbase.cs

Code: [Select]
private float volume;

And modified the Volume property like this

Code: [Select]
//this part:
      // Override this member to override default volume.
      protected virtual float Volume
      {
         get
         {
            return 1.0f;
         }
      }

//was replaced by:
      public float Volume
      {
         get
         {
            return volume;
         }
         set
         {
            volume = value;
         }
      }

//So, of course, I don't override the Volume properties in my music files anymore, but I still do for my sound effects.

It would be even better to add controls in the options menu to set a max volume to sound effects and a max volume to music rather than hardcoding it in GameForm like I did.

I will leave that to your more than able hands bluemonkmn.  I suppose you would also prefer to include all of this code into fmodbase.cs only, but I don't see how I could do that.  Since SGDK2 is your application, I'll let you see if any of this is of interest to you or not.

I hope it's not too messy!

Thanks bluemonkmn!
Legacy of Kain: Revival completed!
http://lokrevival.webs.com

See also my company website:
http://chivalrousgames.com

bluemonkmn

  • SGDK Author
  • Administrator
  • Fanatic
  • *****
  • Posts: 2733
    • ICQ Messenger - 2678251
    • MSN Messenger - BlueMonkMN@gmail.com
    • View Profile
    • http://sgdk2.sf.net/
    • Email
Re: FMod features in SGDK2
« Reply #4 on: 2010-01-12, 03:28:25 PM »
I think the changes to GameForm should be different because you should be able to run projects without importing fmodbase.cs.  I think the currently proposed code will have an error if you try to run a project without importing fmodbase.cs.  My suggestion is to try to confine all the changes to fmodbase.cs.  Is there a way to hook into events raised from GameForm from FModBase.cs?  I will try to look into this when I get a chance if you don't get to it first.

bluemonkmn

  • SGDK Author
  • Administrator
  • Fanatic
  • *****
  • Posts: 2733
    • ICQ Messenger - 2678251
    • MSN Messenger - BlueMonkMN@gmail.com
    • View Profile
    • http://sgdk2.sf.net/
    • Email
Re: FMod features in SGDK2
« Reply #5 on: 2010-01-16, 08:24:14 PM »
I implemented the ability to cross-fade music by only changing fmodbase.cs:

Add these declarations to class FMODBase
Code: [Select]
      private float lastSetVolume;
      private static FMODBase music = null;
      private static FMODBase oldMusic = null;

Change PlaySound to return a boolean and track the last set volume:
Code: [Select]
      [Description("Play an FMOD sound effect. Returns true if the sound was (re-)started.")]
      public static bool PlaySound([System.ComponentModel.Editor("CustomObject", "UITypeEditor")] CustomObjects.FMODBase Sound, SoundReplay ReplayOption)
      {
         LoadSound(Sound);
         if (Sound.isPlaying)
         {
            switch(ReplayOption)
            {
               case SoundReplay.Continue:
                  return false;
               case SoundReplay.StartNew:
                  break;
               case SoundReplay.Restart:
                  Sound.Stop();
                  break;
            }
         }
         ERRCHECK(system.playSound(FMOD.CHANNELINDEX.FREE, Sound.sound, false, ref Sound.channel));
         ERRCHECK(Sound.channel.setCallback(updateCallback));
         ERRCHECK(Sound.channel.setVolume(Sound.Volume));
         Sound.lastSetVolume = Sound.Volume;
         return true;
      }

Add PlayMusic and ManageMusic functions:
Code: [Select]
      [Description("Play an FMOD sound as background music which will fade out when new music starts.")]
      public static void PlayMusic([System.ComponentModel.Editor("CustomObject", "UITypeEditor")] CustomObjects.FMODBase Sound)
      {
         bool newSoundStarted = PlaySound(Sound, SoundReplay.Continue);

         if ((music != Sound) && (music != null))
         {
            if ((oldMusic != null) && (Sound != oldMusic))
               oldMusic.Stop();
            oldMusic = music;
            if (newSoundStarted)
            {
               Sound.lastSetVolume = .005f;
               ERRCHECK(Sound.channel.setVolume(Sound.lastSetVolume));
            }
         }
         music = Sound;
      }

      private static void ManageMusic()
      {
         if (oldMusic != null)
         {
            oldMusic.lastSetVolume -= .005f;
            if (oldMusic.lastSetVolume < 0)
            {
               oldMusic.Stop();
               oldMusic = null;
            }
            else
            {
               ERRCHECK(oldMusic.channel.setVolume(oldMusic.lastSetVolume));
            }
         }
         if (music != null)
         {
            if (music.lastSetVolume < music.Volume)
            {
               music.lastSetVolume += .005f;
               if (music.lastSetVolume > music.Volume)
                  music.lastSetVolume = music.Volume;
               ERRCHECK(music.channel.setVolume(music.lastSetVolume));
            }
         }
      }

Call ManageMusic from OnFrameStart
Code: [Select]
      public static void OnFrameStart()
      {
         ERRCHECK(system.update());
         ManageMusic();
      }

Update Channel_Callback to track when music ends:
Code: [Select]
      private static FMOD.RESULT Channel_Callback(IntPtr channelraw, FMOD.CHANNEL_CALLBACKTYPE type, IntPtr commanddata1, IntPtr commanddata2)
      {
         try
         {
            for(int i=0; i<soundList.Count; i++)
            {
               FMODBase snd = (FMODBase)soundList[i];
               if ((snd.channel != null) && (snd.channel.getRaw() == channelraw) && (type == FMOD.CHANNEL_CALLBACKTYPE.END))
               {
                  snd.channel = null;
                  if (snd == oldMusic)
                     oldMusic = null;
                  if (snd == music)
                     music = null;
               }
            }
            return FMOD.RESULT.OK;
         }
         catch(System.Exception ex)
         {
            return FMOD.RESULT.ERR_UPDATE;
         }
      }

Update Stop to track when music ends
Code: [Select]
      private void Stop()
      {
         if(isPlaying)
            ERRCHECK(channel.stop());
         channel = null;
         if (this == oldMusic)
            oldMusic = null;
          if (this == music)
            music = null;         
      }

I committed these changes to SVN

Vincent

  • SGDK2 Addict
  • Expert
  • Fanatic
  • *****
  • Posts: 601
  • Legacy of Kain: Revival is completed!!!
    • View Profile
    • Chivalrous Games
    • Email
Re: FMod features in SGDK2
« Reply #6 on: 2010-01-20, 12:06:01 PM »
Well...  :-[

I guess I won't implement your changes in my project, bluemonkmn.  I already added some other stuff related to the sounds and I don't want to try to reproduce this stuff to make it fit with your code right now.  So I won't test your new code for now.  Probably in a future project.

Anyway, I'm sure it will be useful for some other guys out there.

Thanks again! :)
Legacy of Kain: Revival completed!
http://lokrevival.webs.com

See also my company website:
http://chivalrousgames.com

bluemonkmn

  • SGDK Author
  • Administrator
  • Fanatic
  • *****
  • Posts: 2733
    • ICQ Messenger - 2678251
    • MSN Messenger - BlueMonkMN@gmail.com
    • View Profile
    • http://sgdk2.sf.net/
    • Email
Re: FMod features in SGDK2
« Reply #7 on: 2010-01-21, 05:43:25 AM »
The nice thing about SGDK2 is we don't all have to use exactly the same framework.  A project using its own custom code doesn't have to worry too much that it will run properly on a different version of SGDK (at least doesn't have to worry as much as SGDK1 did).

SPYmaps

  • Visitor
  • *
  • Posts: 8
    • View Profile
    • SPYmaps - SP-leveldesign
    • Email
Re: FMod features in SGDK2
« Reply #8 on: 2010-12-03, 05:46:46 AM »
Vincent, i downloaded and tried to play you're game but i did get an error message that says;

c:\Users\leon\Downloads\GAME DEV\games\LokRevival\LokRevival\Display.cs(11,30) : error CS0234: the type of the name of the nameplace or space Enums does excist in the name place or space OpenTK.Graphics.OpenGL (is there missing a assembly change?)

c:\Users\leon\Downloads\GAME DEV\games\LokRevival\LokRevival\Display.cs(65,32) : error CS0246: the type of the namespacename is not found, (is there missing a userinstruction of assembly change?)

i did translate it myself in to English, originaly the error text was in Dutch, (because i am Dutch, although i can't remember having installed SGDK 2.0 in Dutch, i nornaly choose Englsih for installation software.

do you know what to do because i would like to give you're beta a try,
by the way, do you know if there are many people who are having trouble with playing it, due to that it is played on a different pc?

leon
I LOVE SP-MAPPING, (check my site for sp-mappacks, sp-mods, movies of them etc.)

bluemonkmn

  • SGDK Author
  • Administrator
  • Fanatic
  • *****
  • Posts: 2733
    • ICQ Messenger - 2678251
    • MSN Messenger - BlueMonkMN@gmail.com
    • View Profile
    • http://sgdk2.sf.net/
    • Email
Re: FMod features in SGDK2
« Reply #9 on: 2010-12-03, 06:22:58 AM »
Where did you download the project from?  You may have downloaded an old version of the project.  I don't know if Vincent has posted a current version of the SGDK2 file for general download.

Vincent

  • SGDK2 Addict
  • Expert
  • Fanatic
  • *****
  • Posts: 601
  • Legacy of Kain: Revival is completed!!!
    • View Profile
    • Chivalrous Games
    • Email
Re: FMod features in SGDK2
« Reply #10 on: 2010-12-03, 10:36:42 AM »
Hi Leon!

I will release a true beta version in a couple of weeks (the whole game but with bugs, glitches and balancing issues still to solve).  Probably near december 24th.  The project in the repository is old (november 2009) and really doesn't qualify as a beta.

Sorry to have you wait a little. :)
Legacy of Kain: Revival completed!
http://lokrevival.webs.com

See also my company website:
http://chivalrousgames.com

SPYmaps

  • Visitor
  • *
  • Posts: 8
    • View Profile
    • SPYmaps - SP-leveldesign
    • Email
Re: FMod features in SGDK2
« Reply #11 on: 2010-12-06, 05:23:57 AM »
no problem, and i am not sure anymore where i did download it from.
i just googeled it and did find it somewere.

leon
I LOVE SP-MAPPING, (check my site for sp-mappacks, sp-mods, movies of them etc.)

Servicerci

  • Guest
FMod features in SGDK2
« Reply #12 on: 2016-11-04, 12:07:24 PM »
I would email as well, never hurts to ask questions.

Something to note about Eriks FMOD

bluemonkmn

  • SGDK Author
  • Administrator
  • Fanatic
  • *****
  • Posts: 2733
    • ICQ Messenger - 2678251
    • MSN Messenger - BlueMonkMN@gmail.com
    • View Profile
    • http://sgdk2.sf.net/
    • Email
Re: FMod features in SGDK2
« Reply #13 on: 2016-11-05, 07:22:01 AM »
Servicerci, that comment doesn't make any sense. Can you prove that you're not a bot before I delete your account?