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