-
-
Notifications
You must be signed in to change notification settings - Fork 3.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add ability to mute audio sinks #16813
Conversation
0821fe6
to
fc22fa2
Compare
Changes like this definitely shouldn't be blocked on the Better Audio work :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I really like this! This packs quite a lot of punch for such a small change, and I like the design!
I've left a few nitpicks, but otherwise LGTM!
Co-authored-by: Nathan Graule <[email protected]>
- There is no output device in CI for this test to pass. - There is no equivalent `SpatialSink::new_idle` in rodio. - For now it's probably best to just rely on unit tests for `AudioSink` and code review for `SpatialAudioSink`. - Might be able to see if a `SpatialSink::try_new_idle` could be added to rodio, but that's for another change.
What's the reasoning for edit: reworded |
Since there's no native support for sink muting in rodio, this is like the least complex alternative to me. Since if we set the sink output to zero, we lose the original volume, we then have to store it somewhere. The |
I get the need to store it separately, just unclear on |
Ah I didn't get your original question then. |
I feel like "managed volume being volume: f32
muted: bool IMO, "the volume the user wants when the sink is unmuted" is conceptually not a temporary thing. But that detail is hidden from users, so not something I feel the need to fuss over. 👍 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems like PlaybackSettings
should get a corresponding muted
field so that AudioPlayer
can be spawned in a muted state.
Right now, if an app author wanted to, for example, persist and restore a user's "muted" preference, implementing that would be tricky for them.
@rparrett thanks for the review and suggestion to update Re:
The volume the user wants when the sink is unmuted is whatever is returned from I feel the Supposing we used two fields for this per your suggestion, then if we're unmuted, we're unnecessarily tracking the volume in our own |
# Objective - #16813 added the ability to mute sinks and added a new method `toggle_mute()`. - Leaving `toggle()` as is creates inconsistency and a bit of confusion about what is being toggled. ## Solution - Rename `toggle()` to `toggle_playback()`. - The choice to use the `_playback` suffix was easy because the method comment was already telling us what is being toggled: `Toggles playback of the sink.` - [Raised in Discord] and got the OK from Alice. [Raised in Discord]: https://discord.com/channels/691052431525675048/749430447326625812/1318000355824504905 ## Testing - I ran the example and also updated the instruction text to make it clear `Space` is toggling the playback not just pausing. - I added a unit test for `toggle_playback()` because why not. --- ## Showcase Example instructions: <img width="292" alt="image" src="https://github.com/user-attachments/assets/585c36c6-c4d7-428b-acbe-a92f3a37b460" /> ## Migration Guide - `AudioSinkPlayback`'s `toggle` method has been renamed to `toggle_playback`. This was done to create consistency with the `toggle_mute` method added in #16813. Change instances of `toggle` to `toggle_playback`. E.g.: Before: ```rust fn pause(keyboard_input: Res<ButtonInput<KeyCode>>, sink: Single<&AudioSink>) { if keyboard_input.just_pressed(KeyCode::Space) { sink.toggle(); } } ``` After: ```rust fn pause(keyboard_input: Res<ButtonInput<KeyCode>>, sink: Single<&AudioSink>) { if keyboard_input.just_pressed(KeyCode::Space) { sink.toggle_playback(); } } ```
# Objective - Allow users to mute audio. ```rust fn mute( keyboard_input: Res<ButtonInput<KeyCode>>, mut sink: Single<&mut AudioSink, With<MyMusic>>, ) { if keyboard_input.just_pressed(KeyCode::KeyM) { sink.toggle_mute(); } } ``` - I want to be able to press, say, `M` and mute all my audio. I want this for dev, but I'm sure it's a useful player setting as well. - Muting is different to pausing—I don't want to pause my sounds, I want them to keep playing but with no volume. For example if I have background music playing which is made up of 5 tracks, I want to be able to temporarily mute my background music, and if I unmute at, say, track 4, I want to play track 4 rather than have had everything paused and still be on the first track. - I want to be able to continue to control the volume of my audio even when muted. Like in the example, if I have muted my audio but I use the volume up/down controls, I want Bevy to remember those volume changes so that when I unmute, the volume corresponds to that. ## Solution - Add methods to audio to allow muting, unmuting and toggling muting. - To preserve the user's intended volume, each sink needs to keep track of a "managed volume". - I checked `rodio` and I don't see any built in support for doing this, so I added it to `bevy_audio`. - I'm interested to hear if this is a good idea or a bad idea. To me, this API looks nice and looks usable, but I'm aware it involves some changes to the existing API and now also requires mutable access in some places compared to before. - I'm also aware of work on *Better Audio*, but I'm hoping that if this change isn't too wild it might be a useful addition considering we don't really know when we'll eventually get better audio. ## Testing - Update and run the example: `cargo run --example audio_control` - Run the example: `cargo run --example soundtrack` - Update and run the example: `cargo run --example spatial_audio_3d` - Add unit tests. --- ## Showcase See 2 changed examples that show how you can mute an audio sink and a spatial audio sink. ## Migration Guide - The `AudioSinkPlayback` trait now has 4 new methods to allow you to mute audio sinks: `is_muted`, `mute`, `unmute` and `toggle_mute`. You can use these methods on `bevy_audio`'s `AudioSink` and `SpatialAudioSink` components to manage the sink's mute state. - `AudioSinkPlayback`'s `set_volume` method now takes a mutable reference instead of an immutable one. Update your code which calls `set_volume` on `AudioSink` and `SpatialAudioSink` components to take a mutable reference. E.g.: Before: ```rust fn increase_volume(sink: Single<&AudioSink>) { sink.set_volume(sink.volume() + 0.1); } ``` After: ```rust fn increase_volume(mut sink: Single<&mut AudioSink>) { let current_volume = sink.volume(); sink.set_volume(current_volume + 0.1); } ``` - The `PlaybackSettings` component now has a `muted` field which you can use to spawn your audio in a muted state. `PlaybackSettings` also now has a helper method `muted` which you can use when building the component. E.g.: ```rust commands.spawn(( // ... AudioPlayer::new(asset_server.load("sounds/Windless Slopes.ogg")), PlaybackSettings::LOOP.with_spatial(true).muted(), )); ``` --------- Co-authored-by: Nathan Graule <[email protected]>
# Objective - bevyengine#16813 added the ability to mute sinks and added a new method `toggle_mute()`. - Leaving `toggle()` as is creates inconsistency and a bit of confusion about what is being toggled. ## Solution - Rename `toggle()` to `toggle_playback()`. - The choice to use the `_playback` suffix was easy because the method comment was already telling us what is being toggled: `Toggles playback of the sink.` - [Raised in Discord] and got the OK from Alice. [Raised in Discord]: https://discord.com/channels/691052431525675048/749430447326625812/1318000355824504905 ## Testing - I ran the example and also updated the instruction text to make it clear `Space` is toggling the playback not just pausing. - I added a unit test for `toggle_playback()` because why not. --- ## Showcase Example instructions: <img width="292" alt="image" src="https://github.com/user-attachments/assets/585c36c6-c4d7-428b-acbe-a92f3a37b460" /> ## Migration Guide - `AudioSinkPlayback`'s `toggle` method has been renamed to `toggle_playback`. This was done to create consistency with the `toggle_mute` method added in bevyengine#16813. Change instances of `toggle` to `toggle_playback`. E.g.: Before: ```rust fn pause(keyboard_input: Res<ButtonInput<KeyCode>>, sink: Single<&AudioSink>) { if keyboard_input.just_pressed(KeyCode::Space) { sink.toggle(); } } ``` After: ```rust fn pause(keyboard_input: Res<ButtonInput<KeyCode>>, sink: Single<&AudioSink>) { if keyboard_input.just_pressed(KeyCode::Space) { sink.toggle_playback(); } } ```
# Objective - Allow users to mute audio. ```rust fn mute( keyboard_input: Res<ButtonInput<KeyCode>>, mut sink: Single<&mut AudioSink, With<MyMusic>>, ) { if keyboard_input.just_pressed(KeyCode::KeyM) { sink.toggle_mute(); } } ``` - I want to be able to press, say, `M` and mute all my audio. I want this for dev, but I'm sure it's a useful player setting as well. - Muting is different to pausing—I don't want to pause my sounds, I want them to keep playing but with no volume. For example if I have background music playing which is made up of 5 tracks, I want to be able to temporarily mute my background music, and if I unmute at, say, track 4, I want to play track 4 rather than have had everything paused and still be on the first track. - I want to be able to continue to control the volume of my audio even when muted. Like in the example, if I have muted my audio but I use the volume up/down controls, I want Bevy to remember those volume changes so that when I unmute, the volume corresponds to that. ## Solution - Add methods to audio to allow muting, unmuting and toggling muting. - To preserve the user's intended volume, each sink needs to keep track of a "managed volume". - I checked `rodio` and I don't see any built in support for doing this, so I added it to `bevy_audio`. - I'm interested to hear if this is a good idea or a bad idea. To me, this API looks nice and looks usable, but I'm aware it involves some changes to the existing API and now also requires mutable access in some places compared to before. - I'm also aware of work on *Better Audio*, but I'm hoping that if this change isn't too wild it might be a useful addition considering we don't really know when we'll eventually get better audio. ## Testing - Update and run the example: `cargo run --example audio_control` - Run the example: `cargo run --example soundtrack` - Update and run the example: `cargo run --example spatial_audio_3d` - Add unit tests. --- ## Showcase See 2 changed examples that show how you can mute an audio sink and a spatial audio sink. ## Migration Guide - The `AudioSinkPlayback` trait now has 4 new methods to allow you to mute audio sinks: `is_muted`, `mute`, `unmute` and `toggle_mute`. You can use these methods on `bevy_audio`'s `AudioSink` and `SpatialAudioSink` components to manage the sink's mute state. - `AudioSinkPlayback`'s `set_volume` method now takes a mutable reference instead of an immutable one. Update your code which calls `set_volume` on `AudioSink` and `SpatialAudioSink` components to take a mutable reference. E.g.: Before: ```rust fn increase_volume(sink: Single<&AudioSink>) { sink.set_volume(sink.volume() + 0.1); } ``` After: ```rust fn increase_volume(mut sink: Single<&mut AudioSink>) { let current_volume = sink.volume(); sink.set_volume(current_volume + 0.1); } ``` - The `PlaybackSettings` component now has a `muted` field which you can use to spawn your audio in a muted state. `PlaybackSettings` also now has a helper method `muted` which you can use when building the component. E.g.: ```rust commands.spawn(( // ... AudioPlayer::new(asset_server.load("sounds/Windless Slopes.ogg")), PlaybackSettings::LOOP.with_spatial(true).muted(), )); ``` --------- Co-authored-by: Nathan Graule <[email protected]>
# Objective - bevyengine#16813 added the ability to mute sinks and added a new method `toggle_mute()`. - Leaving `toggle()` as is creates inconsistency and a bit of confusion about what is being toggled. ## Solution - Rename `toggle()` to `toggle_playback()`. - The choice to use the `_playback` suffix was easy because the method comment was already telling us what is being toggled: `Toggles playback of the sink.` - [Raised in Discord] and got the OK from Alice. [Raised in Discord]: https://discord.com/channels/691052431525675048/749430447326625812/1318000355824504905 ## Testing - I ran the example and also updated the instruction text to make it clear `Space` is toggling the playback not just pausing. - I added a unit test for `toggle_playback()` because why not. --- ## Showcase Example instructions: <img width="292" alt="image" src="https://github.com/user-attachments/assets/585c36c6-c4d7-428b-acbe-a92f3a37b460" /> ## Migration Guide - `AudioSinkPlayback`'s `toggle` method has been renamed to `toggle_playback`. This was done to create consistency with the `toggle_mute` method added in bevyengine#16813. Change instances of `toggle` to `toggle_playback`. E.g.: Before: ```rust fn pause(keyboard_input: Res<ButtonInput<KeyCode>>, sink: Single<&AudioSink>) { if keyboard_input.just_pressed(KeyCode::Space) { sink.toggle(); } } ``` After: ```rust fn pause(keyboard_input: Res<ButtonInput<KeyCode>>, sink: Single<&AudioSink>) { if keyboard_input.just_pressed(KeyCode::Space) { sink.toggle_playback(); } } ```
Objective
M
and mute all my audio. I want this for dev, but I'm sure it's a useful player setting as well.Solution
rodio
and I don't see any built in support for doing this, so I added it tobevy_audio
.Testing
cargo run --example audio_control
cargo run --example soundtrack
cargo run --example spatial_audio_3d
Showcase
See 2 changed examples that show how you can mute an audio sink and a spatial audio sink.
Migration Guide
AudioSinkPlayback
trait now has 4 new methods to allow you to mute audio sinks:is_muted
,mute
,unmute
andtoggle_mute
. You can use these methods onbevy_audio
'sAudioSink
andSpatialAudioSink
components to manage the sink's mute state.AudioSinkPlayback
'sset_volume
method now takes a mutable reference instead of an immutable one. Update your code which callsset_volume
onAudioSink
andSpatialAudioSink
components to take a mutable reference. E.g.:Before:
After:
PlaybackSettings
component now has amuted
field which you can use to spawn your audio in a muted state.PlaybackSettings
also now has a helper methodmuted
which you can use when building the component. E.g.: