Thin but safe ALSA wrappers for Rust

Overview

ALSA bindings for Rust

Thin but safe wrappers for ALSA, the most common API for accessing audio devices on Linux.

crates.io API documentation license

The ALSA API is rather big, so everything is not covered yet, but expect the following to work:

  • Audio Playback (example in pcm module docs)

  • Audio Recording

  • Mixer controls

  • HCtl API (jack detection example in hctl module docs)

  • Raw midi

  • Midi sequencer (most of it)

  • Ctl API

  • Device name hints (example in device_name module docs)

  • Enumerations of all of the above

  • Poll and/or wait for all of the above

The following is not yet implemented (mostly because nobody asked for them) :

  • Separate timer API (snd_timer_*)

  • Config API (snd_config_*)

  • Plug-in API

Quickstart guide / API design:

  • Most functions map 1-to-1 to alsa-lib functions, e g, ctl::CardInfo::get_id() is a wrapper around snd_ctl_card_info_get_id and the alsa-lib documentation can be consulted for additional information.

  • Structs are RAII and closed/freed on drop, e g, when a PCM struct is dropped, snd_pcm_close is called.

  • To read and write buffers, call the io_* methods. It will return a separate struct from which you can read or write, and which can also be used for mmap (if supported by the driver).

  • Error handling - most alsa-lib functions can return errors, so the return value from these is a Result.

  • Enumeration of cards, devices etc is done through structs implementing Iterator.

  • Many structs implement poll::Descriptors, to combine with poll or mio. Or just use wait if you don't need non-blocking functionality.

Notes:

  • To run the tests successfully, there must be a "default" sound card configured. This is usually not a problem when running on normal hardware, but some CI systems, docker images etc, might not have that configured by default.
