⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 soundfont.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
		} else			prev = p;	}	if (removed)		rebuild_presets(sflist);	return removed;}/* * Read an info record from the user buffer and save it on the current * open soundfont. */static intload_info(snd_sf_list_t *sflist, const void __user *data, long count){	snd_soundfont_t *sf;	snd_sf_zone_t *zone;	soundfont_voice_rec_hdr_t hdr;	int i;	/* patch must be opened */	if ((sf = sflist->currsf) == NULL)		return -EINVAL;	if (is_special_type(sf->type))		return -EINVAL;	if (count < (long)sizeof(hdr)) {		printk("Soundfont error: invalid patch zone length\n");		return -EINVAL;	}	if (copy_from_user((char*)&hdr, data, sizeof(hdr)))		return -EFAULT;		data += sizeof(hdr);	count -= sizeof(hdr);	if (hdr.nvoices <= 0 || hdr.nvoices >= 100) {		printk("Soundfont error: Illegal voice number %d\n", hdr.nvoices);		return -EINVAL;	}	if (count < (long)sizeof(soundfont_voice_info_t)*hdr.nvoices) {		printk("Soundfont Error: patch length(%ld) is smaller than nvoices(%d)\n",		       count, hdr.nvoices);		return -EINVAL;	}	switch (hdr.write_mode) {	case SNDRV_SFNT_WR_EXCLUSIVE:		/* exclusive mode - if the instrument already exists,		   return error */		for (zone = sf->zones; zone; zone = zone->next) {			if (!zone->mapped &&			    zone->bank == hdr.bank &&			    zone->instr == hdr.instr)				return -EINVAL;		}		break;	case SNDRV_SFNT_WR_REPLACE:		/* replace mode - remove the instrument if it already exists */		remove_info(sflist, sf, hdr.bank, hdr.instr);		break;	}	for (i = 0; i < hdr.nvoices; i++) {		snd_sf_zone_t tmpzone;		/* copy awe_voice_info parameters */		if (copy_from_user(&tmpzone.v, data, sizeof(tmpzone.v))) {			return -EFAULT;		}		data += sizeof(tmpzone.v);		count -= sizeof(tmpzone.v);		tmpzone.bank = hdr.bank;		tmpzone.instr = hdr.instr;		tmpzone.mapped = 0;		tmpzone.v.sf_id = sf->id;		if (tmpzone.v.mode & SNDRV_SFNT_MODE_INIT_PARM)			init_voice_parm(&tmpzone.v.parm);		/* create a new zone */		if ((zone = sf_zone_new(sflist, sf)) == NULL) {			return -ENOMEM;		}		/* copy the temporary data */		zone->bank = tmpzone.bank;		zone->instr = tmpzone.instr;		zone->v = tmpzone.v;		/* look up the sample */		zone->sample = set_sample(sf, &zone->v);	}	return 0;}/* initialize voice_info record */static voidinit_voice_info(soundfont_voice_info_t *avp){	memset(avp, 0, sizeof(*avp));	avp->root = 60;	avp->high = 127;	avp->velhigh = 127;	avp->fixkey = -1;	avp->fixvel = -1;	avp->fixpan = -1;	avp->pan = -1;	avp->amplitude = 127;	avp->scaleTuning = 100;	init_voice_parm(&avp->parm);}/* initialize voice_parm record: * Env1/2: delay=0, attack=0, hold=0, sustain=0, decay=0, release=0. * Vibrato and Tremolo effects are zero. * Cutoff is maximum. * Chorus and Reverb effects are zero. */static voidinit_voice_parm(soundfont_voice_parm_t *pp){	memset(pp, 0, sizeof(*pp));	pp->moddelay = 0x8000;	pp->modatkhld = 0x7f7f;	pp->moddcysus = 0x7f7f;	pp->modrelease = 0x807f;	pp->voldelay = 0x8000;	pp->volatkhld = 0x7f7f;	pp->voldcysus = 0x7f7f;	pp->volrelease = 0x807f;	pp->lfo1delay = 0x8000;	pp->lfo2delay = 0x8000;	pp->cutoff = 0xff;}	/* search the specified sample */static snd_sf_sample_t *set_sample(snd_soundfont_t *sf, soundfont_voice_info_t *avp){	snd_sf_sample_t *sample;	sample = find_sample(sf, avp->sample);	if (sample == NULL)		return NULL;	/* add in the actual sample offsets:	 * The voice_info addresses define only the relative offset	 * from sample pointers.  Here we calculate the actual DRAM	 * offset from sample pointers.	 */	avp->start += sample->v.start;	avp->end += sample->v.end;	avp->loopstart += sample->v.loopstart;	avp->loopend += sample->v.loopend;	/* copy mode flags */	avp->sample_mode = sample->v.mode_flags;	return sample;}/* find the sample pointer with the given id in the soundfont */static snd_sf_sample_t *find_sample(snd_soundfont_t *sf, int sample_id){	snd_sf_sample_t *p;	if (sf == NULL)		return NULL;	for (p = sf->samples; p; p = p->next) {		if (p->v.sample == sample_id)			return p;	}	return NULL;}/* * Load sample information, this can include data to be loaded onto * the soundcard.  It can also just be a pointer into soundcard ROM. * If there is data it will be written to the soundcard via the callback * routine. */static intload_data(snd_sf_list_t *sflist, const void __user *data, long count){	snd_soundfont_t *sf;	soundfont_sample_info_t sample_info;	snd_sf_sample_t *sp;	long off;	/* patch must be opened */	if ((sf = sflist->currsf) == NULL)		return -EINVAL;	if (is_special_type(sf->type))		return -EINVAL;	if (copy_from_user(&sample_info, data, sizeof(sample_info)))		return -EFAULT;	off = sizeof(sample_info);	if (sample_info.size != (count-off)/2)		return -EINVAL;	/* Check for dup */	if (find_sample(sf, sample_info.sample)) {		/* if shared sample, skip this data */		if (sf->type & SNDRV_SFNT_PAT_SHARED)			return 0;		return -EINVAL;	}	/* Allocate a new sample structure */	if ((sp = sf_sample_new(sflist, sf)) == NULL)		return -ENOMEM;	sp->v = sample_info;	sp->v.sf_id = sf->id;	sp->v.dummy = 0;	sp->v.truesize = sp->v.size;	/*	 * If there is wave data then load it.	 */	if (sp->v.size > 0) {		int  rc;		rc = sflist->callback.sample_new			(sflist->callback.private_data, sp, sflist->memhdr,			 data + off, count - off);		if (rc < 0) {			sf_sample_delete(sflist, sf, sp);			return rc;		}		sflist->mem_used += sp->v.truesize;	}	return count;}/* log2_tbl[i] = log2(i+128) * 0x10000 */static int log_tbl[129] = {	0x70000, 0x702df, 0x705b9, 0x7088e, 0x70b5d, 0x70e26, 0x710eb, 0x713aa,	0x71663, 0x71918, 0x71bc8, 0x71e72, 0x72118, 0x723b9, 0x72655, 0x728ed,	0x72b80, 0x72e0e, 0x73098, 0x7331d, 0x7359e, 0x7381b, 0x73a93, 0x73d08,	0x73f78, 0x741e4, 0x7444c, 0x746b0, 0x74910, 0x74b6c, 0x74dc4, 0x75019,	0x75269, 0x754b6, 0x75700, 0x75946, 0x75b88, 0x75dc7, 0x76002, 0x7623a,	0x7646e, 0x766a0, 0x768cd, 0x76af8, 0x76d1f, 0x76f43, 0x77164, 0x77382,	0x7759d, 0x777b4, 0x779c9, 0x77bdb, 0x77dea, 0x77ff5, 0x781fe, 0x78404,	0x78608, 0x78808, 0x78a06, 0x78c01, 0x78df9, 0x78fef, 0x791e2, 0x793d2,	0x795c0, 0x797ab, 0x79993, 0x79b79, 0x79d5d, 0x79f3e, 0x7a11d, 0x7a2f9,	0x7a4d3, 0x7a6ab, 0x7a880, 0x7aa53, 0x7ac24, 0x7adf2, 0x7afbe, 0x7b188,	0x7b350, 0x7b515, 0x7b6d8, 0x7b899, 0x7ba58, 0x7bc15, 0x7bdd0, 0x7bf89,	0x7c140, 0x7c2f5, 0x7c4a7, 0x7c658, 0x7c807, 0x7c9b3, 0x7cb5e, 0x7cd07,	0x7ceae, 0x7d053, 0x7d1f7, 0x7d398, 0x7d538, 0x7d6d6, 0x7d872, 0x7da0c,	0x7dba4, 0x7dd3b, 0x7ded0, 0x7e063, 0x7e1f4, 0x7e384, 0x7e512, 0x7e69f,	0x7e829, 0x7e9b3, 0x7eb3a, 0x7ecc0, 0x7ee44, 0x7efc7, 0x7f148, 0x7f2c8,	0x7f446, 0x7f5c2, 0x7f73d, 0x7f8b7, 0x7fa2f, 0x7fba5, 0x7fd1a, 0x7fe8d,	0x80000,};/* convert from linear to log value * * conversion: value = log2(amount / base) * ratio * * argument: *   amount = linear value (unsigned, 32bit max) *   offset = base offset (:= log2(base) * 0x10000) *   ratio = division ratio * */intsnd_sf_linear_to_log(unsigned int amount, int offset, int ratio){	int v;	int s, low, bit;		if (amount < 2)		return 0;	for (bit = 0; ! (amount & 0x80000000L); bit++)		amount <<= 1;	s = (amount >> 24) & 0x7f;	low = (amount >> 16) & 0xff;	/* linear approxmimation by lower 8 bit */	v = (log_tbl[s + 1] * low + log_tbl[s] * (0x100 - low)) >> 8;	v -= offset;	v = (v * ratio) >> 16;	v += (24 - bit) * ratio;	return v;}#define OFFSET_MSEC		653117		/* base = 1000 */#define OFFSET_ABSCENT		851781		/* base = 8176 */#define OFFSET_SAMPLERATE	1011119		/* base = 44100 */#define ABSCENT_RATIO		1200#define TIMECENT_RATIO		1200#define SAMPLERATE_RATIO	4096/* * mHz to abscent * conversion: abscent = log2(MHz / 8176) * 1200 */static intfreq_to_note(int mhz){	return snd_sf_linear_to_log(mhz, OFFSET_ABSCENT, ABSCENT_RATIO);}/* convert Hz to AWE32 rate offset: * sample pitch offset for the specified sample rate * rate=44100 is no offset, each 4096 is 1 octave (twice). * eg, when rate is 22050, this offset becomes -4096. * * conversion: offset = log2(Hz / 44100) * 4096 */static intcalc_rate_offset(int hz){	return snd_sf_linear_to_log(hz, OFFSET_SAMPLERATE, SAMPLERATE_RATIO);}/* calculate GUS envelope time */static intcalc_gus_envelope_time(int rate, int start, int end){	int r, p, t;	r = (3 - ((rate >> 6) & 3)) * 3;	p = rate & 0x3f;	t = end - start;	if (t < 0) t = -t;	if (13 > r)		t = t << (13 - r);	else		t = t >> (r - 13);	return (t * 10) / (p * 441);}/* convert envelope time parameter to soundfont parameters *//* attack & decay/release time table (msec) */static short attack_time_tbl[128] = {32767, 32767, 5989, 4235, 2994, 2518, 2117, 1780, 1497, 1373, 1259, 1154, 1058, 970, 890, 816,707, 691, 662, 634, 607, 581, 557, 533, 510, 489, 468, 448, 429, 411, 393, 377,361, 345, 331, 317, 303, 290, 278, 266, 255, 244, 234, 224, 214, 205, 196, 188,180, 172, 165, 158, 151, 145, 139, 133, 127, 122, 117, 112, 107, 102, 98, 94,90, 86, 82, 79, 75, 72, 69, 66, 63, 61, 58, 56, 53, 51, 49, 47,45, 43, 41, 39, 37, 36, 34, 33, 31, 30, 29, 28, 26, 25, 24, 23,22, 21, 20, 19, 19, 18, 17, 16, 16, 15, 15, 14, 13, 13, 12, 12,11, 11, 10, 10, 10, 9, 9, 8, 8, 8, 8, 7, 7, 7, 6, 0,};static short decay_time_tbl[128] = {32767, 32767, 22614, 15990, 11307, 9508, 7995, 6723, 5653, 5184, 4754, 4359, 3997, 3665, 3361, 3082,2828, 2765, 2648, 2535, 2428, 2325, 2226, 2132, 2042, 1955, 1872, 1793, 1717, 1644, 1574, 1507,1443, 1382, 1324, 1267, 1214, 1162, 1113, 1066, 978, 936, 897, 859, 822, 787, 754, 722,691, 662, 634, 607, 581, 557, 533, 510, 489, 468, 448, 429, 411, 393, 377, 361,345, 331, 317, 303, 290, 278, 266, 255, 244, 234, 224, 214, 205, 196, 188, 180,172, 165, 158, 151, 145, 139, 133, 127, 122, 117, 112, 107, 102, 98, 94, 90,86, 82, 79, 75, 72, 69, 66, 63, 61, 58, 56, 53, 51, 49, 47, 45,43, 41, 39, 37, 36, 34, 33, 31, 30, 29, 28, 26, 25, 24, 23, 22,};/* delay time = 0x8000 - msec/92 */intsnd_sf_calc_parm_hold(int msec){	int val = (0x7f * 92 - msec) / 92;	if (val < 1) val = 1;	if (val >= 126) val = 126;	return val;}/* search an index for specified time from given time table */static intcalc_parm_search(int msec, short *table){	int left = 1, right = 127, mid;	while (left < right) {		mid = (left + right) / 2;		if (msec < (int)table[mid])			left = mid + 1;		else			right = mid;	}	return left;}/* attack time: search from time table */intsnd_sf_calc_parm_attack(int msec){	return calc_parm_search(msec, attack_time_tbl);}/* decay/release time: search from time table */intsnd_sf_calc_parm_decay(int msec){	return calc_parm_search(msec, decay_time_tbl);}int snd_sf_vol_table[128] = {	255,111,95,86,79,74,70,66,63,61,58,56,54,52,50,49,	47,46,45,43,42,41,40,39,38,37,36,35,34,34,33,32,	31,31,30,29,29,28,27,27,26,26,25,24,24,23,23,22,	22,21,21,21,20,20,19,19,18,18,18,17,17,16,16,16,	15,15,15,14,14,14,13,13,13,12,12,12,11,11,11,10,	10,10,10,9,9,9,8,8,8,8,7,7,7,7,6,6,	6,6,5,5,5,5,5,4,4,4,4,3,3,3,3,3,	2,2,2,2,2,1,1,1,1,1,0,0,0,0,0,0,};#define calc_gus_sustain(val)  (0x7f - snd_sf_vol_table[(val)/2])#define calc_gus_attenuation(val)	snd_sf_vol_table[(val)/2]/* load GUS patch */static intload_guspatch(snd_sf_list_t *sflist, const char __user *data, long count, int client){	struct patch_info patch;	snd_soundfont_t *sf;	snd_sf_zone_t *zone;	snd_sf_sample_t *smp;	int note, sample_id;	int rc;	if (count < (long)sizeof(patch)) {		snd_printk("patch record too small %ld\n", count);		return -EINVAL;	}	if (copy_from_user(&patch, data, sizeof(patch)))		return -EFAULT;		count -= sizeof(patch);	data += sizeof(patch);	sf = newsf(sflist, SNDRV_SFNT_PAT_TYPE_GUS|SNDRV_SFNT_PAT_SHARED, NULL);	if (sf == NULL)		return -ENOMEM;	if ((smp = sf_sample_new(sflist, sf)) == NULL)		return -ENOMEM;	sample_id = sflist->sample_counter;	smp->v.sample = sample_id;	smp->v.start = 0;	smp->v.end = patch.len;	smp->v.loopstart = patch.loop_start;	smp->v.loopend = patch.loop_end;	smp->v.size = patch.len;	/* set up mode flags */	smp->v.mode_flags = 0;	if (!(patch.mode & WAVE_16_BITS))		smp->v.mode_flags |= SNDRV_SFNT_SAMPLE_8BITS;	if (patch.mode & WAVE_UNSIGNED)		smp->v.mode_flags |= SNDRV_SFNT_SAMPLE_UNSIGNED;	smp->v.mode_flags |= SNDRV_SFNT_SAMPLE_NO_BLANK;	if (!(patch.mode & (WAVE_LOOPING|WAVE_BIDIR_LOOP|WAVE_LOOP_BACK)))		smp->v.mode_flags |= SNDRV_SFNT_SAMPLE_SINGLESHOT;	if (patch.mode & WAVE_BIDIR_LOOP)		smp->v.mode_flags |= SNDRV_SFNT_SAMPLE_BIDIR_LOOP;	if (patch.mode & WAVE_LOOP_BACK)		smp->v.mode_flags |= SNDRV_SFNT_SAMPLE_REVERSE_LOOP;	if (patch.mode & WAVE_16_BITS) {		/* convert to word offsets */		smp->v.size /= 2;		smp->v.end /= 2;		smp->v.loopstart /= 2;		smp->v.loopend /= 2;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -