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)
参数 name
、type
、subtype
和 nvoices
用于创建用于 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);
除了 open
和 close
回调之外,允许它们为 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_index
、file_mode
和 seq_mode
由 OSS 音序器初始化。app_index
是应用程序索引,对于每个打开 OSS 音序器的应用程序都是唯一的。file_mode
是指示文件操作模式的位标志。有关其含义,请参阅 seq_oss.h
。seq_mode
是音序器操作模式。在当前版本中,仅使用 SND_OSSSEQ_MODE_SYNTH
。
接下来的两个字段,addr
和 private_data
,必须由合成器驱动程序在打开回调时填充。addr
包含分配给此设备的 ALSA 音序器端口的地址。如果驱动程序为 private_data
分配了内存,则必须在关闭回调中自行释放。
最后一个字段 event_passing
指示如何翻译音符开/关事件。在 PROCESS_EVENTS
模式下,音符 255 被视为速度变化,并且关键压力事件被传递到端口。在 PASS_EVENTS
模式下,所有音符开/关事件都未经修改地传递到端口。PROCESS_KEYPRESS
模式检查高于 128 的音符,并将其视为关键压力事件(主要用于 Emu8000 驱动程序)。
打开回调¶
每次使用 OSS 音序器的应用程序打开此设备时,都会调用 open
。这不能为 NULL。通常,打开回调执行以下过程
分配私有数据记录。
创建一个 ALSA 音序器端口。
在
arg->addr
上设置新的端口地址。在
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_PRIVATE
和 SEQ_VOLUME
事件)作为事件类型 SND_SEQ_OSS_PRIVATE 传递。OSS 音序器传递这些事件 8 字节数据包,不做任何修改。底层驱动程序应适当处理这些事件。
MIDI 设备接口¶
由于 OSS 仿真通过接收来自 ALSA 音序器的通知来自动探测 ALSA MIDI 音序器端口的创建和删除,因此 MIDI 设备不需要像合成器设备那样显式注册。但是,注册到 ALSA 音序器的 MIDI port_info 必须包含组名 SND_SEQ_GROUP_DEVICE
和 capability-bit CAP_READ
或 CAP_WRITE
。此外,还必须定义订阅功能 CAP_SUBS_READ
或 CAP_SUBS_WRITE
。如果未满足这些条件,则该端口不会注册为 OSS 音序器 MIDI 设备。
通过 MIDI 设备的事件在 OSS 音序器中解析并转换为相应的 ALSA 音序器事件。来自 MIDI 音序器的输入也由 OSS 音序器转换为 MIDI 字节事件。这与 seq_midi 模块的工作方式相反。
已知问题/待办事项¶
尚未实现通过 ALSA 乐器层加载补丁。