__ __ | |--.---.-.-----.-----.-----.| |.--.--.-----. | _ | _ |__ --| -__| _ || || | | _ | |_____|___._|_____|_____| __||__||_____|___ | |__| |_____| baseplug is a high-level model/view/controller-ish audio plugin framework. nightly-only right now, because of GATs and min_specialization. baseplug is still largely prototypal, but is maturing quickly. i highly encourage looking at the examples and building experiments with it. though there will be API breakage in the future, i do not see a significant divergence from the existing structures. with that said, baseplug is not currently in a place where you should *ship* any plugins built with it. as the baseplug APIs change, there is a high likelihood that your users' sessions will break, presets won't load correctly, and automation will be incorrect. the primary goal for the 0.1 milestone is resolving these issues of forward-compatibility, and at that juncture we will lift the above advisement against shipping plugins. i'm making this public in its pre-pre-alpha state to get feedback from folks. please file issues if things act weird or something's unclear. do note that, though i have extensive experience in audio dev, i am largely a neophyte when it comes to advanced rust usage, proper code style and best practices. especially when it comes to error handling in procmacros. best way to get in touch is to join the rust audio discord: https://discord.gg/8rPCp9Q -w
MVC audio plugin framework for rust
Overview
Comments
-
Implement offset_of! using MaybeUninit and addr_of! to avoid UB
The existing implementation of the
offset_of!
macro dereferences a null pointer, which invokes undefined behavior and results in a compiler warning. Change it to useaddr_of!
on aMaybeUninit
instead.Compiler Explorer shows this compiling down to a single
lea
instruction with optimizations on, so performance should not be an issue: https://godbolt.org/z/57deqbaM5 -
fix issue #29
Figured out how to fix issue #29. It was a matter of figuring out where it wanted me to put the where Self: 'proc, P: 'proc, T: 'proc like it said in the error message.
-
fix for issue #29
Figured out how to fix issue #29. It was a matter of figuring out where it wanted me to put the
where Self: 'proc, P: 'proc, T: 'proc
like it said in the error message.I'm using the RustyDAW org account for this since I've already forked baseview with my own account.
-
Fails to compile on latest rust nightly compiler
I have updated to the latest rust nightly compiler, and baseplug now fails to compile with the following error:
error: Missing required bounds on Process --> src/model.rs:11:5 | 11 | type Process<'proc>; | ^^^^^^^^^^^^^^^^^^^- | | | help: add the required where clauses: `where P: 'proc, Self: 'proc, T: 'proc` error: could not compile `baseplug` due to previous error warning: build failed, waiting for other jobs to finish... error: build failed
-
use HasRawWindowHandle instead of RawWindowHandle
Baseview requires a struct that implements
HasRawWindowHandle
, which means the user must convert theRawWindowHandle
given inPluginUI::ui_open()
into a struct that implements that. This PR fixes that by converting it at the baseview level.It is called
TrustedWindowHandle
because of it mirrors this: https://github.com/rust-windowing/raw-window-handle/blob/master/src/lib.rs#L210. I don't believe that this is in crates.io yet, so I created a temporary one.Instead of the user doing this:
fn ui_open(parent: RawWindowHandle) -> WindowOpenResult<Self::Handle> { let settings = iced_baseview::Settings { window: WindowOpenOptions { title: String::from("iced-baseplug-examples gain"), size: Size::new(Self::ui_size().0 as f64, Self::ui_size().1 as f64), scale: WindowScalePolicy::SystemScaleFactor, }, flags: (), }; // TODO: Fix this mess in baseplug. struct ParentWindow(RawWindowHandle); unsafe impl HasRawWindowHandle for ParentWindow { fn raw_window_handle(&self) -> RawWindowHandle { self.0 } } let handle = iced_baseview::IcedWindow::<ui::GainUI>::open_parented(&ParentWindow(parent), settings); Ok(handle) }
They can now do this:
fn ui_open(parent: &impl HasRawWindowHandle) -> WindowOpenResult<Self::Handle> { let settings = iced_baseview::Settings { window: WindowOpenOptions { title: String::from("iced-baseplug-examples gain"), size: Size::new(Self::ui_size().0 as f64, Self::ui_size().1 as f64), scale: WindowScalePolicy::SystemScaleFactor, }, flags: (), }; let handle = iced_baseview::IcedWindow::<ui::GainUI>::open_parented(parent, settings); Ok(handle) }
-
Create CHECKLIST.md
I believe it would be massively helpful to have a checklist that highlights the differences and similarities between plugin formats. This would both inform developers who aren't that familiar with plugin APIs (like myself) on how each of these work, and it will make how to create an abstraction over them much clearer.
I had to make assumptions on what the VST2 functions do. Feel free to add and correct me on them!
-
Impossible to create audio effects with MIDI in?
Creating a plugin implementation with:
const INPUT_CHANNELS: usize = 2; const OUTPUT_CHANNELS: usize = 2;
that also implements
MidiReceiver
creates something that is flagged by Ableton and RENoise as an instrument with sidechain, when it should be an effect with 2 input channels. Does baseplug have a manual setting for this, like JUCE? Should this be a const in thePlugin
trait? -
Donwfall85/feature/numbers
This branch implements the Num, Real and Discrete traits to represent numbers. The main objective is to replace the Float trait which is not very well designed. I only implemented the basic operations to keep the current behaviour but it is of course possible to play others (All credit goes to SamiP for implementing these traits).
The next step would be to allow the use of other primitive types than f32. To do this, you have to play with the Translatable <T, P: Plugin, Model> trait.
I tried the following implementation but quickly found myself stuck:
impl <P: Plugin, Model, T> Translatable <T, P, Model> for T where T: Real + AsPrimitive <f32>.
This allows you to use f32 or f64. However, when we want to do the same thing for integers, we end up with a conflict:
impl <P: Plugin, Model, T> Translatable <T, P, Model> for T where T: Discrete + AsPrimitive <f32>.
We have two blanket implementations and this is not allowed by Rust until we can do mutual trait exclusions.
One solution that works is to implement the
Translatable <T, P: Plugin, Model>
trait for each type with a macro:macro_rules! impl_real { ( $($t:ty),* ) => { $( impl<P: Plugin, Model> Translatable<$t, P, Model> for $t { fn xlate_in(param: &Param<P, Model>, normalised: f32) -> $t { ... } fn xlate_out(&self, param: &Param<P, Model>) -> f32 { ... } }) * } } impl_real! { f32, f64 } macro_rules! impl_discrete { ( $($t:ty),* ) => { $( impl<P: Plugin, Model> Translatable<$t, P, Model> for $t { fn xlate_in(param: &Param<P, Model>, normalised: f32) -> $t { . } fn xlate_out(&self, param: &Param<P, Model>) -> f32 { . } }) * } } impl_discrete! { i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize }
With this solution, it is possible to use any scalar type to build a parameter.
I need your vision on which solution would be most appropriate in the context of the project.
-
Donwfall85/feature/enum impl
Here is my attempt to implement enums in baseplug model. We can now write models like that:
baseplug::model! { #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] enum MyEnum { A, B, } #[derive(Debug, Serialize, Deserialize)] struct MyModel { #[parameter(name = "param")] param: MyEnum } }
Nearly all the job is done in the proc macro.
There is one thing that I would like to improve but I haven't any solution right now. We now need to import baseplug::Translatable and baseplug::Param in the plugin since the proc macro generates the implementation of the Translatable trait for the enum.
Let me know what do you think and how I can improve it.
-
UI Model synchronization
So far this seems to work for float parameters/entries (Smooth & Unsmoothed). I haven't yet figured out how to sync
Declick
parameters/entries yet, but this is a huge start.Sorry if this PR is a bit of a mess. It took a lot of changes to get this working. :D
-
Combining baseplug with rsynth
Hi, I'm the maintainer of rsynth, an "API abstraction for API's for audio plugins and applications". My "strategy" with
rsynth
was to stay away from UI's, hoping that others (with more expertise in UI development) would work on that.baseplug
illustrates for me that this was the good strategy :-)I'd like developers (including me) to be able to combine
rsynth
withbaseplug
for the UI for writing their plugins. What do you think about this?
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
A low-level windowing system geared towards making audio plugin UIs.
baseview A low-level windowing system geared towards making audio plugin UIs. baseview abstracts the platform-specific windowing APIs (winapi, cocoa,
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
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
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
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
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
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
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
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
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
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
Cross-platform audio for Rust
quad-snd High-level, light-weight, and opinionated audio library. Web: WebAudio Android: OpenSLES Linux: Alsa macOS: CoreAudio Windows: Wasapi iOS: Co
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
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
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()
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
Rust-crate with functions and helpers for working with music / audio, inspired by computer music languages.
music-math This crate contains common functions and helpers for working with music / audio in Rust. Most of these are inspired by similar functions fo
A collection of filters for real-time audio processing
Audio Filters A collection of filters for real-time audio processing Feature Progress #![no_std] (via libm) f32 & f64 capable (via num-traits) SIMD Do