Problem with Volume Sliders

SosaseesSosasees Posts: 104Member
edited July 20 in GUI

Old Title: Why do the Volume sliders reset after level transitions, but only visually?


When I change the Volume in One Level, the Sliders properly show the Volume of each bus (Left Image).
But after I enter the next level, the Volume remains the same but the Sliders show Full Volume (Right Image).

How could I fix this visual disconnect?
These are my Volume Changing Signals:

func _on_Sound_value_changed(value):
    AudioServer.set_bus_volume_db(
            AudioServer.get_bus_index("Sounds"),
            linear2db(value)
    )

func _on_Music_value_changed(value):
    AudioServer.set_bus_volume_db(
            AudioServer.get_bus_index("Music"),
            linear2db(value)
    )

Tags :

Best Answer

  • TwistedTwiglegTwistedTwigleg Posts: 2,831
    edited July 11 Accepted Answer

    You probably need to set the sliders when the scene is shown. If you have the sliders and you know what bus to use, then the code to retrieve the value should look something like this:

    func _ready():
        $SoundSlider.value = AudioServer.get_bus_volume_db(
            AudioServer.get_bus_index("Sounds")
        )
        $MusicSlider.value = AudioServer.get_bus_volume_db(
            AudioServer.get_bus_index("Music")
        )
    

    Edit: Fixed formatting.

Answers

  • MegalomaniakMegalomaniak Posts: 2,748Admin
    edited July 10

    And wheres the code handling the visible gui updating? Please show that too.

    If you have none then you need to implement it. A function that is able set/update the sliders values.

  • SosaseesSosasees Posts: 104Member
    edited July 10

    Well, I've actually tried and failed that before. 🤷🏿‍♀️

  • TwistedTwiglegTwistedTwigleg Posts: 2,831Admin
    edited July 11 Accepted Answer

    You probably need to set the sliders when the scene is shown. If you have the sliders and you know what bus to use, then the code to retrieve the value should look something like this:

    func _ready():
        $SoundSlider.value = AudioServer.get_bus_volume_db(
            AudioServer.get_bus_index("Sounds")
        )
        $MusicSlider.value = AudioServer.get_bus_volume_db(
            AudioServer.get_bus_index("Music")
        )
    

    Edit: Fixed formatting.

  • MegalomaniakMegalomaniak Posts: 2,748Admin

    Doing it in ready should do it yes.

  • SosaseesSosasees Posts: 104Member
    edited July 14

    @TwistedTwigleg Thanks very much! Now I've gotten slightly further to fixing my problem.
    But it's not finished yet:

    The Volume Sliders DO now show the accurate volume upon loading a new scene,
    but it's only because the Audio gets muted and the Sliders get reset to Minimum after every time a level gets loaded.

    I still need the Volume to remain between Scene Loadings. But for that, I'll make a new Discussion if you aren't too fast to answer.

  • TwistedTwiglegTwistedTwigleg Posts: 2,831Admin

    @Sosasees said:
    @TwistedTwigleg Thanks very much! Now I've gotten slightly further to fixing my problem.
    But it's not finished yet:

    The Volume Sliders DO now show the accurate volume upon loading a new scene,
    but it's only because the Audio gets muted and the Sliders get reset to Minimum after every time a level gets loaded.

    I still need the Volume to remain between Scene Loadings. But for that, I'll make a new Discussion if you aren't too fast to answer.

    Sounds like something is changing the volume to the minimum. What does the script for loading/changing scenes look like? Also, are you setting the audio level anywhere else? Once the AudioServer has an audio bus volume set, it should retain it unless it is overridden.

    Also: while I understand what you are saying, please don't make the speed of my reply decide whether you make a new discussion or not. Having the discussion here or making a new one is fine, though given it is related to this issue I think this discussion may be better, but regardless please do not make my hastiness or lack thereof be the deciding factor. Thanks :smile:

  • SosaseesSosasees Posts: 104Member
    edited July 14

    @TwistedTwigleg said:
    Sounds like something is changing the volume to the minimum. What does the script for loading/changing scenes look like? Also, are you setting the audio level anywhere else? Once the AudioServer has an audio bus volume set, it should retain it unless it is overridden.
    […]

    As far as I'm aware, nothing is overriding the AudioBus Volumes.
    Before I followed the answer:

    • the Sliders showed the Maximum Volume after each Loading, reguardless of the actual Volume.
    • But the Volumes stayed the same between loadings.
      Only after I applied the answer, the Audio gets silenced after each Loading.

    The're's no One Script for Loading a level.

    This is how the Player Script resets the level:

    [...]
                get_tree().reload_current_scene()
    [...]
    

    This is how the Exit Script loads the Next Level:

    [...]
    export (String, FILE, "*.tscn") var destination #The Next Level
    [...}
                get_tree().change_scene(destination)
    

    @TwistedTwigleg said:
    […]
    Also: while I understand what you are saying, please don't make the speed of my reply decide whether you make a new discussion or not. Having the discussion here or making a new one is fine, though given it is related to this issue I think this discussion may be better, but regardless please do not make my hastiness or lack thereof be the deciding factor. Thanks :smile:

    This sounds like really good forum advice.
    I wanted to make it a new discussion if the reply didn't came already, because I was not sure if it was a good practice to ask related but different questions in the comments of the same question.
    Especially since the forum has a linear comment flow as suppose to starting mini-threads by replying to individual comments.

  • TwistedTwiglegTwistedTwigleg Posts: 2,831Admin
    edited July 15

    Hmm, so it doesn't seem to be caused by the scene changing. In the _ready function, maybe try adding the following print statement and code:

    func _ready():
        var sounds_volume = AudioServer.get_bus_volume_db(AudioServer.get_bus_index("Sounds"))
        var music_volume =  AudioServer.get_bus_volume_db(AudioServer.get_bus_index("Music"))
    
        print ("Sound volume is: ", sounds_volume)
        print ("Music volume is: ", music_volume)
    
        $SoundSlider.value = sounds_volume
        $MusicSlider.value = music_volume
    

    Then you can see if it is the slider value assignment causing the issue, or whether the value being retrieved by the audio server is causing the issue. That should, hopefully, help pin down the issue.

  • SosaseesSosasees Posts: 104Member
    edited July 15

    @TwistedTwigleg said:
    […]
    Then you can see if it is the slider value assignment causing the issue, or whether the value being retrieved by the audio server is causing the issue. That should, hopefully, help pin down the issue.

    I basically already had this code: The only difference is, that the _ready(): print() was missing.

    extends VBoxContainer
    
    func _ready():
        print(AudioServer.get_bus_volume_db(AudioServer.get_bus_index("Sounds")),
        ", ", AudioServer.get_bus_volume_db(AudioServer.get_bus_index("Music"))
        )
    
    func _on_Sound_value_changed(value):
        AudioServer.set_bus_volume_db(
                AudioServer.get_bus_index("Sounds"),
                linear2db(value) )
    
    func _on_Sounds_ready():
        $Sounds/Slider.value = AudioServer.get_bus_volume_db(
            AudioServer.get_bus_index("Sounds") )
        pass
    
    
    func _on_Music_value_changed(value):
        AudioServer.set_bus_volume_db(
                AudioServer.get_bus_index("Music"),
                linear2db(value) )
    
    func _on_Music_ready():
        $Music/Slider.value = AudioServer.get_bus_volume_db(
            AudioServer.get_bus_index("Music") )
        pass
    

    After every Loading, the Console displays One more line of -inf, -inf,
    which corresponds to the Volumes muting to -Infinity after every Loading.

  • TwistedTwiglegTwistedTwigleg Posts: 2,831Admin

    Maybe remove the use of linear2db when setting the volume in the AudioServer and see if that fixes it? From what I can tell, linear2db is for converting a normalized float into a db range, as seen in this Godot engine blog post (which granted, is on the older side).

  • SosaseesSosasees Posts: 104Member
    edited July 16

    @TwistedTwigleg If I remove linear2db, the Volume is permanantly set to Full Volume

  • SosaseesSosasees Posts: 104Member
    edited July 16

    Now I wanted to try saving and retrieving the Volume Slider Values to a ConfigFile,
    but I failed to understand how it works.

  • TwistedTwiglegTwistedTwigleg Posts: 2,831Admin

    @Sosasees said:
    @TwistedTwigleg If I remove linear2db, the Volume is permanantly set to Full Volume

    Hmm, at least we know that is not the issue.

    Now I wanted to try saving and retrieving the Volume Slider Values to a ConfigFile, but I failed to understand how it works.

    The ConfigFile is really interesting and powerful, but unfortunately there is really not a lot of material covering it. That said, something like this should work for saving and loading the audio:

    extends VBoxContainer
    
    const AUDIO_FILEPATH = "user://audio_settings.cfg"
    var config_file
    
    func _ready():
        config_file = ConfigFile.new()
        var error = config_file.load(AUDIO_FILEPATH)
        if err != OK:
            print ("Audio configuration file not found!")
        else:
            print ("Audio configuration file loaded")
    
    func _on_Sound_value_changed(value):
        AudioServer.set_bus_volume_db(
            AudioServer.get_bus_index("Sounds"),
            linear2db(value) )
        # Save the setting and file
        config_file.set_value("audio", "sound_volume", linear2db(value))
        config_file.save(AUDIO_FILEPATH)
    
    
    func _on_Sounds_ready():
        if (config_file.has_section_key("audio", "sound_volume"):
            var volume = config_file.get_value("audio", "sound_volume")
            $Sounds/Slider.value  = volume
        else:
            $Sounds/Slider.value = AudioServer.get_bus_volume_db(
                AudioServer.get_bus_index("Sounds") )
    
    func _on_Music_value_changed(value):
        AudioServer.set_bus_volume_db(
            AudioServer.get_bus_index("Music"),
            linear2db(value) )
        # Save the setting and file
        config_file.set_value("audio", "music_volume", linear2db(value))
        config_file.save(AUDIO_FILEPATH)
    
    func _on_Music_ready():
        if (config_file.has_section_key("audio", "music_volume"):
            var volume = config_file.get_value("audio", "music_volume")
            $Sounds/Slider.value  = volume
        else:
            $Music/Slider.value = AudioServer.get_bus_volume_db(
                AudioServer.get_bus_index("Music") )
        pass
    

    Ideally you'd only save changes once you are about to change scenes, but the code above should at least give an idea about how to go about using a ConfigFile.

  • CalinouCalinou Posts: 451Admin Godot Developer
    edited July 17

    ConfigFile.get_value() accepts an optional 3rd default parameter which will be used if the value can't be found in the file. You can use this to avoid littering your code with if ConfigFile.has_section_key(...) calls.

  • SosaseesSosasees Posts: 104Member
    edited July 18

    @TwistedTwigleg said:
    […]
    The ConfigFile is really interesting and powerful, but unfortunately there is really not a lot of material covering it. That said, something like this should work for saving and loading the audio:

      extends VBoxContainer
      [...]
          pass
    

    This is way too much at once! Could I please get the changes explained step-by-step?

  • TwistedTwiglegTwistedTwigleg Posts: 2,831Admin

    Could I please get the changes explained step-by-step?

    Sure, though I'm just going to explain each chunk instead of step-by-step, as it will be faster and easier to write, and it shouldn't impact the explanation any:

    extends VBoxContainer
    
    const AUDIO_FILEPATH = "user://audio_settings.cfg"
    var config_file
    

    AUDIO_FILEPATH is the filepath we are going to save the config file at. The user:// directory is a special Godot directory that maps to a location on the file system that can be read and written to by Godot. There's a page on the documentation if you are curious about where this file goes, which I can link to later if desired.
    config_file is just a class variable that we'll be using to hold the reference to the ConfigFile, nothing fancy.

    func _ready():
        config_file = ConfigFile.new()
        var error = config_file.load(AUDIO_FILEPATH)
        if error != OK:
            print ("Audio configuration file not found!")
        else:
            print ("Audio configuration file loaded")
    

    First, this function makes a new ConfigFile and assigns it to the config_file variable. Then, we try to load the file at AUDIO_FILEPATH, which is a location where the file will be stored. We assign the returned value of the load function to a variable called error. Then we check to see if error is NOT equal to OK, and this will occur if the file is not found, meaning no configuration has been saved yet. If error is equal to OK, then that means we have successfully loaded the config file.

    func _on_Sound_value_changed(value):
        AudioServer.set_bus_volume_db(
            AudioServer.get_bus_index("Sounds"),
            linear2db(value) )
        # Save the setting and file
        config_file.set_value("audio", "sound_volume", linear2db(value))
        config_file.save(AUDIO_FILEPATH)
    

    Nothing fancy here until the bit after the comment. What we are doing here is storing the new sound volume in the config file, in the section audio with the key sound_volume. This means we can later access this value using the same section and key combo. Finally, we tell the config file to save itself so when we need to load it later, we have up-to-date values.

    func _on_Sounds_ready():
        if (config_file.has_section_key("audio", "sound_volume"):
            var volume = config_file.get_value("audio", "sound_volume")
            $Sounds/Slider.value  = volume
        else:
            $Sounds/Slider.value = AudioServer.get_bus_volume_db(
                AudioServer.get_bus_index("Sounds") )
    
        # New version based on Calinou's suggestion (remove version above if using new version)
        # var volume = config_file.get_value("audio", "sound_volume", AudioServer.get_bus_volume_db(AudioServer.get_bus_index("Sounds")))
        # $Sounds/Slider.value  = volume
    

    First, we check to see if there is a value stored in the section audio with the key sound_volume. If there is, then we get that value from config_file using the get_value function and assign it to a function variable called volume. We then assign the value of the slider to this value.
    If there is NOT a value stored in the section audio with the key sound_volume, then we simply get the volume from the AudioServer like normal.

    However, as @Calinou mentioned, we can simplify this code by taking advantage of the get_value function. The third, optional, argument in the get_value function will be returned if the key does not exist in the config_file. So, we can make this third argument the AudioServer's sound instead, allowing us to use just two lines of code. If the value exists in the config_file, then the new version will return it, while if it does not, the new version will simply return the third argument instead.

    func _on_Music_value_changed(value):
        AudioServer.set_bus_volume_db(
            AudioServer.get_bus_index("Music"),
            linear2db(value) )
        # Save the setting and file
        config_file.set_value("audio", "music_volume", linear2db(value))
        config_file.save(AUDIO_FILEPATH)
    

    Nothing fancy here until the bit after the comment, and its the same as the _on_Sound_value_changed function, just for music.

    func _on_Music_ready():
        if (config_file.has_section_key("audio", "music_volume"):
            var volume = config_file.get_value("audio", "music_volume")
            $Music/Slider.value  = volume
        else:
            $Music/Slider.value = AudioServer.get_bus_volume_db(
                AudioServer.get_bus_index("Music") )
        pass
    
        # New version based on Calinou's suggestion (remove version above if using new version)
        # var volume = config_file.get_value("audio", "music_volume", AudioServer.get_bus_volume_db(AudioServer.get_bus_index("Music")))
        # $Music/Slider.value  = volume
    

    Same thing here: It's the same code as _on_Sound_ready, it's just for music instead of sound. As I mentioned in the note above, you can simplify the code.


    Hopefully that helps explain things a bit!

  • SosaseesSosasees Posts: 104Member

    @TwistedTwigleg @Calinou In both instances of the line
    if (config_file.has_section_key( [...] )):,
    I get an error message upon running the game:

    Invalid call. Nonexistent function 'has_section_key' in base 'Nil'.

  • TwistedTwiglegTwistedTwigleg Posts: 2,831Admin
    edited July 18

    The error message is saying that the config_file variable has not been assigned to anything, that it's nill. Did you include the code in the _ready function?

  • SosaseesSosasees Posts: 104Member

    @TwistegTwigleg Yes, this is the _ready() code:

    func _ready():
        configFile = ConfigFile.new()
        var error = configFile.load(configPath)
        if error != OK:
            print ("Audio configuration file not found!")
        else:
            print ("Audio configuration file loaded")
    
  • SosaseesSosasees Posts: 104Member

    Am I now allowed to advertise the Game Repository?

    I've been trying to avoid advertisment because advertisment is annoying,
    but now I feel like it might be needed.

  • MegalomaniakMegalomaniak Posts: 2,748Admin
    edited July 19

    Not sure what you mean? Sharing your games repo, if you don't mind people getting access to it, is perfectly fine.

    edit: that is to say it is at your own discretion. We don't particularly have rules against advertising things so long as it isn't rather obvious spamming.

  • SosaseesSosasees Posts: 104Member

    @Megalomaniak said:
    Sharing your games repo, if you don't mind people getting access to it, is perfectly fine.

    What if I decide that I want people to have access to my game repository right now, but then I didn't foresee that at least 1 month later, I no longer want to have other people accessing it?

  • MegalomaniakMegalomaniak Posts: 2,748Admin

    Is your repo on github? I think there might be settings to set it to private later? If I'm reading this right, that should be possible:
    https://docs.github.com/en/enterprise/2.13/user/articles/setting-repository-visibility

  • SosaseesSosasees Posts: 104Member
    edited July 20

    @Sosasees said:

    @Megalomaniak said:
    Sharing your games repo, if you don't mind people getting access to it, is perfectly fine.

    What if I decide that I want people to have access to my game repository right now, but then I didn't foresee that at least 1 month later, I no longer want to have other people accessing it?

    @Megalomaniak said:
    Is your repo on github? I think there might be settings to set it to private later? If I'm reading this right, that should be possible:
    https://docs.github.com/en/enterprise/2.13/user/articles/setting-repository-visibility

    I know how to set repositories to private. My question was, if I have to delete all mentions of the Repo when setting the Repo to Private.

  • MegalomaniakMegalomaniak Posts: 2,748Admin

    If the repo is private then the links to it shouldn't be a problem I'd imagine. This is a forum, over time links are bound to be broken. That's just natural, sad as it may sometimes be.

  • SosaseesSosasees Posts: 104Member

    @Megalomaniak said:
    If the repo is private then the links to it shouldn't be a problem I'd imagine. This is a forum, over time links are bound to be broken. That's just natural, sad as it may sometimes be.

    This is really helpful!
    I don't plan to private the Game Repository anytime soon, but I still asked, just to be safe.

  • SosaseesSosasees Posts: 104Member

    This is the Game Repository: https://www.github.com/sosasees/flinkimaus

    This is the issue which is relevant to fixing the Volume Sliders: https://github.com/sosasees/flinkimaus/issues/28

  • SosaseesSosasees Posts: 104Member
    edited July 22

    Now I fixed the problem described in the Title and Root Comment.

    I still need help keeping the Volumes between Scenes.
    I have made variables for the Sliders (soundVol, musicVol),
    but I need to keep them between scenes.

    Mostly, anything that works will suffice. I already tried making a ConfigFile, but it doesn't work because of the error

    Invalid call. Nonexistent function 'has_section_key' in base 'Nil'.


    Not to sound very harsh and angry, but: Now I hope that you know why I wanted to make this a separate discussion: Now it takes up the majority of a discussion with a completely unrelated Title and Root Comment.

    Actually, I think i WILL continue it in a new discussion.
    EDIT: This link leads to the new discussion

  • TwistedTwiglegTwistedTwigleg Posts: 2,831Admin
    edited July 22

    @Sosasees said:
    Not to sound very harsh and angry, but: Now I hope that you know why I wanted to make this a separate discussion: Now it takes up the majority of a discussion with a completely unrelated Title and Root Comment.

    Actually, I think i WILL continue it in a new discussion.
    EDIT: This link leads to the new discussion

    That’s fair, I have no issue with new discussions. The only thing I had an issue with previously (in this thread) about making new discussions in this thread was making the timeliness of my reply being the deciding factor, not necessarily making a new thread. If you think it warrant’s a new discussion, then that’s fine. As I mentioned in that reply:

    Having the discussion here or making a new one is fine, though given it is related to this issue I think this discussion may be better, but regardless please do not make my hastiness or lack thereof be the deciding factor.

    So, it’s all good :smile:

Leave a Comment

BoldItalicStrikethroughOrdered listUnordered list
Emoji
Image
Align leftAlign centerAlign rightToggle HTML viewToggle full pageToggle lights
Drop image/file