A safe, fast, and ergonomic framework to create LV2 plugins for audio processing, written in...

A safe, fast, and ergonomic framework to create LV2 Core specification:

Rust-LV2

A safe, fast, and ergonomic framework to create LV2 plugins for audio processing, written in Rust.

This library is a work in progress.

It provides the following features, through the LV2 Core specification:

  • Lightweight, realtime non-blocking and allocation-free audio processing.
  • Generates all the boilerplate to make a LV2 plugin binary, usable by any LV2 host.
  • Any number of ports / Any channel mapping, which can be different for input and output.
    This obviously includes Mono, Stereo, Surround, etc., any configuration your CPU can handle.
  • Can be extended to support any additional features, extensions and port types.
    They can be official, unofficial or completely custom.

Through the LV2 official additional specifications, this library also provides many additional features, including:

  • MIDI processing
  • Serialization of custom data structures, and plugin-plugin or plugin-GUI communication and property manipulation
  • State management
  • Asynchronous work processing
  • Custom Graphical User Interfaces, both in a toolkit-agnostic and in a platform-agnostic way (Not yet implemented)
  • Presets handling (Not yet implemented)
  • ... and more! (Not yet implemented either)

Note that this library will only provide Rust bindings for the official LV2 specifications, however it is compatible with any other arbitrary or custom specification, and other, external crates are able and welcome to provide Rust bindings to any other specification that will integrate with this library.

Example

This example contains the code of a simple amplification plugin. Please note that this isn't the only thing required to create a plugin, see the documentation below for more details.

About this framework

Q&A

Does my host program support it?

Plugins created with rust-lv2 are compatible to all LV2 hosts that comply to the specifications. If your application uses lilv, it's a good sign that it will support your plugin. Some prime examples are Carla and Ardour.

Can I host plugins with rust-lv2?

Currently, hosting plugins is not supported. This project was initialy started to create plugins using safe Rust and therefore, it is very plugin-centric. There are plans for integrated plugin hosting or a spin-off project, but those won't start in the near future.

However, there is a lot of code that can be re-used for a hosting framework. If you want to create such a framework, you should take a look at lv2-sys, urid, and lv2-atom.

A bare hosting framework would require an RDF triple store which can load Turtle files, an internal store for plugin interfaces and their extensions, a centralized URID map store, and a graph based work scheduling system to execute run functions in order.

Documentation

There are multiple valuable sources of documentation:

  • "The Rust-LV2 book" describes how to use Rust-LV2 in general, broad terms. It's the ideal point to get started and is updated with every new version of Rust-LV2.
  • The API documentation.
  • The LV2 specification reference.

Features

Internally, this framework is built of several sub-crates which are re-exported by the lv2 crate. All dependencies are optional and can be enabled via features. These are:

  • lv2-atom: General data IO.
  • lv2-core: Implementation of the core LV2 specification.
  • lv2-midi: MIDI message extension for lv2-midi. Support for the wmidi crate can be enabled with the wmidi feature.
  • lv2-state: Extension for LV2 plugins to store their state.
  • lv2-time: Specification to describe position in time and passage of time, in both real and musical terms.
  • lv2-units: Measuring unit definitions.
  • lv2-urid: LV2 integration of the URID concept.
  • lv2-worker: Work scheduling library that allows real-time capable LV2 plugins to execute non-real-time actions.
  • urid: Idiomatic URID support.

Sub-crates with an lv2- prefix implement a certain LV2 specification, which can be looked up in the reference. Enabling a crate only adds new content, it does not remove or break others.

There are also feature sets that account for common scenarios:

  • minimal_plugin: The bare minimum to create plugins. Includes lv2-core and urid.
  • plugin: Usual crates for standard plugins. Includes lv2-core, lv2-atom, lv2-midi, lv2-urid, and urid. This is the default.
  • full: All sub-crates.

Supported targets

Rust-LV2 uses pregenerated C API bindings for different targets in order to increase usability and building speed. Rust has a lot of supported targets, but our maintaining power is limited and therefore, only certain targets can be supported. We've ranked different targets in Tiers, just like rustc does, which gives you a general understanding of what to expect of a target. The tables below list the supported targets, the used binding in the lv2-sys crate, and, if applicable, the maintainer and the last verification of that target.

The bindings itself are generated with the LV2 systool and verified by building the example plugins of the book and testing them with a host of that target.

Tier 1

