#midi #music #alsa

rmididings

根据mididings灵感,编写自己的MIDI路由器/处理器

5个版本

0.2.1 2021年6月30日
0.2.0 2021年6月27日
0.1.2 2021年6月18日
0.1.1 2021年6月16日
0.1.0 2021年6月16日

#337 in 音频

GPL-3.0-or-later

115KB
2K SLoC

RMididings

RMididings是mididingsRust中的部分克隆,允许用户使用类似于mididings的语法进行MIDI事件路由和处理。Mididings是一个基于Python的MIDI路由器和处理程序。

目前处于早期开发阶段,许多功能尚不可用。以下是

  • NoteOnNoteOffCtrlSysEx事件。
  • 支持alsa后端,使其与Linux相关联。
  • 有限的过滤器、修饰器和生成器集合。
  • 有限的连接集合:Chain!Fork!Not!
  • 场景和子场景、场景切换以及运行单个补丁。
  • 预、后、初始化、退出和控制补丁。
  • (新)本地的Osc事件,可以在补丁中处理。

一些缺失的功能可以实施,但使用Rust有一些限制,例如语法可能不同,并且不支持过滤器等参数类型的所有变体。有时语法有点混乱(例如,与Process)。我们将看看哪些可以改进。

运行

您需要1.52.0+的RustCargo。获取最新Rust的最简单方法是使用Rustup

您还需要ALSA头文件。在Debian上,您需要运行apt-get install libasound2-dev,在Fedora上dnf install alsa-lib-devel

Rmididings是一个crate,这意味着您编写自己的程序来使用它。让我们从一个简单的例子开始。创建一个项目目录,并创建一个子目录src,在其中放置以下文件,将其命名为main.rs

// src/main.rs
#[macro_use]
extern crate rmididings;
use rmididings::*;

fn main() -> Result<(), Box<dyn std::error::Error>> {
  let mut md = RMididings::new()?;

  md.config(ConfigArguments {
    in_ports:  &[["input",  "Virtual Keyboard:Virtual Keyboard"]],
    out_ports: &[["output", "midisnoop:MIDI Input"]],
    ..ConfigArguments::default()
  })?;

  md.run(RunArguments {
    patch: &Pass(),
    ..RunArguments::default()
  })?;

  Ok(())
}

要运行此程序,您还需要在项目目录中有一个Cargo.toml

[package]
name = "myproject"
version = "0.0.1"

[dependencies]
rmididings = "^0.2.0"

然后,在项目目录中运行 cargo run,设置完成。这个示例程序将所有事件从输入端口传递到输出端口。在运行之前,如果已经运行了 vkeybdmidisnoop(在 Debian/Ubuntu 中具有相同的包名),它们将自动连接。使用 Ctrl-C 终止程序。

构建补丁

上面的补丁只是通过 Pass() 传递所有事件。当我们开始构建过滤器链时,它变得更加有趣。而不是使用 &Pass(),我们可以使用以下

&Chain!(
  ChannelFilter(1),
  Fork!(
    Pass(),
    Chain!(Transpose(4), VelocityMultiply(0.8)),
    Chain!(Transpose(7), VelocityMultiply(0.5))
  ),
  Channel(2)
)

这个链忽略除了通道 1 以外的任何通道,并为音符返回一个主和弦,高音符略微衰减。最后,所有音符都通过通道 2 发送出去。

场景

除了补丁之外,还可以将 scenes 传递给 run 函数

md.run(RunArguments {
    scenes: &[
        // Scene 1
        &Scene {
            name: "Run",
            patch: &Pass(),
            ..Scene::default()
        },
        // Scene 2
        &Scene {
            name: "Pause",
            patch: &Discard(),
            ..Scene::default()
        }
    ],
    control: &Fork!(
      Chain!(KeyFilter(62), SceneSwitch(2), Discard()),
      Chain!(KeyFilter(60), SceneSwitch(1), Discard())
    ),
    ..RunArguments::default()
})?;

这里有两个场景,一个传递所有事件,一个丢弃它们。始终运行 control 补丁,这里使用中央 C 和随后的 D 来在场景之间切换。

计划

参见 问题

许可证

GPL-3.0 或更高版本 或更高版本。

依赖项

~2.4–3.5MB
~76K SLoC