Adventure Game Studio

AGS Support => Beginners' Technical Questions => Topic started by: rongel on Fri 12/02/2021 10:32:29

Title: System.Volume reset when loading a save game
Post by: rongel on Fri 12/02/2021 10:32:29
I have a sound issue connected to the System.Volume. Here's my situation:

I have a simple sound system that has adjustable sliders for Main Volume and Music Volume. Main volume is connected to System.Volume and Music Volume to eAudioTypeMusic.

Everything seems to work during the game. Problems start when I have adjusted the Main Volume and load a save game. Here's two different scenarios:

1. I lower the Main Volume, save the game and exit. I start the game again, load the save, and the Main Volume is playing at default value, eventhough the slider is still set to a low value.
2. I lower the Main Volume, save the game, adjust the Main Volume slider to default again, then load the save. The volume is playing at the default value, but the slider is set to a low value.

So I want the System.Volume to be always using the values from the Main Volume slider. Currently it resets to a default volume when loading a game. The Music Volume works fine, it's always playing at the same value as the Music Volume slider, even if I exit the game and start it again.

I've tried all sorts of tricks to set the System.Volume to the correct value using the eEventRestoreGame. I even tried to save the System.Volume to a config.dat-file. I think I got it right, but it had no effect, the System.Volume was still reset after loading a game. The System.Volume seems to work nicely otherwise, but is it a bad idea to use it to control the master volume? How can I make it to remember the saved values?

Title: Re: System.Volume reset when loading a save game
Post by: Khris on Fri 12/02/2021 11:15:50
It sounds like you should update the bad volume value according to the slider in eEventRestoreGame? Since the slider's value does get saved correctly.

You said it had no effect; can you show the code you've used?
Title: Re: System.Volume reset when loading a save game
Post by: rongel on Fri 12/02/2021 11:49:53
QuoteIt sounds like you should update the bad volume value according to the slider in eEventRestoreGame? Since the slider's value does get saved correctly.

Yes, exactly, I've tried to do something like that using this in eEventRestoreGame:

Code (ags) Select
System.Volume = sldMasterVolume.Value;

It had no effect. Just to check I also used this:

Code (ags) Select
System.Volume =10;

That worked, and the sound was muted when loading the game. Is it normal behaviour that System.Volume resets? It's possible that there's somehting funny in my code which does this.

QuoteYou said it had no effect; can you show the code you've used?

I used this when saving the game (the code was mostly copied from another thread) :

Code (ags) Select
function SaveVolume()
{
  // Save custom config
  music_vol = sldMasterVolume.Value;
  File* config = File.Open("$SAVEGAMEDIR$/config.dat", eFileWrite);
  config.WriteInt(music_vol);
  config.Close();
}


And this in eEventRestoreGame:

Code (ags) Select
void AfterLoadGame()
{
  File* config = File.Open("$SAVEGAMEDIR$/config.dat", eFileRead);
  music_vol = config.ReadInt();
  config.Close();
   
  System.Volume = music_vol;
}


It seemed to work, I mean it didn't give any errors, but the actual volume didn't change.
Title: Re: System.Volume reset when loading a save game
Post by: Khris on Fri 12/02/2021 11:59:03
I can kinda see why the volume setting isn't part of a save game (since the volume level isn't really part of the game state, unlike inventory etc.)
However I have no idea why changing the volume level like that has no effect. The only explanation I can think of is that the code doesn't actually run.
Title: Re: System.Volume reset when loading a save game
Post by: rongel on Fri 12/02/2021 12:23:00
QuoteHowever I have no idea why changing the volume level like that has no effect. The only explanation I can think of is that the code doesn't actually run.

I did some quick tests with other AGS games that I have and it seemed that they have the same behaviour. I tested the Urban Witch Story, and Kathy Rain. In both games the master volume was reseted to max when loading a game. In Urban Witch Story the volume slider was still in zero where I had put it, in Kathy Rain it was back in max.

