#audio-devices #audio-player #midi-file #song #events #channel

app mtrack

多轨音频和MIDI播放器,适用于现场表演

4 个版本

0.1.3 2024年5月27日
0.1.2 2024年4月16日
0.1.1 2024年3月26日
0.1.0 2024年3月26日

#118 in 音频

GPL-3.0 许可协议

160KB
3K SLoC

mtrack

Actions Status codecov Crates.io Version License: GPL v3 Contributor Covenant

mtrack 是一个多轨播放器,旨在在小型设备(如Raspberry Pi)上运行。它可以通过类兼容接口输出多个音频轨以及MIDI输出。这里的一般意图是允许通过脚本来远程控制 mtrack,而不是需要舞台上的电脑或平板电脑。

免提多轨播放

mtrack 的理念是提供一种在直播情况下播放多轨的方法,而不需要使用你的手。在直播情况下,我经常发现自己需要在表演时照看DAW。 mtrack 的目的就是通过提供一种非常简单的播放歌曲的机制来避免这种情况。

mtrack 可以从多个音频文件中读取,并将这些文件中存在的声道重新排列和组合成一个单一的音频流,该流路由到类兼容音频接口。此外, mtrack 可以同时播放MIDI文件和音频,从而允许舞台设备的自动化。 mtrack 还可以在歌曲选择时发出MIDI事件,并监听MIDI事件以控制 mtrack 播放器。

mtrack 的一般行为

mtrack 希望有以下行为循环

  1. mtrack 从用户定义的播放列表中的第一个项目开始。项目被选中,但尚未播放。
  2. 在没有歌曲播放时,用户可以通过使用 nextprevious 事件来选择播放列表中的歌曲。当歌曲正在播放时, nextprevious 是不活跃的。
  3. 用户可以使用 play 事件开始播放歌曲,并使用 stop 事件停止正在播放的歌曲。当歌曲正在播放时, play 将不执行任何操作,而当歌曲没有播放时, stop 也将不执行任何操作。
  4. 如果用户需要播放其播放列表中没有的歌曲,用户可以使用 all_songs 事件来切换到一个包含用户歌曲仓库中所有歌曲排序列表的播放列表。如果用户希望使用原始播放列表,则可以使用 playlist 事件。

上述事件可以通过 MIDI 消息触发。

安装

mtrack 可以通过 cargo 安装。

$ cargo install mtrack

如果您想在启动时使用 mtrack,建议将其复制到 /usr/local/bin

$ sudo cp ~/.cargo/bin/mtrack /usr/local/bin/mtrack

确定支持的设备

您可以通过运行 mtrack devices 来确定 mtrack 识别的音频设备。

$ mtrack devices
Devices:
- UltraLite-mk5 (Channels=22) (Alsa)
- bcm2835 Headphones (Channels=8) (Alsa)

括号前的名称是 mtrack 使用的标识符。因此,在引用第一个音频设备时,您将使用字符串 UltraLite-mk5

您还可以通过运行 mtrack midi-devices 来确定支持的 MIDI 设备。

$ mtrack midi-devices
Devices:
- Midi Through:Midi Through Port-0 14:0 (Input/Output)
- UltraLite-mk5:UltraLite-mk5 MIDI 1 28:0 (Input/Output)

第一个冒号前的名称是 mtrack 使用的标识符。在引用第二个 MIDI 设备时,您将使用字符串 UltraLite-mk5

mtrack 仓库和辅助文件的结构

歌曲仓库

歌曲仓库是磁盘上的一个位置,存放着您的伴奏音乐、MIDI 文件和歌曲定义。歌曲仓库不需要任何特定的布局,因为 mtrack 会尝试解析它找到的任何/所有 yaml 文件以查找歌曲定义。

歌曲

一首歌由以下部分组成

  • 一个或多个音频文件。
  • 可选的 MIDI 文件。
  • 歌曲定义。

音频文件必须具有相同的比特率。它们的长度不必相同。mtrack 播放器将播放,直到最后一个音频(或 MIDI)文件播放完毕。

歌曲在 yaml 文件中定义

# The name of the song. This name is primarily used when constructing
# playlists for mtrack.
name: The Song Name

# An optional MIDI event to emit when the song is selected on the
# playlist. This will occur even if the song is not playing. This is
# useful to trigger events on a remote device, such as a MIDI controller.
midi_event:
  type: program_change
  channel: 16
  program: 3

# An optional MIDI file to play along with the audio.
midi_file: Song Automation.mid

# The tracks associated with this song.
tracks:
# The click track only has one channel, so we can just indicate which output channel
# we want directly.
- name: click
  file: click.wav # File paths are relative to the song.yaml file.
# Similarly, our cue only has one channel.
- name: cue
  file: /mnt/song-storage/cue.wav # Or file paths can be absolute.
# Our backing track file has two channels, so we have to specify `file_channel` to let
# mtrack know which channel from the file to use.
- name: backing-track-l
  file: Backing Tracks.wav
  file_channel: 1
# We can re-use our backing track file and specify the other channel if we'd like to do
# stereo.
- name: backing-track-r
  file: Backing Tracks.wav
  file_channel: 2
# Our keys file has two channels, but we're only interested in one.
- name: keys
  file: Keys.wav
  file_channel: 1
---
# We can define multiple songs in one file.
name: The Song Name (alternate version)
...

我们可以使用 mtrack songs 命令测试我们的歌曲仓库

$ mtrack songs /mnt/song-storage
Songs (count: 23):
- Name: The first really cool song
  Duration: 5:10
  Channels: 11
  Sample Rate: 44100
  Midi Message: Some(Midi { channel: u4(15), message: ProgramChange { program: u7(0) } })
  Midi File:None
  Tracks: click, cue, backing-track-l, backing-track-r, keys
- Name: The next really cool song
  ...

您可以使用 mtrack play 播放单个歌曲

$ mtrack play -m my-midi-device my-audio-device click=1,cue=2 /mnt/song-storage "My cool song"
2024-03-22T21:24:25.588828Z  INFO emit (midir): mtrack::midi::midir: Emitting event. device="my-midi-device:my-midi-device MIDI 1 28:0" event="Midi { channel: u4(15), message: ProgramChange { program: u7(3) } }"
2024-03-22T21:24:25.589420Z  INFO player: mtrack::player: Waiting for song to finish. song="My cool song"
2024-03-22T21:24:25.589992Z  INFO play song (rodio): mtrack::audio::rodio: Playing song. device="my-audio-device" song="My cool song" duration="4:14"
2024-03-22T21:24:25.676452Z  INFO play song (midir): mtrack::midi::midir: Playing song MIDI. device="my-midi-device:my-midi-device MIDI 1 28:0" song="My cool song" duration="4:14"

播放列表

播放列表定义是一个简单的 yaml 文件

# This is a simple file that contains, in order, the names of all songs
# that mtrack should play. The names of the songs are defined in the
# song repository, which can be found in mtrack.yaml.
songs:
- Sound check
- A really cool song
- Another cool song
- The slow one
- A really fast one
- Outro tape

这将按照给定顺序播放指定的歌曲,等待您触发歌曲。

mtrack 进程定义

要将 mtrack 作为可由 MIDI 控制的独立播放器启动,您需要创建一个播放器配置文件

# This audio device will be matched as best as possible against the devices on your system.
# Run `mtrack devices` to see a list of the devices that mtrack recognizes.
audio_device: UltraLite-mk5

# This MIDI device will be matched as best as possible against the devices on your system.
# Run `mtrack midi-devices` to see a list of the devices that mtrack recognizes.
midi_device: UltraLite-mk5

# The directory where all of your songs are located, frequently referred to as the song repository.
# If the path is not absolute, it will be relative to the location of this file.
songs: /mnt/song-storage

