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 |
|
---|
37 | static int open_patch(snd_sf_list_t *sflist, const char *data, int count, int client);
|
---|
38 | static snd_soundfont_t *newsf(snd_sf_list_t *sflist, int type, char *name);
|
---|
39 | static int is_identical_font(snd_soundfont_t *sf, int type, unsigned char *name);
|
---|
40 | static int close_patch(snd_sf_list_t *sflist);
|
---|
41 | static int probe_data(snd_sf_list_t *sflist, int sample_id);
|
---|
42 | static void set_zone_counter(snd_sf_list_t *sflist, snd_soundfont_t *sf, snd_sf_zone_t *zp);
|
---|
43 | static snd_sf_zone_t *sf_zone_new(snd_sf_list_t *sflist, snd_soundfont_t *sf);
|
---|
44 | static void set_sample_counter(snd_sf_list_t *sflist, snd_soundfont_t *sf, snd_sf_sample_t *sp);
|
---|
45 | static snd_sf_sample_t *sf_sample_new(snd_sf_list_t *sflist, snd_soundfont_t *sf);
|
---|
46 | static void sf_sample_delete(snd_sf_list_t *sflist, snd_soundfont_t *sf, snd_sf_sample_t *sp);
|
---|
47 | static int load_map(snd_sf_list_t *sflist, const void *data, int count);
|
---|
48 | static int load_info(snd_sf_list_t *sflist, const void *data, long count);
|
---|
49 | static int remove_info(snd_sf_list_t *sflist, snd_soundfont_t *sf, int bank, int instr);
|
---|
50 | static void init_voice_info(soundfont_voice_info_t *avp);
|
---|
51 | static void init_voice_parm(soundfont_voice_parm_t *pp);
|
---|
52 | static snd_sf_sample_t *set_sample(snd_soundfont_t *sf, soundfont_voice_info_t *avp);
|
---|
53 | static snd_sf_sample_t *find_sample(snd_soundfont_t *sf, int sample_id);
|
---|
54 | static int load_data(snd_sf_list_t *sflist, const void *data, long count);
|
---|
55 | static void rebuild_presets(snd_sf_list_t *sflist);
|
---|
56 | static void add_preset(snd_sf_list_t *sflist, snd_sf_zone_t *cur);
|
---|
57 | static void delete_preset(snd_sf_list_t *sflist, snd_sf_zone_t *zp);
|
---|
58 | static snd_sf_zone_t *search_first_zone(snd_sf_list_t *sflist, int bank, int preset, int key);
|
---|
59 | 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);
|
---|
60 | static int get_index(int bank, int instr, int key);
|
---|
61 | static void snd_sf_init(snd_sf_list_t *sflist);
|
---|
62 | static void snd_sf_clear(snd_sf_list_t *sflist);
|
---|
63 |
|
---|
64 | /*
|
---|
65 | * lock access to sflist
|
---|
66 | */
|
---|
67 | static 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 | */
|
---|
86 | static void
|
---|
87 | unlock_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 | */
|
---|
97 | int
|
---|
98 | snd_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 | */
|
---|
119 | int
|
---|
120 | snd_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) */
|
---|
212 | static inline int
|
---|
213 | is_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 */
|
---|
222 | static int
|
---|
223 | open_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 | */
|
---|
257 | static snd_soundfont_t *
|
---|
258 | newsf(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 */
|
---|
292 | static int
|
---|
293 | is_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 | */
|
---|
304 | static int
|
---|
305 | close_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 */
|
---|
317 | static int
|
---|
318 | probe_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 | */
|
---|
332 | static void
|
---|
333 | set_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 | */
|
---|
343 | static snd_sf_zone_t *
|
---|
344 | sf_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 | */
|
---|
363 | static void
|
---|
364 | set_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 | */
|
---|
374 | static snd_sf_sample_t *
|
---|
375 | sf_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 | */
|
---|
393 | static void
|
---|
394 | sf_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 */
|
---|
405 | static int
|
---|
406 | load_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 */
|
---|
470 | static int
|
---|
471 | remove_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 | */
|
---|
501 | static int
|
---|
502 | load_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 */
|
---|
599 | static void
|
---|
600 | init_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 | */
|
---|
623 | static void
|
---|
624 | init_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 */
|
---|
645 | static snd_sf_sample_t *
|
---|
646 | set_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 */
|
---|
671 | static snd_sf_sample_t *
|
---|
672 | find_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 | */
|
---|
693 | static int
|
---|
694 | load_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
|
---|
745 | if (rc < 0) {
|
---|
746 | sf_sample_delete(sflist, sf, sp);
|
---|
747 | return rc;
|
---|
748 | }
|
---|
749 | sflist->mem_used += sp->v.truesize;
|
---|
750 | }
|
---|
751 |
|
---|
752 | return count;
|
---|
753 | }
|
---|
754 |
|
---|
755 |
|
---|
756 | /* log2_tbl[i] = log2(i+128) * 0x10000 */
|
---|
757 | static 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 | */
|
---|
787 | int
|
---|
788 | snd_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 | */
|
---|
819 | static int
|
---|
820 | freq_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 | */
|
---|
832 | static int
|
---|
833 | calc_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 */
|
---|
840 | static int
|
---|
841 | calc_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) */
|
---|
858 | static 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 |
|
---|
869 | static 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 */
|
---|
881 | int
|
---|
882 | snd_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 */
|
---|
891 | static int
|
---|
892 | calc_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 */
|
---|
906 | int
|
---|
907 | snd_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 */
|
---|
913 | int
|
---|
914 | snd_sf_calc_parm_decay(int msec)
|
---|
915 | {
|
---|
916 | return calc_parm_search(msec, decay_time_tbl);
|
---|
917 | }
|
---|
918 |
|
---|
919 | int 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 */
|
---|
935 | static int
|
---|
936 | load_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 */
|
---|
1108 | int
|
---|
1109 | snd_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 | */
|
---|
1127 | static void
|
---|
1128 | rebuild_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 | */
|
---|
1155 | static void
|
---|
1156 | add_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 | */
|
---|
1187 | static void
|
---|
1188 | delete_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 | */
|
---|
1213 | int
|
---|
1214 | snd_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 | */
|
---|
1238 | static snd_sf_zone_t *
|
---|
1239 | search_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 | */
|
---|
1257 | static int
|
---|
1258 | 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)
|
---|
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 | */
|
---|
1300 | static int
|
---|
1301 | get_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 | */
|
---|
1317 | static void
|
---|
1318 | snd_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 | */
|
---|
1336 | static void
|
---|
1337 | snd_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 | */
|
---|
1365 | snd_sf_list_t *
|
---|
1366 | snd_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 | */
|
---|
1389 | void
|
---|
1390 | snd_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 | */
|
---|
1408 | int
|
---|
1409 | snd_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 | */
|
---|
1424 | int
|
---|
1425 | snd_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 | */
|
---|
1473 | int
|
---|
1474 | snd_soundfont_mem_used(snd_sf_list_t *sflist)
|
---|
1475 | {
|
---|
1476 | return sflist->mem_used;
|
---|
1477 | }
|
---|