blob: 36d53bd317ede3f2d3cc1974c7003a7746789d14 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Soundfont generic routines.
3 * It is intended that these should be used by any driver that is willing
4 * to accept soundfont patches.
5 *
6 * Copyright (C) 1999 Steve Ratcliffe
7 * Copyright (c) 1999-2000 Takashi Iwai <tiwai@suse.de>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23/*
24 * Deal with reading in of a soundfont. Code follows the OSS way
25 * of doing things so that the old sfxload utility can be used.
26 * Everything may change when there is an alsa way of doing things.
27 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070028#include <asm/uaccess.h>
29#include <linux/slab.h>
30#include <sound/core.h>
31#include <sound/soundfont.h>
32#include <sound/seq_oss_legacy.h>
33
34/* Prototypes for static functions */
35
Takashi Iwai03da3122005-11-17 14:24:47 +010036static int open_patch(struct snd_sf_list *sflist, const char __user *data,
37 int count, int client);
38static struct snd_soundfont *newsf(struct snd_sf_list *sflist, int type, char *name);
39static int is_identical_font(struct snd_soundfont *sf, int type, unsigned char *name);
40static int close_patch(struct snd_sf_list *sflist);
41static int probe_data(struct snd_sf_list *sflist, int sample_id);
42static void set_zone_counter(struct snd_sf_list *sflist,
43 struct snd_soundfont *sf, struct snd_sf_zone *zp);
44static struct snd_sf_zone *sf_zone_new(struct snd_sf_list *sflist,
45 struct snd_soundfont *sf);
46static void set_sample_counter(struct snd_sf_list *sflist,
47 struct snd_soundfont *sf, struct snd_sf_sample *sp);
48static struct snd_sf_sample *sf_sample_new(struct snd_sf_list *sflist,
49 struct snd_soundfont *sf);
50static void sf_sample_delete(struct snd_sf_list *sflist,
51 struct snd_soundfont *sf, struct snd_sf_sample *sp);
52static int load_map(struct snd_sf_list *sflist, const void __user *data, int count);
53static int load_info(struct snd_sf_list *sflist, const void __user *data, long count);
54static int remove_info(struct snd_sf_list *sflist, struct snd_soundfont *sf,
55 int bank, int instr);
56static void init_voice_info(struct soundfont_voice_info *avp);
57static void init_voice_parm(struct soundfont_voice_parm *pp);
58static struct snd_sf_sample *set_sample(struct snd_soundfont *sf,
59 struct soundfont_voice_info *avp);
60static struct snd_sf_sample *find_sample(struct snd_soundfont *sf, int sample_id);
61static int load_data(struct snd_sf_list *sflist, const void __user *data, long count);
62static void rebuild_presets(struct snd_sf_list *sflist);
63static void add_preset(struct snd_sf_list *sflist, struct snd_sf_zone *cur);
64static void delete_preset(struct snd_sf_list *sflist, struct snd_sf_zone *zp);
65static struct snd_sf_zone *search_first_zone(struct snd_sf_list *sflist,
66 int bank, int preset, int key);
67static int search_zones(struct snd_sf_list *sflist, int *notep, int vel,
68 int preset, int bank, struct snd_sf_zone **table,
69 int max_layers, int level);
Linus Torvalds1da177e2005-04-16 15:20:36 -070070static int get_index(int bank, int instr, int key);
Takashi Iwai03da3122005-11-17 14:24:47 +010071static void snd_sf_init(struct snd_sf_list *sflist);
72static void snd_sf_clear(struct snd_sf_list *sflist);
Linus Torvalds1da177e2005-04-16 15:20:36 -070073
74/*
75 * lock access to sflist
76 */
77static void
Takashi Iwai03da3122005-11-17 14:24:47 +010078lock_preset(struct snd_sf_list *sflist)
Linus Torvalds1da177e2005-04-16 15:20:36 -070079{
80 unsigned long flags;
Ingo Molnaref9f0a42006-01-16 16:31:42 +010081 mutex_lock(&sflist->presets_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070082 spin_lock_irqsave(&sflist->lock, flags);
83 sflist->presets_locked = 1;
84 spin_unlock_irqrestore(&sflist->lock, flags);
85}
86
87
88/*
89 * remove lock
90 */
91static void
Takashi Iwai03da3122005-11-17 14:24:47 +010092unlock_preset(struct snd_sf_list *sflist)
Linus Torvalds1da177e2005-04-16 15:20:36 -070093{
94 unsigned long flags;
95 spin_lock_irqsave(&sflist->lock, flags);
96 sflist->presets_locked = 0;
97 spin_unlock_irqrestore(&sflist->lock, flags);
Ingo Molnaref9f0a42006-01-16 16:31:42 +010098 mutex_unlock(&sflist->presets_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070099}
100
101
102/*
103 * close the patch if the patch was opened by this client.
104 */
105int
Takashi Iwai03da3122005-11-17 14:24:47 +0100106snd_soundfont_close_check(struct snd_sf_list *sflist, int client)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107{
108 unsigned long flags;
109 spin_lock_irqsave(&sflist->lock, flags);
110 if (sflist->open_client == client) {
111 spin_unlock_irqrestore(&sflist->lock, flags);
112 return close_patch(sflist);
113 }
114 spin_unlock_irqrestore(&sflist->lock, flags);
115 return 0;
116}
117
118
119/*
120 * Deal with a soundfont patch. Any driver could use these routines
121 * although it was designed for the AWE64.
122 *
123 * The sample_write and callargs pararameters allow a callback into
124 * the actual driver to write sample data to the board or whatever
125 * it wants to do with it.
126 */
127int
Takashi Iwai03da3122005-11-17 14:24:47 +0100128snd_soundfont_load(struct snd_sf_list *sflist, const void __user *data,
129 long count, int client)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130{
Takashi Iwai03da3122005-11-17 14:24:47 +0100131 struct soundfont_patch_info patch;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132 unsigned long flags;
133 int rc;
134
135 if (count < (long)sizeof(patch)) {
136 snd_printk("patch record too small %ld\n", count);
137 return -EINVAL;
138 }
139 if (copy_from_user(&patch, data, sizeof(patch)))
140 return -EFAULT;
141
142 count -= sizeof(patch);
143 data += sizeof(patch);
144
145 if (patch.key != SNDRV_OSS_SOUNDFONT_PATCH) {
146 snd_printk("'The wrong kind of patch' %x\n", patch.key);
147 return -EINVAL;
148 }
149 if (count < patch.len) {
150 snd_printk("Patch too short %ld, need %d\n", count, patch.len);
151 return -EINVAL;
152 }
153 if (patch.len < 0) {
154 snd_printk("poor length %d\n", patch.len);
155 return -EINVAL;
156 }
157
158 if (patch.type == SNDRV_SFNT_OPEN_PATCH) {
159 /* grab sflist to open */
160 lock_preset(sflist);
161 rc = open_patch(sflist, data, count, client);
162 unlock_preset(sflist);
163 return rc;
164 }
165
166 /* check if other client already opened patch */
167 spin_lock_irqsave(&sflist->lock, flags);
168 if (sflist->open_client != client) {
169 spin_unlock_irqrestore(&sflist->lock, flags);
170 return -EBUSY;
171 }
172 spin_unlock_irqrestore(&sflist->lock, flags);
173
174 lock_preset(sflist);
175 rc = -EINVAL;
176 switch (patch.type) {
177 case SNDRV_SFNT_LOAD_INFO:
178 rc = load_info(sflist, data, count);
179 break;
180 case SNDRV_SFNT_LOAD_DATA:
181 rc = load_data(sflist, data, count);
182 break;
183 case SNDRV_SFNT_CLOSE_PATCH:
184 rc = close_patch(sflist);
185 break;
186 case SNDRV_SFNT_REPLACE_DATA:
187 /*rc = replace_data(&patch, data, count);*/
188 break;
189 case SNDRV_SFNT_MAP_PRESET:
190 rc = load_map(sflist, data, count);
191 break;
192 case SNDRV_SFNT_PROBE_DATA:
193 rc = probe_data(sflist, patch.optarg);
194 break;
195 case SNDRV_SFNT_REMOVE_INFO:
196 /* patch must be opened */
Eric Sesterhennd20cad62006-05-31 11:55:17 +0200197 if (!sflist->currsf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198 snd_printk("soundfont: remove_info: patch not opened\n");
199 rc = -EINVAL;
200 } else {
201 int bank, instr;
202 bank = ((unsigned short)patch.optarg >> 8) & 0xff;
203 instr = (unsigned short)patch.optarg & 0xff;
204 if (! remove_info(sflist, sflist->currsf, bank, instr))
205 rc = -EINVAL;
206 else
207 rc = 0;
208 }
209 break;
210 }
211 unlock_preset(sflist);
212
213 return rc;
214}
215
216
217/* check if specified type is special font (GUS or preset-alias) */
218static inline int
219is_special_type(int type)
220{
221 type &= 0x0f;
222 return (type == SNDRV_SFNT_PAT_TYPE_GUS ||
223 type == SNDRV_SFNT_PAT_TYPE_MAP);
224}
225
226
227/* open patch; create sf list */
228static int
Takashi Iwai03da3122005-11-17 14:24:47 +0100229open_patch(struct snd_sf_list *sflist, const char __user *data,
230 int count, int client)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231{
Takashi Iwai03da3122005-11-17 14:24:47 +0100232 struct soundfont_open_parm parm;
233 struct snd_soundfont *sf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 unsigned long flags;
235
236 spin_lock_irqsave(&sflist->lock, flags);
237 if (sflist->open_client >= 0 || sflist->currsf) {
238 spin_unlock_irqrestore(&sflist->lock, flags);
239 return -EBUSY;
240 }
241 spin_unlock_irqrestore(&sflist->lock, flags);
242
243 if (copy_from_user(&parm, data, sizeof(parm)))
244 return -EFAULT;
245
246 if (is_special_type(parm.type)) {
247 parm.type |= SNDRV_SFNT_PAT_SHARED;
248 sf = newsf(sflist, parm.type, NULL);
249 } else
250 sf = newsf(sflist, parm.type, parm.name);
251 if (sf == NULL) {
252 return -ENOMEM;
253 }
254
255 spin_lock_irqsave(&sflist->lock, flags);
256 sflist->open_client = client;
257 sflist->currsf = sf;
258 spin_unlock_irqrestore(&sflist->lock, flags);
259
260 return 0;
261}
262
263/*
264 * Allocate a new soundfont structure.
265 */
Takashi Iwai03da3122005-11-17 14:24:47 +0100266static struct snd_soundfont *
267newsf(struct snd_sf_list *sflist, int type, char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268{
Takashi Iwai03da3122005-11-17 14:24:47 +0100269 struct snd_soundfont *sf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270
271 /* check the shared fonts */
272 if (type & SNDRV_SFNT_PAT_SHARED) {
273 for (sf = sflist->fonts; sf; sf = sf->next) {
274 if (is_identical_font(sf, type, name)) {
275 return sf;
276 }
277 }
278 }
279
280 /* not found -- create a new one */
Takashi Iwai561b2202005-09-09 14:22:34 +0200281 sf = kzalloc(sizeof(*sf), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 if (sf == NULL)
283 return NULL;
284 sf->id = sflist->fonts_size;
285 sflist->fonts_size++;
286
287 /* prepend this record */
288 sf->next = sflist->fonts;
289 sflist->fonts = sf;
290
291 sf->type = type;
292 sf->zones = NULL;
293 sf->samples = NULL;
294 if (name)
295 memcpy(sf->name, name, SNDRV_SFNT_PATCH_NAME_LEN);
296
297 return sf;
298}
299
300/* check if the given name matches to the existing list */
301static int
Takashi Iwai03da3122005-11-17 14:24:47 +0100302is_identical_font(struct snd_soundfont *sf, int type, unsigned char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303{
304 return ((sf->type & SNDRV_SFNT_PAT_SHARED) &&
305 (sf->type & 0x0f) == (type & 0x0f) &&
306 (name == NULL ||
307 memcmp(sf->name, name, SNDRV_SFNT_PATCH_NAME_LEN) == 0));
308}
309
310/*
311 * Close the current patch.
312 */
313static int
Takashi Iwai03da3122005-11-17 14:24:47 +0100314close_patch(struct snd_sf_list *sflist)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315{
316 unsigned long flags;
317
318 spin_lock_irqsave(&sflist->lock, flags);
319 sflist->currsf = NULL;
320 sflist->open_client = -1;
321 spin_unlock_irqrestore(&sflist->lock, flags);
322
323 rebuild_presets(sflist);
324
325 return 0;
326
327}
328
329/* probe sample in the current list -- nothing to be loaded */
330static int
Takashi Iwai03da3122005-11-17 14:24:47 +0100331probe_data(struct snd_sf_list *sflist, int sample_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332{
333 /* patch must be opened */
334 if (sflist->currsf) {
335 /* search the specified sample by optarg */
336 if (find_sample(sflist->currsf, sample_id))
337 return 0;
338 }
339 return -EINVAL;
340}
341
342/*
343 * increment zone counter
344 */
345static void
Takashi Iwai03da3122005-11-17 14:24:47 +0100346set_zone_counter(struct snd_sf_list *sflist, struct snd_soundfont *sf,
347 struct snd_sf_zone *zp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348{
349 zp->counter = sflist->zone_counter++;
350 if (sf->type & SNDRV_SFNT_PAT_LOCKED)
351 sflist->zone_locked = sflist->zone_counter;
352}
353
354/*
355 * allocate a new zone record
356 */
Takashi Iwai03da3122005-11-17 14:24:47 +0100357static struct snd_sf_zone *
358sf_zone_new(struct snd_sf_list *sflist, struct snd_soundfont *sf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359{
Takashi Iwai03da3122005-11-17 14:24:47 +0100360 struct snd_sf_zone *zp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361
Takashi Iwai561b2202005-09-09 14:22:34 +0200362 if ((zp = kzalloc(sizeof(*zp), GFP_KERNEL)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 return NULL;
364 zp->next = sf->zones;
365 sf->zones = zp;
366
367 init_voice_info(&zp->v);
368
369 set_zone_counter(sflist, sf, zp);
370 return zp;
371}
372
373
374/*
375 * increment sample couter
376 */
377static void
Takashi Iwai03da3122005-11-17 14:24:47 +0100378set_sample_counter(struct snd_sf_list *sflist, struct snd_soundfont *sf,
379 struct snd_sf_sample *sp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380{
381 sp->counter = sflist->sample_counter++;
382 if (sf->type & SNDRV_SFNT_PAT_LOCKED)
383 sflist->sample_locked = sflist->sample_counter;
384}
385
386/*
387 * allocate a new sample list record
388 */
Takashi Iwai03da3122005-11-17 14:24:47 +0100389static struct snd_sf_sample *
390sf_sample_new(struct snd_sf_list *sflist, struct snd_soundfont *sf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391{
Takashi Iwai03da3122005-11-17 14:24:47 +0100392 struct snd_sf_sample *sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393
Takashi Iwai561b2202005-09-09 14:22:34 +0200394 if ((sp = kzalloc(sizeof(*sp), GFP_KERNEL)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 return NULL;
396
397 sp->next = sf->samples;
398 sf->samples = sp;
399
400 set_sample_counter(sflist, sf, sp);
401 return sp;
402}
403
404/*
405 * delete sample list -- this is an exceptional job.
406 * only the last allocated sample can be deleted.
407 */
408static void
Takashi Iwai03da3122005-11-17 14:24:47 +0100409sf_sample_delete(struct snd_sf_list *sflist, struct snd_soundfont *sf,
410 struct snd_sf_sample *sp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411{
412 /* only last sample is accepted */
413 if (sp == sf->samples) {
414 sf->samples = sp->next;
415 kfree(sp);
416 }
417}
418
419
420/* load voice map */
421static int
Takashi Iwai03da3122005-11-17 14:24:47 +0100422load_map(struct snd_sf_list *sflist, const void __user *data, int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423{
Takashi Iwai03da3122005-11-17 14:24:47 +0100424 struct snd_sf_zone *zp, *prevp;
425 struct snd_soundfont *sf;
426 struct soundfont_voice_map map;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427
428 /* get the link info */
429 if (count < (int)sizeof(map))
430 return -EINVAL;
431 if (copy_from_user(&map, data, sizeof(map)))
432 return -EFAULT;
433
434 if (map.map_instr < 0 || map.map_instr >= SF_MAX_INSTRUMENTS)
435 return -EINVAL;
436
437 sf = newsf(sflist, SNDRV_SFNT_PAT_TYPE_MAP|SNDRV_SFNT_PAT_SHARED, NULL);
438 if (sf == NULL)
439 return -ENOMEM;
440
441 prevp = NULL;
442 for (zp = sf->zones; zp; prevp = zp, zp = zp->next) {
443 if (zp->mapped &&
444 zp->instr == map.map_instr &&
445 zp->bank == map.map_bank &&
446 zp->v.low == map.map_key &&
447 zp->v.start == map.src_instr &&
448 zp->v.end == map.src_bank &&
449 zp->v.fixkey == map.src_key) {
450 /* the same mapping is already present */
451 /* relink this record to the link head */
452 if (prevp) {
453 prevp->next = zp->next;
454 zp->next = sf->zones;
455 sf->zones = zp;
456 }
457 /* update the counter */
458 set_zone_counter(sflist, sf, zp);
459 return 0;
460 }
461 }
462
463 /* create a new zone */
464 if ((zp = sf_zone_new(sflist, sf)) == NULL)
465 return -ENOMEM;
466
467 zp->bank = map.map_bank;
468 zp->instr = map.map_instr;
469 zp->mapped = 1;
470 if (map.map_key >= 0) {
471 zp->v.low = map.map_key;
472 zp->v.high = map.map_key;
473 }
474 zp->v.start = map.src_instr;
475 zp->v.end = map.src_bank;
476 zp->v.fixkey = map.src_key;
477 zp->v.sf_id = sf->id;
478
479 add_preset(sflist, zp);
480
481 return 0;
482}
483
484
485/* remove the present instrument layers */
486static int
Takashi Iwai03da3122005-11-17 14:24:47 +0100487remove_info(struct snd_sf_list *sflist, struct snd_soundfont *sf,
488 int bank, int instr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489{
Takashi Iwai03da3122005-11-17 14:24:47 +0100490 struct snd_sf_zone *prev, *next, *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 int removed = 0;
492
493 prev = NULL;
494 for (p = sf->zones; p; p = next) {
495 next = p->next;
496 if (! p->mapped &&
497 p->bank == bank && p->instr == instr) {
498 /* remove this layer */
499 if (prev)
500 prev->next = next;
501 else
502 sf->zones = next;
503 removed++;
504 kfree(p);
505 } else
506 prev = p;
507 }
508 if (removed)
509 rebuild_presets(sflist);
510 return removed;
511}
512
513
514/*
515 * Read an info record from the user buffer and save it on the current
516 * open soundfont.
517 */
518static int
Takashi Iwai03da3122005-11-17 14:24:47 +0100519load_info(struct snd_sf_list *sflist, const void __user *data, long count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520{
Takashi Iwai03da3122005-11-17 14:24:47 +0100521 struct snd_soundfont *sf;
522 struct snd_sf_zone *zone;
523 struct soundfont_voice_rec_hdr hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 int i;
525
526 /* patch must be opened */
527 if ((sf = sflist->currsf) == NULL)
528 return -EINVAL;
529
530 if (is_special_type(sf->type))
531 return -EINVAL;
532
533 if (count < (long)sizeof(hdr)) {
534 printk("Soundfont error: invalid patch zone length\n");
535 return -EINVAL;
536 }
537 if (copy_from_user((char*)&hdr, data, sizeof(hdr)))
538 return -EFAULT;
539
540 data += sizeof(hdr);
541 count -= sizeof(hdr);
542
543 if (hdr.nvoices <= 0 || hdr.nvoices >= 100) {
544 printk("Soundfont error: Illegal voice number %d\n", hdr.nvoices);
545 return -EINVAL;
546 }
547
Takashi Iwai03da3122005-11-17 14:24:47 +0100548 if (count < (long)sizeof(struct soundfont_voice_info) * hdr.nvoices) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 printk("Soundfont Error: patch length(%ld) is smaller than nvoices(%d)\n",
550 count, hdr.nvoices);
551 return -EINVAL;
552 }
553
554 switch (hdr.write_mode) {
555 case SNDRV_SFNT_WR_EXCLUSIVE:
556 /* exclusive mode - if the instrument already exists,
557 return error */
558 for (zone = sf->zones; zone; zone = zone->next) {
559 if (!zone->mapped &&
560 zone->bank == hdr.bank &&
561 zone->instr == hdr.instr)
562 return -EINVAL;
563 }
564 break;
565 case SNDRV_SFNT_WR_REPLACE:
566 /* replace mode - remove the instrument if it already exists */
567 remove_info(sflist, sf, hdr.bank, hdr.instr);
568 break;
569 }
570
571 for (i = 0; i < hdr.nvoices; i++) {
Takashi Iwai03da3122005-11-17 14:24:47 +0100572 struct snd_sf_zone tmpzone;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573
574 /* copy awe_voice_info parameters */
575 if (copy_from_user(&tmpzone.v, data, sizeof(tmpzone.v))) {
576 return -EFAULT;
577 }
578
579 data += sizeof(tmpzone.v);
580 count -= sizeof(tmpzone.v);
581
582 tmpzone.bank = hdr.bank;
583 tmpzone.instr = hdr.instr;
584 tmpzone.mapped = 0;
585 tmpzone.v.sf_id = sf->id;
586 if (tmpzone.v.mode & SNDRV_SFNT_MODE_INIT_PARM)
587 init_voice_parm(&tmpzone.v.parm);
588
589 /* create a new zone */
590 if ((zone = sf_zone_new(sflist, sf)) == NULL) {
591 return -ENOMEM;
592 }
593
594 /* copy the temporary data */
595 zone->bank = tmpzone.bank;
596 zone->instr = tmpzone.instr;
597 zone->v = tmpzone.v;
598
599 /* look up the sample */
600 zone->sample = set_sample(sf, &zone->v);
601 }
602
603 return 0;
604}
605
606
607/* initialize voice_info record */
608static void
Takashi Iwai03da3122005-11-17 14:24:47 +0100609init_voice_info(struct soundfont_voice_info *avp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610{
611 memset(avp, 0, sizeof(*avp));
612
613 avp->root = 60;
614 avp->high = 127;
615 avp->velhigh = 127;
616 avp->fixkey = -1;
617 avp->fixvel = -1;
618 avp->fixpan = -1;
619 avp->pan = -1;
620 avp->amplitude = 127;
621 avp->scaleTuning = 100;
622
623 init_voice_parm(&avp->parm);
624}
625
626/* initialize voice_parm record:
627 * Env1/2: delay=0, attack=0, hold=0, sustain=0, decay=0, release=0.
628 * Vibrato and Tremolo effects are zero.
629 * Cutoff is maximum.
630 * Chorus and Reverb effects are zero.
631 */
632static void
Takashi Iwai03da3122005-11-17 14:24:47 +0100633init_voice_parm(struct soundfont_voice_parm *pp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634{
635 memset(pp, 0, sizeof(*pp));
636
637 pp->moddelay = 0x8000;
638 pp->modatkhld = 0x7f7f;
639 pp->moddcysus = 0x7f7f;
640 pp->modrelease = 0x807f;
641
642 pp->voldelay = 0x8000;
643 pp->volatkhld = 0x7f7f;
644 pp->voldcysus = 0x7f7f;
645 pp->volrelease = 0x807f;
646
647 pp->lfo1delay = 0x8000;
648 pp->lfo2delay = 0x8000;
649
650 pp->cutoff = 0xff;
651}
652
653/* search the specified sample */
Takashi Iwai03da3122005-11-17 14:24:47 +0100654static struct snd_sf_sample *
655set_sample(struct snd_soundfont *sf, struct soundfont_voice_info *avp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656{
Takashi Iwai03da3122005-11-17 14:24:47 +0100657 struct snd_sf_sample *sample;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658
659 sample = find_sample(sf, avp->sample);
660 if (sample == NULL)
661 return NULL;
662
663 /* add in the actual sample offsets:
664 * The voice_info addresses define only the relative offset
665 * from sample pointers. Here we calculate the actual DRAM
666 * offset from sample pointers.
667 */
668 avp->start += sample->v.start;
669 avp->end += sample->v.end;
670 avp->loopstart += sample->v.loopstart;
671 avp->loopend += sample->v.loopend;
672
673 /* copy mode flags */
674 avp->sample_mode = sample->v.mode_flags;
675
676 return sample;
677}
678
679/* find the sample pointer with the given id in the soundfont */
Takashi Iwai03da3122005-11-17 14:24:47 +0100680static struct snd_sf_sample *
681find_sample(struct snd_soundfont *sf, int sample_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682{
Takashi Iwai03da3122005-11-17 14:24:47 +0100683 struct snd_sf_sample *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684
685 if (sf == NULL)
686 return NULL;
687
688 for (p = sf->samples; p; p = p->next) {
689 if (p->v.sample == sample_id)
690 return p;
691 }
692 return NULL;
693}
694
695
696/*
697 * Load sample information, this can include data to be loaded onto
698 * the soundcard. It can also just be a pointer into soundcard ROM.
699 * If there is data it will be written to the soundcard via the callback
700 * routine.
701 */
702static int
Takashi Iwai03da3122005-11-17 14:24:47 +0100703load_data(struct snd_sf_list *sflist, const void __user *data, long count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704{
Takashi Iwai03da3122005-11-17 14:24:47 +0100705 struct snd_soundfont *sf;
706 struct soundfont_sample_info sample_info;
707 struct snd_sf_sample *sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 long off;
709
710 /* patch must be opened */
711 if ((sf = sflist->currsf) == NULL)
712 return -EINVAL;
713
714 if (is_special_type(sf->type))
715 return -EINVAL;
716
717 if (copy_from_user(&sample_info, data, sizeof(sample_info)))
718 return -EFAULT;
719
720 off = sizeof(sample_info);
721
722 if (sample_info.size != (count-off)/2)
723 return -EINVAL;
724
725 /* Check for dup */
726 if (find_sample(sf, sample_info.sample)) {
727 /* if shared sample, skip this data */
728 if (sf->type & SNDRV_SFNT_PAT_SHARED)
729 return 0;
730 return -EINVAL;
731 }
732
733 /* Allocate a new sample structure */
734 if ((sp = sf_sample_new(sflist, sf)) == NULL)
735 return -ENOMEM;
736
737 sp->v = sample_info;
738 sp->v.sf_id = sf->id;
739 sp->v.dummy = 0;
740 sp->v.truesize = sp->v.size;
741
742 /*
743 * If there is wave data then load it.
744 */
745 if (sp->v.size > 0) {
746 int rc;
747 rc = sflist->callback.sample_new
748 (sflist->callback.private_data, sp, sflist->memhdr,
749 data + off, count - off);
750 if (rc < 0) {
751 sf_sample_delete(sflist, sf, sp);
752 return rc;
753 }
754 sflist->mem_used += sp->v.truesize;
755 }
756
757 return count;
758}
759
760
761/* log2_tbl[i] = log2(i+128) * 0x10000 */
762static int log_tbl[129] = {
763 0x70000, 0x702df, 0x705b9, 0x7088e, 0x70b5d, 0x70e26, 0x710eb, 0x713aa,
764 0x71663, 0x71918, 0x71bc8, 0x71e72, 0x72118, 0x723b9, 0x72655, 0x728ed,
765 0x72b80, 0x72e0e, 0x73098, 0x7331d, 0x7359e, 0x7381b, 0x73a93, 0x73d08,
766 0x73f78, 0x741e4, 0x7444c, 0x746b0, 0x74910, 0x74b6c, 0x74dc4, 0x75019,
767 0x75269, 0x754b6, 0x75700, 0x75946, 0x75b88, 0x75dc7, 0x76002, 0x7623a,
768 0x7646e, 0x766a0, 0x768cd, 0x76af8, 0x76d1f, 0x76f43, 0x77164, 0x77382,
769 0x7759d, 0x777b4, 0x779c9, 0x77bdb, 0x77dea, 0x77ff5, 0x781fe, 0x78404,
770 0x78608, 0x78808, 0x78a06, 0x78c01, 0x78df9, 0x78fef, 0x791e2, 0x793d2,
771 0x795c0, 0x797ab, 0x79993, 0x79b79, 0x79d5d, 0x79f3e, 0x7a11d, 0x7a2f9,
772 0x7a4d3, 0x7a6ab, 0x7a880, 0x7aa53, 0x7ac24, 0x7adf2, 0x7afbe, 0x7b188,
773 0x7b350, 0x7b515, 0x7b6d8, 0x7b899, 0x7ba58, 0x7bc15, 0x7bdd0, 0x7bf89,
774 0x7c140, 0x7c2f5, 0x7c4a7, 0x7c658, 0x7c807, 0x7c9b3, 0x7cb5e, 0x7cd07,
775 0x7ceae, 0x7d053, 0x7d1f7, 0x7d398, 0x7d538, 0x7d6d6, 0x7d872, 0x7da0c,
776 0x7dba4, 0x7dd3b, 0x7ded0, 0x7e063, 0x7e1f4, 0x7e384, 0x7e512, 0x7e69f,
777 0x7e829, 0x7e9b3, 0x7eb3a, 0x7ecc0, 0x7ee44, 0x7efc7, 0x7f148, 0x7f2c8,
778 0x7f446, 0x7f5c2, 0x7f73d, 0x7f8b7, 0x7fa2f, 0x7fba5, 0x7fd1a, 0x7fe8d,
779 0x80000,
780};
781
782/* convert from linear to log value
783 *
784 * conversion: value = log2(amount / base) * ratio
785 *
786 * argument:
787 * amount = linear value (unsigned, 32bit max)
788 * offset = base offset (:= log2(base) * 0x10000)
789 * ratio = division ratio
790 *
791 */
792int
793snd_sf_linear_to_log(unsigned int amount, int offset, int ratio)
794{
795 int v;
796 int s, low, bit;
797
798 if (amount < 2)
799 return 0;
800 for (bit = 0; ! (amount & 0x80000000L); bit++)
801 amount <<= 1;
802 s = (amount >> 24) & 0x7f;
803 low = (amount >> 16) & 0xff;
804 /* linear approxmimation by lower 8 bit */
805 v = (log_tbl[s + 1] * low + log_tbl[s] * (0x100 - low)) >> 8;
806 v -= offset;
807 v = (v * ratio) >> 16;
808 v += (24 - bit) * ratio;
809 return v;
810}
811
Takashi Iwai95ff17562006-04-28 15:13:40 +0200812EXPORT_SYMBOL(snd_sf_linear_to_log);
813
814
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815#define OFFSET_MSEC 653117 /* base = 1000 */
816#define OFFSET_ABSCENT 851781 /* base = 8176 */
817#define OFFSET_SAMPLERATE 1011119 /* base = 44100 */
818
819#define ABSCENT_RATIO 1200
820#define TIMECENT_RATIO 1200
821#define SAMPLERATE_RATIO 4096
822
823/*
824 * mHz to abscent
825 * conversion: abscent = log2(MHz / 8176) * 1200
826 */
827static int
828freq_to_note(int mhz)
829{
830 return snd_sf_linear_to_log(mhz, OFFSET_ABSCENT, ABSCENT_RATIO);
831}
832
833/* convert Hz to AWE32 rate offset:
834 * sample pitch offset for the specified sample rate
835 * rate=44100 is no offset, each 4096 is 1 octave (twice).
836 * eg, when rate is 22050, this offset becomes -4096.
837 *
838 * conversion: offset = log2(Hz / 44100) * 4096
839 */
840static int
841calc_rate_offset(int hz)
842{
843 return snd_sf_linear_to_log(hz, OFFSET_SAMPLERATE, SAMPLERATE_RATIO);
844}
845
846
847/* calculate GUS envelope time */
848static int
849calc_gus_envelope_time(int rate, int start, int end)
850{
851 int r, p, t;
852 r = (3 - ((rate >> 6) & 3)) * 3;
853 p = rate & 0x3f;
854 t = end - start;
855 if (t < 0) t = -t;
856 if (13 > r)
857 t = t << (13 - r);
858 else
859 t = t >> (r - 13);
860 return (t * 10) / (p * 441);
861}
862
863/* convert envelope time parameter to soundfont parameters */
864
865/* attack & decay/release time table (msec) */
866static short attack_time_tbl[128] = {
86732767, 32767, 5989, 4235, 2994, 2518, 2117, 1780, 1497, 1373, 1259, 1154, 1058, 970, 890, 816,
868707, 691, 662, 634, 607, 581, 557, 533, 510, 489, 468, 448, 429, 411, 393, 377,
869361, 345, 331, 317, 303, 290, 278, 266, 255, 244, 234, 224, 214, 205, 196, 188,
870180, 172, 165, 158, 151, 145, 139, 133, 127, 122, 117, 112, 107, 102, 98, 94,
87190, 86, 82, 79, 75, 72, 69, 66, 63, 61, 58, 56, 53, 51, 49, 47,
87245, 43, 41, 39, 37, 36, 34, 33, 31, 30, 29, 28, 26, 25, 24, 23,
87322, 21, 20, 19, 19, 18, 17, 16, 16, 15, 15, 14, 13, 13, 12, 12,
87411, 11, 10, 10, 10, 9, 9, 8, 8, 8, 8, 7, 7, 7, 6, 0,
875};
876
877static short decay_time_tbl[128] = {
87832767, 32767, 22614, 15990, 11307, 9508, 7995, 6723, 5653, 5184, 4754, 4359, 3997, 3665, 3361, 3082,
8792828, 2765, 2648, 2535, 2428, 2325, 2226, 2132, 2042, 1955, 1872, 1793, 1717, 1644, 1574, 1507,
8801443, 1382, 1324, 1267, 1214, 1162, 1113, 1066, 978, 936, 897, 859, 822, 787, 754, 722,
881691, 662, 634, 607, 581, 557, 533, 510, 489, 468, 448, 429, 411, 393, 377, 361,
882345, 331, 317, 303, 290, 278, 266, 255, 244, 234, 224, 214, 205, 196, 188, 180,
883172, 165, 158, 151, 145, 139, 133, 127, 122, 117, 112, 107, 102, 98, 94, 90,
88486, 82, 79, 75, 72, 69, 66, 63, 61, 58, 56, 53, 51, 49, 47, 45,
88543, 41, 39, 37, 36, 34, 33, 31, 30, 29, 28, 26, 25, 24, 23, 22,
886};
887
888/* delay time = 0x8000 - msec/92 */
889int
890snd_sf_calc_parm_hold(int msec)
891{
892 int val = (0x7f * 92 - msec) / 92;
893 if (val < 1) val = 1;
894 if (val >= 126) val = 126;
895 return val;
896}
897
898/* search an index for specified time from given time table */
899static int
900calc_parm_search(int msec, short *table)
901{
902 int left = 1, right = 127, mid;
903 while (left < right) {
904 mid = (left + right) / 2;
905 if (msec < (int)table[mid])
906 left = mid + 1;
907 else
908 right = mid;
909 }
910 return left;
911}
912
913/* attack time: search from time table */
914int
915snd_sf_calc_parm_attack(int msec)
916{
917 return calc_parm_search(msec, attack_time_tbl);
918}
919
920/* decay/release time: search from time table */
921int
922snd_sf_calc_parm_decay(int msec)
923{
924 return calc_parm_search(msec, decay_time_tbl);
925}
926
927int snd_sf_vol_table[128] = {
928 255,111,95,86,79,74,70,66,63,61,58,56,54,52,50,49,
929 47,46,45,43,42,41,40,39,38,37,36,35,34,34,33,32,
930 31,31,30,29,29,28,27,27,26,26,25,24,24,23,23,22,
931 22,21,21,21,20,20,19,19,18,18,18,17,17,16,16,16,
932 15,15,15,14,14,14,13,13,13,12,12,12,11,11,11,10,
933 10,10,10,9,9,9,8,8,8,8,7,7,7,7,6,6,
934 6,6,5,5,5,5,5,4,4,4,4,3,3,3,3,3,
935 2,2,2,2,2,1,1,1,1,1,0,0,0,0,0,0,
936};
937
938
939#define calc_gus_sustain(val) (0x7f - snd_sf_vol_table[(val)/2])
940#define calc_gus_attenuation(val) snd_sf_vol_table[(val)/2]
941
942/* load GUS patch */
943static int
Takashi Iwai03da3122005-11-17 14:24:47 +0100944load_guspatch(struct snd_sf_list *sflist, const char __user *data,
945 long count, int client)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946{
947 struct patch_info patch;
Takashi Iwai03da3122005-11-17 14:24:47 +0100948 struct snd_soundfont *sf;
949 struct snd_sf_zone *zone;
950 struct snd_sf_sample *smp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951 int note, sample_id;
952 int rc;
953
954 if (count < (long)sizeof(patch)) {
955 snd_printk("patch record too small %ld\n", count);
956 return -EINVAL;
957 }
958 if (copy_from_user(&patch, data, sizeof(patch)))
959 return -EFAULT;
960
961 count -= sizeof(patch);
962 data += sizeof(patch);
963
964 sf = newsf(sflist, SNDRV_SFNT_PAT_TYPE_GUS|SNDRV_SFNT_PAT_SHARED, NULL);
965 if (sf == NULL)
966 return -ENOMEM;
967 if ((smp = sf_sample_new(sflist, sf)) == NULL)
968 return -ENOMEM;
969 sample_id = sflist->sample_counter;
970 smp->v.sample = sample_id;
971 smp->v.start = 0;
972 smp->v.end = patch.len;
973 smp->v.loopstart = patch.loop_start;
974 smp->v.loopend = patch.loop_end;
975 smp->v.size = patch.len;
976
977 /* set up mode flags */
978 smp->v.mode_flags = 0;
979 if (!(patch.mode & WAVE_16_BITS))
980 smp->v.mode_flags |= SNDRV_SFNT_SAMPLE_8BITS;
981 if (patch.mode & WAVE_UNSIGNED)
982 smp->v.mode_flags |= SNDRV_SFNT_SAMPLE_UNSIGNED;
983 smp->v.mode_flags |= SNDRV_SFNT_SAMPLE_NO_BLANK;
984 if (!(patch.mode & (WAVE_LOOPING|WAVE_BIDIR_LOOP|WAVE_LOOP_BACK)))
985 smp->v.mode_flags |= SNDRV_SFNT_SAMPLE_SINGLESHOT;
986 if (patch.mode & WAVE_BIDIR_LOOP)
987 smp->v.mode_flags |= SNDRV_SFNT_SAMPLE_BIDIR_LOOP;
988 if (patch.mode & WAVE_LOOP_BACK)
989 smp->v.mode_flags |= SNDRV_SFNT_SAMPLE_REVERSE_LOOP;
990
991 if (patch.mode & WAVE_16_BITS) {
992 /* convert to word offsets */
993 smp->v.size /= 2;
994 smp->v.end /= 2;
995 smp->v.loopstart /= 2;
996 smp->v.loopend /= 2;
997 }
998 /*smp->v.loopend++;*/
999
1000 smp->v.dummy = 0;
1001 smp->v.truesize = 0;
1002 smp->v.sf_id = sf->id;
1003
1004 /* set up voice info */
1005 if ((zone = sf_zone_new(sflist, sf)) == NULL) {
1006 sf_sample_delete(sflist, sf, smp);
1007 return -ENOMEM;
1008 }
1009
1010 /*
1011 * load wave data
1012 */
1013 if (sflist->callback.sample_new) {
1014 rc = sflist->callback.sample_new
Takashi Iwai03da3122005-11-17 14:24:47 +01001015 (sflist->callback.private_data, smp, sflist->memhdr,
1016 data, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 if (rc < 0) {
1018 sf_sample_delete(sflist, sf, smp);
1019 return rc;
1020 }
1021 /* memory offset is updated after */
1022 }
1023
1024 /* update the memory offset here */
1025 sflist->mem_used += smp->v.truesize;
1026
1027 zone->v.sample = sample_id; /* the last sample */
1028 zone->v.rate_offset = calc_rate_offset(patch.base_freq);
1029 note = freq_to_note(patch.base_note);
1030 zone->v.root = note / 100;
1031 zone->v.tune = -(note % 100);
1032 zone->v.low = (freq_to_note(patch.low_note) + 99) / 100;
1033 zone->v.high = freq_to_note(patch.high_note) / 100;
1034 /* panning position; -128 - 127 => 0-127 */
1035 zone->v.pan = (patch.panning + 128) / 2;
1036#if 0
1037 snd_printk("gus: basefrq=%d (ofs=%d) root=%d,tune=%d, range:%d-%d\n",
1038 (int)patch.base_freq, zone->v.rate_offset,
1039 zone->v.root, zone->v.tune, zone->v.low, zone->v.high);
1040#endif
1041
1042 /* detuning is ignored */
1043 /* 6points volume envelope */
1044 if (patch.mode & WAVE_ENVELOPES) {
1045 int attack, hold, decay, release;
1046 attack = calc_gus_envelope_time
1047 (patch.env_rate[0], 0, patch.env_offset[0]);
1048 hold = calc_gus_envelope_time
1049 (patch.env_rate[1], patch.env_offset[0],
1050 patch.env_offset[1]);
1051 decay = calc_gus_envelope_time
1052 (patch.env_rate[2], patch.env_offset[1],
1053 patch.env_offset[2]);
1054 release = calc_gus_envelope_time
1055 (patch.env_rate[3], patch.env_offset[1],
1056 patch.env_offset[4]);
1057 release += calc_gus_envelope_time
1058 (patch.env_rate[4], patch.env_offset[3],
1059 patch.env_offset[4]);
1060 release += calc_gus_envelope_time
1061 (patch.env_rate[5], patch.env_offset[4],
1062 patch.env_offset[5]);
1063 zone->v.parm.volatkhld =
1064 (snd_sf_calc_parm_hold(hold) << 8) |
1065 snd_sf_calc_parm_attack(attack);
1066 zone->v.parm.voldcysus = (calc_gus_sustain(patch.env_offset[2]) << 8) |
1067 snd_sf_calc_parm_decay(decay);
1068 zone->v.parm.volrelease = 0x8000 | snd_sf_calc_parm_decay(release);
1069 zone->v.attenuation = calc_gus_attenuation(patch.env_offset[0]);
1070#if 0
1071 snd_printk("gus: atkhld=%x, dcysus=%x, volrel=%x, att=%d\n",
1072 zone->v.parm.volatkhld,
1073 zone->v.parm.voldcysus,
1074 zone->v.parm.volrelease,
1075 zone->v.attenuation);
1076#endif
1077 }
1078
1079 /* fast release */
1080 if (patch.mode & WAVE_FAST_RELEASE) {
1081 zone->v.parm.volrelease = 0x807f;
1082 }
1083
1084 /* tremolo effect */
1085 if (patch.mode & WAVE_TREMOLO) {
1086 int rate = (patch.tremolo_rate * 1000 / 38) / 42;
1087 zone->v.parm.tremfrq = ((patch.tremolo_depth / 2) << 8) | rate;
1088 }
1089 /* vibrato effect */
1090 if (patch.mode & WAVE_VIBRATO) {
1091 int rate = (patch.vibrato_rate * 1000 / 38) / 42;
1092 zone->v.parm.fm2frq2 = ((patch.vibrato_depth / 6) << 8) | rate;
1093 }
1094
1095 /* scale_freq, scale_factor, volume, and fractions not implemented */
1096
1097 if (!(smp->v.mode_flags & SNDRV_SFNT_SAMPLE_SINGLESHOT))
1098 zone->v.mode = SNDRV_SFNT_MODE_LOOPING;
1099 else
1100 zone->v.mode = 0;
1101
1102 /* append to the tail of the list */
1103 /*zone->bank = ctrls[AWE_MD_GUS_BANK];*/
1104 zone->bank = 0;
1105 zone->instr = patch.instr_no;
1106 zone->mapped = 0;
1107 zone->v.sf_id = sf->id;
1108
1109 zone->sample = set_sample(sf, &zone->v);
1110
1111 /* rebuild preset now */
1112 add_preset(sflist, zone);
1113
1114 return 0;
1115}
1116
1117/* load GUS patch */
1118int
Takashi Iwai03da3122005-11-17 14:24:47 +01001119snd_soundfont_load_guspatch(struct snd_sf_list *sflist, const char __user *data,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 long count, int client)
1121{
1122 int rc;
1123 lock_preset(sflist);
1124 rc = load_guspatch(sflist, data, count, client);
1125 unlock_preset(sflist);
1126 return rc;
1127}
1128
1129
1130/*
1131 * Rebuild the preset table. This is like a hash table in that it allows
1132 * quick access to the zone information. For each preset there are zone
1133 * structures linked by next_instr and by next_zone. Former is the whole
1134 * link for this preset, and latter is the link for zone (i.e. instrument/
1135 * bank/key combination).
1136 */
1137static void
Takashi Iwai03da3122005-11-17 14:24:47 +01001138rebuild_presets(struct snd_sf_list *sflist)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139{
Takashi Iwai03da3122005-11-17 14:24:47 +01001140 struct snd_soundfont *sf;
1141 struct snd_sf_zone *cur;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142
1143 /* clear preset table */
1144 memset(sflist->presets, 0, sizeof(sflist->presets));
1145
1146 /* search all fonts and insert each font */
1147 for (sf = sflist->fonts; sf; sf = sf->next) {
1148 for (cur = sf->zones; cur; cur = cur->next) {
1149 if (! cur->mapped && cur->sample == NULL) {
1150 /* try again to search the corresponding sample */
1151 cur->sample = set_sample(sf, &cur->v);
1152 if (cur->sample == NULL)
1153 continue;
1154 }
1155
1156 add_preset(sflist, cur);
1157 }
1158 }
1159}
1160
1161
1162/*
1163 * add the given zone to preset table
1164 */
1165static void
Takashi Iwai03da3122005-11-17 14:24:47 +01001166add_preset(struct snd_sf_list *sflist, struct snd_sf_zone *cur)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167{
Takashi Iwai03da3122005-11-17 14:24:47 +01001168 struct snd_sf_zone *zone;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169 int index;
1170
1171 zone = search_first_zone(sflist, cur->bank, cur->instr, cur->v.low);
1172 if (zone && zone->v.sf_id != cur->v.sf_id) {
1173 /* different instrument was already defined */
Takashi Iwai03da3122005-11-17 14:24:47 +01001174 struct snd_sf_zone *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 /* compare the allocated time */
1176 for (p = zone; p; p = p->next_zone) {
1177 if (p->counter > cur->counter)
1178 /* the current is older.. skipped */
1179 return;
1180 }
1181 /* remove old zones */
1182 delete_preset(sflist, zone);
1183 zone = NULL; /* do not forget to clear this! */
1184 }
1185
1186 /* prepend this zone */
1187 if ((index = get_index(cur->bank, cur->instr, cur->v.low)) < 0)
1188 return;
1189 cur->next_zone = zone; /* zone link */
1190 cur->next_instr = sflist->presets[index]; /* preset table link */
1191 sflist->presets[index] = cur;
1192}
1193
1194/*
1195 * delete the given zones from preset_table
1196 */
1197static void
Takashi Iwai03da3122005-11-17 14:24:47 +01001198delete_preset(struct snd_sf_list *sflist, struct snd_sf_zone *zp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199{
1200 int index;
Takashi Iwai03da3122005-11-17 14:24:47 +01001201 struct snd_sf_zone *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202
1203 if ((index = get_index(zp->bank, zp->instr, zp->v.low)) < 0)
1204 return;
1205 for (p = sflist->presets[index]; p; p = p->next_instr) {
1206 while (p->next_instr == zp) {
1207 p->next_instr = zp->next_instr;
1208 zp = zp->next_zone;
1209 if (zp == NULL)
1210 return;
1211 }
1212 }
1213}
1214
1215
1216/*
1217 * Search matching zones from preset table.
1218 * The note can be rewritten by preset mapping (alias).
1219 * The found zones are stored on 'table' array. max_layers defines
1220 * the maximum number of elements in this array.
1221 * This function returns the number of found zones. 0 if not found.
1222 */
1223int
Takashi Iwai03da3122005-11-17 14:24:47 +01001224snd_soundfont_search_zone(struct snd_sf_list *sflist, int *notep, int vel,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225 int preset, int bank,
1226 int def_preset, int def_bank,
Takashi Iwai03da3122005-11-17 14:24:47 +01001227 struct snd_sf_zone **table, int max_layers)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228{
1229 int nvoices;
1230 unsigned long flags;
1231
1232 /* this function is supposed to be called atomically,
1233 * so we check the lock. if it's busy, just returns 0 to
1234 * tell the caller the busy state
1235 */
1236 spin_lock_irqsave(&sflist->lock, flags);
1237 if (sflist->presets_locked) {
1238 spin_unlock_irqrestore(&sflist->lock, flags);
1239 return 0;
1240 }
Takashi Iwai03da3122005-11-17 14:24:47 +01001241 nvoices = search_zones(sflist, notep, vel, preset, bank,
1242 table, max_layers, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243 if (! nvoices) {
1244 if (preset != def_preset || bank != def_bank)
Takashi Iwai03da3122005-11-17 14:24:47 +01001245 nvoices = search_zones(sflist, notep, vel,
1246 def_preset, def_bank,
1247 table, max_layers, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248 }
1249 spin_unlock_irqrestore(&sflist->lock, flags);
1250 return nvoices;
1251}
1252
1253
1254/*
1255 * search the first matching zone
1256 */
Takashi Iwai03da3122005-11-17 14:24:47 +01001257static struct snd_sf_zone *
1258search_first_zone(struct snd_sf_list *sflist, int bank, int preset, int key)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259{
1260 int index;
Takashi Iwai03da3122005-11-17 14:24:47 +01001261 struct snd_sf_zone *zp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262
1263 if ((index = get_index(bank, preset, key)) < 0)
1264 return NULL;
1265 for (zp = sflist->presets[index]; zp; zp = zp->next_instr) {
1266 if (zp->instr == preset && zp->bank == bank)
1267 return zp;
1268 }
1269 return NULL;
1270}
1271
1272
1273/*
1274 * search matching zones from sflist. can be called recursively.
1275 */
1276static int
Takashi Iwai03da3122005-11-17 14:24:47 +01001277search_zones(struct snd_sf_list *sflist, int *notep, int vel,
1278 int preset, int bank, struct snd_sf_zone **table,
1279 int max_layers, int level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280{
Takashi Iwai03da3122005-11-17 14:24:47 +01001281 struct snd_sf_zone *zp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282 int nvoices;
1283
1284 zp = search_first_zone(sflist, bank, preset, *notep);
1285 nvoices = 0;
1286 for (; zp; zp = zp->next_zone) {
1287 if (*notep >= zp->v.low && *notep <= zp->v.high &&
1288 vel >= zp->v.vellow && vel <= zp->v.velhigh) {
1289 if (zp->mapped) {
1290 /* search preset mapping (aliasing) */
1291 int key = zp->v.fixkey;
1292 preset = zp->v.start;
1293 bank = zp->v.end;
1294
1295 if (level > 5) /* too deep alias level */
1296 return 0;
1297 if (key < 0)
1298 key = *notep;
1299 nvoices = search_zones(sflist, &key, vel,
1300 preset, bank, table,
1301 max_layers, level + 1);
1302 if (nvoices > 0)
1303 *notep = key;
1304 break;
1305 }
1306 table[nvoices++] = zp;
1307 if (nvoices >= max_layers)
1308 break;
1309 }
1310 }
1311
1312 return nvoices;
1313}
1314
1315
1316/* calculate the index of preset table:
1317 * drums are mapped from 128 to 255 according to its note key.
1318 * other instruments are mapped from 0 to 127.
1319 * if the index is out of range, return -1.
1320 */
1321static int
1322get_index(int bank, int instr, int key)
1323{
1324 int index;
1325 if (SF_IS_DRUM_BANK(bank))
1326 index = key + SF_MAX_INSTRUMENTS;
1327 else
1328 index = instr;
1329 index = index % SF_MAX_PRESETS;
1330 if (index < 0)
1331 return -1;
1332 return index;
1333}
1334
1335/*
1336 * Initialise the sflist structure.
1337 */
1338static void
Takashi Iwai03da3122005-11-17 14:24:47 +01001339snd_sf_init(struct snd_sf_list *sflist)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340{
1341 memset(sflist->presets, 0, sizeof(sflist->presets));
1342
1343 sflist->mem_used = 0;
1344 sflist->currsf = NULL;
1345 sflist->open_client = -1;
1346 sflist->fonts = NULL;
1347 sflist->fonts_size = 0;
1348 sflist->zone_counter = 0;
1349 sflist->sample_counter = 0;
1350 sflist->zone_locked = 0;
1351 sflist->sample_locked = 0;
1352}
1353
1354/*
1355 * Release all list records
1356 */
1357static void
Takashi Iwai03da3122005-11-17 14:24:47 +01001358snd_sf_clear(struct snd_sf_list *sflist)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359{
Takashi Iwai03da3122005-11-17 14:24:47 +01001360 struct snd_soundfont *sf, *nextsf;
1361 struct snd_sf_zone *zp, *nextzp;
1362 struct snd_sf_sample *sp, *nextsp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363
1364 for (sf = sflist->fonts; sf; sf = nextsf) {
1365 nextsf = sf->next;
1366 for (zp = sf->zones; zp; zp = nextzp) {
1367 nextzp = zp->next;
1368 kfree(zp);
1369 }
1370 for (sp = sf->samples; sp; sp = nextsp) {
1371 nextsp = sp->next;
1372 if (sflist->callback.sample_free)
Takashi Iwai03da3122005-11-17 14:24:47 +01001373 sflist->callback.sample_free(sflist->callback.private_data,
1374 sp, sflist->memhdr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375 kfree(sp);
1376 }
1377 kfree(sf);
1378 }
1379
1380 snd_sf_init(sflist);
1381}
1382
1383
1384/*
1385 * Create a new sflist structure
1386 */
Takashi Iwai03da3122005-11-17 14:24:47 +01001387struct snd_sf_list *
1388snd_sf_new(struct snd_sf_callback *callback, struct snd_util_memhdr *hdr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389{
Takashi Iwai03da3122005-11-17 14:24:47 +01001390 struct snd_sf_list *sflist;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391
Takashi Iwai561b2202005-09-09 14:22:34 +02001392 if ((sflist = kzalloc(sizeof(*sflist), GFP_KERNEL)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393 return NULL;
1394
Ingo Molnaref9f0a42006-01-16 16:31:42 +01001395 mutex_init(&sflist->presets_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396 spin_lock_init(&sflist->lock);
1397 sflist->memhdr = hdr;
1398
1399 if (callback)
1400 sflist->callback = *callback;
1401
1402 snd_sf_init(sflist);
1403 return sflist;
1404}
1405
1406
1407/*
1408 * Free everything allocated off the sflist structure.
1409 */
1410void
Takashi Iwai03da3122005-11-17 14:24:47 +01001411snd_sf_free(struct snd_sf_list *sflist)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412{
1413 if (sflist == NULL)
1414 return;
1415
1416 lock_preset(sflist);
1417 if (sflist->callback.sample_reset)
1418 sflist->callback.sample_reset(sflist->callback.private_data);
1419 snd_sf_clear(sflist);
1420 unlock_preset(sflist);
1421
1422 kfree(sflist);
1423}
1424
1425/*
1426 * Remove all samples
1427 * The soundcard should be silet before calling this function.
1428 */
1429int
Takashi Iwai03da3122005-11-17 14:24:47 +01001430snd_soundfont_remove_samples(struct snd_sf_list *sflist)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431{
1432 lock_preset(sflist);
1433 if (sflist->callback.sample_reset)
1434 sflist->callback.sample_reset(sflist->callback.private_data);
1435 snd_sf_clear(sflist);
1436 unlock_preset(sflist);
1437
1438 return 0;
1439}
1440
1441/*
1442 * Remove unlocked samples.
1443 * The soundcard should be silent before calling this function.
1444 */
1445int
Takashi Iwai03da3122005-11-17 14:24:47 +01001446snd_soundfont_remove_unlocked(struct snd_sf_list *sflist)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447{
Takashi Iwai03da3122005-11-17 14:24:47 +01001448 struct snd_soundfont *sf;
1449 struct snd_sf_zone *zp, *nextzp;
1450 struct snd_sf_sample *sp, *nextsp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451
1452 lock_preset(sflist);
1453
1454 if (sflist->callback.sample_reset)
1455 sflist->callback.sample_reset(sflist->callback.private_data);
1456
1457 /* to be sure */
1458 memset(sflist->presets, 0, sizeof(sflist->presets));
1459
1460 for (sf = sflist->fonts; sf; sf = sf->next) {
1461 for (zp = sf->zones; zp; zp = nextzp) {
1462 if (zp->counter < sflist->zone_locked)
1463 break;
1464 nextzp = zp->next;
1465 sf->zones = nextzp;
1466 kfree(zp);
1467 }
1468
1469 for (sp = sf->samples; sp; sp = nextsp) {
1470 if (sp->counter < sflist->sample_locked)
1471 break;
1472 nextsp = sp->next;
1473 sf->samples = nextsp;
1474 sflist->mem_used -= sp->v.truesize;
1475 if (sflist->callback.sample_free)
Takashi Iwai03da3122005-11-17 14:24:47 +01001476 sflist->callback.sample_free(sflist->callback.private_data,
1477 sp, sflist->memhdr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 kfree(sp);
1479 }
1480 }
1481
1482 sflist->zone_counter = sflist->zone_locked;
1483 sflist->sample_counter = sflist->sample_locked;
1484
1485 rebuild_presets(sflist);
1486
1487 unlock_preset(sflist);
1488 return 0;
1489}