A Tier 1 target for rust-lv2 also has to be a Tier 1 target of rustc. You can check the platform support page to see which targets are included and what they provide. Additionally, there has to be a maintainer of rust-lv2 who has access to a machine that runs this target and who can generate and verify bindings on this machine. This means that if you have a problem running your code on a Tier 1 target, there will be a maintainer who can help you.

Target Binding Maintainer Last Verification
x86_64-unknown-linux-gnu linux/x86_64.rs @Janonard 10. of May 2020, using Carla v2.1, running on Arch Linux
x86-unknown-linux-gnu linux/x86.rs @Janonard 16th of May 2020, using Carla v2.1, running on Linux Mint 19.3 32-bit

Tier 2

A Tier 2 target is a target that is at least in Tier 2 of rustc and has a generated binding. However, it might not work (well) and there might not be a maintainer who has access to a machine that runs this target and who can generate and verify bindings on this machine. This means that if you have a problem running your code on a Tier 2 target, you're stepping into uncharted territory.

Target Binding
aarch64-unknown-linux-gnu aarch64.rs
arm-unknown-linux-gnueabi arm.rs
arm-unknown-linux-gnueabihf arm.rs
armv5te-unknown-linux-gnueabi arm.rs
armv7-unknown-linux-gnueabi arm.rs
armv7-unknown-linux-gnueabihf arm.rs
thumbv7neon-unknown-linux-gnueabihf arm.rs
x86_64-pc-windows-msvc windows.rs

License

Licensed under either of

  • Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
  • MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)

at your option.

Issues

Collection of the latest Issues

Jikstra

Jikstra

5

Is there a way to spawn an own thread? I need to retrieve data from a serial device and somehow send midi messages into the run method. I tried spawning a thread in Plugin::new but it seems like this is forbidden? Using lv2_worker also seems more of a hack for my use case, as i don't want to pass data from run to a worker, but have a worker running all the time.

jrpear

jrpear

:lady_beetle: Bug
6

When I do:

, Carla crashes after adding the MIDI Gate plugin. I get this output:

The other three examples don't have this issue for me.

prokopyl

prokopyl

:lady_beetle: Bug
4

As of now, all port types return &'static references to their contents, which allows them to be stored outside of the run() function, at which point the host could invalidate them (the following code compiles fine today):

While this example is rather obvious in that it's doing something very odd, issues can be viciously subtle with more complex port types such as Atom: one could want to store a deserialized value.

I haven't made any in-depth testing, but I see two solutions to this:

The first would be to make PortType generic over a 'a lifetime:

However, this has a cascading effect, which would force all downstream users of port types to specify their lifetimes:

The second option would be to make the associated types themselves generic:

However, this would require Generic Associated Types being stabilized, but while it seems to be making steady progress, there doesn't seem to be any deadline coming soon.

Both options are breaking changes however.

I think we could potentially use the first solution now, and move to GATs when they are stabilized, making two breaking changes.

prokopyl

prokopyl

:left_speech_bubble: Discussion
1

I am making this issue to separate the conversation about the implementation in #93, and the following questions that were raised:

  • Should the in-place-compatible port types be the default?
  • Should in-place-broken processing be supported at all?

There was already a rather large conversation and many points that were stated in the discussion thread in #93 which I won't reproduce here.

Considering this change, if implemented, would not be done until after the next major release (since it would be breaking), discussing it can wait, while restoring compatibility with hosts that do not allow inPlaceBroken (see #89) is more pressing. :slightly_smiling_face:

Janonard

Janonard

question
2

Right now, it might not be as important to have a contribution guide or a code of conduct, but it may be when looking into the future. I simply like having things sorted out and right now, we have no pressure yet. Any ideas?

Versions

Find the latest versions by id

0.6.0 - Oct 23, 2020

We are happy to release the new version 0.6.0 of Rust-LV2, a safe, fast, and ergonomic framework to create LV2 plugins for audio processing, written in Rust.

What has changed?

  1. The C API bindings are now generated by maintainers. Previously, the bindings were generated at compile time by the user, which required additional dependencies and a properly installed clang. Now, usage of the Rust-LV2 framework is way easier and compile times are way shorter.
  2. The Rust-LV2 book is out now, explaining the concepts and API of Rust-LV2 using real plugins.
  3. Saving files along with the plugin state is now supported by the lv2-atom crate.

v0.5.1 - Mar 28, 2020

We are happy to release the new version 0.5.1 of rust-lv2, a safe, fast, and ergonomic framework to create LV2 plugins for audio processing, written in Rust.

This release adds wmidi and lv2-units to the plugin feature set of lv2. This change was made since these features are almost always used by simple plugins that process MIDI messages; Plugins that process MIDI messages but don't use wmidi are pretty rare.

v0.5.0 - Mar 27, 2020

We are happy to release the new version 0.5.0 of rust-lv2, a safe, fast, and ergonomic framework to create LV2 plugins for audio processing, written in Rust.

What has changed?

  1. The Worker features and extensions were implemented and are ready to be used now.
  2. The uri attribute was introduced, which implements UriBound for the attributed type.
  3. The lv2 crate has been expanded to a powerful and configurable re-export crate.
  4. Host features are now accessible from all plugin methods and a second feature collection type was introduced. All methods in the audio threading class (e.g. run) have access to an instance of this second collection.
  5. The UriBound and URID types as well as code that belongs to them has moved to their own crate, called urid. This change was made to make this code more reusable and to flatten the dependency graph.

Porting projects to version 0.5

Updating your dependencies

First of all, you're advised to use the lv2 crate to access the framework. This crate has optional dependencies to all sub-crates now, which can be activated via features. Let's assume that your dependency section looked like this before:

This dependency section translates to the following:

The features lv2-core, lv2-atom, lv2-midi, lv2-urid, and urid are enabled by default and therefore don't need to be listed.

Using the re-export crate

After the update, you can not directly use the sub-crates anymore. Instead, you should use them via the lv2 re-export crate. A use lv2_core becomes a lv2::core now. lv2 also provides the super-prelude, which includes the preludes of all enabled sub-crates. You can simply use lv2::prelude::* to get all you need!

Using the uri attribute

Previously, you had to implement the unsafe, but very useful UriBound trait manually. Now, you can write something neat like this:

This attribute can implement UriBound for structs, enums, unions and type definitions and is safe to use since it always adds the null terminator to the generated URI.

API changes

The following types were renamed that were commonly used in plugins:

  • lv2_urid::Map -> lv2_urid::LV2Map
  • lv2_urid::Unmap -> lv2_urid::LV2Umap

The lv2_core::plugin::Plugin trait has had some changes too:

  • All feature collections are mutably borrowed now.
  • There are two different feature collection types now, one for instantiation class methods and one for audio class methods.

Assuming that your previous Plugin implementation looks like this:

You should now use something like this:

v0.4.1 - Feb 23, 2020

After a year of development, rust-lv2 is now released for the first time.

These new crates were released along with the release:

  • lv2-atom v1.0.1
  • lv2-core v1.0.1
  • lv2-core-derive v1.0.1
  • lv2-midi v1.0.1
  • lv2-state v1.0.1
  • lv2-sys v1.0.1
  • lv2-time v0.1.1
  • lv2-units v0.1.1
  • lv2-urid v1.0.1
  • lv2-urid-derive v1.0.1

Information - Updated May 13, 2022

Stars: 125
Forks: 13
Issues: 12

Rust bindings for libinjection

Add libinjection to dependencies of Cargo

Rust bindings for libinjection

Rust Compiled Templates — ructe

This is my attempt at writing a HTML template system for Rust

Rust Compiled Templates — ructe

Rust bindings for the C++ api of PyTorch

LIghtweight wrapper for pytorch eg libtorch in rust

Rust bindings for the C++ api of PyTorch

Rust leveldb bindings

Almost-complete bindings for leveldb for Rust

Rust leveldb bindings

rust-analyzer is a modular compiler frontend for the Rust language

It also contains some tips & tricks to help you be more productive when using rust-analyzer

rust-analyzer is a modular compiler frontend for the Rust language

Rust-Lightning is a Bitcoin Lightning library written in Rust

lightning, does not handle networking, persistence, or any other I/O

Rust-Lightning is a Bitcoin Lightning library written in Rust

Rust FUSE - Filesystem in Userspace

Rust library crate for easy implementation of Crate documentation

Rust FUSE - Filesystem in Userspace

Rust crate to implement a counterpart to the PBRT book's (3rd edition) C++ code:

Some images of the test scenes are shown below, but you can find more

Rust crate to implement a counterpart to the PBRT book's (3rd edition) C++ code:

Rust Persian Calendar

1** provides functionality for conversion among Persian (Solar Hijri) and Gregorian calendars

Rust Persian Calendar

Rust DjangoHashers

A Rust port of the password primitives used in alternatice implementation: the package library that requires OpenSSL

Rust DjangoHashers

Rust web application

Diesel (ORM) is used to work with the database

Rust web application

Rust bindings for Sciter

this page for other language bindings (Delphi / D / Go /

Rust bindings for Sciter
Facebook Instagram Twitter GitHub Dribbble
Privacy