Skip to content
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

Implement custom sounds #341

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open

Implement custom sounds #341

wants to merge 7 commits into from

Conversation

nc7s
Copy link
Contributor

@nc7s nc7s commented Mar 9, 2025

Resolves #337.

Each commit is self contained (hopefully) and comes with explanation in its message (mostly). But to sum it up, notable changes are

  • A new [sound.collection] config section to specify custom sounds, which can be used as play-sound(name=custom-name); section name could be adjusted
  • A default-sounds feature to allow removing, well, default sounds
  • play-sound(path=...) for "one-off" settings

for (name, path) in collection {
// TODO: Do we really want to panic here? Or should it be
// silenced?
crate::sound::play_sound::add_sound(name, path).unwrap();
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why would we want to have a panic ? That's not how bacon should behave

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, hence the TODO.

Do we silence it, or warn about it? If warn, where should the warning go?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahem. Do you think bacon should warn about sounds that failed to load?

nc7s added 6 commits April 1, 2025 01:16
To allow custom sounds, we need a mutable sound list. This is achieved
through an once_cell::Lazy<RwLock<HashMap<&str, Sound>>>. It's a global
static because the sound list is basically global in each run. RwLock is
suitable for our situation where writes are rare and reads are often.
HashMap is to ease retrieving sounds by name.

Names and bytes are leaked because they are basically static in each
run.
With custom sounds, users might want to reduce executable size by
removing the default sounds. Make them an optional feature.
With custom sounds, there's no way to know their durations beforehand,
like for default sounds. rodio has the `Source::total_duration()` trait
method, which is implemented on its `Decoder`, so that is used. But it
returns an `Option<Duration>`, i.e. reading is not guaranteed. Thus we
ignore the interrupt for such sounds, for now.
@nc7s
Copy link
Contributor Author

nc7s commented Mar 31, 2025

Hmm, I seem to have mistakenly assumed it's OK to only listen for interrupt if the duration is known. The sound is then not played at all, not yet sure why.

But instead of trying to "fix" acquiring duration, I think it's reasonable to just set a maximum duration: it's a notification sound, after all, it shouldn't last longer than a few seconds.

@c-git
Copy link
Contributor

c-git commented Mar 31, 2025

Hmm, I seem to have mistakenly assumed it's OK to only listen for interrupt if the duration is known. The sound is then not played at all, not yet sure why.

But instead of trying to "fix" acquiring duration, I think it's reasonable to just set a maximum duration: it's a notification sound, after all, it shouldn't last longer than a few seconds.

I use the default sounds and have no issue but when I used to do custom sounds (in the previous framework I used when I was using python) they were several seconds long. It was actually an audio report of the outcome. It would tell me if it passed or failed and the error count. I know the sounds won't be doing that but just pointing out that if we allow custom duration is not necessarily safe to assume it will be short. I haven't had time to look at the code myself. Is it possible to send to a separate thread or something like that if it's blocking something else so the user can choose any sound they like? If it's too complicated maybe it's not worth it but I just wanted to point out that I don't think it's a safe assumption. Alternatively we could ask the use for a max duration to play from the sound. Maybe it's their favourite song and they don't want to crate a cropped version but they don't actually want the whole 5 minutes.

@nc7s
Copy link
Contributor Author

nc7s commented Apr 1, 2025

Alternatively we could ask the use for a max duration to play from the sound.

Sure could do, add an option duration to [sound.collection] entries and maybe the play-sound action.

Maybe it's their favourite song and they don't want to crate a cropped version but they don't actually want the whole 5 minutes.

Agreed, which is basically the source of my idea of a default duration/cutoff. But then again,

not necessarily safe to assume it will be short

It's a notification sound, when a job is done - there is a reason why the pre-picked sounds are short, with the longest being 2 seconds (2, success) and the shortest being 0.25 seconds (store-scanner-beep), and the longer ones mostly just have some hardly audible fade-in and -out. Notifications happen a lot. A lot. Sounds gonna overlap if long yet not cut off. There's gonna be cutoff anyway, so why not set a "standard" one? Ability to set custom duration could be offered if the user feel like it, as said above.

.. But this all comes from the lack of assured ability to measure duration. It's baffling symphonia couldn't. I'm experimenting with it to see if this can be fixed. Could even go as far as suggesting to replace mp3 with ogg - mp3 is not an open format, even if its patents expired; compared, ogg (container) and vorbis/opus (audio stream) are open formats. Still, being able to set the duration for a sound seems useful.

@nc7s
Copy link
Contributor Author

nc7s commented Apr 1, 2025

The culprit of rodio being unable to read duration should be RustAudio/rodio#696, fixed in RustAudio/rodio#697, merged early last month. I've asked if they could release it to avoid a git+rev dependency.

@nc7s
Copy link
Contributor Author

nc7s commented Apr 1, 2025

FWIW, if we are to not disturb the user listening to some music, duration.unwrap_or(Duration::MAX) would allow playing something with the duration up to practically infinity. It could even be used to get rid of the duration field of embedded sounds.

@c-git
Copy link
Contributor

c-git commented Apr 1, 2025

I wouldn't over index on it. I might be the only person who sets long running tasks in bacon and wants a longer sound.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Custom sounds
3 participants