How to make a master volume slider? [SOLVED]

Discuss how to use the Ren'Py engine to create visual novels and story-based games. New releases are announced in this section.
Forum rules
This is the right place for Ren'Py help. Please ask one question per thread, use a descriptive subject like 'NotFound error in option.rpy' , and include all the relevant information - especially any relevant code and traceback messages. Use the code tag to format scripts.
Post Reply
Message
Author
Desertopa
Regular
Posts: 28
Joined: Fri Aug 30, 2019 7:14 pm
Contact:

How to make a master volume slider? [SOLVED]

#1 Post by Desertopa »

I've looked around for info on this, but haven't found anything applicable in the documentation, but I feel like it must be doable. Does anyone know how to create a working master volume slider in Ren'Py? One separate from the music, SFX and voice sliders, which adjusts the baseline for all the volume channels.

As far as I can recall, most commercial VNs I've played have a master volume slider, but I'm not clear on how to implement one given that Ren'Py doesn't include it as a default function.
Last edited by Desertopa on Wed Dec 02, 2020 10:53 am, edited 1 time in total.

User avatar
hell_oh_world
Miko-Class Veteran
Posts: 777
Joined: Fri Jul 12, 2019 5:21 am
Contact:

Re: How to make a master volume slider?

#2 Post by hell_oh_world »

I guess you just combine the other channels.

Code: Select all

bar:
  action [Preference("music volume"), Preference("sound volume"), Preference("voice volume")]

Desertopa
Regular
Posts: 28
Joined: Fri Aug 30, 2019 7:14 pm
Contact:

Re: How to make a master volume slider?

#3 Post by Desertopa »

If I'm understanding what you're suggesting, this would create a slider which would simultaneously adjust all the other sliders, but what I'm looking to implement is a slider which acts as a multiplier to all the other sliders, so it adjusts the volume of all the channels up and down in the same proportion, while the other sliders can be used to adjust them relative to each other.

User avatar
hell_oh_world
Miko-Class Veteran
Posts: 777
Joined: Fri Jul 12, 2019 5:21 am
Contact:

Re: How to make a master volume slider?

#4 Post by hell_oh_world »

Okay, sorry, I realized that my answer is entirely wrong. Guess I should not answer questions first thing in the morning. Anyways, this one is working.

Code: Select all

default persistent.master_volume = 0.0

init python:
    def MasterVolumeValue():
        return FieldValue(persistent, "master_volume", 1.0, action=Function(_changeVolumes))

    def _changeVolumes():
        renpy.run(
            [
                Preference("music volume", persistent.master_volume),
                Preference("sound volume", persistent.master_volume),
                Preference("voice volume", persistent.master_volume)
            ]
        )

screen something:
  bar:
    value MasterVolumeValue()
EDIT
but what I'm looking to implement is a slider which acts as a multiplier to all the other sliders, so it adjusts the volume of all the channels up and down in the same proportion, while the other sliders can be used to adjust them relative to each other.
Eh... Not sure if I'm getting it right, but what you want actually requires to get the current volume of each channel and multiply it with a multiplier? no? That would be tricky imo.
If the volume is involved, you can probably use renpy.game.preferences.volumes.get("name_of_mixer") to get the volume of the channel.
ANOTHER EDIT
Okay, tried to find a workaround, here's what I got.

Code: Select all

default persistent.master_volume = 1.0

# add here the mixers that you want to be controlled and give them a starting value, sfx = sound
default persistent.last_volumes = dict(
    music=1.0, sfx=1.0, voice=1.0
)

# if you want to set them by default to the current value of the mixer do below.
# init 3000:
#   default persistent.last_volumes = dict(
#       music=preferences.volumes.get("music", 0.0),
#       sfx=preferences.volumes.get("sfx", 0.0),
#       voice=preferences.volumes.get("voice", 0.0),
#   )
# or
#   default persistent.last_volumes = preferences.volumes.copy()

init python:
    def MasterVolumeValue():
        return FieldValue(persistent, "master_volume", 1.0, action=Function(_changeVolumes))

    def VolumeValue(mixer):
        volumes = preferences.volumes
        return DictValue(volumes, mixer, 1.0, action=SetDict(persistent.last_volumes, mixer, volumes.get(mixer)))

    def _changeVolume(mixer):
        factor = persistent.master_volume

        volume = persistent.last_volumes[mixer]
        volume = max(min(volume * factor, 1.0), 0.0)

        renpy.run(SetMixer("{}".format(mixer), volume))

    def _changeVolumes():
        for volume in persistent.last_volumes:
          _changeVolume(volume)
then in your bars that adjust the music, sfx, voice, or any other mixers, you'll just use the bar value VolumeValue(mixer_name) instead of the Preference("mixer_name volume") value. this one is important, as the value object stores the last volume.

Code: Select all

vbox:
  text "Music Volume"
  bar:
    value VolumeValue("music")
    
vbox:
  text "Sound Volume"
  bar:
    value VolumeValue("sfx")
    
vbox:
  text "Voice Volume"
  bar:
    value VolumeValue("voice")
then like in my previous example, you'll just have to use the MasterVolumeValue() value in your bar that controls the master_volume.
One thing to note though, I observed, that this works if the bar is dragged and released, just clicking the bar to change the slider won't work. I'm guessing that this would require additional work with the adjustment object/bar value of the bar, but I don't know, might try to find some workaround though.
LAST EDIT (HOPEFULLY)

Code: Select all

init python:
    class VolumeValue(DictValue):
        def __init__(self, mixer, *args, **kwargs):
            DictValue.__init__(self, preferences.volumes, mixer, 1.0, *args, **kwargs)

            self.mixer = mixer

        def changed(self, value):
            DictValue.changed(self, value)
            persistent.last_volumes[self.mixer] = value
just replace the VolumeValue function in my example with this one.

Desertopa
Regular
Posts: 28
Joined: Fri Aug 30, 2019 7:14 pm
Contact:

Re: How to make a master volume slider?

#5 Post by Desertopa »

Sorry for the slow reply, I was having trouble implementing this myself, but a friend of mine was able to successfully troubleshoot it and get it working, so I can confirm that this did work.

Thailandian
Regular
Posts: 30
Joined: Tue Jun 01, 2021 6:24 am
Contact:

Re: How to make a master volume slider? [SOLVED]

#6 Post by Thailandian »

For anyone else coming to this thread late, there is a much easier way to do this, via a rather arcane function:
renpy.music.set_volume(volume, delay=0, channel=u'music') link, which "Sets the volume of this channel, as a fraction of the volume of the mixer controlling the channel." There is also an alias for "sound" but none for "voice" - go figure!

So to make your master volume control, you only need to define one persistent variable in options.rpy:

Code: Select all

define persistent.audio_master = 1.0
Then the function:

Code: Select all

init python:
  def setVolumes():
      pam = persistent.audio_master
      renpy.music.set_volume(pam)
      renpy.sound.set_volume(pam)
      renpy.music.set_volume(pam, channel="voice") #because there is no renpy.voice.set_volume function with a default channel
And finally, call the function via an action in the bar or vbar code.

Code: Select all

vbar value FieldValue(persistent, "audio_master", range=1.0, style="slider", action=setVolumes)
According to the documentation, this action is called " when the field has changed" so no need for special code to repeatedly call the function as the slider moves.

When I first started out trying to make a master volume control, I was surprised that it was so difficult and that there wasn't a built-in function to perform it. Turns out there is one, but as usual, it's hidden away in the weeds :roll:

lewishunter
Newbie
Posts: 13
Joined: Sun Aug 01, 2021 8:06 pm
Contact:

Re: How to make a master volume slider? [SOLVED]

#7 Post by lewishunter »

Still buggy.

The last code posted indeed works but the volume resets to 1.0 when reloading the game or returning to the main menu from the game. And I also found it not working when quickly clicking a button (it makes the button sound even if the vol its 0).

Would be nice a clean master volume.

Thailandian
Regular
Posts: 30
Joined: Tue Jun 01, 2021 6:24 am
Contact:

Re: How to make a master volume slider? [SOLVED]

#8 Post by Thailandian »

Yes I have been trying to find a way to assign these values during init without success.

Best idea I've come up with so far is to write an alternative play function that includes a call to setVolumes.

I'm guessing, since renpy.music.set_volume seems to have no equivalent screen or standard renpy functions, that this is still a work in progress so hopefully will be more developed in future versions.

Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot], Google [Bot]