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

📄 opl3_seq.c

📁 linux-2.6.15.6
💻 C
字号:
/* *  Copyright (c) by Uros Bizjak <uros@kss-loka.si> * *  Midi Sequencer interface routines for OPL2/OPL3/OPL4 FM * *  OPL2/3 FM instrument loader: *   alsa-tools/seq/sbiload/ * *   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 * */#include "opl3_voice.h"#include <linux/init.h>#include <linux/moduleparam.h>#include <sound/initval.h>MODULE_AUTHOR("Uros Bizjak <uros@kss-loka.si>");MODULE_LICENSE("GPL");MODULE_DESCRIPTION("ALSA driver for OPL3 FM synth");int use_internal_drums = 0;module_param(use_internal_drums, bool, 0444);MODULE_PARM_DESC(use_internal_drums, "Enable internal OPL2/3 drums.");int snd_opl3_synth_use_inc(opl3_t * opl3){	if (!try_module_get(opl3->card->module))		return -EFAULT;	return 0;}void snd_opl3_synth_use_dec(opl3_t * opl3){	module_put(opl3->card->module);}int snd_opl3_synth_setup(opl3_t * opl3){	int idx;	down(&opl3->access_mutex);	if (opl3->used) {		up(&opl3->access_mutex);		return -EBUSY;	}	opl3->used++;	up(&opl3->access_mutex);	snd_opl3_reset(opl3);	for (idx = 0; idx < MAX_OPL3_VOICES; idx++) {		opl3->voices[idx].state = SNDRV_OPL3_ST_OFF;		opl3->voices[idx].time = 0;		opl3->voices[idx].keyon_reg = 0x00;	}	opl3->use_time = 0;	opl3->connection_reg = 0x00;	if (opl3->hardware >= OPL3_HW_OPL3) {		/* Clear 4-op connections */		opl3->command(opl3, OPL3_RIGHT | OPL3_REG_CONNECTION_SELECT,				 opl3->connection_reg);		opl3->max_voices = MAX_OPL3_VOICES;	}	return 0;}void snd_opl3_synth_cleanup(opl3_t * opl3){	unsigned long flags;	/* Stop system timer */	spin_lock_irqsave(&opl3->sys_timer_lock, flags);	if (opl3->sys_timer_status) {		del_timer(&opl3->tlist);		opl3->sys_timer_status = 0;	}	spin_unlock_irqrestore(&opl3->sys_timer_lock, flags);	snd_opl3_reset(opl3);	down(&opl3->access_mutex);	opl3->used--;	up(&opl3->access_mutex);}static int snd_opl3_synth_use(void *private_data, snd_seq_port_subscribe_t * info){	opl3_t *opl3 = private_data;	int err;	if ((err = snd_opl3_synth_setup(opl3)) < 0)		return err;	if (use_internal_drums) {		/* Percussion mode */		opl3->voices[6].state = opl3->voices[7].state = 			opl3->voices[8].state = SNDRV_OPL3_ST_NOT_AVAIL;		snd_opl3_load_drums(opl3);		opl3->drum_reg = OPL3_PERCUSSION_ENABLE;		opl3->command(opl3, OPL3_LEFT | OPL3_REG_PERCUSSION, opl3->drum_reg);	} else {		opl3->drum_reg = 0x00;	}	if (info->sender.client != SNDRV_SEQ_CLIENT_SYSTEM) {		if ((err = snd_opl3_synth_use_inc(opl3)) < 0)			return err;	}	opl3->synth_mode = SNDRV_OPL3_MODE_SEQ;	return 0;}static int snd_opl3_synth_unuse(void *private_data, snd_seq_port_subscribe_t * info){	opl3_t *opl3 = private_data;	snd_opl3_synth_cleanup(opl3);	if (info->sender.client != SNDRV_SEQ_CLIENT_SYSTEM)		snd_opl3_synth_use_dec(opl3);	return 0;}/* * MIDI emulation operators */snd_midi_op_t opl3_ops = {	.note_on =		snd_opl3_note_on,	.note_off =		snd_opl3_note_off,	.key_press =		snd_opl3_key_press,	.note_terminate =	snd_opl3_terminate_note,	.control =		snd_opl3_control,	.nrpn =			snd_opl3_nrpn,	.sysex =		snd_opl3_sysex,};static int snd_opl3_synth_event_input(snd_seq_event_t * ev, int direct,				      void *private_data, int atomic, int hop){	opl3_t *opl3 = private_data;	if (ev->type >= SNDRV_SEQ_EVENT_INSTR_BEGIN &&	    ev->type <= SNDRV_SEQ_EVENT_INSTR_CHANGE) {		if (direct) {			snd_seq_instr_event(&opl3->fm_ops, opl3->ilist, ev,					    opl3->seq_client, atomic, hop);		}	} else {		snd_midi_process_event(&opl3_ops, ev, opl3->chset);	}	return 0;}/* ------------------------------ */static void snd_opl3_synth_free_port(void *private_data){	opl3_t *opl3 = private_data;	snd_midi_channel_free_set(opl3->chset);}static int snd_opl3_synth_create_port(opl3_t * opl3){	snd_seq_port_callback_t callbacks;	char name[32];	int voices, opl_ver;	voices = (opl3->hardware < OPL3_HW_OPL3) ?		MAX_OPL2_VOICES : MAX_OPL3_VOICES;	opl3->chset = snd_midi_channel_alloc_set(16);	if (opl3->chset == NULL)		return -ENOMEM;	opl3->chset->private_data = opl3;	memset(&callbacks, 0, sizeof(callbacks));	callbacks.owner = THIS_MODULE;	callbacks.use = snd_opl3_synth_use;	callbacks.unuse = snd_opl3_synth_unuse;	callbacks.event_input = snd_opl3_synth_event_input;	callbacks.private_free = snd_opl3_synth_free_port;	callbacks.private_data = opl3;	opl_ver = (opl3->hardware & OPL3_HW_MASK) >> 8;	sprintf(name, "OPL%i FM Port", opl_ver);	opl3->chset->client = opl3->seq_client;	opl3->chset->port = snd_seq_event_port_attach(opl3->seq_client, &callbacks,						      SNDRV_SEQ_PORT_CAP_WRITE |						      SNDRV_SEQ_PORT_CAP_SUBS_WRITE,						      SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC |						      SNDRV_SEQ_PORT_TYPE_MIDI_GM |						      SNDRV_SEQ_PORT_TYPE_SYNTH,						      16, voices,						      name);	if (opl3->chset->port < 0) {		snd_midi_channel_free_set(opl3->chset);		return opl3->chset->port;	}	return 0;}/* ------------------------------ */static int snd_opl3_seq_new_device(snd_seq_device_t *dev){	opl3_t *opl3;	int client;	snd_seq_client_callback_t callbacks;	snd_seq_client_info_t cinfo;	int opl_ver;	opl3 = *(opl3_t **)SNDRV_SEQ_DEVICE_ARGPTR(dev);	if (opl3 == NULL)		return -EINVAL;	spin_lock_init(&opl3->voice_lock);	opl3->seq_client = -1;	/* allocate new client */	memset(&callbacks, 0, sizeof(callbacks));	callbacks.private_data = opl3;	callbacks.allow_output = callbacks.allow_input = 1;	client = opl3->seq_client =	    snd_seq_create_kernel_client(opl3->card, opl3->seq_dev_num, &callbacks);	if (client < 0)		return client;	/* change name of client */	memset(&cinfo, 0, sizeof(cinfo));	cinfo.client = client;	cinfo.type = KERNEL_CLIENT;	opl_ver = (opl3->hardware & OPL3_HW_MASK) >> 8;	sprintf(cinfo.name, "OPL%i FM synth", opl_ver);	snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, &cinfo);	snd_opl3_synth_create_port(opl3);	/* initialize instrument list */	opl3->ilist = snd_seq_instr_list_new();	if (opl3->ilist == NULL) {		snd_seq_delete_kernel_client(client);		opl3->seq_client = -1;		return -ENOMEM;	}	opl3->ilist->flags = SNDRV_SEQ_INSTR_FLG_DIRECT;	snd_seq_fm_init(&opl3->fm_ops, NULL);	/* setup system timer */	init_timer(&opl3->tlist);	opl3->tlist.function = snd_opl3_timer_func;	opl3->tlist.data = (unsigned long) opl3;	spin_lock_init(&opl3->sys_timer_lock);	opl3->sys_timer_status = 0;#ifdef CONFIG_SND_SEQUENCER_OSS	snd_opl3_init_seq_oss(opl3, cinfo.name);#endif	return 0;}static int snd_opl3_seq_delete_device(snd_seq_device_t *dev){	opl3_t *opl3;	opl3 = *(opl3_t **)SNDRV_SEQ_DEVICE_ARGPTR(dev);	if (opl3 == NULL)		return -EINVAL;#ifdef CONFIG_SND_SEQUENCER_OSS	snd_opl3_free_seq_oss(opl3);#endif	if (opl3->seq_client >= 0) {		snd_seq_delete_kernel_client(opl3->seq_client);		opl3->seq_client = -1;	}	if (opl3->ilist)		snd_seq_instr_list_free(&opl3->ilist);	return 0;}static int __init alsa_opl3_seq_init(void){	static snd_seq_dev_ops_t ops =	{		snd_opl3_seq_new_device,		snd_opl3_seq_delete_device	};	return snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_OPL3, &ops,					      sizeof(opl3_t*));}static void __exit alsa_opl3_seq_exit(void){	snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_OPL3);}module_init(alsa_opl3_seq_init)module_exit(alsa_opl3_seq_exit)

⌨️ 快捷键说明

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