Cross-platform audio for Rust

Overview

quad-snd

High-level, light-weight, and opinionated audio library.

  • Web: WebAudio
  • Android: OpenSLES
  • Linux: Alsa
  • macOS: CoreAudio
  • Windows: Wasapi
  • iOS: CoreAudio

Being high-level enough allows quad-snd to use very different approaches to each backend. For example, for WebAudio all the playback and mixing is based on Audio nodes, while in OpenSLES quad-snd itself is responsible for mixing.

quad-snd lacks lots of features and the best way to use the library - either fork a repo and fine-tune it for your needs or just copy-paste some code from certain audio backends.

Biggest difference from any other sound library in rust:
quad-snd is small. Each backend implementation is ~300LoC code and is self sufficient - you can copy-paste the whole thing and run it, (almost)no common code, dependencies or anything like that would be required.

The only dependency is audrey. audrey helps backends that do not have file parsing functionality (all the platforms but web) to get bytes out of encoded .wav/.ogg. When web is not required - getting rid of audrey and use anything else(or nothing at all) for audio decoding is a super easy fix.

Attribution

While building quad-snd I looked into the implementation of the following libraries:

https://github.com/floooh/sokol/blob/master/sokol_audio.h
https://github.com/norse-rs/audir
https://github.com/unrust/uni-snd