So it seems it's easier to reset the slider to max when loading the game, so that it matches the volume. Is this a bug / a feature in AGS, or does someone know a way how to load a System.Volume from a save game? I can live with adjusting the slider, main thing is that their values match.
Title: Re: System.Volume reset when loading a save game
Post by: Laura Hunt on Fri 12/02/2021 12:36:04
This is what I have in my game_start() function:

Code (ags) Select
  File *customplayerdata = File.Open("$SAVEGAMEDIR$/playersettings.dat", eFileRead);
  if (customplayerdata == null) {
    System.Volume = 70;
    Game.TextReadingSpeed = 11;
  }
  else {
    System.Volume = customplayerdata.ReadInt();
    Game.TextReadingSpeed = customplayerdata.ReadInt();
    sAudioVolume.Value = System.Volume;
    sTextSpeed.Value = Game.TextReadingSpeed;
    customplayerdata.Close();
  }


Looks like the difference with your code is that I explicitely set both the slider value and the System Volume values. No idea if it might make a difference, but maybe it'll help!

EDIT: This is a complete shot in the dark, but could this have something to do with the fact that you're closing the file and then assigning System.Volume = music_vol? (and maybe you have your variables mixed up? You did mention that you have a Global volume and a Music volume, but here it seems like you're assigning the Music value to the Global volume). Maybe you could try skipping that step and simply doing System.Volume = config.ReadInt() without that intermediate variable?
Title: Re: System.Volume reset when loading a save game
Post by: rongel on Fri 12/02/2021 12:57:11
Quote from: Laura Hunt on Fri 12/02/2021 12:36:04
This is what I have in my game_start() function:

Thanks Laura! I'll try to test this soon. Maybe adding the slider values to the config file helps. Can you confirm that changing the system volume works in your game? I mean to mute (for example) the system.volume from the slider, save the game, exit, start it again and load the game and check if it's still muted?

In my code I had a value called music_vol, but it was just because the copy / pasting, it should've been called system_vol.
Title: Re: System.Volume reset when loading a save game
Post by: rongel on Fri 12/02/2021 14:33:46
Quote from: Laura Hunt on Fri 12/02/2021 12:36:04
Maybe you could try skipping that step and simply doing System.Volume = config.ReadInt() without that intermediate variable?

I tried using this very simple script, I think it should have worked?

Code (ags) Select

// When saving the game
function SaveVolume()
{
  // Save custom config
  File* config = File.Open("$SAVEGAMEDIR$/config.dat", eFileWrite);
  config.WriteInt(System.Volume);
  config.Close();
}


And this:

Code (ags) Select

// in eEventRestoreGame
function AfterLoadGame()
{
  File* config = File.Open("$SAVEGAMEDIR$/config.dat", eFileRead);
  System.Volume = config.ReadInt();
  config.Close();
}


But it had no effect, the System.Value was again maxed, when loading the save (it should have been muted).
Title: Re: System.Volume reset when loading a save game
Post by: Laura Hunt on Fri 12/02/2021 14:46:23
That is SO weird.

I take it you're calling the AfterLoadGame() function from inside eEventRestoreGame, but that you have actually declared the function at the top of your global script and imported it from the global script header, right?

Could you copy your whole on_event function here, if it's not too massive?

This is how mine looks like:

Spoiler
Code (ags) Select
function on_event(EventType event, int data)
{
  if (event == eEventRestoreGame && data == 23) { // I only have one save slot, number 23, but in other cases data != 999 would do I guess
    File *customplayerdata = File.Open("$SAVEGAMEDIR$/playersettings.dat", eFileRead);
    if (customplayerdata != null) {
      System.Volume = customplayerdata.ReadInt();
      Game.TextReadingSpeed = customplayerdata.ReadInt();
      sAudioVolume.Value = System.Volume;
      sTextSpeed.Value = Game.TextReadingSpeed;
      customplayerdata.Close();
    }
  }
 
  if (event == eEventRestoreGame && data == 999) {
    // do some stuff here, irrelevant for our current purposes
    game_start();
  }
}
[close]
Title: Re: System.Volume reset when loading a save game
Post by: rongel on Fri 12/02/2021 15:17:59
Yep, here it is. The first block is an old inventorybar fix, but shouldn't be connected.

Code (ags) Select
function on_event (EventType event, int data)   
{
  // Makes the inventory backround deselect bug to go away!
  if (event == eEventGUIMouseDown && mouse.IsButtonDown(eMouseRight) && data == gInventoryBar.ID)
  {
    GUIControl *theControl = GUIControl.GetAtScreenXY(mouse.x, mouse.y);
    if (theControl==InvWin_Walter) //the InvWindow
    {
      InventoryItem *i = InventoryItem.GetAtScreenXY(mouse.x, mouse.y);
      if (i == null)
      {
        player.ActiveInventory = null;   // lose active inv
        mouse.Mode=eModeInteract;
      }
    }
  }
 
  // RESTORE GAME (Load saved System.Volume ei toimi!)
  if(event == eEventRestoreGame && data !=999) {
   
    AfterLoadGame();
   
  }
}


I wasn't using that "&& data !=999" bit at first. I added it and tested, but no difference. I wasn't sure what you ment by this: 
Quoteand imported it from the global script header, right?
Except this mysterious sound issue, the on_event seems to be working fine, and I can see things happen when I use it.
Title: Re: System.Volume reset when loading a save game
Post by: Laura Hunt on Fri 12/02/2021 15:34:33
Quote from: rongel on Fri 12/02/2021 15:17:59
I wasn't sure what you ment by this: 
Quoteand imported it from the global script header, right?

If you define a function in your global script, you need to add it to the header (globalscript.ash) so it can be used anywhere in the game, although I'm not 100% sure if that is relevant here. I don't know if it'll change anything, but I guess it doesn't hurt to go to GlobalScript / Edit Header in the navigation panel, and add this line:

Code (ags) Select
import function AfterLoadGame();

Maybe it would also be a good idea to just put your whole code there instead of the function call and see if it makes a difference?

Code (ags) Select
  if (event == eEventRestoreGame) {
   
      File* config = File.Open("$SAVEGAMEDIR$/config.dat", eFileRead);
      System.Volume = config.ReadInt();
      sldMasterVolume.Value = System.Volume;
      config.Close();   
  }


Title: Re: System.Volume reset when loading a save game
Post by: rongel on Fri 12/02/2021 15:49:25
QuoteIf you define a function in your global script, you need to add it to the header (globalscript.ash) so it can be used anywhere in the game, although I'm not 100% sure if that is relevant here.

Ah, yes. I didn't have that in the header, but I tried this adding the whole code there too, and it didn't help. Weird thing is that I can do this, for example:


Code (ags) Select
if(event == eEventRestoreGame && data !=999) {
    System.Volume =10;
  }


And the volume nicely jumps to the correct value. It seems I can only change the volume here by giving it a fixed number. Using an int doesn't seem to affect it. So that has me thinking that it is a bug of some sort. Especially when I saw the same behaviour in the two games I tested. I think I just reset the slider to max value when loading the game, and then the volume and the slider values are in sync.
Title: Re: System.Volume reset when loading a save game
Post by: Laura Hunt on Fri 12/02/2021 15:56:31
Quote from: rongel on Fri 12/02/2021 15:49:25
QuoteIf you define a function in your global script, you need to add it to the header (globalscript.ash) so it can be used anywhere in the game, although I'm not 100% sure if that is relevant here.

Ah, yes. I didn't have that in the header, but I tried this adding the whole code there too, and it didn't help.

Yeah, I guess it makes sense because this is always called from global script, so there's no need to import it. Worth a try though!


Quote from: rongel on Fri 12/02/2021 15:49:25
Weird thing is that I can do this, for example:


Code (ags) Select
if(event == eEventRestoreGame && data !=999) {
    System.Volume =10;
  }


And the volume nicely jumps to the correct value. It seems I can only change the volume here by giving it a fixed number. Using an int doesn't seem to affect it. So that has me thinking that it is a bug of some sort. Especially when I saw the same behaviour in the two games I tested. I think I just reset the slider to max value when loading the game, and then the volume and the slider values are in sync.

