📄 soundfont.c
字号:
} /*smp->v.loopend++;*/ smp->v.dummy = 0; smp->v.truesize = 0; smp->v.sf_id = sf->id; /* set up voice info */ if ((zone = sf_zone_new(sflist, sf)) == NULL) { sf_sample_delete(sflist, sf, smp); return -ENOMEM; } /* * load wave data */ if (sflist->callback.sample_new) { rc = sflist->callback.sample_new (sflist->callback.private_data, smp, sflist->memhdr, data, count); if (rc < 0) { sf_sample_delete(sflist, sf, smp); return rc; } /* memory offset is updated after */ } /* update the memory offset here */ sflist->mem_used += smp->v.truesize; zone->v.sample = sample_id; /* the last sample */ zone->v.rate_offset = calc_rate_offset(patch.base_freq); note = freq_to_note(patch.base_note); zone->v.root = note / 100; zone->v.tune = -(note % 100); zone->v.low = (freq_to_note(patch.low_note) + 99) / 100; zone->v.high = freq_to_note(patch.high_note) / 100; /* panning position; -128 - 127 => 0-127 */ zone->v.pan = (patch.panning + 128) / 2;#if 0 snd_printk("gus: basefrq=%d (ofs=%d) root=%d,tune=%d, range:%d-%d\n", (int)patch.base_freq, zone->v.rate_offset, zone->v.root, zone->v.tune, zone->v.low, zone->v.high);#endif /* detuning is ignored */ /* 6points volume envelope */ if (patch.mode & WAVE_ENVELOPES) { int attack, hold, decay, release; attack = calc_gus_envelope_time (patch.env_rate[0], 0, patch.env_offset[0]); hold = calc_gus_envelope_time (patch.env_rate[1], patch.env_offset[0], patch.env_offset[1]); decay = calc_gus_envelope_time (patch.env_rate[2], patch.env_offset[1], patch.env_offset[2]); release = calc_gus_envelope_time (patch.env_rate[3], patch.env_offset[1], patch.env_offset[4]); release += calc_gus_envelope_time (patch.env_rate[4], patch.env_offset[3], patch.env_offset[4]); release += calc_gus_envelope_time (patch.env_rate[5], patch.env_offset[4], patch.env_offset[5]); zone->v.parm.volatkhld = (snd_sf_calc_parm_hold(hold) << 8) | snd_sf_calc_parm_attack(attack); zone->v.parm.voldcysus = (calc_gus_sustain(patch.env_offset[2]) << 8) | snd_sf_calc_parm_decay(decay); zone->v.parm.volrelease = 0x8000 | snd_sf_calc_parm_decay(release); zone->v.attenuation = calc_gus_attenuation(patch.env_offset[0]);#if 0 snd_printk("gus: atkhld=%x, dcysus=%x, volrel=%x, att=%d\n", zone->v.parm.volatkhld, zone->v.parm.voldcysus, zone->v.parm.volrelease, zone->v.attenuation);#endif } /* fast release */ if (patch.mode & WAVE_FAST_RELEASE) { zone->v.parm.volrelease = 0x807f; } /* tremolo effect */ if (patch.mode & WAVE_TREMOLO) { int rate = (patch.tremolo_rate * 1000 / 38) / 42; zone->v.parm.tremfrq = ((patch.tremolo_depth / 2) << 8) | rate; } /* vibrato effect */ if (patch.mode & WAVE_VIBRATO) { int rate = (patch.vibrato_rate * 1000 / 38) / 42; zone->v.parm.fm2frq2 = ((patch.vibrato_depth / 6) << 8) | rate; } /* scale_freq, scale_factor, volume, and fractions not implemented */ if (!(smp->v.mode_flags & SNDRV_SFNT_SAMPLE_SINGLESHOT)) zone->v.mode = SNDRV_SFNT_MODE_LOOPING; else zone->v.mode = 0; /* append to the tail of the list */ /*zone->bank = ctrls[AWE_MD_GUS_BANK];*/ zone->bank = 0; zone->instr = patch.instr_no; zone->mapped = 0; zone->v.sf_id = sf->id; zone->sample = set_sample(sf, &zone->v); /* rebuild preset now */ add_preset(sflist, zone); return 0;}/* load GUS patch */intsnd_soundfont_load_guspatch(snd_sf_list_t *sflist, const char __user *data, long count, int client){ int rc; lock_preset(sflist); rc = load_guspatch(sflist, data, count, client); unlock_preset(sflist); return rc;}/* * Rebuild the preset table. This is like a hash table in that it allows * quick access to the zone information. For each preset there are zone * structures linked by next_instr and by next_zone. Former is the whole * link for this preset, and latter is the link for zone (i.e. instrument/ * bank/key combination). */static voidrebuild_presets(snd_sf_list_t *sflist){ snd_soundfont_t *sf; snd_sf_zone_t *cur; /* clear preset table */ memset(sflist->presets, 0, sizeof(sflist->presets)); /* search all fonts and insert each font */ for (sf = sflist->fonts; sf; sf = sf->next) { for (cur = sf->zones; cur; cur = cur->next) { if (! cur->mapped && cur->sample == NULL) { /* try again to search the corresponding sample */ cur->sample = set_sample(sf, &cur->v); if (cur->sample == NULL) continue; } add_preset(sflist, cur); } }}/* * add the given zone to preset table */static voidadd_preset(snd_sf_list_t *sflist, snd_sf_zone_t *cur){ snd_sf_zone_t *zone; int index; zone = search_first_zone(sflist, cur->bank, cur->instr, cur->v.low); if (zone && zone->v.sf_id != cur->v.sf_id) { /* different instrument was already defined */ snd_sf_zone_t *p; /* compare the allocated time */ for (p = zone; p; p = p->next_zone) { if (p->counter > cur->counter) /* the current is older.. skipped */ return; } /* remove old zones */ delete_preset(sflist, zone); zone = NULL; /* do not forget to clear this! */ } /* prepend this zone */ if ((index = get_index(cur->bank, cur->instr, cur->v.low)) < 0) return; cur->next_zone = zone; /* zone link */ cur->next_instr = sflist->presets[index]; /* preset table link */ sflist->presets[index] = cur;}/* * delete the given zones from preset_table */static voiddelete_preset(snd_sf_list_t *sflist, snd_sf_zone_t *zp){ int index; snd_sf_zone_t *p; if ((index = get_index(zp->bank, zp->instr, zp->v.low)) < 0) return; for (p = sflist->presets[index]; p; p = p->next_instr) { while (p->next_instr == zp) { p->next_instr = zp->next_instr; zp = zp->next_zone; if (zp == NULL) return; } }}/* * Search matching zones from preset table. * The note can be rewritten by preset mapping (alias). * The found zones are stored on 'table' array. max_layers defines * the maximum number of elements in this array. * This function returns the number of found zones. 0 if not found. */intsnd_soundfont_search_zone(snd_sf_list_t *sflist, int *notep, int vel, int preset, int bank, int def_preset, int def_bank, snd_sf_zone_t **table, int max_layers){ int nvoices; unsigned long flags; /* this function is supposed to be called atomically, * so we check the lock. if it's busy, just returns 0 to * tell the caller the busy state */ spin_lock_irqsave(&sflist->lock, flags); if (sflist->presets_locked) { spin_unlock_irqrestore(&sflist->lock, flags); return 0; } nvoices = search_zones(sflist, notep, vel, preset, bank, table, max_layers, 0); if (! nvoices) { if (preset != def_preset || bank != def_bank) nvoices = search_zones(sflist, notep, vel, def_preset, def_bank, table, max_layers, 0); } spin_unlock_irqrestore(&sflist->lock, flags); return nvoices;}/* * search the first matching zone */static snd_sf_zone_t *search_first_zone(snd_sf_list_t *sflist, int bank, int preset, int key){ int index; snd_sf_zone_t *zp; if ((index = get_index(bank, preset, key)) < 0) return NULL; for (zp = sflist->presets[index]; zp; zp = zp->next_instr) { if (zp->instr == preset && zp->bank == bank) return zp; } return NULL;}/* * search matching zones from sflist. can be called recursively. */static intsearch_zones(snd_sf_list_t *sflist, int *notep, int vel, int preset, int bank, snd_sf_zone_t **table, int max_layers, int level){ snd_sf_zone_t *zp; int nvoices; zp = search_first_zone(sflist, bank, preset, *notep); nvoices = 0; for (; zp; zp = zp->next_zone) { if (*notep >= zp->v.low && *notep <= zp->v.high && vel >= zp->v.vellow && vel <= zp->v.velhigh) { if (zp->mapped) { /* search preset mapping (aliasing) */ int key = zp->v.fixkey; preset = zp->v.start; bank = zp->v.end; if (level > 5) /* too deep alias level */ return 0; if (key < 0) key = *notep; nvoices = search_zones(sflist, &key, vel, preset, bank, table, max_layers, level + 1); if (nvoices > 0) *notep = key; break; } table[nvoices++] = zp; if (nvoices >= max_layers) break; } } return nvoices;}/* calculate the index of preset table: * drums are mapped from 128 to 255 according to its note key. * other instruments are mapped from 0 to 127. * if the index is out of range, return -1. */static intget_index(int bank, int instr, int key){ int index; if (SF_IS_DRUM_BANK(bank)) index = key + SF_MAX_INSTRUMENTS; else index = instr; index = index % SF_MAX_PRESETS; if (index < 0) return -1; return index;}/* * Initialise the sflist structure. */static voidsnd_sf_init(snd_sf_list_t *sflist){ memset(sflist->presets, 0, sizeof(sflist->presets)); sflist->mem_used = 0; sflist->currsf = NULL; sflist->open_client = -1; sflist->fonts = NULL; sflist->fonts_size = 0; sflist->zone_counter = 0; sflist->sample_counter = 0; sflist->zone_locked = 0; sflist->sample_locked = 0;}/* * Release all list records */static voidsnd_sf_clear(snd_sf_list_t *sflist){ snd_soundfont_t *sf, *nextsf; snd_sf_zone_t *zp, *nextzp; snd_sf_sample_t *sp, *nextsp; for (sf = sflist->fonts; sf; sf = nextsf) { nextsf = sf->next; for (zp = sf->zones; zp; zp = nextzp) { nextzp = zp->next; kfree(zp); } for (sp = sf->samples; sp; sp = nextsp) { nextsp = sp->next; if (sflist->callback.sample_free) sflist->callback.sample_free(sflist->callback.private_data, sp, sflist->memhdr); kfree(sp); } kfree(sf); } snd_sf_init(sflist);}/* * Create a new sflist structure */snd_sf_list_t *snd_sf_new(snd_sf_callback_t *callback, snd_util_memhdr_t *hdr){ snd_sf_list_t *sflist; if ((sflist = kzalloc(sizeof(*sflist), GFP_KERNEL)) == NULL) return NULL; init_MUTEX(&sflist->presets_mutex); spin_lock_init(&sflist->lock); sflist->memhdr = hdr; if (callback) sflist->callback = *callback; snd_sf_init(sflist); return sflist;}/* * Free everything allocated off the sflist structure. */voidsnd_sf_free(snd_sf_list_t *sflist){ if (sflist == NULL) return; lock_preset(sflist); if (sflist->callback.sample_reset) sflist->callback.sample_reset(sflist->callback.private_data); snd_sf_clear(sflist); unlock_preset(sflist); kfree(sflist);}/* * Remove all samples * The soundcard should be silet before calling this function. */intsnd_soundfont_remove_samples(snd_sf_list_t *sflist){ lock_preset(sflist); if (sflist->callback.sample_reset) sflist->callback.sample_reset(sflist->callback.private_data); snd_sf_clear(sflist); unlock_preset(sflist); return 0;}/* * Remove unlocked samples. * The soundcard should be silent before calling this function. */intsnd_soundfont_remove_unlocked(snd_sf_list_t *sflist){ snd_soundfont_t *sf; snd_sf_zone_t *zp, *nextzp; snd_sf_sample_t *sp, *nextsp; lock_preset(sflist); if (sflist->callback.sample_reset) sflist->callback.sample_reset(sflist->callback.private_data); /* to be sure */ memset(sflist->presets, 0, sizeof(sflist->presets)); for (sf = sflist->fonts; sf; sf = sf->next) { for (zp = sf->zones; zp; zp = nextzp) { if (zp->counter < sflist->zone_locked) break; nextzp = zp->next; sf->zones = nextzp; kfree(zp); } for (sp = sf->samples; sp; sp = nextsp) { if (sp->counter < sflist->sample_locked) break; nextsp = sp->next; sf->samples = nextsp; sflist->mem_used -= sp->v.truesize; if (sflist->callback.sample_free) sflist->callback.sample_free(sflist->callback.private_data, sp, sflist->memhdr); kfree(sp); } } sflist->zone_counter = sflist->zone_locked; sflist->sample_counter = sflist->sample_locked; rebuild_presets(sflist); unlock_preset(sflist); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -