Code Monkey home page Code Monkey logo

kira's Introduction

Kira

Kira is a backend-agnostic library to create expressive audio for games. It provides tweens for smoothly adjusting properties of sounds, a flexible mixer for applying effects to audio, a clock system for precisely timing audio events, and spatial audio support.

Examples

Playing a sound multiple times simultaneously:

use kira::{
	manager::{
		AudioManager, AudioManagerSettings,
		backend::DefaultBackend,
	},
	sound::static_sound::StaticSoundData,
};

// Create an audio manager. This plays sounds and manages resources.
let mut manager = AudioManager::<DefaultBackend>::new(AudioManagerSettings::default())?;
let sound_data = StaticSoundData::from_file("sound.ogg")?;
manager.play(sound_data.clone())?;
// After a couple seconds...
manager.play(sound_data.clone())?;
// Cloning the sound data will not use any extra memory.

Gradually speeding up a sound over time:

use std::time::Duration;

use kira::{
	manager::{
		AudioManager, AudioManagerSettings,
		backend::DefaultBackend,
	},
	sound::static_sound::StaticSoundData,
	tween::Tween,
};

let mut manager = AudioManager::<DefaultBackend>::new(AudioManagerSettings::default())?;
let sound_data = StaticSoundData::from_file("sound.ogg")?;
let mut sound = manager.play(sound_data)?;
// Start smoothly adjusting the playback rate parameter.
sound.set_playback_rate(
	2.0,
	Tween {
		duration: Duration::from_secs(3),
		..Default::default()
	},
);

Playing a sound with a low-pass filter applied (this makes the audio sound muffled):

use kira::{
	manager::{
		AudioManager, AudioManagerSettings,
		backend::DefaultBackend,
	},
	sound::static_sound::StaticSoundData,
	track::{
		TrackBuilder,
		effect::filter::FilterBuilder,
	},
};

let mut manager = AudioManager::<DefaultBackend>::new(AudioManagerSettings::default())?;
// Create a mixer sub-track with a filter.
let track = manager.add_sub_track({
	let mut builder = TrackBuilder::new();
	builder.add_effect(FilterBuilder::new().cutoff(1000.0));
	builder
})?;
// Play the sound on the track.
let sound_data = StaticSoundData::from_file("sound.ogg")?.output_destination(&track);
manager.play(sound_data)?;

Playing sounds in time with a musical beat:

use kira::{
	manager::{
		AudioManager, AudioManagerSettings,
		backend::DefaultBackend,
	},
	sound::static_sound::StaticSoundData,
	clock::ClockSpeed,
};

const TEMPO: f64 = 120.0;

let mut manager = AudioManager::<DefaultBackend>::new(AudioManagerSettings::default())?;
// Create a clock that ticks 120 times per second. In this case,
// each tick is one musical beat. We can use a tick to represent any
// arbitrary amount of time.
let mut clock = manager.add_clock(ClockSpeed::TicksPerMinute(TEMPO))?;
// Play a sound 2 ticks (beats) from now.
let sound_data_1 = StaticSoundData::from_file("sound1.ogg")?
	.start_time(clock.time() + 2);
manager.play(sound_data_1)?;
// Play a different sound 4 ticks (beats) from now.
let sound_data_2 = StaticSoundData::from_file("sound2.ogg")?
	.start_time(clock.time() + 4);
manager.play(sound_data_2)?;
// Start the clock.
clock.start()?;

Platform support

Kira is mainly meant for desktop platforms. Most testing has occurred on Windows, but it has been used successfully on Mac and Linux.

Kira can also be used in wasm environments with the following limitations:

  • Static sounds cannot be loaded from files
  • Streaming sounds are not supported because they make heavy use of threads

If you'd like to help improve wasm support, please reach out!

Roadmap

Features I'd like to have:

  • C API
  • Spatial audio features:
    • Doppler effect
    • Reverb
    • Filtering

Contributing

I'd love for other people to get involved with development! Since the library is still in the early stages, I'm open to all kinds of input - bug reports, feature requests, design critiques, etc. Feel free to open an issue or pull request!

License

This project is licensed under either of

  • Apache License, Version 2.0 (LICENSE-APACHE)
  • MIT license (LICENSE-MIT)

at your option.

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in kira by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

kira's People

Contributors

a1phyr avatar darthdeus avatar fawni avatar glowcoil avatar ikbencasdoei avatar jakerr avatar moxinilian avatar niklasei avatar nobbele avatar solarliner avatar striezel avatar tesselode avatar trobanga avatar zeozeozeo avatar zicklag avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

kira's Issues

Build StaticSoundData from buffer

Hello all,

I’m attempting to use this in a game (more similar to an emulator) where I’m receiving audio data in a u8 buffer. I tried looking around but it seems there’s no real way of creating a sound data object that I can just send off to play. I already know the num of channels and rate.

It could also be this library isn’t meant to be used this way. Any help would be appreciated :)

Upgrade to Symphonia v0.5

Symphonia v0.5 has recently shipped with much improved support for MP3, as well as improvements for pretty much the entire rest of the codecs it supports. I see kira-loaders currently uses v0.4; it would be nice to upgrade to v0.5 to get those improvements.

v0.5 is not semver compatible with v0.4.x, so Kira users will not get this upgrade simply by running cargo update; this requires an explicit version bump in your Cargo.toml.

Playing StreamingSoundData panics in 0.8

After updating from 0.7.0 -> 0.8.1 I'm getting an error when trying to play StreamingSoundData.
Here's the stack trace, let me know if anything else might be helpful.

thread '<unnamed>' panicked at 'did not get expected frame after seeking decoder', /vendor/kira/src/sound/streaming/sound/decode_scheduler.rs:159:22
   0:     0x55f1096ae84a - std::backtrace_rs::backtrace::libunwind::trace::heb3166a6cb1fd02b
                               at /rustc/ef982929c0b653436a6ea6892a2a839fba7c8b57/library/std/src/../../backtrace/src/backtrace/libunwind.rs:93:5
   1:     0x55f1096ae84a - std::backtrace_rs::backtrace::trace_unsynchronized::h34837841e045a1d4
                               at /rustc/ef982929c0b653436a6ea6892a2a839fba7c8b57/library/std/src/../../backtrace/src/backtrace/mod.rs:66:5
   2:     0x55f1096ae84a - std::sys_common::backtrace::_print_fmt::h4348a4b63f328ee4
                               at /rustc/ef982929c0b653436a6ea6892a2a839fba7c8b57/library/std/src/sys_common/backtrace.rs:65:5
   3:     0x55f1096ae84a - <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt::h1bad440d01eeeb29
                               at /rustc/ef982929c0b653436a6ea6892a2a839fba7c8b57/library/std/src/sys_common/backtrace.rs:44:22
   4:     0x55f1096d386e - core::fmt::write::hb5a073c651a6cb64
                               at /rustc/ef982929c0b653436a6ea6892a2a839fba7c8b57/library/core/src/fmt/mod.rs:1232:17
   5:     0x55f1096ab875 - std::io::Write::write_fmt::h97cc768331421fb2
                               at /rustc/ef982929c0b653436a6ea6892a2a839fba7c8b57/library/std/src/io/mod.rs:1682:15
   6:     0x55f1096ae615 - std::sys_common::backtrace::_print::h23bd93d6897965f3
                               at /rustc/ef982929c0b653436a6ea6892a2a839fba7c8b57/library/std/src/sys_common/backtrace.rs:47:5
   7:     0x55f1096ae615 - std::sys_common::backtrace::print::h4d41ae33ce7a824f
                               at /rustc/ef982929c0b653436a6ea6892a2a839fba7c8b57/library/std/src/sys_common/backtrace.rs:34:9
   8:     0x55f1096affcf - std::panicking::default_hook::{{closure}}::h8ab48635107c713a
                               at /rustc/ef982929c0b653436a6ea6892a2a839fba7c8b57/library/std/src/panicking.rs:267:22
   9:     0x55f1096afd0b - std::panicking::default_hook::h6305ca3c910e41d2
                               at /rustc/ef982929c0b653436a6ea6892a2a839fba7c8b57/library/std/src/panicking.rs:286:9
  10:     0x55f1096b06d9 - std::panicking::rust_panic_with_hook::ha8dfad8ee636a9a3
                               at /rustc/ef982929c0b653436a6ea6892a2a839fba7c8b57/library/std/src/panicking.rs:688:13
  11:     0x55f1096b0479 - std::panicking::begin_panic_handler::{{closure}}::h4fcf608bbbd27b26
                               at /rustc/ef982929c0b653436a6ea6892a2a839fba7c8b57/library/std/src/panicking.rs:579:13
  12:     0x55f1096aecfc - std::sys_common::backtrace::__rust_end_short_backtrace::h86f63ffb2338c5c8
                               at /rustc/ef982929c0b653436a6ea6892a2a839fba7c8b57/library/std/src/sys_common/backtrace.rs:137:18
  13:     0x55f1096b0182 - rust_begin_unwind
                               at /rustc/ef982929c0b653436a6ea6892a2a839fba7c8b57/library/std/src/panicking.rs:575:5
  14:     0x55f108d82353 - core::panicking::panic_fmt::ha12d43373dd0f588
                               at /rustc/ef982929c0b653436a6ea6892a2a839fba7c8b57/library/core/src/panicking.rs:64:14
  15:     0x55f1096d15d1 - core::panicking::panic_display::h17cae662562d6a06
                               at /rustc/ef982929c0b653436a6ea6892a2a839fba7c8b57/library/core/src/panicking.rs:147:5
  16:     0x55f1096d157b - core::panicking::panic_str::hfa275bfdfc298aa4
                               at /rustc/ef982929c0b653436a6ea6892a2a839fba7c8b57/library/core/src/panicking.rs:131:5
  17:     0x55f108d82316 - core::option::expect_failed::h09e72beb5cdbcf2e
                               at /rustc/ef982929c0b653436a6ea6892a2a839fba7c8b57/library/core/src/option.rs:1924:5
  18:     0x55f1092987cc - core::option::Option<T>::expect::h45a4a6c94b2112a8
                               at /rustc/ef982929c0b653436a6ea6892a2a839fba7c8b57/library/core/src/option.rs:786:21
  19:     0x55f1092987cc - kira::sound::streaming::sound::decode_scheduler::DecodeScheduler<Error>::frame_at_index::h1ffee1aa2b581f79
                               at /vendor/kira/src/sound/streaming/sound/decode_scheduler.rs:159:7
  20:     0x55f109298fc5 - kira::sound::streaming::sound::decode_scheduler::DecodeScheduler<Error>::run::ha0b5650e36e80c0c
                               at /vendor/kira/src/sound/streaming/sound/decode_scheduler.rs:120:15
  21:     0x55f10929971f - kira::sound::streaming::sound::decode_scheduler::DecodeScheduler<Error>::start::{{closure}}::h8d76de61f9a6d530
                               at /vendor/kira/src/sound/streaming/sound/decode_scheduler.rs:85:10
  22:     0x55f109270e10 - std::sys_common::backtrace::__rust_begin_short_backtrace::ha54d63d75c2749dc
                               at /rustc/ef982929c0b653436a6ea6892a2a839fba7c8b57/library/std/src/sys_common/backtrace.rs:121:18
  23:     0x55f10926cd40 - std::thread::Builder::spawn_unchecked_::{{closure}}::{{closure}}::h35a6626b5833273f
                               at /rustc/ef982929c0b653436a6ea6892a2a839fba7c8b57/library/std/src/thread/mod.rs:558:17
  24:     0x55f109443294 - <core::panic::unwind_safe::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once::hfdabcee9c49c59f1
                               at /rustc/ef982929c0b653436a6ea6892a2a839fba7c8b57/library/core/src/panic/unwind_safe.rs:271:9
  25:     0x55f109443110 - std::panicking::try::do_call::hedb9f28a17b1b15a
                               at /rustc/ef982929c0b653436a6ea6892a2a839fba7c8b57/library/std/src/panicking.rs:483:40
  26:     0x55f10944321b - __rust_try
  27:     0x55f109442f2c - std::panicking::try::hbb5be7c505a66fc5
                               at /rustc/ef982929c0b653436a6ea6892a2a839fba7c8b57/library/std/src/panicking.rs:447:19
  28:     0x55f1092d60b0 - std::panic::catch_unwind::h698223ec4512f974
                               at /rustc/ef982929c0b653436a6ea6892a2a839fba7c8b57/library/std/src/panic.rs:140:14
  29:     0x55f10926c640 - std::thread::Builder::spawn_unchecked_::{{closure}}::h9231232d909805a1
                               at /rustc/ef982929c0b653436a6ea6892a2a839fba7c8b57/library/std/src/thread/mod.rs:557:30
  30:     0x55f1092b83af - core::ops::function::FnOnce::call_once{{vtable.shim}}::hc087fc5fef99e45e
                               at /rustc/ef982929c0b653436a6ea6892a2a839fba7c8b57/library/core/src/ops/function.rs:250:5
  31:     0x55f1096b4d13 - <alloc::boxed::Box<F,A> as core::ops::function::FnOnce<Args>>::call_once::h9646bd6a135081c9
                               at /rustc/ef982929c0b653436a6ea6892a2a839fba7c8b57/library/alloc/src/boxed.rs:1988:9
  32:     0x55f1096b4d13 - <alloc::boxed::Box<F,A> as core::ops::function::FnOnce<Args>>::call_once::h180d98f11b902552
                               at /rustc/ef982929c0b653436a6ea6892a2a839fba7c8b57/library/alloc/src/boxed.rs:1988:9
  33:     0x55f1096b4d13 - std::sys::unix::thread::Thread::new::thread_start::h83489d4028ebb6e1
                               at /rustc/ef982929c0b653436a6ea6892a2a839fba7c8b57/library/std/src/sys/unix/thread.rs:108:17
  34:     0x7fd40599e609 - start_thread
                               at /build/glibc-SzIz7B/glibc-2.31/nptl/pthread_create.c:477:8
  35:     0x7fd40576c133 - clone
                               at /build/glibc-SzIz7B/glibc-2.31/misc/../sysdeps/unix/sysv/linux/x86_64/clone.S:95
  36:                0x0 - <unknown>

