]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * Midi Sequencer interface routines. | |
3 | * | |
4 | * Copyright (C) 1999 Steve Ratcliffe | |
5 | * Copyright (c) 1999-2000 Takashi Iwai <tiwai@suse.de> | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify | |
8 | * it under the terms of the GNU General Public License as published by | |
9 | * the Free Software Foundation; either version 2 of the License, or | |
10 | * (at your option) any later version. | |
11 | * | |
12 | * This program is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | * GNU General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public License | |
18 | * along with this program; if not, write to the Free Software | |
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
20 | */ | |
21 | ||
22 | #include "emux_voice.h" | |
23 | #include <linux/slab.h> | |
24 | ||
25 | ||
26 | /* Prototypes for static functions */ | |
27 | static void free_port(void *private); | |
03da312a TI |
28 | static void snd_emux_init_port(struct snd_emux_port *p); |
29 | static int snd_emux_use(void *private_data, struct snd_seq_port_subscribe *info); | |
30 | static int snd_emux_unuse(void *private_data, struct snd_seq_port_subscribe *info); | |
31 | static int get_client(struct snd_card *card, int index, char *name); | |
1da177e4 LT |
32 | |
33 | /* | |
34 | * MIDI emulation operators | |
35 | */ | |
03da312a | 36 | static struct snd_midi_op emux_ops = { |
1da177e4 LT |
37 | snd_emux_note_on, |
38 | snd_emux_note_off, | |
39 | snd_emux_key_press, | |
40 | snd_emux_terminate_note, | |
41 | snd_emux_control, | |
42 | snd_emux_nrpn, | |
43 | snd_emux_sysex, | |
44 | }; | |
45 | ||
46 | ||
47 | /* | |
48 | * number of MIDI channels | |
49 | */ | |
50 | #define MIDI_CHANNELS 16 | |
51 | ||
52 | /* | |
53 | * type flags for MIDI sequencer port | |
54 | */ | |
55 | #define DEFAULT_MIDI_TYPE (SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC |\ | |
56 | SNDRV_SEQ_PORT_TYPE_MIDI_GM |\ | |
57 | SNDRV_SEQ_PORT_TYPE_MIDI_GS |\ | |
58 | SNDRV_SEQ_PORT_TYPE_MIDI_XG |\ | |
59 | SNDRV_SEQ_PORT_TYPE_DIRECT_SAMPLE) | |
60 | ||
61 | /* | |
62 | * Initialise the EMUX Synth by creating a client and registering | |
63 | * a series of ports. | |
64 | * Each of the ports will contain the 16 midi channels. Applications | |
65 | * can connect to these ports to play midi data. | |
66 | */ | |
67 | int | |
03da312a | 68 | snd_emux_init_seq(struct snd_emux *emu, struct snd_card *card, int index) |
1da177e4 LT |
69 | { |
70 | int i; | |
03da312a | 71 | struct snd_seq_port_callback pinfo; |
1da177e4 LT |
72 | char tmpname[64]; |
73 | ||
74 | sprintf(tmpname, "%s WaveTable", emu->name); | |
75 | emu->client = get_client(card, index, tmpname); | |
76 | if (emu->client < 0) { | |
77 | snd_printk("can't create client\n"); | |
78 | return -ENODEV; | |
79 | } | |
80 | ||
81 | if (emu->num_ports < 0) { | |
82 | snd_printk("seqports must be greater than zero\n"); | |
83 | emu->num_ports = 1; | |
84 | } else if (emu->num_ports >= SNDRV_EMUX_MAX_PORTS) { | |
85 | snd_printk("too many ports." | |
86 | "limited max. ports %d\n", SNDRV_EMUX_MAX_PORTS); | |
87 | emu->num_ports = SNDRV_EMUX_MAX_PORTS; | |
88 | } | |
89 | ||
90 | memset(&pinfo, 0, sizeof(pinfo)); | |
91 | pinfo.owner = THIS_MODULE; | |
92 | pinfo.use = snd_emux_use; | |
93 | pinfo.unuse = snd_emux_unuse; | |
94 | pinfo.event_input = snd_emux_event_input; | |
95 | ||
96 | for (i = 0; i < emu->num_ports; i++) { | |
03da312a | 97 | struct snd_emux_port *p; |
1da177e4 LT |
98 | |
99 | sprintf(tmpname, "%s Port %d", emu->name, i); | |
100 | p = snd_emux_create_port(emu, tmpname, MIDI_CHANNELS, | |
101 | 0, &pinfo); | |
102 | if (p == NULL) { | |
103 | snd_printk("can't create port\n"); | |
104 | return -ENOMEM; | |
105 | } | |
106 | ||
107 | p->port_mode = SNDRV_EMUX_PORT_MODE_MIDI; | |
108 | snd_emux_init_port(p); | |
109 | emu->ports[i] = p->chset.port; | |
110 | emu->portptrs[i] = p; | |
111 | } | |
112 | ||
113 | return 0; | |
114 | } | |
115 | ||
116 | ||
117 | /* | |
118 | * Detach from the ports that were set up for this synthesizer and | |
119 | * destroy the kernel client. | |
120 | */ | |
121 | void | |
03da312a | 122 | snd_emux_detach_seq(struct snd_emux *emu) |
1da177e4 LT |
123 | { |
124 | if (emu->voices) | |
125 | snd_emux_terminate_all(emu); | |
126 | ||
127 | down(&emu->register_mutex); | |
128 | if (emu->client >= 0) { | |
129 | snd_seq_delete_kernel_client(emu->client); | |
130 | emu->client = -1; | |
131 | } | |
132 | up(&emu->register_mutex); | |
133 | } | |
134 | ||
135 | ||
136 | /* | |
137 | * create a sequencer port and channel_set | |
138 | */ | |
139 | ||
03da312a TI |
140 | struct snd_emux_port * |
141 | snd_emux_create_port(struct snd_emux *emu, char *name, | |
142 | int max_channels, int oss_port, | |
143 | struct snd_seq_port_callback *callback) | |
1da177e4 | 144 | { |
03da312a | 145 | struct snd_emux_port *p; |
1da177e4 LT |
146 | int i, type, cap; |
147 | ||
148 | /* Allocate structures for this channel */ | |
561b220a | 149 | if ((p = kzalloc(sizeof(*p), GFP_KERNEL)) == NULL) { |
1da177e4 LT |
150 | snd_printk("no memory\n"); |
151 | return NULL; | |
152 | } | |
03da312a | 153 | p->chset.channels = kcalloc(max_channels, sizeof(struct snd_midi_channel), GFP_KERNEL); |
1da177e4 LT |
154 | if (p->chset.channels == NULL) { |
155 | snd_printk("no memory\n"); | |
156 | kfree(p); | |
157 | return NULL; | |
158 | } | |
159 | for (i = 0; i < max_channels; i++) | |
160 | p->chset.channels[i].number = i; | |
161 | p->chset.private_data = p; | |
162 | p->chset.max_channels = max_channels; | |
163 | p->emu = emu; | |
164 | p->chset.client = emu->client; | |
165 | #ifdef SNDRV_EMUX_USE_RAW_EFFECT | |
166 | snd_emux_create_effect(p); | |
167 | #endif | |
168 | callback->private_free = free_port; | |
169 | callback->private_data = p; | |
170 | ||
171 | cap = SNDRV_SEQ_PORT_CAP_WRITE; | |
172 | if (oss_port) { | |
173 | type = SNDRV_SEQ_PORT_TYPE_SPECIFIC; | |
174 | } else { | |
175 | type = DEFAULT_MIDI_TYPE; | |
176 | cap |= SNDRV_SEQ_PORT_CAP_SUBS_WRITE; | |
177 | } | |
178 | ||
179 | p->chset.port = snd_seq_event_port_attach(emu->client, callback, | |
180 | cap, type, max_channels, | |
181 | emu->max_voices, name); | |
182 | ||
183 | return p; | |
184 | } | |
185 | ||
186 | ||
187 | /* | |
188 | * release memory block for port | |
189 | */ | |
190 | static void | |
191 | free_port(void *private_data) | |
192 | { | |
03da312a | 193 | struct snd_emux_port *p; |
1da177e4 LT |
194 | |
195 | p = private_data; | |
196 | if (p) { | |
197 | #ifdef SNDRV_EMUX_USE_RAW_EFFECT | |
198 | snd_emux_delete_effect(p); | |
199 | #endif | |
200 | kfree(p->chset.channels); | |
201 | kfree(p); | |
202 | } | |
203 | } | |
204 | ||
205 | ||
206 | #define DEFAULT_DRUM_FLAGS (1<<9) | |
207 | ||
208 | /* | |
209 | * initialize the port specific parameters | |
210 | */ | |
211 | static void | |
03da312a | 212 | snd_emux_init_port(struct snd_emux_port *p) |
1da177e4 LT |
213 | { |
214 | p->drum_flags = DEFAULT_DRUM_FLAGS; | |
215 | p->volume_atten = 0; | |
216 | ||
217 | snd_emux_reset_port(p); | |
218 | } | |
219 | ||
220 | ||
221 | /* | |
222 | * reset port | |
223 | */ | |
224 | void | |
03da312a | 225 | snd_emux_reset_port(struct snd_emux_port *port) |
1da177e4 LT |
226 | { |
227 | int i; | |
228 | ||
229 | /* stop all sounds */ | |
230 | snd_emux_sounds_off_all(port); | |
231 | ||
232 | snd_midi_channel_set_clear(&port->chset); | |
233 | ||
234 | #ifdef SNDRV_EMUX_USE_RAW_EFFECT | |
235 | snd_emux_clear_effect(port); | |
236 | #endif | |
237 | ||
238 | /* set port specific control parameters */ | |
239 | port->ctrls[EMUX_MD_DEF_BANK] = 0; | |
240 | port->ctrls[EMUX_MD_DEF_DRUM] = 0; | |
241 | port->ctrls[EMUX_MD_REALTIME_PAN] = 1; | |
242 | ||
243 | for (i = 0; i < port->chset.max_channels; i++) { | |
03da312a | 244 | struct snd_midi_channel *chan = port->chset.channels + i; |
1da177e4 LT |
245 | chan->drum_channel = ((port->drum_flags >> i) & 1) ? 1 : 0; |
246 | } | |
247 | } | |
248 | ||
249 | ||
250 | /* | |
251 | * input sequencer event | |
252 | */ | |
253 | int | |
03da312a | 254 | snd_emux_event_input(struct snd_seq_event *ev, int direct, void *private_data, |
1da177e4 LT |
255 | int atomic, int hop) |
256 | { | |
03da312a | 257 | struct snd_emux_port *port; |
1da177e4 LT |
258 | |
259 | port = private_data; | |
260 | snd_assert(port != NULL && ev != NULL, return -EINVAL); | |
261 | ||
262 | snd_midi_process_event(&emux_ops, ev, &port->chset); | |
263 | ||
264 | return 0; | |
265 | } | |
266 | ||
267 | ||
268 | /* | |
269 | * increment usage count | |
270 | */ | |
271 | int | |
03da312a | 272 | snd_emux_inc_count(struct snd_emux *emu) |
1da177e4 LT |
273 | { |
274 | emu->used++; | |
275 | if (!try_module_get(emu->ops.owner)) | |
276 | goto __error; | |
277 | if (!try_module_get(emu->card->module)) { | |
278 | module_put(emu->ops.owner); | |
279 | __error: | |
280 | emu->used--; | |
281 | return 0; | |
282 | } | |
283 | return 1; | |
284 | } | |
285 | ||
286 | ||
287 | /* | |
288 | * decrease usage count | |
289 | */ | |
290 | void | |
03da312a | 291 | snd_emux_dec_count(struct snd_emux *emu) |
1da177e4 LT |
292 | { |
293 | module_put(emu->card->module); | |
294 | emu->used--; | |
295 | if (emu->used <= 0) | |
296 | snd_emux_terminate_all(emu); | |
297 | module_put(emu->ops.owner); | |
298 | } | |
299 | ||
300 | ||
301 | /* | |
302 | * Routine that is called upon a first use of a particular port | |
303 | */ | |
304 | static int | |
03da312a | 305 | snd_emux_use(void *private_data, struct snd_seq_port_subscribe *info) |
1da177e4 | 306 | { |
03da312a TI |
307 | struct snd_emux_port *p; |
308 | struct snd_emux *emu; | |
1da177e4 LT |
309 | |
310 | p = private_data; | |
311 | snd_assert(p != NULL, return -EINVAL); | |
312 | emu = p->emu; | |
313 | snd_assert(emu != NULL, return -EINVAL); | |
314 | ||
315 | down(&emu->register_mutex); | |
316 | snd_emux_init_port(p); | |
317 | snd_emux_inc_count(emu); | |
318 | up(&emu->register_mutex); | |
319 | return 0; | |
320 | } | |
321 | ||
322 | /* | |
323 | * Routine that is called upon the last unuse() of a particular port. | |
324 | */ | |
325 | static int | |
03da312a | 326 | snd_emux_unuse(void *private_data, struct snd_seq_port_subscribe *info) |
1da177e4 | 327 | { |
03da312a TI |
328 | struct snd_emux_port *p; |
329 | struct snd_emux *emu; | |
1da177e4 LT |
330 | |
331 | p = private_data; | |
332 | snd_assert(p != NULL, return -EINVAL); | |
333 | emu = p->emu; | |
334 | snd_assert(emu != NULL, return -EINVAL); | |
335 | ||
336 | down(&emu->register_mutex); | |
337 | snd_emux_sounds_off_all(p); | |
338 | snd_emux_dec_count(emu); | |
339 | up(&emu->register_mutex); | |
340 | return 0; | |
341 | } | |
342 | ||
343 | ||
344 | /* | |
345 | * Create a sequencer client | |
346 | */ | |
347 | static int | |
03da312a | 348 | get_client(struct snd_card *card, int index, char *name) |
1da177e4 | 349 | { |
03da312a | 350 | struct snd_seq_client_info cinfo; |
1da177e4 LT |
351 | int client; |
352 | ||
1da177e4 | 353 | /* Find a free client, start from 1 as the MPU expects to use 0 */ |
83e8ad69 | 354 | client = snd_seq_create_kernel_client(card, index); |
1da177e4 LT |
355 | if (client < 0) |
356 | return client; | |
357 | ||
358 | memset(&cinfo, 0, sizeof(cinfo)); | |
359 | cinfo.client = client; | |
360 | cinfo.type = KERNEL_CLIENT; | |
361 | strcpy(cinfo.name, name); | |
362 | snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, &cinfo); | |
363 | ||
364 | return client; | |
365 | } | |
366 | ||
367 | ||
368 | /* | |
369 | * attach virtual rawmidi devices | |
370 | */ | |
03da312a | 371 | int snd_emux_init_virmidi(struct snd_emux *emu, struct snd_card *card) |
1da177e4 LT |
372 | { |
373 | int i; | |
374 | ||
375 | emu->vmidi = NULL; | |
376 | if (emu->midi_ports <= 0) | |
377 | return 0; | |
378 | ||
03da312a | 379 | emu->vmidi = kcalloc(emu->midi_ports, sizeof(struct snd_rawmidi *), GFP_KERNEL); |
1da177e4 LT |
380 | if (emu->vmidi == NULL) |
381 | return -ENOMEM; | |
382 | ||
383 | for (i = 0; i < emu->midi_ports; i++) { | |
03da312a TI |
384 | struct snd_rawmidi *rmidi; |
385 | struct snd_virmidi_dev *rdev; | |
1da177e4 LT |
386 | if (snd_virmidi_new(card, emu->midi_devidx + i, &rmidi) < 0) |
387 | goto __error; | |
388 | rdev = rmidi->private_data; | |
389 | sprintf(rmidi->name, "%s Synth MIDI", emu->name); | |
390 | rdev->seq_mode = SNDRV_VIRMIDI_SEQ_ATTACH; | |
391 | rdev->client = emu->client; | |
392 | rdev->port = emu->ports[i]; | |
393 | if (snd_device_register(card, rmidi) < 0) { | |
394 | snd_device_free(card, rmidi); | |
395 | goto __error; | |
396 | } | |
397 | emu->vmidi[i] = rmidi; | |
398 | //snd_printk("virmidi %d ok\n", i); | |
399 | } | |
400 | return 0; | |
401 | ||
402 | __error: | |
403 | //snd_printk("error init..\n"); | |
404 | snd_emux_delete_virmidi(emu); | |
405 | return -ENOMEM; | |
406 | } | |
407 | ||
03da312a | 408 | int snd_emux_delete_virmidi(struct snd_emux *emu) |
1da177e4 LT |
409 | { |
410 | int i; | |
411 | ||
412 | if (emu->vmidi == NULL) | |
413 | return 0; | |
414 | ||
415 | for (i = 0; i < emu->midi_ports; i++) { | |
416 | if (emu->vmidi[i]) | |
417 | snd_device_free(emu->card, emu->vmidi[i]); | |
418 | } | |
419 | kfree(emu->vmidi); | |
420 | emu->vmidi = NULL; | |
421 | return 0; | |
422 | } |