2 releases

0.1.1 Oct 23, 2020
0.1.0 Mar 27, 2020

#11 in #lv2


Used in lv2

MIT/Apache

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

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