2 releases
0.1.1 | Oct 23, 2020 |
---|---|
0.1.0 | Mar 27, 2020 |
#11 in #lv2
Used in lv2
1MB
15K
SLoC
Rust-LV2's library to implement LV2 Worker extension.
Work scheduling library that allows real-time capable LV2 plugins to execute
non-real-time actions. This is a part of
rust-lv2
, a safe, fast, and ergonomic
framework to create LV2 plugins for audio processing,
written in Rust.
Documentation
The original LV2 API (in the C
programming language) is documented by
"the LV2 book". This book is in the process of
being translated to Rust along with the development of rust-lv2
(link) and describes how to
properly use rust-lv2
.
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.
lib.rs
:
Work scheduling library that allows real-time capable LV2 plugins to execute non-real-time actions.
This crate allows plugins to schedule work that must be performed in another thread. Plugins can use this interface to safely perform work that is not real-time safe, and receive the result in the run context. A typical use case is a sampler reading and caching data from disk. You can look at the LV2 Worker Specification for more details.
Example
use std::any::Any;
use lv2_core::feature::*;
use lv2_core::prelude::*;
use urid::*;
use lv2_worker::*;
#[derive(PortCollection)]
struct Ports {}
/// Requested features
#[derive(FeatureCollection)]
struct AudioFeatures<'a> {
///host feature allowing to schedule some work
schedule: Schedule<'a, EgWorker>,
}
//custom datatype
struct WorkMessage {
cycle: usize,
task: usize,
}
/// A plugin that do some work in another thread
struct EgWorker {
// The schedule handler needs to know the plugin type in order to access the `WorkData` type.
cycle: usize,
end_cycle: usize,
}
/// URI identifier
unsafe impl UriBound for EgWorker {
const URI: &'static [u8] = b"urn:rust-lv2-more-examples:eg-worker-rs\0";
}
impl Plugin for EgWorker {
type Ports = Ports;
type InitFeatures = ();
type AudioFeatures = AudioFeatures<'static>;
fn new(_plugin_info: &PluginInfo, _features: &mut Self::InitFeatures) -> Option<Self> {
Some(Self {
cycle: 0,
end_cycle: 1,
})
}
fn run(&mut self, _ports: &mut Ports, features: &mut Self::AudioFeatures, _: u32) {
self.cycle += 1;
let cycle = self.cycle;
println!("cycle {} started", cycle);
for task in 0..10 {
let work = WorkMessage { cycle, task };
// schedule some work, passing some data and check for error
if let Err(e) = features.schedule.schedule_work(work) {
eprintln!("Can't schedule work: {}", e);
}
}
}
fn extension_data(uri: &Uri) -> Option<&'static dyn Any> {
match_extensions![uri, WorkerDescriptor<Self>]
}
}
/// Implementing the extension.
impl Worker for EgWorker {
// data type sent by the schedule handler and received by the `work` method.
type WorkData = WorkMessage;
// data type sent by the response handler and received by the `work_response` method.
type ResponseData = String;
fn work(
//response handler need to know the plugin type.
response_handler: &ResponseHandler<Self>,
data: Self::WorkData,
) -> Result<(), WorkerError> {
println!("work received: cycle {}, task {}", data.cycle, data.task);
if data.task >= 5 {
if let Err(e) = response_handler.respond(format!(
"response to cycle {}, task {}",
data.cycle, data.task
)) {
eprintln!("Can't respond: {}", e);
}
};
Ok(())
}
fn work_response(
&mut self,
data: Self::ResponseData,
_features: &mut Self::AudioFeatures,
) -> Result<(), WorkerError> {
println!("work_response received: {}", data);
Ok(())
}
fn end_run(&mut self, _features: &mut Self::AudioFeatures) -> Result<(), WorkerError> {
println!("cycle {} ended", self.end_cycle);
self.end_cycle += 1;
Ok(())
}
}
Dependencies
~1.5MB
~37K SLoC