Safe rust abstractions over libpd.

Overview

libpd-rs

Build and Test Status Code Coverage

Safe rust abstractions over libpd-sys.

Pure Data (Pd) is a visual programming language developed by Miller Puckette in the 1990s for creating interactive computer music and multimedia works. While Puckette is the main author of the program, Pd is an open-source project with a large developer base working on new extensions. It is released under BSD-3-Clause.

Though pd is designed as a desktop application, libpd is an open source project which exposes it as a C library opening the possibility to embed the functionality of pd to any platform which C can compile to.

libpd-rs aims to bring libpd to the Rust ecosystem. It aims to expose the full functionality of libpd with some extra additions such as bundling commonly used externals and addition of extra functionality for increased ease of use.

It is thoroughly documented, well tested and enriched with various examples to get you started right away.

Now let's make some sound! ๐Ÿ””


Add the following dependencies to your Cargo.toml:

[dependencies]
libpd-rs = "0.1.9"
cpal = "0.13"

Paste the code into your main.rs:

โš ๏ธ Warning โš ๏ธ : This example will produce audio, so please keep your volume at a reasonable level for safety.

use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
use libpd_rs::convenience::PdGlobal;

fn main() -> Result<(), Box<dyn std::error::Error>> {

    // Initialize cpal
    // This could have been another cross platform audio library
    // basically anything which gets you the audio callback of the os.
    let host = cpal::default_host();

    // Currently we're only going to output to the default device
    let device = host.default_output_device().unwrap();

    // Using the default config
    let config = device.default_output_config()?;

    // Let's get the default configuration from the audio driver.
    let sample_rate = config.sample_rate().0 as i32;
    let output_channels = config.channels() as i32;

    // Initialize libpd with that configuration,
    // with no input channels since we're not going to use them.
    let mut pd = PdGlobal::init_and_configure(0, output_channels, sample_rate)?;

    // Let's evaluate a pd patch.
    // We could have opened a `.pd` file also.
    // This patch would play a sine wave at 440hz.
    pd.eval_patch(
        r#"
    #N canvas 577 549 158 168 12;
    #X obj 23 116 dac~;
    #X obj 23 17 osc~ 440;
    #X obj 23 66 *~ 0.1;
    #X obj 81 67 *~ 0.1;
    #X connect 1 0 2 0;
    #X connect 1 0 3 0;
    #X connect 2 0 0 0;
    #X connect 3 0 0 1;
        "#,
    )?;

    // Build the audio stream.
    let output_stream = device.build_output_stream(
        &config.into(),
        move |data: &mut [f32], _: &cpal::OutputCallbackInfo| {
            // Provide the ticks to advance per iteration for the internal scheduler.
            let ticks = libpd_rs::convenience::calculate_ticks(output_channels, data.len() as i32);

            // Here if we had an input buffer we could have modified it to do pre-processing.

            // Process audio, advance internal scheduler.
            libpd_rs::process::process_float(ticks, &[], data);

            // Here we could have done post processing after pd processed our output buffer in place.
        },
        |err| eprintln!("an error occurred on stream: {}", err),
    )?;

    // Turn audio processing on
    pd.activate_audio(true)?;

    // Run the stream
    output_stream.play()?;

    // Wait a bit for listening..
    std::thread::sleep(std::time::Duration::from_secs(5));

    // Turn audio processing off
    pd.activate_audio(false)?;

    // Pause the stream
    output_stream.pause()?;

    // Close the patch
    pd.close_patch()?;

    // Leave
    Ok(())
}

This is just the tip of the iceberg about what you can do with libpd.

The patch we had just evaluated would look like this in pd desktop application:

Running the examples and tests

After cloning the repository, in the repository root run:

cargo run --example <name of the example>

e.g.

cargo run --example with_nannou

Please check the README on examples for more information.

For the tests, you may run cargo test directly.

Next steps

Please check the examples and tests directory if you're learning better when reading code.

Or if you would like to dive in to documentation please go ahead.

Resources

Road map

Support

  • Desktop

    • macOS:
      • x86_64 โœ…
      • aarch64 โœ…
    • linux:
      • x86_64 โœ…
      • aarch64 โœ…
    • windows:
      • msvc
        • x86_64 โœ…
        • aarch64 (not tested but should work)
      • gnu
        • x86_64 (not tested but should work)
        • aarch64 (not tested but should work)
  • Mobile

    • iOS (not yet but will be addressed)
    • Android (not yet but will be addressed)
  • Web (not yet but will be addressed)

List of bundled externals

The way to add externals to libpd is to compile and statically link them.

libpd-rs will be bundling some of the essential and commonly used externals in pure data. This list will be growing as we add more externals.

If you have ideas please consider writing an answer to this post.

  • moog~
  • freeverb~

Contributing

  • Be friendly and productive
  • Follow common practice open source contribution culture
  • Rust code of conduct applies

Thank you ๐Ÿ™

Similar projects

Last words

Generative or algorithmic music is a powerful tool for exploration, pumps up creativity and goes very well together with traditional music making approaches also.

Making apps which produce meaningful sound is difficult, I wish that this crate would ease your way on doing that and make complicated audio ideas in apps accessible to more people.

Comments
  • Improve convenience module

    Improve convenience module

    Currently libpd-rs mirrors libpd in terms of usage and exposed apis.

    I have started writing a convenience module to have one more layer of abstraction over them.

    What I would like to address is the issue of an ergonomic api for ease of use and safety

    enhancement 
    opened by alisomay 1
  • Add functionality to evaluate strings as patches.

    Add functionality to evaluate strings as patches.

    This can be done with writing a temporary file the easiest way. https://docs.rs/tempfile/latest/tempfile/ The PatchFileHandle can be made a struct with an optional field which may hold a reference to the temp dir or file and lives until we close it.

    enhancement 
    opened by alisomay 0
  • Add unit tests to some places

    Add unit tests to some places

    The nature of this project fits more to integration tests.

    On the other hand in the code I have marked some places which could benefit from unit tests.

    Tests should be written for those places.

    Search for TODO in the repository.

    enhancement 
    opened by alisomay 0
  • Fix windows communication

    Fix windows communication

    The underlying problem is fixed in libpd-sys by using our own fork of libpd in it for a while.

    The problem originated because of https://github.com/libpd/libpd/issues/350 and will be fixed when https://github.com/libpd/libpd/pull/351 is merged.

    Until then I'll be using our own fork in https://github.com/alisomay/libpd instead of the upstream.

    opened by alisomay 0
  • Add examples

    Add examples

    I'd like to add multiple examples in an examples folder for people to start fast and easy.

    Some ideas are,

    • Sine (hello world) โœ…
    • Messaging with pd
    • Writing and reading from arrays
    • Usage of some less commonly used functions
    • Embedding to nannou โœ…
    • Embedding to Bevy
    • Examples with specifically with cpal
    • Examples with other cross platform audio libraries.

    I'd like most of the examples to contain nice music. Also I would like that all of them to produce audio.

    enhancement 
    opened by alisomay 0
Owner
Ali Somay
Musician / Software Engineer / Hardware Electronics Enthusiast
Ali Somay
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
High-level PortMidi bindings and wrappers for Rust

portmidi-rs High-level PortMidi bindings for Rust. PortMidi website: http://portmedia.sourceforge.net/portmidi/ Installation Add this to your Cargo.to

Philippe Delrieu 69 Dec 1, 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
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
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
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
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
Rust speech synth

Grail-rs (Work in progress) Grail, A simple formant speech synthesizer, built for portability This is the rust version The goal of this synthesizer is

Dimev 16 Dec 28, 2022
A Spotify downloader written in rust, which does not require a premium account

DownOnSpot A Spotify downloader written in Rust Disclaimer DownOnSpot was not developed for piracy. It is meant to be used in compliance with DMCA, Se

oSumAtrIX 273 Jan 7, 2023