Freeing resources while quitting issue

Seeing this error in console on every quit (and it takes indeed 1 second for program to exit):

Kira failed to free up resources after 1000 milliseconds, giving up

Seems this is the bare minimum example that reproduces this issue for me:

let mut manager = AudioManager::new(AudioManagerSettings::default())?;
let music_track = manager.add_sub_track(SubTrackSettings::default())?;

Tested on macOS.

Edit: Realized that the issue seems to be related to the fact I keep the sub-track reference in the same object as audio manager:

pub struct Audio {
    manager: AudioManager,
    music_track: SubTrackHandle,
}

Not sure how I can workaround this? I do need a reference to this track handle for later use.

Add an API for selecting output audio devices

The API currently doesn't have a feature to select an output device (it always uses the default one given by cpal).

Would it be possible to add an API that lets you query and choose output devices?

Improper Output Device Selection

I tried using the Simple Sound Playback example in the readme with a .wav and .ogg file, but it panics on an internal array access. I then tried using the latest git commit (c2877eb) and tweaked the example based on the current changes, but the behaviour was the same.

The panic message: thread '<unnamed>' panicked at 'index out of bounds: the len is 1 but the index is 1', /home/xelivous/.cargo/git/checkouts/kira-a39b987b43e480e3/c2877eb/kira/src/manager/mod.rs:217:21

frame[1] = out.right;

I'm running on Manjaro; I looked at basic issues pertaining to linux/arch on cpal's repo but none of them seem to apply, and i could run cpal's examples just fine on my system.

