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

📄 soundfont.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *  Soundfont generic routines. *	It is intended that these should be used by any driver that is willing *	to accept soundfont patches. * *  Copyright (C) 1999 Steve Ratcliffe *  Copyright (c) 1999-2000 Takashi Iwai <tiwai@suse.de> * *   This program is free software; you can redistribute it and/or modify *   it under the terms of the GNU General Public License as published by *   the Free Software Foundation; either version 2 of the License, or *   (at your option) any later version. * *   This program is distributed in the hope that it will be useful, *   but WITHOUT ANY WARRANTY; without even the implied warranty of *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *   GNU General Public License for more details. * *   You should have received a copy of the GNU General Public License *   along with this program; if not, write to the Free Software *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA *//* * Deal with reading in of a soundfont.  Code follows the OSS way * of doing things so that the old sfxload utility can be used. * Everything may change when there is an alsa way of doing things. */#include <sound/driver.h>#include <asm/uaccess.h>#include <linux/slab.h>#include <sound/core.h>#include <sound/soundfont.h>#include <sound/seq_oss_legacy.h>/* Prototypes for static functions */static int open_patch(snd_sf_list_t *sflist, const char __user *data, int count, int client);static snd_soundfont_t *newsf(snd_sf_list_t *sflist, int type, char *name);static int is_identical_font(snd_soundfont_t *sf, int type, unsigned char *name);static int close_patch(snd_sf_list_t *sflist);static int probe_data(snd_sf_list_t *sflist, int sample_id);static void set_zone_counter(snd_sf_list_t *sflist, snd_soundfont_t *sf, snd_sf_zone_t *zp);static snd_sf_zone_t *sf_zone_new(snd_sf_list_t *sflist, snd_soundfont_t *sf);static void set_sample_counter(snd_sf_list_t *sflist, snd_soundfont_t *sf, snd_sf_sample_t *sp);static snd_sf_sample_t *sf_sample_new(snd_sf_list_t *sflist, snd_soundfont_t *sf);static void sf_sample_delete(snd_sf_list_t *sflist, snd_soundfont_t *sf, snd_sf_sample_t *sp);static int load_map(snd_sf_list_t *sflist, const void __user *data, int count);static int load_info(snd_sf_list_t *sflist, const void __user *data, long count);static int remove_info(snd_sf_list_t *sflist, snd_soundfont_t *sf, int bank, int instr);static void init_voice_info(soundfont_voice_info_t *avp);static void init_voice_parm(soundfont_voice_parm_t *pp);static snd_sf_sample_t *set_sample(snd_soundfont_t *sf, soundfont_voice_info_t *avp);static snd_sf_sample_t *find_sample(snd_soundfont_t *sf, int sample_id);static int load_data(snd_sf_list_t *sflist, const void __user *data, long count);static void rebuild_presets(snd_sf_list_t *sflist);static void add_preset(snd_sf_list_t *sflist, snd_sf_zone_t *cur);static void delete_preset(snd_sf_list_t *sflist, snd_sf_zone_t *zp);static snd_sf_zone_t *search_first_zone(snd_sf_list_t *sflist, int bank, int preset, int key);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);static int get_index(int bank, int instr, int key);static void snd_sf_init(snd_sf_list_t *sflist);static void snd_sf_clear(snd_sf_list_t *sflist);/* * lock access to sflist */static voidlock_preset(snd_sf_list_t *sflist){	unsigned long flags;	down(&sflist->presets_mutex);	spin_lock_irqsave(&sflist->lock, flags);	sflist->presets_locked = 1;	spin_unlock_irqrestore(&sflist->lock, flags);}/* * remove lock */static voidunlock_preset(snd_sf_list_t *sflist){	unsigned long flags;	spin_lock_irqsave(&sflist->lock, flags);	sflist->presets_locked = 0;	spin_unlock_irqrestore(&sflist->lock, flags);	up(&sflist->presets_mutex);}/* * close the patch if the patch was opened by this client. */intsnd_soundfont_close_check(snd_sf_list_t *sflist, int client){	unsigned long flags;	spin_lock_irqsave(&sflist->lock, flags);	if (sflist->open_client == client)  {		spin_unlock_irqrestore(&sflist->lock, flags);		return close_patch(sflist);	}	spin_unlock_irqrestore(&sflist->lock, flags);	return 0;}/* * Deal with a soundfont patch.  Any driver could use these routines * although it was designed for the AWE64. * * The sample_write and callargs pararameters allow a callback into * the actual driver to write sample data to the board or whatever * it wants to do with it. */intsnd_soundfont_load(snd_sf_list_t *sflist, const void __user *data, long count, int client){	soundfont_patch_info_t patch;	unsigned long flags;	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);	if (patch.key != SNDRV_OSS_SOUNDFONT_PATCH) {		snd_printk("'The wrong kind of patch' %x\n", patch.key);		return -EINVAL;	}	if (count < patch.len) {		snd_printk("Patch too short %ld, need %d\n", count, patch.len);		return -EINVAL;	}	if (patch.len < 0) {		snd_printk("poor length %d\n", patch.len);		return -EINVAL;	}	if (patch.type == SNDRV_SFNT_OPEN_PATCH) {		/* grab sflist to open */		lock_preset(sflist);		rc = open_patch(sflist, data, count, client);		unlock_preset(sflist);		return rc;	}	/* check if other client already opened patch */	spin_lock_irqsave(&sflist->lock, flags);	if (sflist->open_client != client) {		spin_unlock_irqrestore(&sflist->lock, flags);		return -EBUSY;	}	spin_unlock_irqrestore(&sflist->lock, flags);	lock_preset(sflist);	rc = -EINVAL;	switch (patch.type) {	case SNDRV_SFNT_LOAD_INFO:		rc = load_info(sflist, data, count);		break;	case SNDRV_SFNT_LOAD_DATA:		rc = load_data(sflist, data, count);		break;	case SNDRV_SFNT_CLOSE_PATCH:		rc = close_patch(sflist);		break;	case SNDRV_SFNT_REPLACE_DATA:		/*rc = replace_data(&patch, data, count);*/		break;	case SNDRV_SFNT_MAP_PRESET:		rc = load_map(sflist, data, count);		break;	case SNDRV_SFNT_PROBE_DATA:		rc = probe_data(sflist, patch.optarg);		break;	case SNDRV_SFNT_REMOVE_INFO:		/* patch must be opened */		if (sflist->currsf) {			snd_printk("soundfont: remove_info: patch not opened\n");			rc = -EINVAL;		} else {			int bank, instr;			bank = ((unsigned short)patch.optarg >> 8) & 0xff;			instr = (unsigned short)patch.optarg & 0xff;			if (! remove_info(sflist, sflist->currsf, bank, instr))				rc = -EINVAL;			else				rc = 0;		}		break;	}	unlock_preset(sflist);	return rc;}/* check if specified type is special font (GUS or preset-alias) */static inline intis_special_type(int type){	type &= 0x0f;	return (type == SNDRV_SFNT_PAT_TYPE_GUS ||		type == SNDRV_SFNT_PAT_TYPE_MAP);}/* open patch; create sf list */static intopen_patch(snd_sf_list_t *sflist, const char __user *data, int count, int client){	soundfont_open_parm_t parm;	snd_soundfont_t *sf;	unsigned long flags;	spin_lock_irqsave(&sflist->lock, flags);	if (sflist->open_client >= 0 || sflist->currsf) {		spin_unlock_irqrestore(&sflist->lock, flags);		return -EBUSY;	}	spin_unlock_irqrestore(&sflist->lock, flags);	if (copy_from_user(&parm, data, sizeof(parm)))		return -EFAULT;	if (is_special_type(parm.type)) {		parm.type |= SNDRV_SFNT_PAT_SHARED;		sf = newsf(sflist, parm.type, NULL);	} else 		sf = newsf(sflist, parm.type, parm.name);	if (sf == NULL) {		return -ENOMEM;	}	spin_lock_irqsave(&sflist->lock, flags);	sflist->open_client = client;	sflist->currsf = sf;	spin_unlock_irqrestore(&sflist->lock, flags);	return 0;}/* * Allocate a new soundfont structure. */static snd_soundfont_t *newsf(snd_sf_list_t *sflist, int type, char *name){	snd_soundfont_t *sf;	/* check the shared fonts */	if (type & SNDRV_SFNT_PAT_SHARED) {		for (sf = sflist->fonts; sf; sf = sf->next) {			if (is_identical_font(sf, type, name)) {				return sf;			}		}	}	/* not found -- create a new one */	sf = kzalloc(sizeof(*sf), GFP_KERNEL);	if (sf == NULL)		return NULL;	sf->id = sflist->fonts_size;	sflist->fonts_size++;	/* prepend this record */	sf->next = sflist->fonts;	sflist->fonts = sf;	sf->type = type;	sf->zones = NULL;	sf->samples = NULL;	if (name)		memcpy(sf->name, name, SNDRV_SFNT_PATCH_NAME_LEN);	return sf;}/* check if the given name matches to the existing list */static intis_identical_font(snd_soundfont_t *sf, int type, unsigned char *name){	return ((sf->type & SNDRV_SFNT_PAT_SHARED) &&		(sf->type & 0x0f) == (type & 0x0f) &&		(name == NULL ||		 memcmp(sf->name, name, SNDRV_SFNT_PATCH_NAME_LEN) == 0));}/* * Close the current patch. */static intclose_patch(snd_sf_list_t *sflist){	unsigned long flags;	spin_lock_irqsave(&sflist->lock, flags);	sflist->currsf = NULL;	sflist->open_client = -1;	spin_unlock_irqrestore(&sflist->lock, flags);	rebuild_presets(sflist);	return 0;}/* probe sample in the current list -- nothing to be loaded */static intprobe_data(snd_sf_list_t *sflist, int sample_id){	/* patch must be opened */	if (sflist->currsf) {		/* search the specified sample by optarg */		if (find_sample(sflist->currsf, sample_id))			return 0;	}	return -EINVAL;}/* * increment zone counter */static voidset_zone_counter(snd_sf_list_t *sflist, snd_soundfont_t *sf, snd_sf_zone_t *zp){	zp->counter = sflist->zone_counter++;	if (sf->type & SNDRV_SFNT_PAT_LOCKED)		sflist->zone_locked = sflist->zone_counter;}/* * allocate a new zone record */static snd_sf_zone_t *sf_zone_new(snd_sf_list_t *sflist, snd_soundfont_t *sf){	snd_sf_zone_t *zp;	if ((zp = kzalloc(sizeof(*zp), GFP_KERNEL)) == NULL)		return NULL;	zp->next = sf->zones;	sf->zones = zp;	init_voice_info(&zp->v);	set_zone_counter(sflist, sf, zp);	return zp;}/* * increment sample couter */static voidset_sample_counter(snd_sf_list_t *sflist, snd_soundfont_t *sf, snd_sf_sample_t *sp){	sp->counter = sflist->sample_counter++;	if (sf->type & SNDRV_SFNT_PAT_LOCKED)		sflist->sample_locked = sflist->sample_counter;}/* * allocate a new sample list record */static snd_sf_sample_t *sf_sample_new(snd_sf_list_t *sflist, snd_soundfont_t *sf){	snd_sf_sample_t *sp;	if ((sp = kzalloc(sizeof(*sp), GFP_KERNEL)) == NULL)		return NULL;	sp->next = sf->samples;	sf->samples = sp;	set_sample_counter(sflist, sf, sp);	return sp;}/* * delete sample list -- this is an exceptional job. * only the last allocated sample can be deleted. */static voidsf_sample_delete(snd_sf_list_t *sflist, snd_soundfont_t *sf, snd_sf_sample_t *sp){	/* only last sample is accepted */	if (sp == sf->samples) {		sf->samples = sp->next;		kfree(sp);	}}/* load voice map */static intload_map(snd_sf_list_t *sflist, const void __user *data, int count){	snd_sf_zone_t *zp, *prevp;	snd_soundfont_t *sf;	soundfont_voice_map_t map;	/* get the link info */	if (count < (int)sizeof(map))		return -EINVAL;	if (copy_from_user(&map, data, sizeof(map)))		return -EFAULT;	if (map.map_instr < 0 || map.map_instr >= SF_MAX_INSTRUMENTS)		return -EINVAL;		sf = newsf(sflist, SNDRV_SFNT_PAT_TYPE_MAP|SNDRV_SFNT_PAT_SHARED, NULL);	if (sf == NULL)		return -ENOMEM;	prevp = NULL;	for (zp = sf->zones; zp; prevp = zp, zp = zp->next) {		if (zp->mapped &&		    zp->instr == map.map_instr &&		    zp->bank == map.map_bank &&		    zp->v.low == map.map_key &&		    zp->v.start == map.src_instr &&		    zp->v.end == map.src_bank &&		    zp->v.fixkey == map.src_key) {			/* the same mapping is already present */			/* relink this record to the link head */			if (prevp) {				prevp->next = zp->next;				zp->next = sf->zones;				sf->zones = zp;			}			/* update the counter */			set_zone_counter(sflist, sf, zp);			return 0;		}	}	/* create a new zone */	if ((zp = sf_zone_new(sflist, sf)) == NULL)		return -ENOMEM;	zp->bank = map.map_bank;	zp->instr = map.map_instr;	zp->mapped = 1;	if (map.map_key >= 0) {		zp->v.low = map.map_key;		zp->v.high = map.map_key;	}	zp->v.start = map.src_instr;	zp->v.end = map.src_bank;	zp->v.fixkey = map.src_key;	zp->v.sf_id = sf->id;	add_preset(sflist, zp);	return 0;}/* remove the present instrument layers */static intremove_info(snd_sf_list_t *sflist, snd_soundfont_t *sf, int bank, int instr){	snd_sf_zone_t *prev, *next, *p;	int removed = 0;	prev = NULL;	for (p = sf->zones; p; p = next) {		next = p->next;		if (! p->mapped &&		    p->bank == bank && p->instr == instr) {			/* remove this layer */			if (prev)				prev->next = next;			else				sf->zones = next;			removed++;			kfree(p);

⌨️ 快捷键说明

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