~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/synth/emux/soundfont.c

Version: ~ [ linux-5.18-rc6 ] ~ [ linux-5.17.6 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.38 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.114 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.192 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.241 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.277 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.312 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.302 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp