ALSA 上的 OSS 音序器仿真

Copyright (c) 1998,1999 by Takashi Iwai

ver.0.1.8; Nov. 16, 1999

描述

此目录包含 ALSA 上的 OSS 音序器仿真驱动程序。请注意,此程序仍处于开发状态。

它的作用 - 它提供 OSS 音序器的仿真,通过 /dev/sequencer/dev/music 设备进行访问。如果准备了合适的 ALSA 音序器,则大多数使用 OSS 的应用程序都可以运行。

此驱动程序仿真以下功能

  • 普通音序器和 MIDI 事件

    它们被转换为 ALSA 音序器事件,并发送到相应的端口。

  • 定时器事件

    定时器不能通过 ioctl 选择。控制速率固定为 100,与 HZ 无关。也就是说,即使在 Alpha 系统上,一个滴答也总是 1/100 秒。可以在 /dev/music 中更改基本速率和速度。

  • 补丁加载

    它纯粹取决于合成器驱动程序是否支持,因为补丁加载是通过回调到合成器驱动程序实现的。

  • I/O 控制

    大多数控制都被接受。一些控制依赖于合成器驱动程序,甚至依赖于原始 OSS。

此外,您还可以找到以下高级功能

  • 更好的队列机制

    事件在处理之前被排队。

  • 多个应用程序

    您可以同时运行两个或多个应用程序(甚至对于 OSS 音序器)!但是,每个 MIDI 设备都是独占的 - 也就是说,如果一个 MIDI 设备被某个应用程序打开一次,其他应用程序就不能使用它。合成器设备没有这样的限制。

  • 实时事件处理

    事件可以实时处理,无需使用越界 ioctl。要切换到实时模式,请发送 ABSTIME 0 事件。随后的事件将以实时方式处理,无需排队。要关闭实时模式,请发送 RELTIME 0 事件。

  • /proc 接口

    可以通过 /proc/asound/seq/oss 随时显示应用程序和设备的状态。在以后的版本中,配置也将通过 /proc 接口更改。

安装

运行配置脚本,同时启用音序器支持 (--with-sequencer=yes) 和 OSS 仿真 (--with-oss=yes) 选项。将创建一个模块 snd-seq-oss.o。如果您的声卡的合成器模块支持 OSS 仿真(目前只有 Emu8000 驱动程序),则会自动加载此模块。否则,您需要手动加载此模块。

一开始,此模块会探测所有已连接到音序器的 MIDI 端口。之后,端口的创建和删除将由 ALSA 音序器的通知机制监控。

可在 proc 界面中找到可用的合成器和 MIDI 设备。运行 cat /proc/asound/seq/oss,并检查设备。例如,如果您使用 AWE64 卡,您将看到如下内容

OSS sequencer emulation version 0.1.8
ALSA client number 63
ALSA receiver port 0

Number of applications: 0

Number of synth devices: 1
synth 0: [EMU8000]
  type 0x1 : subtype 0x20 : voices 32
  capabilities : ioctl enabled / load_patch enabled

Number of MIDI devices: 3
midi 0: [Emu8000 Port-0] ALSA port 65:0
  capability write / opened none

midi 1: [Emu8000 Port-1] ALSA port 65:1
  capability write / opened none

midi 2: [0: MPU-401 (UART)] ALSA port 64:0
  capability read/write / opened none

请注意,设备编号可能与 /proc/asound/oss-devices 或原始 OSS 驱动程序中的信息不同。使用 /proc/asound/seq/oss 中列出的设备编号,通过 OSS 音序器仿真进行播放。

使用合成器设备

运行您喜欢的程序。我测试了 playmidi-2.4、awemidi-0.4.3、gmod-3.1 和 xmp-1.1.5。您还可以通过 /dev/sequencer 加载采样,如 sfxload。

如果底层驱动程序支持对合成器设备进行多次访问(如 Emu8000 驱动程序),则允许同时运行两个或多个应用程序。

使用 MIDI 设备

到目前为止,只测试了 MIDI 输出。完全没有检查 MIDI 输入,但希望它能工作。使用 /proc/asound/seq/oss 中列出的设备编号。请注意,这些数字大多与 /proc/asound/oss-devices 中的列表不同。

模块选项

可以使用以下模块选项

maxqlen

指定最大读/写队列长度。此队列是 OSS 音序器私有的,因此它独立于 ALSA 音序器的队列长度。默认值为 1024。

seq_oss_debug

指定调试级别,并接受零(= 无调试消息)或正整数。默认值为 0。

队列机制

OSS 音序器仿真使用 ALSA 优先级队列。来自 /dev/sequencer 的事件被处理并放入模块选项指定的队列中。

所有来自 /dev/sequencer 的事件都在开始时被解析。定时事件也在此时被解析,以便事件可以实时处理。发送事件 ABSTIME 0 会将操作模式切换到实时模式,发送事件 RELTIME 0 会关闭它。在实时模式下,所有事件都会立即分发。

排队的事件在 ALSA 音序器调度程序安排的时间之后被分发到相应的 ALSA 音序器端口。

如果写入队列已满,则应用程序会休眠,直到一定数量(默认为一半)在阻塞模式下变空。还实现了写入定时的同步。

来自 MIDI 设备的输入或回声事件存储在读取 FIFO 队列中。如果应用程序在阻塞模式下读取 /dev/sequencer,则该进程将被唤醒。

合成器设备接口

注册

要注册 OSS 合成器设备,请使用 snd_seq_oss_synth_register() 函数

int snd_seq_oss_synth_register(char *name, int type, int subtype, int nvoices,
        snd_seq_oss_callback_t *oper, void *private_data)

参数 nametypesubtypenvoices 用于创建用于 ioctl 的适当 synth_info 结构。返回值是此设备的索引号。必须记住此索引以进行注销。如果注册失败,将返回 -errno。

要释放此设备,请调用 snd_seq_oss_synth_unregister() 函数

int snd_seq_oss_synth_unregister(int index)

其中 index 是注册函数返回的索引号。

回调

OSS 合成器设备具有采样下载和 ioctl(如采样重置)的功能。在 OSS 仿真中,这些特殊功能通过使用回调来实现。注册参数 oper 用于指定这些回调。必须定义以下回调函数

snd_seq_oss_callback_t:
 int (*open)(snd_seq_oss_arg_t *p, void *closure);
 int (*close)(snd_seq_oss_arg_t *p);
 int (*ioctl)(snd_seq_oss_arg_t *p, unsigned int cmd, unsigned long arg);
 int (*load_patch)(snd_seq_oss_arg_t *p, int format, const char *buf, int offs, int count);
 int (*reset)(snd_seq_oss_arg_t *p);

除了 openclose 回调之外,允许它们为 NULL。

每个回调函数都采用参数类型 snd_seq_oss_arg_t 作为第一个参数。

struct snd_seq_oss_arg_t {
    int app_index;
    int file_mode;
    int seq_mode;
    snd_seq_addr_t addr;
    void *private_data;
    int event_passing;
};

前三个字段,app_indexfile_modeseq_mode 由 OSS 音序器初始化。app_index 是应用程序索引,对于每个打开 OSS 音序器的应用程序都是唯一的。file_mode 是指示文件操作模式的位标志。有关其含义,请参阅 seq_oss.hseq_mode 是音序器操作模式。在当前版本中,仅使用 SND_OSSSEQ_MODE_SYNTH

接下来的两个字段,addrprivate_data,必须由合成器驱动程序在打开回调时填充。addr 包含分配给此设备的 ALSA 音序器端口的地址。如果驱动程序为 private_data 分配了内存,则必须在关闭回调中自行释放。

最后一个字段 event_passing 指示如何翻译音符开/关事件。在 PROCESS_EVENTS 模式下,音符 255 被视为速度变化,并且关键压力事件被传递到端口。在 PASS_EVENTS 模式下,所有音符开/关事件都未经修改地传递到端口。PROCESS_KEYPRESS 模式检查高于 128 的音符,并将其视为关键压力事件(主要用于 Emu8000 驱动程序)。

打开回调

每次使用 OSS 音序器的应用程序打开此设备时,都会调用 open。这不能为 NULL。通常,打开回调执行以下过程

  1. 分配私有数据记录。

  2. 创建一个 ALSA 音序器端口。

  3. arg->addr 上设置新的端口地址。

  4. arg->private_data 上设置私有数据记录指针。

