source: GPL/alsa-kernel/synth/emux/soundfont.c@ 1

Last change on this file since 1 was 1, checked in by vladest, 20 years ago

initial import

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