Toggle Music On/Off From UI Widget

Hey all,

I am trying to set up a toggle music on/off button in my UI widget.
I’m initiating the sound file in my PlayerController.
I would like to be able to Toggle the volume on/off from my widget. And the music should only play while the widget is active. When I remove the widget from parent I would like to make sure the music stops.

Here’s my set up so far:

In PlayerController I’m adding the wav file as an audio component. I created a function and execute it after adding the widget.
This part works as intended:

Function:

My UI widget loads first and the music starts playing.

In my UI widget I cast to Player Controller and try to call that function.
When I click the button, instead of stopping the music, it seems to start from the beginning overlapping over and over on each click starting from the beginning of the track.

This is how I’m calling the function from the widget EG:

What am I doing wrong? How is this usually done? I only want the music to be playable if the widget is active. (And the user chooses not to disable it :slight_smile: )

Any tips are greatly appreciated

dont use flip flop.

instead, set a boolean for when music is active. The toggle can then just be NOT bMusicPlaying = bMusicPlaying

image
(this just makes the boolean opposite of whatever it is, and then stores that)

the problem with flip flop, especially on a widget, is that it does not remember its own state. so if widget is removed or constructed a new one or whatever, the flip-flop may not actually be toggling. Whereas the boolean on the player controller is cached, so it holds its state in memory.

to make debug easy you can right click on the boolean and set Watch This value. Then slide the blueprint onto second monitor or whereever you can see it while in play mode and then press the widget buttons. You should see the value changing in real time. You can do the same thing with the flip flop node. The execution wires will highlight when they fire. This will help you see what is actually happening.

Am I doing something wrong???

It’s doing the same thing…

watch the execution wires light up when you press the button though.

You’ll see that the execution flow goes through the boolean, sets it, then… Adds audio component.

So the boolean is getting changed. Watch the value and you will see that with your own eyes.

But, what is not happening is that you aren’t doing anything with the boolean yet! Lol.

So you need to put it to use.

The way to do that is make a Branch node after setting the boolean. The branch node will act like how you had the flip flop. The boolean goes into the branch as the input, and from the True you can set the audio component, and from false you disable it.

This will act the same way as you had before, except that it will always work, even if you destroy the widget or call the function from somewhere else.

1 Like

Fair enough… What do I need to do on the False branch? Is there a node that removes the audio component?
As of right now I have the same add audio component with the volume set to 0. But that still gives me the same issue.
I do not have an option on right click to Watch This value for the boolean :frowning:

Since you already have access to the widget here, why not:

Assuming you’re using a button or some other control, this way you’d need no script in the widget, and no casting.

1 Like

Tried that as well. On the False branch, how do I tell it to stop???

I tried this:

still not working. The music starts as off. If I click the button it turns on, but then it keeps overlapping from the beginning on subsequent clicks

Not sure how you really want it to work, but you’re not even using the boolean value… you just ticked a Branch to be True. Consider the following:

Also, is there a reason to create a new component every time? Maybe create it once and then the widget can just pause and unpause it. Why waste resources.

in the function you had originally, on the B branch of the flip flop, you took the reference to the music and called Stop on it.

You can do the same thing from the False branch. So the only change to your original code is to replace flip flop with a boolean and branch.

1 Like

and here is a more “complete” version with some safety checks:

to make the Get Is Valid Is / Not Valid, right click on the Get Music node, like this:

how to “watch this value” :

you can also debug with print string as well:

1 Like

@BIGTIMEMASTER

Ok, I’m either an idiot… or… a bigger idiot.
I can’t figure out what’s wrong for the life of me.

Here’s my full setup:
PlayerController begin play → at the end, after creating the MainMenu widget I add the ToggleMusic function (which is built in the PlayerController)

The ToggleMusic function:

In the MainMenu EG:

Nothing works. It’s like that button never gets triggered. No sound at all. WTF???

Ok, ok, ok… I am a big idiot…

I had the Music Playing bool set to True initially. That messed it all up.
It’s all working fine now. :slight_smile:

@BIGTIMEMASTER

Well then… this gave me an idea… if I want to add a slider in the widget to control the volume… is there a node I could add in the PlayerController to update the value of the slider and plug it into a volume pin? I’m thinking a float between 0 and 1??? something along those lines? This is just extra, but why not? (if possible)

you can access the sounds volume by dragging of the Music reference and type Volume. Should be a Setter function for that.

As for using a slider, unreal has some built in slider widgets I believe, but I haven’t used them.

What the slider will do is output a 0-1 value though, and you can then use that to adjust your music volume. You may need to use a Map Ranged Clamped node to set the range of volume that you want 0-1 to cover.

Not sure why you pass this stuff back to the player controller though? It’s all stuff that is only associated with the UI menu isn’t it?

1 Like

Same as before:

Using dispatchers for this is by far the most efficient method. As mentioned above (and before), there’s no need to get the PC involved here at all.

Good luck!

It is. I couldn’t find any other way to make it work… that is the only reason I was passing it to the PC.

So, should I move everything in the Widget EG? And that way I don’t need to cast to PC at all? Just keep all the code there?

I’m sorry, still a big noob trying to figure best practices out.

You do not need any code in the widget. Everything is in the pic.

Callback delegates are the bread & butter of comms. This sounds like the perfect use-case scenario. Keep your script as is, but add the slider onValueChanged and adjust the volume (stuff in the red frame) - see if it works.


oh yeah i hadnt really looked into the details of where all the code is happening or why.

but what everynone is showing here is probably the simplest thing to do because it has fewest moving parts (less chance to make mistakes and get confused)

Wait, I’m losing you… Isn’t this done in the PC EG? You said I should not get the PC involved at all???

You could do it all in here. We don’t know what blueprints it is, not sure if you mentioned that. You add the component here, you create the widget here. All the puzzle pieces are here.

The widget communicates back to this blueprints via delegates - the red wires.

At this point it’s up to you if you need to get the PC involved. Does it need to know anything about this stuff?