#lock-free-queue #midi #vst #standalone #host #messages #real-time

audio-processor-standalone-midi

为 VST 主机或 audio-processor-traits 实现者提供独立的 MIDI 主机

22 个版本 (11 个稳定版)

1.12.0 2024 年 8 月 13 日
1.11.0 2024 年 1 月 17 日
1.10.0 2023 年 12 月 7 日
1.9.0 2023 年 5 月 22 日
0.1.0 2021 年 7 月 21 日

#845 in 音频

Download history 9/week @ 2024-05-20 2/week @ 2024-05-27 9/week @ 2024-06-03 14/week @ 2024-06-10 4/week @ 2024-06-17 8/week @ 2024-06-24 152/week @ 2024-07-08 5/week @ 2024-07-15 15/week @ 2024-07-29 5/week @ 2024-08-05 141/week @ 2024-08-12

每月 162 次下载
用于 audio-processor-standalon…

MIT 许可证

330KB
2.5K SLoC

audio-processor-standalone-midi

crates.io docs.rs


此 crate 提供转换为 VST 类型,以便 VST 主机可以使用它。这是由 MidiVSTConverter 提供的。

封装 midir 以提供 MIDI 输入处理。可以使用 MidiHost 启动主机。

当接收到 MIDI 消息时,它们会被推送到一个无锁的 atomic_queue::Queue。消息由 MidiAudioThreadHandler 在音频线程中拾取。

它提供了与 audio-processor-traits - MidiEventHandler 特性

  • rust-vst - PluginInstance
  • 集成方便的独立 MIDI 集成

目前,此主机丢弃超过 3 个字节的 MIDI 消息。此外,队列有界限,必须提供大小。默认实现将使用 MIDI 队列容量为 100。这是一个独立的 MIDI 主机,具有在音频线程中实时处理 MIDI 消息并集成 VST 插件的辅助工具。

这是 https://github.com/yamadapc/augmented-audio 的一部分。

内存安全性

为了与 VST C API 集成,此 crate 进行手动内存分配和处理。这是由于 VST 事件类型无法表示为安全的 Rust 构造(并且由于需要实时安全性)。

实时安全性

此 crate 提供了 host 方面,即 MIDI 主机。当从 midir 接收消息时,此主机进行分配。

事件被转发到无锁队列 (atomic_queue)。

audio_threadvst 模块中,过去应该在音频线程上调用(反)分配的方法将不会分配。这是使用 assert_no_alloc 库进行测试的。

此外,使用 basedrop / audio_garbage_collector 来防止在音频线程上发生(反)分配。

测试覆盖率

该库具有单元测试(尽管应该将其视为实验性的,因为整个存储库都是如此)。

测试覆盖率为 80%。

Actix & Actors

MidiHost 暴露了一个 actix API,用于与 actix actor 系统一起使用。这是为了方便从多个线程与 midi 处理器通信。

用法

要使用此库

fn example() {
    use audio_processor_standalone_midi::audio_thread::MidiAudioThreadHandler;
    use audio_processor_standalone_midi::host::MidiHost;
    use audio_processor_standalone_midi::vst::MidiVSTConverter;
    use basedrop::Collector;

    // GC ======================================================================================
    // See `audio-garbage-collector` for an easier to use wrapper on top of this.
    //
    // `Collector` will let us use reference counted values on the audio-thread, which will be
    // pushed to a queue for de-allocation. You must set-up a background thread that forces it
    // to actually collect garbage from the queue.
    let gc = Collector::new();
    let handle = gc.handle();

    // Host ====================================================================================
    // A host may be created with `new` or `default_with_handle`.
    let mut host = MidiHost::default_with_handle(&handle);
    // It'll connect to all MIDI input ports when started
    // host.start().expect("Failed to connect");
    // The host will push messages onto a lock-free queue. This is a reference counted value.
    let midi_messages_queue = host.messages().clone();

    // Audio-thread ============================================================================
    // ...
    // Within your audio-thread
    // ...
    // You'll want to share a `MidiAudioThreadHandler` between process calls as it pre-allocates
    // buffers.
    let mut midi_audio_thread_handler = MidiAudioThreadHandler::default();

    // On each tick you'll call collect
    midi_audio_thread_handler.collect_midi_messages(&midi_messages_queue);
    // You'll get the MIDI message buffer
    let midi_messages = midi_audio_thread_handler.buffer();
    // ^ This is a `&Vec<MidiMessageEntry>`. If you're using `audio-processor-traits`, you can
    //   pass this into any `MidiEventHandler` implementor.

    // VST interop =============================================================================
    // If you want to interface with a VST plugin, you'll need to convert messages into the
    // C-api.
    // ...
    // You'll want to share this between process calls as it pre-allocates buffers.
    let mut midi_vst_converter = MidiVSTConverter::default();
    midi_vst_converter.accept(&midi_messages);
    // This can be passed into VST plugins.
    let events: &vst::api::Events = midi_vst_converter.events();
}

许可证:MIT

依赖关系

~1–30MB
~452K SLoC