请注意,此合成器端口的 port_info 中的类型位标志不能包含 TYPE_MIDI_GENERIC 位。相反,应使用 TYPE_SPECIFIC。此外,也不应包含 CAP_SUBSCRIPTION 位。这对于将其与其他普通 MIDI 设备区分开来是必要的。如果打开过程成功,则返回零。否则,返回 -errno。

Ioctl 回调

当音序器接收到特定于设备的 ioctl 时,会调用 ioctl 回调。以下两个 ioctl 应由此回调处理

IOCTL_SEQ_RESET_SAMPLES

重置内存中的所有采样 -- 返回 0

IOCTL_SYNTH_MEMAVL

返回可用内存大小

FM_4OP_ENABLE

通常可以忽略

其他 ioctl 在音序器内部处理,而不传递到底层驱动程序。

Load_Patch 回调

load_patch 回调用于采样下载。此回调必须读取用户空间上的数据并传输到每个设备。如果成功,则返回 0,如果失败,则返回 -errno。format 参数是 patch_info 记录中的补丁键。buf 是用户空间指针,其中存储了 patch_info 记录。offs 可以忽略。count 是此采样数据的总数据大小。

关闭回调

当应用程序关闭此设备时,会调用 close 回调。如果在打开回调中分配了任何私有数据,则必须在关闭回调中释放它。ALSA 端口的删除也应在此处完成。此回调不能为 NULL。

重置回调

当应用程序重置或关闭音序器设备时,会调用 reset 回调。回调应立即关闭相关端口上的声音,并初始化端口的状态。如果未定义此回调,则 OSS seq 会向端口发送一个 HEARTBEAT 事件。

事件

大多数事件都由音序器处理并转换为适当的 ALSA 音序器事件,以便每个合成器设备可以通过 ALSA 音序器端口的 input_event 回调接收。驱动程序应实现以下 ALSA 事件

ALSA 事件

原始 OSS 事件

NOTEON

SEQ_NOTEON, MIDI_NOTEON

NOTE

SEQ_NOTEOFF, MIDI_NOTEOFF

KEYPRESS

MIDI_KEY_PRESSURE

CHANPRESS

SEQ_AFTERTOUCH, MIDI_CHN_PRESSURE

PGMCHANGE

SEQ_PGMCHANGE, MIDI_PGM_CHANGE

PITCHBEND

SEQ_CONTROLLER(CTRL_PITCH_BENDER), MIDI_PITCH_BEND

CONTROLLER

MIDI_CTL_CHANGE, SEQ_BALANCE (与 CTL_PAN 一起)

CONTROL14

SEQ_CONTROLLER

REGPARAM

SEQ_CONTROLLER(CTRL_PITCH_BENDER_RANGE)

SYSEX

SEQ_SYSEX

这些行为中的大多数可以通过 Emu8000 底层驱动程序中包含的 MIDI 仿真驱动程序来实现。在未来的版本中,此模块将是独立的。

一些 OSS 事件(SEQ_PRIVATESEQ_VOLUME 事件)作为事件类型 SND_SEQ_OSS_PRIVATE 传递。OSS 音序器传递这些事件 8 字节数据包,不做任何修改。底层驱动程序应适当处理这些事件。

MIDI 设备接口

由于 OSS 仿真通过接收来自 ALSA 音序器的通知来自动探测 ALSA MIDI 音序器端口的创建和删除,因此 MIDI 设备不需要像合成器设备那样显式注册。但是,注册到 ALSA 音序器的 MIDI port_info 必须包含组名 SND_SEQ_GROUP_DEVICE 和 capability-bit CAP_READCAP_WRITE。此外,还必须定义订阅功能 CAP_SUBS_READCAP_SUBS_WRITE。如果未满足这些条件,则该端口不会注册为 OSS 音序器 MIDI 设备。

通过 MIDI 设备的事件在 OSS 音序器中解析并转换为相应的 ALSA 音序器事件。来自 MIDI 音序器的输入也由 OSS 音序器转换为 MIDI 字节事件。这与 seq_midi 模块的工作方式相反。

已知问题/待办事项

  • 尚未实现通过 ALSA 乐器层加载补丁。