That is super weird. I was going to say that it doesn't even make sense because the code I posted earlier works for me, *but* I just realized that actually calling that code in the on_event function is redundant, because I always call it at game_start anyway. So maybe I also have that bug but I haven't noticed it because of my duplicated code :-D

I'm sorry I couldn't help! The last thing I would suggest would be moving the call to load the volume config in game_start if it fits the logic of your game, but otherwise I'm totally out of ideas. Might simply be a weird bug, like you suggested!
Title: Re: System.Volume reset when loading a save game
Post by: rongel on Fri 12/02/2021 16:06:43
Quote from: Laura Hunt on Fri 12/02/2021 15:56:31
I'm sorry I couldn't help! The last thing I would suggest would be moving the call to load the volume config in game_start if it fits the logic of your game, but otherwise I'm totally out of ideas. Might simply be a weird bug, like you suggested!

Thanks anyway! Good to know that I should be doing the right thing here, and that it's not my crappy code!  :-D

A small update, if I use the config file to store the System.Volume and do this:

Code (ags) Select
if(event == eEventRestoreGame && data !=999) {
       
   AfterLoadGame();
   Display("System.Volume is %d", System.Volume);
  }


It displays the correct value! So the game says the System.Volume is 13 for example, but I can hear everything playing at 100 value. It must mean that the config file is working, but the actual sound that is playing doesn't obey the System.Volume. If I adjust the slider, the volume jumps to correct value. Weird...

Title: Re: System.Volume reset when loading a save game
Post by: Vincent on Fri 12/02/2021 16:57:34
I don't have a clue about this but I was thinking that instead having a System.Volume you can split each type of sound separately like for music, sound, speech and ambient sound. So probably it can be avoided having a global volume at all and on slider change it can be done something like this:

Code (ags) Select

function SliderMusic_OnChange(GUIControl *control)
{
  Game.SetAudioTypeVolume(eAudioTypeMusic, SliderMusic.Value, eVolExistingAndFuture);
}
Title: Re: System.Volume reset when loading a save game
Post by: rongel on Fri 12/02/2021 17:27:55
Quote from: Vincent on Fri 12/02/2021 16:57:34
I don't have a clue about this but I was thinking that instead having a System.Volume you can split each type of sound separately like for music, sound, speech and ambient sound.

Thanks for the suggestion! I like the idea of the Master Volume and don't want too many sliders, but if it's not working correctly, I guess I could make a "Sound volume slider" that controls both the sound and the ambient sound. Then I would have the music on one slider and all the sounds on a separate sliders.
Title: Re: System.Volume reset when loading a save game
Post by: Laura Hunt on Fri 12/02/2021 17:36:18
Quote from: rongel on Fri 12/02/2021 17:27:55
Quote from: Vincent on Fri 12/02/2021 16:57:34
I don't have a clue about this but I was thinking that instead having a System.Volume you can split each type of sound separately like for music, sound, speech and ambient sound.

Thanks for the suggestion! I like the idea of the Master Volume and don't want too many sliders, but if it's not working correctly, I guess I could make a "Sound volume slider" that controls both the sound and the ambient sound. Then I would have the music on one slider and all the sounds on a separate sliders.

The problem with this approach is that moving the "sounds" slider does not respect their relative values but instead sets them all to the same volume. I would in fact suggest the opposite: using only a Global Volume slider, which acts as a true master and treats all sounds as percentages of the total.