My best guess from comparing the examples code and the code in kira is that they use device.default_output_config()? while kira uses device.supported_output_configs()?.next(). The difference being that kira pulls in whatever is listed first, even if it's a very incapable interface that isn't the best suited interface. Debugging it a little, it seems that the interface returned is a single channel interface with a sample rate of 384000...

If I change the following config selection chain:

let config = device
.supported_output_configs()?
.next()
.ok_or(AudioError::NoSupportedAudioConfig)?
.with_max_sample_rate()
.config();

Into something like:

let config = device.default_output_config().ok().ok_or(AudioError::NoSupportedAudioConfig)?.config();

Then everything works without problems, although there might be a better way to send out the proper error other than the really dank ok().ok_or() combo. And i'm not sure if you did it with supported_output_configs for some particular reason that would be broken for other people when using default_output_config.


The alternative solution is properly handling when an interface only has a single output frame/channel and mapping it to something like mono but idk if running something at a really meme sample rate has value.

Periodic dropouts/glitches on OS X when other apps are playing audio

I am experiencing periodic (every few seconds) glitches in audio playback under OS X (13.0.1) on Apple Silicon.

#23 may be related, but I am using wired headphones on a M1 MacBook Pro 2020.

The following snippet under kira 0.7.1 reproduces the issue, as long as I have at least one other application playing audio. If nothing else is playing audio, audio playback seems fine!

        let mut manager = AudioManager::<CpalBackend>::new(AudioManagerSettings::default()).unwrap();
        let sound_data = StaticSoundData::from_file("audio.ogg", StaticSoundSettings::default()).unwrap();
        manager.play(sound_data.clone()).unwrap();

        loop {} // keep main thread alive

Have a single sound file and play chunks from them

Hi,

I've read through the book but it's not clear to me how I would have a single file for all my sounds, and just play specific portions of them.

Would I create a single StaticSoundData to load the whole sound, and then somehow ask the manager to play subportions of it? It looks like manager cannot play a sub-section of a sound?

Or would i create separate individual StaticSoundData from my file, each using StaticSoundSettings to define the beginning end of the chunk? It looks like StaticSoundSettings supports start_position but not end_position.

Playing a `StreamingSoundData` intermittently plays a scratchy, sped-up version of the sound

I tried playing this audio file as a StreamingSoundData with a loop point of 7.0. Occasionally, this would work, but sometimes, it would come out as a scratchy mess:

2022-12-11.12-37-30.mp4

Upon closer inspection, this seems to be a sped up version of the track. Sometimes this issue would correct itself at the loop point, but occasionally, it continues forever.

Thus far, I've only been able to reproduce this issue in debug builds (with optimized dependencies). Release builds seem to be unaffected.

Implementing a custom file format is annoying

I am writing a game engine that has to support some custom audio format that wouldn't make sense to include in the library, so I am trying to make my own types to implement SoundData and Sound traits.

It does seem possible to implement it, but I have to duplicate a lot of code from kira: managing volume, panning, resampling audio... Ideally I would like to implement some trait that returns sample rate & decodes audio packets on demand, without copying half of kira into my impls.

One simple solution would be to use StaticSoundData, but I need to use streaming for better loading latency.

Static electricity sound on 3/4 channels, MacOS

Hello! I would like to express my gratitude for this awesome crate. It's the best game sound framework for now. For me, as a musician, it's very comfortable to work with. But, unfortunately, there's a bug while audio is playing.

As you can see on the screenshot that I've attached:
Mixer screen
there is insane clipping on the PH 3/4 channels. All the audio from the computer goes to the AN1/2 and on the PH 3/4 there is a wild electricity sound with +24 dB clipping. I've noticed it in my own project (a game made with Bevy engine) and decided to create completely new clean project "Hello world" using Kira audio only. And the bug is there too.

Besides the screenshot I'm attaching an audio with that sound, which I've recorded (DON'T PLAY IT LOUDLY):
https://github.com/tesselode/kira/assets/128966780/aa7753ba-e97c-4204-9b9b-36e9da46483b

I get the same sound regardless of different songs that I have played. The sound wave looks like this:
Soundwave

After that I've created Cpal basic project (from Cpal's examples folder) to see if the bug came from there. And it turned out, that there is a sound on the 3/4 channel, but it is merely a copy of original sound from the 1/2 channel.

I'll appreciate if you can do anything with it, thanks!

`StaticSoundData` is a performance footgun in debug mode

Using StaticSoundData when symphonia is built with opt-level = 0 can cause long audio processing times of up to twelve seconds. In an application that plays sound effects rapidly (such as a game that makes a sound every time you shoot or move), this is enough to fill the command queue. Ideally, until symphonia can be optimized, this limitation should be documented somewhere.

Update documentation

Hello and high five for this crate, it indeed looks great!

I'm trying it today for the first time and followed the instructions on docs.rs and also from the book (very good initiative).
TBH my audio knowledge is inexistent, but luckily by following your instructions it doesn't look that difficult.

Just opening this issue here because there's some inconsistencies in the examples, e.g.

  • with load / load_sound where the docs points out to kira-loaders, but indeed doesn't look necessary anymore (AudioManager's load_sound seems the way to go).
  • there's something regarding cpal pointing at kira-cpal but I personally didn't need it to play a sound (on MacOS M1).
  • one piece of advice I would have given to newcomers, is that you need to have your program running for as long as the loading of the file + the sound duration, which can easily be achieved by e.g. using tokio sleep for as long as it lasts.
  • I'm especially interested in updates to the mixer section, which is the one I'm the most interested into.

Thanks :)

Getting access to a Frame from a Handle

Hi, and thanks for this great library!
I am experimenting with Kira and bevy, as well as building a super simple audio player for fun. I think it would be great to access a Frame at a time, for example to have a game entity react to the sound or add visualization to audio. I see that there is get_frame_at_position, but this is not implemented for the Handle. Would this be reasonable to add or am I missing a way to make this work with the current state maybe?

`kira-loaders` does not support loading files from memory

The old (0.5) implementation had support for loading files directly from memory (from_ogg_reader etc) instead of file paths. Could we have the same feature in the new version as well?

This would support things like loading sound files from archives, virtual filesystems or network.

Would it Be Possible to Make the `AudioManager` `Sync + Send`?

Hey there, I just wanted to open up the discussion as far as the possibility of making the AudioManager``Sync + Send.

I thought the issue might be related to the audio backend and possibly unavoidable, but then I saw that the CpalBackend is indeed Sync + Send.

The actual issue from the Rust error message seems to be that dyn Sound and dyn Modulator aren't necessarily Sync.

Would there be a way to add a feature flag maybe that additionally restricts Sound and Modulator to be Sync maybe?

Can't complie examples

Hi, I'm new to Rust and would need audio playback for my project. I can't compile your examples. Can you please help me? Thanks.

error[E0061]: this function takes 1 argument but 2 arguments were supplied
--> src/main.rs:15:19
|
15 | let mut manager = AudioManager::new(
| ^^^^^^^^^^^^^^^^^ expected 1 argument
16 | CpalBackend::new()?,
| -------------------
17 | AudioManagerSettings::default(),
| ------------------------------- supplied 2 arguments
|
note: associated function defined here
--> /Users/christian/.cargo/registry/src/github.com-1ecc6299db9ec823/kira-0.5.3/src/manager/mod.rs:143:9
|
143 | pub fn new(settings: AudioManagerSettings) -> Result<Self, SetupError> {
| ^^^

error[E0277]: the ? operator can only be used in a function that returns Result or Option (or another type that implements FromResidual)
--> src/main.rs:16:23
|
8 | / fn abc() {
9 | | extern crate kira;
10 | | extern crate kira_cpal;
11 | | extern crate kira_loaders;
... |
16 | | CpalBackend::new()?,
| | ^ cannot use the ? operator in a function that returns ()
... |
19 | | Result::<(), Box>::Ok(())
20 | | }
| |_- this function should return Result or Option to accept ?
|
= help: the trait FromResidual<Result<Infallible, DeviceSetupError>> is not implemented for ()

error[E0277]: the ? operator can only be used in a function that returns Result or Option (or another type that implements FromResidual)
--> src/main.rs:18:2
|
8 | / fn abc() {
9 | | extern crate kira;
10 | | extern crate kira_cpal;
11 | | extern crate kira_loaders;
... |
18 | | )?;
| | ^ cannot use the ? operator in a function that returns ()
19 | | Result::<(), Box>::Ok(())
20 | | }
| |_- this function should return Result or Option to accept ?
|
= help: the trait FromResidual<Result<Infallible, SetupError>> is not implemented for ()

error[E0308]: mismatched types
--> src/main.rs:19:1
|
19 | Result::<(), Box>::Ok(())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected (), found enum Result
|
= note: expected unit type ()
found enum Result<(), Box<dyn std::error::Error>>
help: consider using a semicolon here
|
19 | Result::<(), Box>::Ok(());
| +
help: try adding a return type
|
8 | fn abc() -> Result<(), Box> {
| +++++++++++++++++++++++++++++++++++++++++

Tween Default

Default for Tween being 10ms linear easing is quite weird, there should at least be some way to create a 0ms tween

Dropping `AudioManager` panics on Android

The minimal reproducing steps are simply dropping a AudioManager.

PanicInfo { payload: Any { .. }, message: Some(called `Option::unwrap()` on a `None` value), location: Location { file: "~/.cargo/registry/src/github.com-1ecc6299db9ec823/kira-0.7.1/src/manager/backend/cpal/desktop/stream_manager/renderer_wrapper.rs", line: 40, col: 9 }, can_unwind: true }

Currently this issue is temporarily fixed by implementing the Drop trait for the oboe backend of cpal (host/oboe/mod.rs):

impl Drop for Stream {
    fn drop(&mut self) {
        match self {
            Self::Input(stream) => {
                stream.borrow_mut().stop();
                stream.borrow_mut().close();
            }
            Self::Output(stream) => {
                stream.borrow_mut().stop();
                stream.borrow_mut().close();
            }
        }
    }
}

Not sure if this is an issue of cpal.

how to stop a streaming sound?

sorry if i'm missing something obvious.

i have a struct that implements Decoder which i wrap into a StreamingSoundData and send to AudioManager::play.

when the stream ends i return an error from decode, but kira continues to busy-wait poll the stream, burning cpu pretty hard.

i can't see a way to tell the audio manager to stop the handle, or to reply from the decoder that the stream has ended.

what should i do?

thanks

CommandQueue full error

self.spatial_scene.add_emitter(position, emitter_settings)

I am getting a ton of CommandQueue full errors. i have about 10 sounds of 20 seconds length playing.
Is there some kind of limit to the emitter?

ps: i am reusing the same StaticSoundData if that matters

External audio effects and roadmap?

Hi! I stumbled upon kira while reading stuff on bevy, while trying to reasearch on the topic of audio engines for games that could lead to expressive uses of audio (most simple example I can think of: "In some action RPG, one of the instruments in the current fighting track represents a character. The more that character loses HPs, the more its associated instrument gets filtered and/or the narrower in the stereo field it becomes")

I had 2 questions re. kira:

  • Reimplementing various audio effects in Rust ought to be very time consuming. But there are much efforts out there to provide reusable audio DSPs. I see that "Plugin system?" is something you marked in todo.md, do you have plans regarding that? Because, besides full-fledged audio plugins (think VST) which often come with lots of licensing and packaging problems, one very interesting avenue I can think of is the Faust ecosystem ( https://faust.grame.fr/ ) which is a super high level DSP writing language, totally open and permissive. It provides lots of audio generation & processing tools out of the box or as community scripts, and builds for a ton of different backends, including Rust code generation, C libs that you can easily statically link against, or JIT compilation and execution of your DSP script via LLVM.
  • I strongly believe not just audio effects but also real-time audio synthesis and note-level (ie MIDI-level) effects have their place in video game music (sure, you're taking a toll on your CPU budget, but you can use that sparingly, and also not all games have to be AAA). Would MIDI and synths be something you would also be interested in supporting down the line?

v0.7.2 (and main) doesn't build for wasm

v0.7.1 compiles fine, but v0.7.2 does not:

dev/kira dc66cd9 cargo check -p kira --target wasm32-unknown-unknown
   Compiling crossbeam-utils v0.8.15
    Checking web-sys v0.3.61
    Checking ringbuf v0.3.2
    Checking cpal v0.14.2
    Checking kira v0.7.1 (C:\Users\Johan\dev\kira\crates\kira)
    Finished dev [unoptimized + debuginfo] target(s) in 1.55s
dev/kira dc66cd9 git co v0.7.2
Previous HEAD position was dc66cd9 version bump
HEAD is now at b2e8bca prepare 0.7.2 release
dev/kira b2e8bca cargo check -p kira --target wasm32-unknown-unknown
    Updating crates.io index
    Checking web-sys v0.3.61
    Checking cpal v0.15.1
    Checking kira v0.7.2 (C:\Users\Johan\dev\kira\crates\kira)
error[E0061]: this function takes 4 arguments but 3 arguments were supplied
   --> crates\kira\src\manager\backend\cpal\wasm.rs:51:24
    |
51  |               let stream = device.build_output_stream(
    |  _________________________________^^^^^^^^^^^^^^^^^^^-
52  | |                 &config,
53  | |                 move |data: &mut [f32], _| {
54  | |                     renderer.on_start_processing();
...   |
65  | |                 move |_| {},
66  | |             )?;
    | |_____________- an argument of type `Option<Duration>` is missing
    |
note: associated function defined here
   --> C:\Users\Johan\.cargo\registry\src\github.com-1ecc6299db9ec823\cpal-0.15.1\src\traits.rs:153:8
    |
153 |     fn build_output_stream<T, D, E>(
    |        ^^^^^^^^^^^^^^^^^^^
help: provide the argument
    |
51  ~             let stream = device.build_output_stream(&config, move |data: &mut [f32], _| {
52  ~                     renderer.on_start_processing();
53  ~                     for frame in data.chunks_exact_mut(channels as usize) {
54  ~                         let out = renderer.process();
55  ~                         if channels == 1 {
56  ~                             frame[0] = (out.left + out.right) / 2.0;
57  ~                         } else {
58  ~                             frame[0] = out.left;
59  ~                             frame[1] = out.right;
60  ~                         }
61  ~                     }
62  ~                 }, move |_| {}, /* Option<Duration> */)?;
    |

For more information about this error, try `rustc --explain E0061`.
error: could not compile `kira` due to previous error

Infinite media source support

Hey there,

first of all thanks for the great work. This library is core of so many playback libraries!
To my issue, I want to play a radio stream using Kira. The stream is remote and has no content-length as it is infinite. The issue I recognize is that Kira's SymphoniaDecoder::new function tries to determine sample_rate and num_frames at decoder creation and unfortunately it isn't able to determine the num_frames. I guess this is from Kira targeting game development whose would always have files on disk. Could you maybe consider to also allow playing remote files as well? I really like this library and would like to prevent using rodio for streaming and kira for local files (rodio doesn't support seeking or chaning positions).

Here is my example

use std::io::{Read, Seek, SeekFrom};
use std::thread::sleep;
use std::time::Duration;

use kira::manager::{backend::DefaultBackend, AudioManager, AudioManagerSettings};
use kira::sound::streaming::{StreamingSoundData, StreamingSoundSettings};
use reqwest::{Client, Url};
use stream_download::http::HttpStream;
use stream_download::source::SourceStream;
use stream_download::storage::memory::MemoryStorageProvider;
use stream_download::{Settings, StreamDownload};
use symphonia::core::io::MediaSource;

struct RemoteSource {
    reader: StreamDownload<MemoryStorageProvider>,
    content_length: Option<u64>,
}

impl RemoteSource {
    pub async fn from_url(url: String) -> Result<Self, String> {
        let parsed_url = url.parse::<Url>().map_err(|error| format!("Invalid url: {}", error))?;
        let stream = HttpStream::<Client>::create(parsed_url)
            .await
            .map_err(|error| format!("Failed to create stream: {}", error))?;

        let content_length = stream.content_length();
        let reader = StreamDownload::from_stream(stream, MemoryStorageProvider::default(), Settings::default())
            .await
            .map_err(|error| format!("Failed to create download: {}", error))?;

        Ok(RemoteSource { reader, content_length })
    }
}

impl Read for RemoteSource {
    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
        self.reader.read(buf)
    }
}

impl Seek for RemoteSource {
    fn seek(&mut self, pos: SeekFrom) -> std::io::Result<u64> {
        self.reader.seek(pos)
    }
}

impl MediaSource for RemoteSource {
    fn is_seekable(&self) -> bool {
        self.content_length.is_some()
    }

    fn byte_len(&self) -> Option<u64> {
        self.content_length
    }
}

const FILE: &'static str = "H:\\Data\\projects\\mupibox-rs\\admin_interface\\.storage\\audio\\0b7678f1-4121-4d38-be75-c26f86e2e30d-IsItReal.mp3";

#[tokio::main]
async fn main() {
    let mut manager = AudioManager::<DefaultBackend>::new(AudioManagerSettings::default()).expect("manager to load");

    let url = "https://streamtdy.ir-media-tec.com/live/mp3-128/web/play.mp3".to_string();

    let sound = StreamingSoundData::from_media_source(
        RemoteSource::from_url(url).await.expect("source to be loaded"),
        StreamingSoundSettings::default(),
    )
    .expect("stream sound data to be created");

    let mut handle = manager.play(sound).expect("failed to play");

    sleep(Duration::from_secs(5));
}

With these dependencies

[dependencies]
kira = "0.8.5"
symphonia = "0.5.3"
reqwest = { version = "0.11.22", features = ["blocking"] }
stream-download = "0.3.0"
tokio = { version = "1.33.0", features = ["full"] }
rangemap = "1.4.0"

If not I can understand that as well :)

Have a nice day and best regards
fragsalat

Feature Request: PlaybackRate while having the pitch not modify voice.

I don't know if kira has this capability, but when I call set_playback_rate on my sound, I can speed up the sound, but the pitch change makes it sound strange. I want to be able to play the sound at 2x speed without changing the way the voice sounds (like speeding up youtube videos).

I'm an audio noob, so I can't express what I want in precise terminology, but I hope its clear what I'm after.

No sound played on wasm

When I play the sound using AudioManager::play, the console prints the following message:

      The AudioContext was not allowed to start. It must be resumed (or created) after a user gesture on the page.

How should I play a sound on wasm? Is there an example?

Allow frame accurate events

I noticed that Clock::shared is only updated in on_process_start, which causes a delay up to a few milliseconds e.g. in ClockInfoProvider::when_to_start.

I moved the update of Clock::shared into Clock::update and I didn't notice a performance impact. On my machine, running cargo bench has a performance decrease of 3% for simple and (interestingly) almost no impact for with on_start_processing callback.

Do you think it's possible to move it there or maybe enable it with a feature? If you agree I'd be happy to make a PR.

`StaticSoundData` and other types do not implement `Debug`

This makes it hard to do things like Arc::try_unwrap(...) on a StaticSoundData. The guidelines say all types should implement Debug (except for rare exceptions) but it looks like the ringbuf dependency does not, which makes it hard to fix in kira.

Is there any opinion between these options?

  • Manually implement Debug, formatting the obvious fields (and optionally providing something nice for things like consumer)
  • Upgrade the ringbuf dependency (it is behind) and open an issue in their repo; wait for a fix and then auto-derive Debug
  • Use the new-type pattern to wrap ringbuf types and provide a generic Debug implementation inside kira

`set_volume` does not apply immediately

For example, if I write something like this:

if let Ok(mut sound) = manager.play(sound_buf) {
    sound.set_volume(0.01, Tween {
        start_time: StartTime::Immediate,
        duration: Duration::from_secs(0),
        easing: Easing::Linear,
    });
}

the volume doesn't get applied instantly, for a very short time the volume is still at 1.0

Bevy asset loader for StaticSoundData

I am trying to update bevy_kira_audio to Kira 0.6

One part of this is to migrate the asset loaders. The only viable option I currently see to load StaticSoundData is via from_cursor. The problem is, that I cannot satisfy the static lifetime bound for the byte slice.

One option would be to expose from_media_source. Then I can clone the bytes and pass Box::new(Cursor::new(owned_bytes)) as media source. This is the solution I am currently working with from my fork. Do you see any better approach?

Expose loaders and cpal backend using features?

This is really more like a question here. But I found having separate crates I need to have dependencies on core functionality a bit weird. Would it not be better instead of requiring users to have separate dependencies in their Cargo.toml - have the kira-cpal and kira-loaders exposed as features instead? Internally you still have multiple crates, they can still be disabled with default-features = false, custom backend/loader still can be implemented by user, etc.

At least from my experience in Rust this seems to be a more common approach in libraries, but maybe there is a good reason it is the way it is?

Feature request: `TrackHandle` method to stop all sounds currently playing on that track

The closest I can get to this functionality on my own is to either:

  1. manually track all sounds playing on a specific track and iterate through them to call their handle's stop() method
  2. drop the track and make a new one (requiring me to also remake all the attached effects/routes)

I feel like this is a common feature that kira would benefit from having built in. Would it be feasible to implement this?

Feature Request: Unified API for working with Handles

Currently, static and streaming SoundData::Handles have no unified API (e.g. if you are working with both types in the same context you must handle each as a seperate case.
It would be really nice if there was a seperate SoundHandle trait that both static and streaming sound handles implemented to that contained the methods they have in common.

(if something like this already exists, please point me towards it, I'm pretty new to Rust :))

ALSA function 'snd_pcm_hw_params' failed with error 'EIO: I/O error'

I am facing this error on Arch Linux (KDE Plasma 5 on Wayland). I did not know what when wrong, and I cannot reproduce when using symphonia-play (the song still played as expected). Please let me know if you need any additional information.

Step to reproduce:

git clone [email protected]:tesselode/kira-examples.git
cd kira-examples
cargo run -p simple-sound-playback

Full error message:

thread '<unnamed>' panicked at 'called `Result::unwrap()` on an `Err` value: BuildStreamError(BackendSpecific { err: BackendSpecificError { description: "ALSA function 'snd_pcm_hw_params' failed with error 'EIO: I/O error'" } })', /home/thang/.cargo/registry/src/index.crates.io-6f17d22bba15001f/kira-0.8.0/src/manager/backend/cpal/desktop/stream_manager.rs:69:59
stack backtrace:
   0: rust_begin_unwind
             at /rustc/d5c2e9c342b358556da91d61ed4133f6f50fc0c3/library/std/src/panicking.rs:593:5
   1: core::panicking::panic_fmt
             at /rustc/d5c2e9c342b358556da91d61ed4133f6f50fc0c3/library/core/src/panicking.rs:67:14
   2: core::result::unwrap_failed
             at /rustc/d5c2e9c342b358556da91d61ed4133f6f50fc0c3/library/core/src/result.rs:1651:5
   3: core::result::Result<T,E>::unwrap
             at /rustc/d5c2e9c342b358556da91d61ed4133f6f50fc0c3/library/core/src/result.rs:1076:23
   4: kira::manager::backend::cpal::desktop::stream_manager::StreamManager::start::{{closure}}
             at /home/thang/.cargo/registry/src/index.crates.io-6f17d22bba15001f/kira-0.8.0/src/manager/backend/cpal/desktop/stream_manager.rs:69:4

Possible memory leak?

I found that loaded audio resources will not be released after it stops, here is a quick example:

use anyhow::Result;
use kira::{
    manager::{backend::DefaultBackend, AudioManager, AudioManagerSettings},
    sound::static_sound::{StaticSoundData, StaticSoundSettings},
    tween::Tween,
};

fn main() {
    play().unwrap();
}

fn play() -> Result<()> {
    // Create an audio manager. This plays sounds and manages resources.
    let mut manager = AudioManager::<DefaultBackend>::new(AudioManagerSettings::default())?;

    let path = std::env::current_dir()
        .unwrap()
        .join("assets/audio/test.ogg");

    let file = std::fs::File::open(path)?;

    let sound_data = StaticSoundData::from_media_source(file, StaticSoundSettings::new())?;

    let mut handle = manager.play(sound_data)?;

    let mut i = 0;

    loop {
        std::thread::sleep(std::time::Duration::from_secs(1));
        i += 1;

        if i == 10 {
            handle.stop(Tween::default())?;
        }
    }
}

The music will play for 10 seconds and then stop, seeing that no memory usage drop in task manager.

I think it is just because a missing implement of removing it here:

fn remove_unused_sounds(&mut self) {
if self.unused_sound_producer.is_full() {
return;
}
for (_, sound) in self.sounds.drain_filter(|sound| sound.finished()) {
if self.unused_sound_producer.push(sound).is_err() {
panic!("Unused sound producer is full")
}
if self.unused_sound_producer.is_full() {
return;
}
}
}

Stopped sound is moved to unused_sound_producer but no next steps, while simply comment out line 40~45 will fix the problem.

Not sure if the problem exist in other backends or wasm.

Glitchy playback on macOS

Hello, I'm using kira to make a simple little podcast player with a terminal interface, and its been really nice to use so far :)
I am however experiencing some subtle but audible glitches when playing MP3 files on macOS (I have not tried any other OS). I've tried several different files and they all seem to have the same problem.
At first I thought it could have been something with the StreamingSound setup that made this happen, but I'm having the same issues using StaticSound.
I can reproduce it locally using the simple_sound_playback with one of the files I have (seems any MP3 file would do).

Additionally, I tried playing the same file in the example symphonia-play in the Symphonia repo, which did not exhibit the same issue.

Let me know if you want more information, or if I can help out in any way!

Sequencer in new API

In the new kira API, sequencers don't seem to exist. It would be useful to be able to define sequencers of some kind in order to define simple patterns, probably using clock ticks instead of beats (writing a metronome in the new API requires creating many clock instances).

Unnecessary mutable references

From what I can see,
VolumeControlHandle:.set_volume doesn't need &mut because,
Producer::push doesn't need &mut since,
Producer::push_access doesn't need &mut since,
SharedVec::get_mut(), CachePadded::load nor CachePadded::store don't need &mut

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.