# The controller definition. As of now, the valid kinds of controllers are:
# - keyboard
# - midi
# Keyboard is largely for testing and MIDI is intended for actual live usage.
controller:
  kind: midi

  # When mtrack recognizes this MIDI event, it will play the current song if no other song is
  # currently playing.
  play:
    type: control_change
    channel: 16
    controller: 100
    value: 0

  # When mtrack recognizes this MIDI event, it will navigate to the previous song in the playlist
  # if no other song is currently playing.
  prev:
    type: control_change
    channel: 16
    controller: 100
    value: 1

  # When mtrack recognizes this MIDI event, it will navigate to the next song in the playlist
  # if no other song is currently playing.
  next:
    type: control_change
    channel: 16
    controller: 100
    value: 2

  # When mtrack recognizes this MIDI event, it will stop the currently playing song.
  stop:
    type: control_change
    channel: 16
    controller: 100
    value: 3

  # When mtrack recognizes this MIDI event, it will switch to the playlist of all known songs in
  # your song repository.
  all_songs:
    type: control_change
    channel: 16
    controller: 100
    value: 4

  # When mtrack recognizes this MIDI event, it will switch to the defined playlist.
  playlist:
    type: control_change
    channel: 16
    controller: 100
    value: 5

# Mappings of track names to output channels.
track_mappings:
  click: 1
  cue: 2
  backing-track-l: 3
  backing-track-r: 4
  keys: 5

您可以使用 mtrack start /path/to/player.yaml /path/to/playlist.yaml 启动 mtrack 作为进程。

mtrack 在启动时

要使 mtrack 在系统启动时启动,您可以运行

$ sudo mtrack systemd > /etc/systemd/system/mtrack.service

请注意,该服务期望 mtrack/usr/local/bin/mtrack 位置可用。它还期望您在 /etc/default/mtrack 中定义您的播放器配置和播放列表。该文件应包含两个变量:MTRACK_CONFIGPLAYLIST

# The configuration for the mtrack player.
MTRACK_CONFIG=/mnt/storage/mtrack.yaml

# The playlist to use.
PLAYLIST=/mnt/storage/playlist.yaml

定义完成后,您可以使用以下命令启动它

$ systemctl start mtrack

现在它将启动,并且当您重启计算机时将重新启动。您可以通过运行以下命令查看 mtrack 的日志

$ journalctl -u mtrack 

支持的 MIDI 事件

截至目前,以下MIDI事件可以定义为控制器和歌曲发射功能的一部分

# The note_off MIDI event acts as if a note was released.
midi_event:
  type: note_off
  channel: 5 # Channels are expected to be from 1-16.
  note: 5
  velocity: 127
---
# The note_on MIDI event acts as if a note was pressed.
midi_event:
  type: note_on
  channel: 5
  note: 5
  velocity: 127
---
# The aftertouch MIDI event acts as if an aftertouch MIDI event was sent.
midi_event:
  type: aftertouch
  channel: 5
  note: 5
  velocity: 127
---
# The control_change MIDI event can controller values.
midi_event:
  type: control_change
  channel: 5
  controller: 12
  value: 27
---
# The program_change MIDI event can change banks and instruments on various devices.
midi_event:
  type: program_change
  channel: 5
  program: 20
---
# The aftertouch MIDI event acts as if a channel aftertouch MIDI event was sent.
midi_event:
  type: channel_aftertouch
  channel: 5
  velocity: 127
---
# The pitch bend MIDI event acts as if a pitch bend MIDI event was sent.
midi_event:
  type: pitch_bend
  bend: 1234

还有更多可以实施,但这些只是我目前想到的。如果您想添加特定的任何事件,请提交一个问题。否则,我会根据需要添加它们。

已知限制

我只测试了它与MOTU UltraLite-mk5。

MIDI输出未经过充分测试,因此我不知道它与音频播放是否匹配良好。

这是我第一个Rust项目,所以这很可能是令人尴尬的、糟糕的非Rust风格。请随时提交PR以使其更好。

依赖关系

~9–44MB
~639K SLoC