Comments
  • "rust-lld: error: function signature mismatch: audio_init" wasm32-unknown-unknown error

    I'm on MacOS Catalina 10.15.7, quad_snd version 0.1.0-alpha.1 (I'm using an old version because it's what @TanTanDev was using with his game using this, and the latest version doesn't work for me). Here's the full error: note: rust-lld: error: function signature mismatch: audio_init >>> defined as (i32) -> i32 in /Users/{GAME_PATH}/target/wasm32-unknown-unknown/debug/deps/libquad_snd-9a787bf96d4e8e9b.rlib(quad_snd-9a787bf96d4e8e9b.quad_snd.f517ac66-cgu.14.rcgu.o) >>> defined as () -> void in /Users/{GAME_PATH}/target/wasm32-unknown-unknown/debug/deps/libquad_snd-b3ce2925c0a480b8.rlib(quad_snd-b3ce2925c0a480b8.quad_snd.371d2a4f-cgu.10.rcgu.o)

    opened by eboatwright 8
  • asound: try multiple devices if `default` fails

    asound: try multiple devices if `default` fails

    I'm on Pop!_OS, which is a popular distro, and haven't really messed with anything sound related. IDK why default doesn't work for me, and this is probably not the best way to fix it since it bakes in an assumption, but at very least it shouldn't break anything for anyone for whom it works already and I can carry on building stuff :)

    opened by maciejhirsz 5
  • panicked at 'Can't set rate'

    panicked at 'Can't set rate'

    I'm not using pipewire, just alsa & pulseaudio

    thread '<unnamed>' panicked at 'Can't set rate.', /home/sheep/.cargo/registry/s
    rc/github.com-1ecc6299db9ec823/quad-snd-0.2.5/src/alsa_snd.rs:57:9
    note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
    Audio thread died
    

    with RUST_BACKTRACE=1

    thread '<unnamed>' panicked at 'Can't set rate.', /home/sheep/.cargo/registry/s
    rc/github.com-1ecc6299db9ec823/quad-snd-0.2.5/src/alsa_snd.rs:57:9
    stack backtrace:
       0: std::panicking::begin_panic
                 at /rustc/4b91a6ea7258a947e59c6522cd5898e7c0a6a88f/library/std/src
    /panicking.rs:616:12
       1: quad_snd::snd::setup_pcm_device
                 at /home/sheep/.cargo/registry/src/github.com-1ecc6299db9ec823/qua
    d-snd-0.2.5/src/alsa_snd.rs:57:9
       2: quad_snd::snd::audio_thread
                 at /home/sheep/.cargo/registry/src/github.com-1ecc6299db9ec823/qua
    d-snd-0.2.5/src/alsa_snd.rs:104:22
       3: quad_snd::snd::AudioContext::new::{{closure}}
                 at /home/sheep/.cargo/registry/src/github.com-1ecc6299db9ec823/qua
    d-snd-0.2.5/src/alsa_snd.rs:160:13
    
    opened by sleepntsheep 2
  • Version bump

    Version bump

    Chatted about this in discord, but I think we need to do a version bump to get sounds to play on (some versions of?) linux in macroquad. If I change the quad-snd dependency from version = "0.2" to git = "https://github.com/not-fl3/quad-snd" then the examples in macroquad work.

    The last release was 11 months ago, and I see there's been a few changes.

    opened by bbstilson 2
  • Panic: Can't set rate

    Panic: Can't set rate

    Just tried running some of the macroquad examples, but the audio thread paniced. I get the same error just trying the examples here.

    $ cargo run --example simple
        Finished dev [unoptimized + debuginfo] target(s) in 0.01s
         Running `target/debug/examples/simple`
    thread '<unnamed>' panicked at 'Can't set rate.', src/alsa_snd.rs:57:9
    note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
    Audio thread died
    Audio thread died
    

    backtrace:

    stack backtrace:
       0: std::panicking::begin_panic
                 at /rustc/6dba4ed215e7a60f0a2a19c04f3f73691f89c509/library/std/src/panicking.rs:616:12
       1: quad_snd::snd::setup_pcm_device
                 at ./src/alsa_snd.rs:57:9
       2: quad_snd::snd::audio_thread
                 at ./src/alsa_snd.rs:104:22
       3: quad_snd::snd::AudioContext::new::{{closure}}
                 at ./src/alsa_snd.rs:160:13
    note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
    
    opened by joleeee 2
  • 32bit support

    32bit support

    Trying to use this in a Raspberry PI 3 with a stock raspbian 32bit kernel/os.

    consts::PCM_BUFFER_SIZE is set as a u64

    This is causing issues with calls to quad_alsa_sys::snd_pcm_hw_params_set_buffer_size because it's also platform dependent, and will be built to expect an u32 or u64.

    error[E0308]: mismatched types
      --> src/alsa_snd.rs:43:70
       |
    43 |     if sys::snd_pcm_hw_params_set_buffer_size(pcm_handle, hw_params, consts::PCM_BUFFER_SIZE) < 0 {
       |                                                                      ^^^^^^^^^^^^^^^^^^^^^^^ expected `u32`, found `u64`
       |
    help: you can convert a `u64` to a `u32` and panic if the converted value doesn't fit
       |
    43 |     if sys::snd_pcm_hw_params_set_buffer_size(pcm_handle, hw_params, consts::PCM_BUFFER_SIZE.try_into().unwrap()) < 0 {
       |                                                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    

    Also since quad_alsa_sys::snd_pcm_writei will return the frames written as a u32, this line fails:

    error[E0308]: mismatched types
       --> src/alsa_snd.rs:128:29
        |
    128 |         if frames_writen == -libc::EPIPE as i64 {
        |                             ^^^^^^^^^^^^^^^^^^^ expected `i32`, found `i64`
        |
    help: you can convert `frames_writen` from `i32` to `i64`, matching the type of `-libc::EPIPE as i64`
        |
    128 |         if i64::from(frames_writen) == -libc::EPIPE as i64 {
        |            ^^^^^^^^^^^^^^^^^^^^^^^^
    
    error: aborting due to previous error
    

    This later I can certainly do the i64 up convert as suggested, but for the first issue, with the snd_pcm_hw_params_set_buffer_size what is the best way to handle this?

    I am still pretty new to rust. I make it a usize, but quad_alsa_sys is making this a u32 or u64 at compile time probably from the underlying C library. Is this something to be fixed in that library (quad_alsa_sys) to change the function to use usize?

    If I force the const to u32 of course everything works fine, but that's now hard coding it to only work on 32bit systems.

    opened by seerickcode 2
  • Don't override sample rate

    Don't override sample rate

    Upgrading to the latest changes caused it to be unable to play my .wavs, removing the sample rate override seems to fix the issue. error : could not build output stream : The requested stream format is not supported by the device.

    opened by Bombfuse 2
  • Support simple stereo panning

    Support simple stereo panning

    Here is a link supposed to serve as a reference: http://www.cs.cmu.edu/~music/icm-online/readings/panlaws/

    It would be much easier to implement such a thing than some complex binaural sound model based on HRTF. For simple 2D games this should do the work nicely

    opened by madwareru 2
  • Wait for PCM to be ready before writing

    Wait for PCM to be ready before writing

    Pop!_OS has fixed the missing default setting for Alsa, but it was set to pulseaudio instead of pipewire.

    This PR fixes an issue where attempt to write frames to pulseaudio would crash/block the audio thread. Adding this wait fixes it, please don't ask me why, I've no idea what I'm doing here. Tested both pulse and pipewire with the change and both are working.

    opened by maciejhirsz 1
  • Fast `fill_audio_buffer`

    Fast `fill_audio_buffer`

    This drops the simple example from about 60µs to about 6-7µs per buffer fill.

    Couple notes:

    • Zero the buffer ahead of time (.fill(0.0) optimizes to memset).
    • Reversed the nesting of sound_data / buffer iterators, this has two effects:
      • No need to hit the HashMap every sample in the buffer.
      • For multiple sounds operating on one source with buffer in linear fashion should be easier on CPU cache.
    • Replaced the dead flag and retain with a much dumber way to drop sounds (also using swap_remove since we don't care about ordering).
    • unsafe transform of the buffer to &mut [[f32; 2]] to help with some bounds checks.
    opened by maciejhirsz 1
  • Unbreak build on FreeBSD

    Unbreak build on FreeBSD

    alsa-plugins contains OSS plugin which is natively supported on DragonFly, FreeBSD and Solaris. Let's follow cpal. Runtime tested via FishFight (package).

    $ cargo build
    [...]
    error[E0432]: unresolved import `snd`
      --> src/lib.rs:32:9
       |
    32 | pub use snd::{AudioContext, Sound};
       |         ^^^ use of undeclared crate or module `snd`
       |
    help: there is a crate or module with a similar name
       |
    32 | pub use std::{AudioContext, Sound};
       |         ~~~
    
    opened by jbeich 1
  • Allow audio generation

    Allow audio generation

    Not every game neccessarilly wants to play prerecorded audio files, rather they might want to generate the audio in real time.

    To do this the Mixer would have to be exposed publically or rather the AudioContext would have to have an option to specify if the sample should be loaded from a file or the buffer should be filled using a callback or a second thread.

    I'm thinking of a sgstem similar to how rust-sdl2 handles it: example can be found in their docs

    struct SquareWave {
        phase_inc: f32,
        phase: f32,
        volume: f32
    }
    
    impl AudioCallback for SquareWave {
        type Channel = f32;
    
        fn callback(&mut self, out: &mut [f32]) {
            // Generate a square wave
            for x in out.iter_mut() {
                *x = if self.phase <= 0.5 {
                    self.volume
                } else {
                    -self.volume
                };
                self.phase = (self.phase + self.phase_inc) % 1.0;
            }
        }
    }
    

    I'm not completely sure if and how this could be implemented for all the supported platforms, but looking at the alsa module for linux, the mixer already had a function to fill a given buffer

    opened by comcloudway 9
  • setting volume doesn't work on Wasm

    setting volume doesn't work on Wasm

    I just updated audio support in good-web-game and while testing it I noticed that though setting audio volume works fine on desktop it doesn't work on Wasm.

    For a live example check gwg's sounds example: https://psteinhaus.github.io/sounds_example/

    As the example shows neither starting the sound with a certain volume set in the params, nor changing it while playing changes anything on the actual volume.

    opened by PSteinhaus 0
  • Pitch/Playback speed support

    Pitch/Playback speed support

    It would be great to be able to change playback speed/pitch of a sound dynamically so one can introduce variation into repeating sound without spending much memory.

    enhancement 
    opened by koalefant 1
  • Decouple sound and buffer management

    Decouple sound and buffer management

    Hi, this library is really neat! =D

    Little request: currently it seems that the sound file is decoded every time a source is add (at least on WASM). It would be nice to split these into two stages: creation of buffer and sound that uses it, so one could do decoding at load time, and not during the game.

    enhancement 
    opened by koalefant 0
Owner
Fedor Logachev
Fedor Logachev
TinyAudio is a cross-platform audio output library

TinyAudio TinyAudio is a cross-platform audio output library. Its main goal to provide unified access to a default sound output device of your operati

Dmitry Stepanov 39 Apr 4, 2023
Auritia is a DAW coded in Rust and Vue in hopes of having cross platform compatability, while also providing enough features for anyone to use professionally

Steps Install WebView if you're not on Windows 11 Install Node deps npm i To run the dev server do npm run tauri dev Compiling Linux You will need to

Auritia 20 Aug 27, 2022
Cross-platform realtime MIDI processing in Rust.

midir Cross-platform, realtime MIDI processing in Rust. Features midir is inspired by RtMidi and supports the same features*, including virtual ports

Patrick Reisert 392 Dec 27, 2022
Rust audio playback library

Audio playback library Rust playback library. Playback is handled by cpal. MP3 decoding is handled by minimp3. WAV decoding is handled by hound. Vorbi

null 1.2k Jan 1, 2023
Rust bindings for the soloud audio engine library

soloud-rs A crossplatform Rust bindings for the soloud audio engine library. Supported formats: wav, mp3, ogg, flac. The library also comes with a spe

Mohammed Alyousef 38 Dec 8, 2022
Implements the free and open audio codec Opus in Rust.

opus-native Overview Implements the free and open audio codec Opus in Rust. Status This crate is under heavy development. Most functionality is not wo

Nils Hasenbanck 9 Nov 28, 2022
Symphonia is a pure Rust audio decoding and media demuxing library supporting AAC, FLAC, MP3, MP4, OGG, Vorbis, and WAV.

Pure Rust multimedia format demuxing, tag reading, and audio decoding library

Philip Deljanov 1k Jan 2, 2023
Rust - Augmented Audio Libraries

Augmented Audio Libraries In this repository I'll push some experiments trying to use Rust for audio programming. Goals Goal 1: Learn & have fun This

Pedro Tacla Yamada 116 Dec 18, 2022
CLI Rust Audio Visualizer

crav Console-based Rust Audio Visualizer It can run in the terminal but also has a 3D accelerated backend implemented in wgpu. demo compatibility The

null 20 Oct 16, 2022
Simple examples to demonstrate full-stack Rust audio plugin dev with baseplug and iced_audio

iced baseplug examples Simple examples to demonstrate full-stack Rust audio plugin dev with baseplug and iced_audio WIP (The GUI knobs do nothing curr

Billy Messenger 10 Sep 12, 2022
MVC audio plugin framework for rust

__ __ | |--.---.-.-----.-----.-----.| |.--.--.-----. | _ | _ |__ --| -__| _ || || | | _ | |

william light 93 Dec 23, 2022
simple-eq is a crate that implements a simple audio equalizer in Rust.

simple-eq A Simple Audio Equalizer simple-eq is a crate that implements a simple audio equalizer in Rust. It supports a maximum of 32 filter bands. Us

Mike Hilgendorf 11 Sep 17, 2022
A simple GUI audio player written in Rust with egui. Inspired by foobar2000.

Music Player A simple GUI music player inspired by foobar2000 written in Rust using egui. The goal of this project is to learn about making gui/ nativ

Ryan Blecher 5 Sep 16, 2022
Rust Audio Player Daemon

Rust Audio Player Daemon Cause mpd was annoying What rapd trys to do Rapd is not a spotify client, or an advanced music player. Its an audio/music dae

ash 3 Nov 1, 2022
API-agnostic audio plugin framework written in Rust

Because everything is better when you do it yourself - Rust VST3 and CLAP framework and plugins

Robbert van der Helm 415 Dec 27, 2022
DSP real time audio synthesis, effect algorithms and utilities for Rust

synfx-dsp synfx-dsp DSP real time audio synthesis, effect algorithms and utilities for Rust Most of the algorithms and implementations in this library

Weird Constructor 8 Nov 23, 2022
Quite OK Audio format in Rust.

QOA - The Quite Ok Audio Format This is a pure Rust (zero dependency) implementation of the QOA audio format. This code is based off the reference C i

Rafael Carício 10 Apr 16, 2023
A low-overhead and adaptable audio playback library for Rust

Awedio   A low-overhead and adaptable audio playback library for Rust. Examples Play a single sound file: let (mut manager, backend) = awedio::start()

10 Buttons 20 May 25, 2023
Capture system output audio in rust.

RUHear A simple crate that allows you to capture system output audio (what aRe yoU HEARing). Dependencies On windows and linux: cpal On macos: screenc

Charles 3 Feb 7, 2024