(This is a well-known issue with the AGS audio system: https://www.adventuregamestudio.co.uk/forums/index.php?topic=58464.0 or https://www.adventuregamestudio.co.uk/forums/index.php?topic=54251.0)
Title: Re: System.Volume reset when loading a save game
Post by: rongel on Fri 12/02/2021 17:54:20
QuoteThe problem with this approach is that moving the "sounds" slider does not respect their relative values but instead sets them all to the same volume.

Yes, I think this would work if all the sound clips are played at the default volume. So each sound clip has to be at correct volume when importing them into the game. It is a quite big downside that you couldn't adjust the volume clips individually.
Title: Re: System.Volume reset when loading a save game
Post by: Vincent on Fri 12/02/2021 19:01:50
Maybe there would be a problem also if you only have a generic slider for the master volume, if I got that right, because if someone wants to hear only the sound without the music or viceversa which maybe they find boring then they can't do that cause they only have a master volume for everything. Between the two things personally I would prefer having more control for each type of sound even though their relative values can be messed up but that's all your choice
Title: Re: System.Volume reset when loading a save game
Post by: Laura Hunt on Fri 12/02/2021 20:35:14
Quote from: Vincent on Fri 12/02/2021 19:01:50
Maybe there would be a problem also if you only have a generic slider for the master volume, if I got that right, because if someone wants to hear only the sound without the music or viceversa which maybe they find boring then they can't do that cause they only have a master volume for everything. Between the two things personally I would prefer having more control for each type of sound even though their relative values can be messed up but that's all your choice

Oh yes, that's definitely a design decision on my part. I want players to hear the soundscape that I've designed, with the "correct" balance of music and other sounds, so all technical issues aside, I simply do not want to give them control over that. Definitely a personal choice!
Title: Re: System.Volume reset when loading a save game
Post by: Crimson Wizard on Fri 12/02/2021 22:42:57
I hoped the above problem is solved, did not read all the thread. Just wanted to say that System.Volume definitely suppose to be a part of the saved game now. And the usual problem is opposite: that people do not want it to be because that will change the volume when they restore older saves. So they use custom config instead, as noted above in this thread.

There's definitely a historical issue of some properties of the system being in the save while it would be better if they were not. I recall in the past we have removed Gamma setting from being written in the save for this particular reason, but it was more like a quick hack, as there's more to it.


In regards to audio type volume, and having relative adjustment instead of absolute, I and other people posted this or similar advice over years on forums: do not apply slider volume to audiotype volume directly, but have a table of default volumes for your clips and pass all played clips in a loop and set their volume manually as (default volume) * (factor), where factor is from 0.0 to 1.0 and is controlled by your slider(s).
The table may work like this: you make an array of ints sized to max number of channels, and every time new clip is played you
a) take its starting volume and save in the array on corresponding slot
b) recalculate volume value using your slider positions and assign new volume using above rule.
This is more scripting work, but shall give you more control over your sound.
Title: Re: System.Volume reset when loading a save game
Post by: rongel on Fri 12/02/2021 22:55:51
Quote from: Crimson Wizard on Fri 12/02/2021 22:42:57
I hoped the above problem is solved, did not read all the thread. Just wanted to say that System.Volume definitely suppose to be a part of the saved game now.

At least for me, the System.Volume is not saved with the save game. And I can't seem to load it from the config file either. It would be great if someone else could confirm this (or the opposite!). I forgot to mention that I'm using version 3.5.0.23. I'll get back to this tomorrow.
Title: Re: System.Volume reset when loading a save game
Post by: Crimson Wizard on Fri 12/02/2021 23:02:11
Quote from: rongel on Fri 12/02/2021 16:06:43
Code (ags) Select
if(event == eEventRestoreGame && data !=999) {
       
   AfterLoadGame();
   Display("System.Volume is %d", System.Volume);
  }


It displays the correct value! So the game says the System.Volume is 13 for example, but I can hear everything playing at 100 value. It must mean that the config file is working, but the actual sound that is playing doesn't obey the System.Volume. If I adjust the slider, the volume jumps to correct value. Weird...

Ok, so, the values are correct, but they fail to be set to System.Volume. Other possibilities are:
- it's set, but system.volume is not applied to sounds in the engine (engine bug);
- it's set, but you have some script overriding this somewhere (script bug).
Title: Re: System.Volume reset when loading a save game
Post by: rongel on Sat 13/02/2021 09:16:45
Quote from: Crimson Wizard on Fri 12/02/2021 23:02:11
Ok, so, the values are correct, but they fail to be set to System.Volume. Other possibilities are:

I didn't notice any scripts that are overriding System.Volume, but it's possible I missed something. But I got some results just now, something weird is definetely going on! If I put System.Volume =0; before the AfterLoadGame, like this:

Code (ags) Select
if(event == eEventRestoreGame && data !=999) {
   System.Volume =0;   
   AfterLoadGame();
  }


It works! Unless I have put the slider to min value 0... Then it plays the System.Volume at 100% again. Not sure what's going on, but I got it working by giving the slider a Min Value of 1 instead of 0. In the end I have now this system, and I can restore the saved System.Value.

Code (ags) Select
// MASTER VOLUME SLIDER
function sldMasterVolume_OnChange(GUIControl *control)
{
  System.Volume = sldMasterVolume.Value;
  system_vol = sldMasterVolume.Value;
}


Code (ags) Select
// ON EVENT
if(event == eEventRestoreGame && data !=999) {
  System.Volume =0;
  if(system_vol !=0) System.Volume = system_vol;
}


But it's not perfect either, using the slider value of 1 instead of 0, I can't completely mute the sound...
Title: Re: System.Volume reset when loading a save game
Post by: rongel on Sat 13/02/2021 09:40:58
Just trying things here, and for some reason this seems to work.

Code (ags) Select
if(event == eEventRestoreGame && data !=999) {
   System.Volume =1;   
   AfterLoadGame();
  }


The slider is again at 0-100 values, like it should be. The sound is playing at correct volume, when loading a save game. Even if I have muted the volume with the slider, it remembers that and stays muted. Using a zero works too, unless the slider is set to value 0. I can't see no other reason for this than an engine bug.
Title: Re: System.Volume reset when loading a save game
Post by: Crimson Wizard on Sat 13/02/2021 09:42:24
I cannot tell from the script, but do you change the slider's position too when you set System.Volume? They should normally stay in sync.

Also, don't really understand what system_vol is for there.

Maybe I will find time to test this later.
Title: Re: System.Volume reset when loading a save game
Post by: rongel on Sat 13/02/2021 09:53:37
QuoteI cannot tell from the script, but do you change the slider's position too when you set System.Volume? They should normally stay in sync.
No, I don't touch the slider. It's always in the correct position. Moving the slider does this: System.Volume = sldMasterVolume.Value;.

QuoteAlso, don't really understand what system_vol is for there.
Yes, it's not needed. I've tested many different approaches here. Main thing is that I couldn't change the volume unless I put System.Volume =1; before the volume loading script in eEventRestoreGame. Now that I've done that, it seems I can adjust it in many ways.
Title: Re: System.Volume reset when loading a save game
Post by: Cassiebsg on Sun 14/02/2021 22:28:15
On this game (Unexpected at the Rising Star (https://www.adventuregamestudio.co.uk/site/games/game/2201-unexpected-at-the-rising-star/)) I put a lot of work on the settings and sound system (because I'm a complicated person  (laugh) ). I used a module to keep track of all those variables and such.

If you like, give it a test and see if my game has this bug or not. Though I think I tested insistently to make sure the sound system worked as I wanted.
Title: Re: System.Volume reset when loading a save game
Post by: rongel on Mon 15/02/2021 07:49:22
Quote from: Cassiebsg on Sun 14/02/2021 22:28:15
If you like, give it a test and see if my game has this bug or not. Though I think I tested insistently to make sure the sound system worked as I wanted.

Hi! I did a quick test with your game, but I don't think your sound slider uses System.Volume? The sound slider is not a "master volume" and doesn't affect the music, or speech. So everything seems to work nicely. The issue I encountered is only with the System.Volume.
Title: Re: System.Volume reset when loading a save game
Post by: Cassiebsg on Wed 17/02/2021 16:42:31
Ah, didn't knew that. I'm using Game.SetAudioTypeVolume.

Though, if all else fails, you can just set all these types associated  to the same slider, unless you have sliders for all these plus System.Volume. I decided to only let players set the different types of sounds, since they can control their main volume on windows itself or their speakers/headphones...

Anyway, if you want to try the module, it's IniFile by Wyz (https://www.adventuregamestudio.co.uk/forums/index.php?topic=46631.0)
I have set it up to load the file at game.start and on_event Restore.