Comments
  • Alsa 0.6.1 release is not semver compliant

    Alsa 0.6.1 release is not semver compliant

    #89 (and the associated release) broke semver and caused our builds to fail in CI.

    Users are running into the same problem with fresh builds: see this Discord thread.

    Please yank the release; and let us know if there's anything we can do to help out :)

    opened by alice-i-cecile 22
  • Document MidiEvent::encode

    Document MidiEvent::encode

    MidiEvent::encode really needs documentation as to what it does.

    From the signature and the implementation I can see that it returns (in case of success) the number of bytes consumed from the buffer as well as the encoded event (or None if no complete message was encoded).

    Then it also needs to be documented that the event buffer is copied for long (sysex) messages. I guess this is because the documentation of snd_midi_event_encode states that

    When this function returns a system exclusive sequencer event (ev->type is SND_SEQ_EVENT_SYSEX), the data pointer (ev->data.ext.ptr) points into the MIDI event parser's buffer. Therefore, the sequencer event can only be used as long as that buffer remains valid, i.e., until the next call to snd_midi_event_encode, snd_midi_event_encode_byte, snd_midi_event_resize_buffer, snd_midi_event_init, snd_midi_event_reset_encode, or snd_midi_event_free for that MIDI event parser.

    This makes me wonder whether it might be possible to encode this in the Rust typesystem using lifetimes, instead of requiring a copy?

    Furthermore, the documentation of snd_seq_event_input (where currently the data is also copied by Event::extract) has no such comment, which makes me wonder if the buffer there is managed by the event itself (because there is no separate underlying buffer).

    opened by Boddlnagg 17
  • add support for getting snd_pcm_info

    add support for getting snd_pcm_info

    I needed to get the card from a opened pcm, so I've added the snd_pcm_info to pcm.rs

    I left out the nested structs for snd_pcm_class and snd_pcm_sync for now.

    opened by lrbalt 15
  • Share PCM between multiple threads

    Share PCM between multiple threads

    Hi @diwic !

    I'd like to access PCMs from multiple threads (at least two) in order to:

    • Only read/write buffers at real-time priority
    • Gather PCM Status for timestamp / avail data at a specified frequency and at the highest real-time priority. The frequency should not depend on capture or playback frame sizes.

    In order to do that, there will be three threads.

    1. Capture thread
    2. Playback thread
    3. Timestamp/avail status gathering thread.

    Therefore, both capture and playback PCMs need to be shared with the status gathering thread, that'll periodically adjust an asynchronous resampler ratio.

    In alsa-lib tests, the pcm-multi-thread.c example shows how it is possible in C. It's simple, a single static snd_pcm_t *pcm is declared on top and all threads call methods on it.

    Would it be possible to do that with alsa-rs? Right now, I get this error:

    error[E0277]: the trait bound `*mut alsa_sys::snd_pcm_t: std::marker::Sync` is not satisfied in `&alsa::PCM`
       --> src/alsa_audio_time.rs:155:9
        |
    155 |         thread::spawn(|| {
        |         ^^^^^^^^^^^^^ `*mut alsa_sys::snd_pcm_t` cannot be shared between threads safely
    
    opened by supercurio 14
  • Add ability for Event to reference external buffer

    Add ability for Event to reference external buffer

    This is the first version of a PR that allows seq::Event to carry a reference to an external buffer for variable length data (esp. SysEx events). Without this, there is no way to use encode for SysEx messages and then send the message without creating an additional copy of the buffer. I removed the encode_cb variant, because it makes no sense: For the encoded event to be sent, it must contain a reference to the actual buffer. Actually, having a SysEx message that references an empty buffer (which was previously possible by returning None from the callback) is probably an error. ALSA forwards such an event unchecked, but the receiving application might not be able to deal with it.

    I don't consider th e added lifetime for Event<'a> a big usability issue. IMHO it actually makes the API nicer compared to the callback variant. encode now takes the encoder (MidiEvent) by unique reference, so that the encoder can't be messed with while the event still references its buffer. This statically enforces that no method listed in the documentation for encode is called and the underyling buffer within the encoder remains unchanged while the event is alive.

    The following changes could be added on top, but I didn't do it yet because I wanted to get feedbackfirst:

    • event_input could be changed in a similar way to encode, coupling the returned event's lifetime to the Seq instance by taking &mut Seq. In this case, the input buffer of the sequencer instance is directly referenced, and it's not very well documented under what circumstances that buffer might change. Not allowing any method call on Seq while the event is alive should be enough, however, but might be too much, because e.g. you wouldn't be able to call event_output directly after event_input to forward the event to another port.

    • It is desirable to be able to create an Event<'a> directly from a &'a [u8], i.e. a SysEx message that references a buffer managed by the user, without creating a copy. (Update: I have added another commit (the second one) to implement this. Feel free to reject that commit.)

    Update: I have also added a third commit that fixes a preexisting bug that is not directly related to my changes.

    opened by Boddlnagg 14
  • Avoid panic if card gives bad state

    Avoid panic if card gives bad state

    I got a bug report on my DSP project, where it panics when reading the state of a pcm. The panic comes from here : https://github.com/diwic/alsa-rs/blob/master/src/pcm.rs#L159 I'm guessing the card returns an invalid value for the state, but it doesn't happen with any of the hardware I have so I can't check that. Anyway, would it be an option to add an "Invalid" or "Unknown" state variant to avoid a panic with misbehaving hardware? Or let state() return a Result? I can implement something and make a PR, but let's agree on the ifs and how's first :)

    opened by HEnquist 12
  • Segfault on alpine linux in alsa::pcm::PCM::open

    Segfault on alpine linux in alsa::pcm::PCM::open

    alsa::pcm::PCM::open (pcm.rs:135) due to (as far as i can tell) the variable 'r' being 0x0

    I'm not sure how to proceed, the program i've been using to narrow it down was this from the synth-example

    fn main() {
        let args: Vec<_> = std::env::args().collect();
        let req_devname = format!("hw:{}", args[1]);
        let p = alsa::PCM::new(&req_devname, alsa::Direction::Playback, false);
     }
    

    Might it be an issue from alpine using musl?

    opened by lxea 10
  • Selecting timestamp type

    Selecting timestamp type

    Hi @diwic! Thanks a lot for the great work on this crate, it's really useful.

    For the MultiDSP project, I'm researching the best way to implement an asynchronous resampler that'll keep multiple sound cards in sync.

    The best way seems to be leveraging the PCM status delay, avail and timestamps. It is already possible to query that today but the timestamps seem to always of the default type: DMA. For the use case of sound card synchronization, the link time and analog times are useful as well. Documentation: https://www.kernel.org/doc/html/latest/sound/designs/timestamping.html

    I rewrote in Rust alsa_time.c from alsa-lib for experimentation and am now testing from that.

    Is timestamp type support something you're interested adding? If I should implement it myself, would you have recommendations?

    opened by supercurio 9
  • Wrap snd_seq_control_queue

    Wrap snd_seq_control_queue

    This is a follow-up after #16, because I took some time now to look at it. And I'm impressed, the current version contains almost everything that I needed, awesome work! :+1:

    I'm missing only one function: snd_seq_control_queue. Actually I'm using snd_seq_start_queue and snd_seq_stop_queue, but those are defined as macros in the original API (wrapping snd_seq_control_queue). Maybe you can create functions for them also.

    opened by Boddlnagg 8
  • add setting volume in decibel

    add setting volume in decibel

    I've added snd_mixer_selem_set_playback_dB

    This function uses dir to select direction (-1 = accurate or first bellow, 0 = accurate, 1 = accurate or first above). I've added an enum for this called AccuracyDirection but there is also a ValueOr enum in lib.rs. Should I use ValueOr for this function too?

    opened by lrbalt 8
  • Add DSD_U32_LE, DSD_U16_BE, DSD_U32_BE formats

    Add DSD_U32_LE, DSD_U16_BE, DSD_U32_BE formats

    Hello again! Here are the changes to alsa-rs which correspond to this commit in diwic/alsa-sys.

    Thanks once more for all your work on these libraries — I really appreciate it! :grinning:

    opened by danieljrmay 6
Owner
null
PortAudio bindings and wrappers for Rust.

rust-portaudio PortAudio bindings and wrappers for Rust. PortAudio is a free, cross-platform, open-source, audio I/O library. rust-portaudio is still

null 331 Dec 23, 2022
PortAudio bindings and wrappers for Rust.

rust-portaudio PortAudio bindings and wrappers for Rust. PortAudio is a free, cross-platform, open-source, audio I/O library. rust-portaudio is still

null 332 Dec 30, 2022
A library for constructing Groth-Sahai proofs using pre-built wrappers

Groth-Sahai Wrappers A Rust library containing wrappers that facilitate the construction of non-interactive witness-indistinguishable and zero-knowled

Jacob White 1 Mar 7, 2022
Safe rust abstractions over libpd.

libpd-rs Safe rust abstractions over libpd-sys. Pure Data (Pd) is a visual programming language developed by Miller Puckette in the 1990s for creating

Ali Somay 42 Nov 6, 2022
mpc, but implemented in Rust.

rsmpc mpc, but implemented in Rust. Note: This is not meant to be a direct implementation, there will be some differences. For example: I moved the op

Cpt.Howdy 7 Jun 8, 2022
Spotify for the terminal written in Rust 🚀

Spotify TUI A Spotify client for the terminal written in Rust. The terminal in the demo above is using the Rigel theme. Spotify TUI Installation Homeb

Alexander Keliris 14.1k Jan 1, 2023
A rust binding for the FMOD library

rust-fmod This is a rust binding for FMOD, the library developped by FIRELIGHT TECHNOLOGIES. FMOD website : www.fmod.org You can also find it on crate

Guillaume Gomez 55 Nov 2, 2022
Easy Api in Rust to play Sounds

ears ears is a simple library to play sounds and music in Rust. Provides an access to the OpenAL spatialization functionality in a simple way. Accepts

Jan Niklas Hasse 82 Jan 1, 2023
Idiomatic Rust bindings for OpenAL 1.1 and extensions (including EFX).

alto alto provides idiomatic Rust bindings for OpenAL 1.1 and extensions (including EFX). WARNING Because Alto interacts with global C state via dynam

null 80 Aug 7, 2022
Cross-platform audio I/O library in pure Rust

CPAL - Cross-Platform Audio Library Low-level library for audio input and output in pure Rust. This library currently supports the following: Enumerat

null 1.8k Jan 8, 2023
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
A music theory guide written in Rust.

Rust Music Theory A library and executable that provides programmatic implementation of the basis of the music theory. Table of Contents Overview Usag

Ozan Kaşıkçı 551 Dec 21, 2022
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
A Rust environment for sound synthesis and algorithmic composition.

Sorceress A Rust environment for sound synthesis and algorithmic composition, powered by SuperCollider. Overview Sorceress is a Rust crate that provid

Wesley Merkel 82 Dec 26, 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
Gtk/Rust native Spotify client for the GNOME desktop.

Gtk/Rust native Spotify client for the GNOME desktop.

Alexandre Trendel 1.7k Jan 1, 2023
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
A music bot build in Serenity/Rust.

Sunny Flowers is a Discord bot to play media in voice channels. It uses Serenity and Songbird to accomplish this.

Sophie 11 Nov 5, 2022
musify is a simple discord bot to play music within a voice channel, written in the rust programming language.

musify-rs musify is a simple discord bot to play music within a voice channel, written in the rust programming language. Features A simple song queue

NV6 5 Aug 14, 2022