diff options
Diffstat (limited to 'sys/i386/isa/sound/opl3.c')
-rw-r--r-- | sys/i386/isa/sound/opl3.c | 1697 |
1 files changed, 802 insertions, 895 deletions
diff --git a/sys/i386/isa/sound/opl3.c b/sys/i386/isa/sound/opl3.c index 0acd0c6203a0..fbc439883524 100644 --- a/sys/i386/isa/sound/opl3.c +++ b/sys/i386/isa/sound/opl3.c @@ -1,10 +1,10 @@ /* * sound/opl3.c - * + * * A low level driver for Yamaha YM3812 and OPL-3 -chips - * + * * Copyright by Hannu Savolainen 1993 - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: 1. Redistributions of source code must retain the above copyright @@ -12,7 +12,7 @@ * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE @@ -24,7 +24,7 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * + * */ /* @@ -33,291 +33,280 @@ /* * hooft@chem.ruu.nl */ +#include <i386/isa/sound/sound_config.h> -#include "sound_config.h" -#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_YM3812) +#if defined(CONFIG_YM3812) -#include "opl3.h" +#include <i386/isa/sound/opl3.h> +#include <machine/clock.h> #define MAX_VOICE 18 -#define OFFS_4OP 11 /* - * * * Definitions for the operators OP3 and - * * OP4 * * begin here */ - -static int opl3_enabled = 0; -static int left_address = 0x388, right_address = 0x388, both_address = 0; +#define OFFS_4OP 11 + +struct voice_info { + u_char keyon_byte; + long bender; + long bender_range; + u_long orig_freq; + u_long current_freq; + int volume; + int mode; +}; -static int nr_voices = 9; -static int logical_voices[MAX_VOICE] = -{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17}; +typedef struct opl_devinfo { + int left_io, right_io; + int nr_voice; + int lv_map[MAX_VOICE]; -struct voice_info - { - unsigned char keyon_byte; - long bender; - long bender_range; - unsigned long orig_freq; - unsigned long current_freq; - int mode; - }; + struct voice_info voc[MAX_VOICE]; + struct voice_alloc_info *v_alloc; + struct channel_info *chn_info; -static struct voice_info voices[MAX_VOICE]; -static struct voice_alloc_info *voice_alloc; -static struct channel_info *chn_info; + struct sbi_instrument i_map[SBFM_MAXINSTR]; + struct sbi_instrument *act_i[MAX_VOICE]; -static struct sbi_instrument *instrmap; -static struct sbi_instrument *active_instrument[MAX_VOICE] = -{NULL}; + struct synth_info fm_info; -static struct synth_info fm_info = -{"OPL-2", 0, SYNTH_TYPE_FM, FM_TYPE_ADLIB, 0, 9, 0, SBFM_MAXINSTR, 0}; + int busy; + int model; + u_char cmask; -static int already_initialized = 0; + int is_opl4; + sound_os_info *osp; +} + opl_devinfo; -static int opl3_ok = 0; -static int opl3_busy = 0; -static int fm_model = 0; /* +static struct opl_devinfo *devc = NULL; - * * * * 0=no fm, 1=mono, 2=SB Pro 1, 3=SB - * Pro 2 * * */ +static int detected_model; -static int store_instr (int instr_no, struct sbi_instrument *instr); -static void freq_to_fnum (int freq, int *block, int *fnum); -static void opl3_command (int io_addr, unsigned int addr, unsigned int val); -static int opl3_kill_note (int dev, int voice, int note, int velocity); -static unsigned char connection_mask = 0x00; +static int store_instr(int instr_no, struct sbi_instrument * instr); +static void freq_to_fnum(int freq, int *block, int *fnum); +static void opl3_command(int io_addr, u_int addr, u_int val); +static int opl3_kill_note(int dev, int voice, int note, int velocity); void -enable_opl3_mode (int left, int right, int both) +enable_opl3_mode(int left, int right, int both) { - if (opl3_enabled) - return; - - opl3_enabled = 1; - left_address = left; - right_address = right; - both_address = both; - fm_info.capabilities = SYNTH_CAP_OPL3; - fm_info.synth_subtype = FM_TYPE_OPL3; + /* NOP */ } static void -enter_4op_mode (void) +enter_4op_mode(void) { - int i; - static int voices_4op[MAX_VOICE] = - {0, 1, 2, 9, 10, 11, 6, 7, 8, 15, 16, 17}; - - connection_mask = 0x3f; /* Connect all possible 4 OP voices */ - opl3_command (right_address, CONNECTION_SELECT_REGISTER, 0x3f); - - for (i = 0; i < 3; i++) - physical_voices[i].voice_mode = 4; - for (i = 3; i < 6; i++) - physical_voices[i].voice_mode = 0; - - for (i = 9; i < 12; i++) - physical_voices[i].voice_mode = 4; - for (i = 12; i < 15; i++) - physical_voices[i].voice_mode = 0; - - for (i = 0; i < 12; i++) - logical_voices[i] = voices_4op[i]; - voice_alloc->max_voice = nr_voices = 12; + int i; + static int v4op[MAX_VOICE] = + {0, 1, 2, 9, 10, 11, 6, 7, 8, 15, 16, 17}; + + devc->cmask = 0x3f; /* Connect all possible 4 OP voice operators */ + opl3_command(devc->right_io, CONNECTION_SELECT_REGISTER, 0x3f); + + for (i = 0; i < 3; i++) + pv_map[i].voice_mode = 4; + for (i = 3; i < 6; i++) + pv_map[i].voice_mode = 0; + + for (i = 9; i < 12; i++) + pv_map[i].voice_mode = 4; + for (i = 12; i < 15; i++) + pv_map[i].voice_mode = 0; + + for (i = 0; i < 12; i++) + devc->lv_map[i] = v4op[i]; + devc->v_alloc->max_voice = devc->nr_voice = 12; } static int -opl3_ioctl (int dev, - unsigned int cmd, unsigned int arg) +opl3_ioctl(int dev, + u_int cmd, ioctl_arg arg) { - switch (cmd) - { + switch (cmd) { case SNDCTL_FM_LOAD_INSTR: - { - struct sbi_instrument ins; - - IOCTL_FROM_USER ((char *) &ins, (char *) arg, 0, sizeof (ins)); + { + struct sbi_instrument ins; - if (ins.channel < 0 || ins.channel >= SBFM_MAXINSTR) - { - printk ("FM Error: Invalid instrument number %d\n", ins.channel); - return RET_ERROR (EINVAL); - } + bcopy(&(((char *) arg)[0]), (char *) &ins, sizeof(ins)); - pmgr_inform (dev, PM_E_PATCH_LOADED, ins.channel, 0, 0, 0); - return store_instr (ins.channel, &ins); - } - break; + if (ins.channel < 0 || ins.channel >= SBFM_MAXINSTR) { + printf("FM Error: Invalid instrument number %d\n", ins.channel); + return -(EINVAL); + } + pmgr_inform(dev, PM_E_PATCH_LOADED, ins.channel, 0, 0, 0); + return store_instr(ins.channel, &ins); + } + break; case SNDCTL_SYNTH_INFO: - fm_info.nr_voices = (nr_voices == 12) ? 6 : nr_voices; - - IOCTL_TO_USER ((char *) arg, 0, &fm_info, sizeof (fm_info)); - return 0; - break; + devc->fm_info.nr_voices = (devc->nr_voice == 12) ? 6 : devc->nr_voice; + bcopy(&devc->fm_info, &(((char *) arg)[0]), sizeof(devc->fm_info)); + return 0; + break; case SNDCTL_SYNTH_MEMAVL: - return 0x7fffffff; - break; + return 0x7fffffff; + break; case SNDCTL_FM_4OP_ENABLE: - if (opl3_enabled) - enter_4op_mode (); - return 0; - break; + if (devc->model == 2) + enter_4op_mode(); + return 0; + break; default: - return RET_ERROR (EINVAL); + return -(EINVAL); } } int -opl3_detect (int ioaddr) +opl3_detect(int ioaddr, sound_os_info * osp) { - /* - * This function returns 1 if the FM chicp is present at the given I/O port - * The detection algorithm plays with the timer built in the FM chip and - * looks for a change in the status register. - * - * Note! The timers of the FM chip are not connected to AdLib (and compatible) - * boards. - * - * Note2! The chip is initialized if detected. - */ - - unsigned char stat1, stat2; - int i; - - if (already_initialized) - { - return 0; /* - * Do avoid duplicate initializations - */ + /* + * This function returns 1 if the FM chip is present at the given + * I/O port The detection algorithm plays with the timer built in the + * FM chip and looks for a change in the status register. + * + * Note! The timers of the FM chip are not connected to AdLib (and + * compatible) boards. + * + * Note2! The chip is initialized if detected. + */ + + u_char stat1, stat2, signature; + int i; + + if (devc != NULL) + return 0; + + devc = (struct opl_devinfo *) malloc(sizeof(*devc), M_DEVBUF, M_NOWAIT); + if (!devc) + panic("SOUND: Cannot allocate memory\n"); + + if (devc == NULL) { + printf("OPL3: Can't allocate memory for device control structure\n"); + return 0; } + devc->osp = osp; - if (opl3_enabled) - ioaddr = left_address; - - opl3_command (ioaddr, TIMER_CONTROL_REGISTER, TIMER1_MASK | TIMER2_MASK); /* - * Reset - * timers - * 1 - * and - * 2 - */ - opl3_command (ioaddr, TIMER_CONTROL_REGISTER, IRQ_RESET); /* - * Reset the - * IRQ of FM - * * chicp - */ - - stat1 = INB (ioaddr); /* - * Read status register - */ - - if ((stat1 & 0xE0) != 0x00) - { - return 0; /* - * Should be 0x00 - */ + /* Reset timers 1 and 2 */ + opl3_command(ioaddr, TIMER_CONTROL_REGISTER, TIMER1_MASK | TIMER2_MASK); + + /* Reset the IRQ of the FM chip */ + opl3_command(ioaddr, TIMER_CONTROL_REGISTER, IRQ_RESET); + + signature = stat1 = inb(ioaddr); /* Status register */ + + if ((stat1 & 0xE0) != 0x00) { + return 0; /* Should be 0x00 */ } + opl3_command(ioaddr, TIMER1_REGISTER, 0xff); /* Set timer1 to 0xff */ + + opl3_command(ioaddr, TIMER_CONTROL_REGISTER, + TIMER2_MASK | TIMER1_START); /* Unmask and start timer 1 */ + + + DELAY(150); /* Now we have to delay at least 80 usec */ + + stat2 = inb(ioaddr); /* Read status after timers have expired */ - opl3_command (ioaddr, TIMER1_REGISTER, 0xff); /* - * Set timer 1 to - * 0xff - */ - opl3_command (ioaddr, TIMER_CONTROL_REGISTER, - TIMER2_MASK | TIMER1_START); /* - * Unmask and start timer 1 - */ - - /* - * Now we have to delay at least 80 msec - */ - - for (i = 0; i < 50; i++) - tenmicrosec (); /* - * To be sure - */ - - stat2 = INB (ioaddr); /* - * Read status after timers have expired - */ - - /* - * Stop the timers - */ - - opl3_command (ioaddr, TIMER_CONTROL_REGISTER, TIMER1_MASK | TIMER2_MASK); /* - * Reset - * timers - * 1 - * and - * 2 - */ - opl3_command (ioaddr, TIMER_CONTROL_REGISTER, IRQ_RESET); /* - * Reset the - * IRQ of FM - * * chicp - */ - - if ((stat2 & 0xE0) != 0xc0) - { - return 0; /* - * There is no YM3812 - */ + /* + * Stop the timers + */ + + /* Reset timers 1 and 2 */ + opl3_command(ioaddr, TIMER_CONTROL_REGISTER, TIMER1_MASK | TIMER2_MASK); + /* Reset the IRQ of the FM chip */ + opl3_command(ioaddr, TIMER_CONTROL_REGISTER, IRQ_RESET); + + if ((stat2 & 0xE0) != 0xc0) { + return 0; /* There is no YM3812 */ } + /* + * There is a FM chicp in this address. Detect the type (OPL2 to + * OPL4) + */ - /* - * There is a FM chicp in this address. Now set some default values. - */ + if (signature == 0x06) {/* OPL2 */ + detected_model = 2; + } else if (signature == 0x00) { /* OPL3 or OPL4 */ + u_char tmp; - for (i = 0; i < 9; i++) - opl3_command (ioaddr, KEYON_BLOCK + i, 0); /* - * Note off - */ + detected_model = 3; - opl3_command (ioaddr, TEST_REGISTER, ENABLE_WAVE_SELECT); - opl3_command (ioaddr, PERCUSSION_REGISTER, 0x00); /* - * Melodic mode. - */ + /* + * Detect availability of OPL4 (_experimental_). Works + * propably only after a cold boot. In addition the OPL4 port + * of the chip may not be connected to the PC bus at all. + */ - return 1; + opl3_command(ioaddr + 2, OPL3_MODE_REGISTER, 0x00); + opl3_command(ioaddr + 2, OPL3_MODE_REGISTER, OPL3_ENABLE | OPL4_ENABLE); + + if ((tmp = inb(ioaddr)) == 0x02) { /* Have a OPL4 */ + detected_model = 4; + } + if (!0) { /* OPL4 port is free */ /* XXX check here lr970711 */ + int tmp; + + outb(ioaddr - 8, 0x02); /* Select OPL4 ID register */ + DELAY(10); + tmp = inb(ioaddr - 7); /* Read it */ + DELAY(10); + + if (tmp == 0x20) { /* OPL4 should return 0x20 here */ + detected_model = 4; + + outb(ioaddr - 8, 0xF8); /* Select OPL4 FM mixer control */ + DELAY(10); + outb(ioaddr - 7, 0x1B); /* Write value */ + DELAY(10); + } else + detected_model = 3; + } + opl3_command(ioaddr + 2, OPL3_MODE_REGISTER, 0); + + } + for (i = 0; i < 9; i++) + opl3_command(ioaddr, KEYON_BLOCK + i, 0); /* Note off */ + + opl3_command(ioaddr, TEST_REGISTER, ENABLE_WAVE_SELECT); + opl3_command(ioaddr, PERCUSSION_REGISTER, 0x00); /* Melodic mode. */ + + return 1; } static int -opl3_kill_note (int dev, int voice, int note, int velocity) +opl3_kill_note(int dev, int voice, int note, int velocity) { - struct physical_voice_info *map; + struct physical_voice_info *map; - if (voice < 0 || voice >= nr_voices) - return 0; + if (voice < 0 || voice >= devc->nr_voice) + return 0; - voice_alloc->map[voice] = 0; + devc->v_alloc->map[voice] = 0; - map = &physical_voices[logical_voices[voice]]; + map = &pv_map[devc->lv_map[voice]]; - DEB (printk ("Kill note %d\n", voice)); + DEB(printf("Kill note %d\n", voice)); - if (map->voice_mode == 0) - return 0; + if (map->voice_mode == 0) + return 0; - opl3_command (map->ioaddr, KEYON_BLOCK + map->voice_num, voices[voice].keyon_byte & ~0x20); + opl3_command(map->ioaddr, KEYON_BLOCK + map->voice_num, + devc->voc[voice].keyon_byte & ~0x20); - voices[voice].keyon_byte = 0; - voices[voice].bender = 0; - voices[voice].bender_range = 200; /* - * 200 cents = 2 semitones - */ - voices[voice].orig_freq = 0; - voices[voice].current_freq = 0; - voices[voice].mode = 0; + devc->voc[voice].keyon_byte = 0; + devc->voc[voice].bender = 0; + devc->voc[voice].volume = 64; + devc->voc[voice].bender_range = 200; /* 200 cents = 2 semitones */ + devc->voc[voice].orig_freq = 0; + devc->voc[voice].current_freq = 0; + devc->voc[voice].mode = 0; - return 0; + return 0; } #define HIHAT 0 @@ -329,27 +318,28 @@ opl3_kill_note (int dev, int voice, int note, int velocity) #define DEFAULT TOMTOM static int -store_instr (int instr_no, struct sbi_instrument *instr) +store_instr(int instr_no, struct sbi_instrument * instr) { - if (instr->key != FM_PATCH && (instr->key != OPL3_PATCH || !opl3_enabled)) - printk ("FM warning: Invalid patch format field (key) 0x%x\n", instr->key); - memcpy ((char *) &(instrmap[instr_no]), (char *) instr, sizeof (*instr)); + if (instr->key !=FM_PATCH && (instr->key !=OPL3_PATCH || devc->model != 2)) + printf("FM warning: Invalid patch format field (key) 0x%x\n", + instr->key); + bcopy((char *) instr, (char *) &(devc->i_map[instr_no]), sizeof(*instr)); - return 0; + return 0; } static int -opl3_set_instr (int dev, int voice, int instr_no) +opl3_set_instr(int dev, int voice, int instr_no) { - if (voice < 0 || voice >= nr_voices) - return 0; + if (voice < 0 || voice >= devc->nr_voice) + return 0; - if (instr_no < 0 || instr_no >= SBFM_MAXINSTR) - return 0; + if (instr_no < 0 || instr_no >= SBFM_MAXINSTR) + return 0; - active_instrument[voice] = &instrmap[instr_no]; - return 0; + devc->act_i[voice] = &devc->i_map[instr_no]; + return 0; } /* @@ -362,563 +352,464 @@ opl3_set_instr (int dev, int voice, int instr_no) * it saves a lot of log() calculations. (RH) */ char fm_volume_table[128] = -{-64, -48, -40, -35, -32, -29, -27, -26, /* - * 0 - 7 - */ - -24, -23, -21, -20, -19, -18, -18, -17, /* - * 8 - 15 - */ - -16, -15, -15, -14, -13, -13, -12, -12, /* - * 16 - 23 - */ - -11, -11, -10, -10, -10, -9, -9, -8, /* - * 24 - 31 - */ - -8, -8, -7, -7, -7, -6, -6, -6,/* - * 32 - 39 - */ - -5, -5, -5, -5, -4, -4, -4, -4,/* - * 40 - 47 - */ - -3, -3, -3, -3, -2, -2, -2, -2,/* - * 48 - 55 - */ - -2, -1, -1, -1, -1, 0, 0, 0, /* - * 56 - 63 - */ - 0, 0, 0, 1, 1, 1, 1, 1, /* - * 64 - 71 - */ - 1, 2, 2, 2, 2, 2, 2, 2, /* - * 72 - 79 - */ - 3, 3, 3, 3, 3, 3, 3, 4, /* - * 80 - 87 - */ - 4, 4, 4, 4, 4, 4, 4, 5, /* - * 88 - 95 - */ - 5, 5, 5, 5, 5, 5, 5, 5, /* - * 96 - 103 - */ - 6, 6, 6, 6, 6, 6, 6, 6, /* - * 104 - 111 - */ - 6, 7, 7, 7, 7, 7, 7, 7, /* - * 112 - 119 - */ - 7, 7, 7, 8, 8, 8, 8, 8}; /* - - - * * * * 120 - 127 */ +{ + -64, -48, -40, -35, -32, -29, -27, -26, + -24, -23, -21, -20, -19, -18, -18, -17, + -16, -15, -15, -14, -13, -13, -12, -12, + -11, -11, -10, -10, -10, -9, -9, -8, + -8, -8, -7, -7, -7, -6, -6, -6, + -5, -5, -5, -5, -4, -4, -4, -4, + -3, -3, -3, -3, -2, -2, -2, -2, + -2, -1, -1, -1, -1, 0, 0, 0, + 0, 0, 0, 1, 1, 1, 1, 1, + 1, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 4, + 4, 4, 4, 4, 4, 4, 4, 5, + 5, 5, 5, 5, 5, 5, 5, 5, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 8, 8, 8, 8, 8}; static void -calc_vol (unsigned char *regbyte, int volume) +calc_vol(u_char *regbyte, int volume, int main_vol) { - int level = (~*regbyte & 0x3f); + int level = (~*regbyte & 0x3f); - if (level) - level += fm_volume_table[volume]; + if (main_vol > 127) + main_vol = 127; - if (level > 0x3f) - level = 0x3f; - if (level < 0) - level = 0; + volume = (volume * main_vol) / 127; - *regbyte = (*regbyte & 0xc0) | (~level & 0x3f); + if (level) + level += fm_volume_table[volume]; + + RANGE (level, 0, 0x3f ); + + *regbyte = (*regbyte & 0xc0) | (~level & 0x3f); } static void -set_voice_volume (int voice, int volume) +set_voice_volume(int voice, int volume, int main_vol) { - unsigned char vol1, vol2, vol3, vol4; - struct sbi_instrument *instr; - struct physical_voice_info *map; + u_char vol1, vol2, vol3, vol4; + struct sbi_instrument *instr; + struct physical_voice_info *map; - if (voice < 0 || voice >= nr_voices) - return; + if (voice < 0 || voice >= devc->nr_voice) + return; - map = &physical_voices[logical_voices[voice]]; + map = &pv_map[devc->lv_map[voice]]; - instr = active_instrument[voice]; + instr = devc->act_i[voice]; - if (!instr) - instr = &instrmap[0]; + if (!instr) + instr = &devc->i_map[0]; - if (instr->channel < 0) - return; + if (instr->channel < 0) + return; - if (voices[voice].mode == 0) - return; + if (devc->voc[voice].mode == 0) + return; - if (voices[voice].mode == 2) - { /* - * 2 OP voice - */ + if (devc->voc[voice].mode == 2) { - vol1 = instr->operators[2]; - vol2 = instr->operators[3]; + vol1 = instr->operators[2]; + vol2 = instr->operators[3]; - if ((instr->operators[10] & 0x01)) - { /* - * Additive synthesis - */ - calc_vol (&vol1, volume); - calc_vol (&vol2, volume); - } - else - { /* - * FM synthesis - */ - calc_vol (&vol2, volume); + if ((instr->operators[10] & 0x01)) { + calc_vol(&vol1, volume, main_vol); } + calc_vol(&vol2, volume, main_vol); - opl3_command (map->ioaddr, KSL_LEVEL + map->op[0], vol1); /* - * Modulator - * volume - */ - opl3_command (map->ioaddr, KSL_LEVEL + map->op[1], vol2); /* - * Carrier - * volume - */ - } - else - { /* - * 4 OP voice - */ - int connection; + opl3_command(map->ioaddr, KSL_LEVEL + map->op[0], vol1); + opl3_command(map->ioaddr, KSL_LEVEL + map->op[1], vol2); + } else { /* 4 OP voice */ + int connection; - vol1 = instr->operators[2]; - vol2 = instr->operators[3]; - vol3 = instr->operators[OFFS_4OP + 2]; - vol4 = instr->operators[OFFS_4OP + 3]; + vol1 = instr->operators[2]; + vol2 = instr->operators[3]; + vol3 = instr->operators[OFFS_4OP + 2]; + vol4 = instr->operators[OFFS_4OP + 3]; - /* - * The connection method for 4 OP voices is defined by the rightmost - * bits at the offsets 10 and 10+OFFS_4OP - */ + /* + * The connection method for 4 OP devc->voc is defined by the + * rightmost bits at the offsets 10 and 10+OFFS_4OP + */ - connection = ((instr->operators[10] & 0x01) << 1) | (instr->operators[10 + OFFS_4OP] & 0x01); + connection = ((instr->operators[10] & 0x01) << 1) | (instr->operators[10 + OFFS_4OP] & 0x01); - switch (connection) - { + switch (connection) { case 0: - calc_vol (&vol4, volume); /* - * Just the OP 4 is carrier - */ - break; + calc_vol(&vol4, volume, main_vol); + break; case 1: - calc_vol (&vol2, volume); - calc_vol (&vol4, volume); - break; + calc_vol(&vol2, volume, main_vol); + calc_vol(&vol4, volume, main_vol); + break; case 2: - calc_vol (&vol1, volume); - calc_vol (&vol4, volume); - break; + calc_vol(&vol1, volume, main_vol); + calc_vol(&vol4, volume, main_vol); + break; case 3: - calc_vol (&vol1, volume); - calc_vol (&vol3, volume); - calc_vol (&vol4, volume); - break; - - default: /* - * Why ?? - */ ; + calc_vol(&vol1, volume, main_vol); + calc_vol(&vol3, volume, main_vol); + calc_vol(&vol4, volume, main_vol); + break; + + default:; } - opl3_command (map->ioaddr, KSL_LEVEL + map->op[0], vol1); - opl3_command (map->ioaddr, KSL_LEVEL + map->op[1], vol2); - opl3_command (map->ioaddr, KSL_LEVEL + map->op[2], vol3); - opl3_command (map->ioaddr, KSL_LEVEL + map->op[3], vol4); + opl3_command(map->ioaddr, KSL_LEVEL + map->op[0], vol1); + opl3_command(map->ioaddr, KSL_LEVEL + map->op[1], vol2); + opl3_command(map->ioaddr, KSL_LEVEL + map->op[2], vol3); + opl3_command(map->ioaddr, KSL_LEVEL + map->op[3], vol4); } } static int -opl3_start_note (int dev, int voice, int note, int volume) +opl3_start_note(int dev, int voice, int note, int volume) { - unsigned char data, fpc; - int block, fnum, freq, voice_mode; - struct sbi_instrument *instr; - struct physical_voice_info *map; + u_char data, fpc; + int block, fnum, freq, voice_mode; + struct sbi_instrument *instr; + struct physical_voice_info *map; - if (voice < 0 || voice >= nr_voices) - return 0; + if (voice < 0 || voice >= devc->nr_voice) + return 0; - map = &physical_voices[logical_voices[voice]]; + map = &pv_map[devc->lv_map[voice]]; - if (map->voice_mode == 0) - return 0; + if (map->voice_mode == 0) + return 0; - if (note == 255) /* - * Just change the volume - */ - { - set_voice_volume (voice, volume); - return 0; + if (note == 255) { /* Just change the volume */ + set_voice_volume(voice, volume, devc->voc[voice].volume); + return 0; } - - /* - * Kill previous note before playing - */ - opl3_command (map->ioaddr, KSL_LEVEL + map->op[1], 0xff); /* - * Carrier - * volume to - * min - */ - opl3_command (map->ioaddr, KSL_LEVEL + map->op[0], 0xff); /* - * Modulator - * volume to - */ - - if (map->voice_mode == 4) - { - opl3_command (map->ioaddr, KSL_LEVEL + map->op[2], 0xff); - opl3_command (map->ioaddr, KSL_LEVEL + map->op[3], 0xff); + /* + * Kill previous note before playing + */ + opl3_command(map->ioaddr, KSL_LEVEL + map->op[1], 0xff); /* Carrier volume to min */ + opl3_command(map->ioaddr, KSL_LEVEL + map->op[0], 0xff); /* Modulator volume to */ + + if (map->voice_mode == 4) { + opl3_command(map->ioaddr, KSL_LEVEL + map->op[2], 0xff); + opl3_command(map->ioaddr, KSL_LEVEL + map->op[3], 0xff); } + opl3_command(map->ioaddr, KEYON_BLOCK + map->voice_num, 0x00); /* Note off */ - opl3_command (map->ioaddr, KEYON_BLOCK + map->voice_num, 0x00); /* - * Note - * off - */ - - instr = active_instrument[voice]; + instr = devc->act_i[voice]; - if (!instr) - instr = &instrmap[0]; + if (!instr) + instr = &devc->i_map[0]; - if (instr->channel < 0) - { - printk ( - "OPL3: Initializing voice %d with undefined instrument\n", + if (instr->channel < 0) { + printf( "OPL3: Initializing voice %d with undefined instrument\n", voice); - return 0; + return 0; } + if (map->voice_mode == 2 && instr->key == OPL3_PATCH) + return 0; /* Cannot play */ - if (map->voice_mode == 2 && instr->key == OPL3_PATCH) - return 0; /* - * Cannot play - */ + voice_mode = map->voice_mode; - voice_mode = map->voice_mode; + if (voice_mode == 4) { + int voice_shift; - if (voice_mode == 4) - { - int voice_shift; + voice_shift = (map->ioaddr == devc->left_io) ? 0 : 3; + voice_shift += map->voice_num; - voice_shift = (map->ioaddr == left_address) ? 0 : 3; - voice_shift += map->voice_num; + if (instr->key != OPL3_PATCH) { /* Just 2 OP patch */ + voice_mode = 2; + devc->cmask &= ~(1 << voice_shift); + } else + devc->cmask |= (1 << voice_shift); - if (instr->key != OPL3_PATCH) /* - * Just 2 OP patch - */ - { - voice_mode = 2; - connection_mask &= ~(1 << voice_shift); - } - else - { - connection_mask |= (1 << voice_shift); - } - - opl3_command (right_address, CONNECTION_SELECT_REGISTER, connection_mask); + opl3_command(devc->right_io, CONNECTION_SELECT_REGISTER, devc->cmask); } - - /* - * Set Sound Characteristics - */ - opl3_command (map->ioaddr, AM_VIB + map->op[0], instr->operators[0]); - opl3_command (map->ioaddr, AM_VIB + map->op[1], instr->operators[1]); - - /* - * Set Attack/Decay - */ - opl3_command (map->ioaddr, ATTACK_DECAY + map->op[0], instr->operators[4]); - opl3_command (map->ioaddr, ATTACK_DECAY + map->op[1], instr->operators[5]); - - /* - * Set Sustain/Release - */ - opl3_command (map->ioaddr, SUSTAIN_RELEASE + map->op[0], instr->operators[6]); - opl3_command (map->ioaddr, SUSTAIN_RELEASE + map->op[1], instr->operators[7]); - - /* - * Set Wave Select - */ - opl3_command (map->ioaddr, WAVE_SELECT + map->op[0], instr->operators[8]); - opl3_command (map->ioaddr, WAVE_SELECT + map->op[1], instr->operators[9]); - - /* - * Set Feedback/Connection - */ - fpc = instr->operators[10]; - if (!(fpc & 0x30)) - fpc |= 0x30; /* - * Ensure that at least one chn is enabled - */ - opl3_command (map->ioaddr, FEEDBACK_CONNECTION + map->voice_num, - fpc); - - /* - * If the voice is a 4 OP one, initialize the operators 3 and 4 also - */ - - if (voice_mode == 4) - { - - /* - * Set Sound Characteristics - */ - opl3_command (map->ioaddr, AM_VIB + map->op[2], instr->operators[OFFS_4OP + 0]); - opl3_command (map->ioaddr, AM_VIB + map->op[3], instr->operators[OFFS_4OP + 1]); - - /* - * Set Attack/Decay - */ - opl3_command (map->ioaddr, ATTACK_DECAY + map->op[2], instr->operators[OFFS_4OP + 4]); - opl3_command (map->ioaddr, ATTACK_DECAY + map->op[3], instr->operators[OFFS_4OP + 5]); - - /* - * Set Sustain/Release - */ - opl3_command (map->ioaddr, SUSTAIN_RELEASE + map->op[2], instr->operators[OFFS_4OP + 6]); - opl3_command (map->ioaddr, SUSTAIN_RELEASE + map->op[3], instr->operators[OFFS_4OP + 7]); - - /* - * Set Wave Select - */ - opl3_command (map->ioaddr, WAVE_SELECT + map->op[2], instr->operators[OFFS_4OP + 8]); - opl3_command (map->ioaddr, WAVE_SELECT + map->op[3], instr->operators[OFFS_4OP + 9]); - - /* - * Set Feedback/Connection - */ - fpc = instr->operators[OFFS_4OP + 10]; - if (!(fpc & 0x30)) - fpc |= 0x30; /* - * Ensure that at least one chn is enabled - */ - opl3_command (map->ioaddr, FEEDBACK_CONNECTION + map->voice_num + 3, fpc); + /* + * Set Sound Characteristics + */ + opl3_command(map->ioaddr, AM_VIB + map->op[0], instr->operators[0]); + opl3_command(map->ioaddr, AM_VIB + map->op[1], instr->operators[1]); + + /* + * Set Attack/Decay + */ + opl3_command(map->ioaddr, ATTACK_DECAY + map->op[0], instr->operators[4]); + opl3_command(map->ioaddr, ATTACK_DECAY + map->op[1], instr->operators[5]); + + /* + * Set Sustain/Release + */ + opl3_command(map->ioaddr,SUSTAIN_RELEASE + map->op[0], instr->operators[6]); + opl3_command(map->ioaddr,SUSTAIN_RELEASE + map->op[1], instr->operators[7]); + + /* + * Set Wave Select + */ + opl3_command(map->ioaddr, WAVE_SELECT + map->op[0], instr->operators[8]); + opl3_command(map->ioaddr, WAVE_SELECT + map->op[1], instr->operators[9]); + + /* + * Set Feedback/Connection + */ + fpc = instr->operators[10]; + if (!(fpc & 0x30)) + fpc |= 0x30; /* Ensure that at least one chn is enabled */ + opl3_command(map->ioaddr, FEEDBACK_CONNECTION + map->voice_num, fpc); + + /* + * If the voice is a 4 OP one, initialize the operators 3 and 4 also + */ + + if (voice_mode == 4) { + + /* + * Set Sound Characteristics + */ + opl3_command(map->ioaddr, AM_VIB + map->op[2], + instr->operators[OFFS_4OP + 0]); + opl3_command(map->ioaddr, AM_VIB + map->op[3], + instr->operators[OFFS_4OP + 1]); + + /* + * Set Attack/Decay + */ + opl3_command(map->ioaddr, ATTACK_DECAY + map->op[2], + instr->operators[OFFS_4OP + 4]); + opl3_command(map->ioaddr, ATTACK_DECAY + map->op[3], + instr->operators[OFFS_4OP + 5]); + + /* + * Set Sustain/Release + */ + opl3_command(map->ioaddr, SUSTAIN_RELEASE + map->op[2], + instr->operators[OFFS_4OP + 6]); + opl3_command(map->ioaddr, SUSTAIN_RELEASE + map->op[3], + instr->operators[OFFS_4OP + 7]); + + /* + * Set Wave Select + */ + opl3_command(map->ioaddr, WAVE_SELECT + map->op[2], + instr->operators[OFFS_4OP + 8]); + opl3_command(map->ioaddr, WAVE_SELECT + map->op[3], + instr->operators[OFFS_4OP + 9]); + + /* + * Set Feedback/Connection + */ + fpc = instr->operators[OFFS_4OP + 10]; + if (!(fpc & 0x30)) + fpc |= 0x30; /* Ensure that at least one chn is enabled */ + opl3_command(map->ioaddr,FEEDBACK_CONNECTION + map->voice_num + 3, fpc); } + devc->voc[voice].mode = voice_mode; - voices[voice].mode = voice_mode; - - set_voice_volume (voice, volume); + set_voice_volume(voice, volume, devc->voc[voice].volume); - freq = voices[voice].orig_freq = note_to_freq (note) / 1000; + freq = devc->voc[voice].orig_freq = note_to_freq(note) / 1000; - /* - * Since the pitch bender may have been set before playing the note, we - * have to calculate the bending now. - */ + /* + * Since the pitch bender may have been set before playing the note, + * we have to calculate the bending now. + */ - freq = compute_finetune (voices[voice].orig_freq, voices[voice].bender, voices[voice].bender_range); - voices[voice].current_freq = freq; + freq = compute_finetune(devc->voc[voice].orig_freq, + devc->voc[voice].bender, devc->voc[voice].bender_range); + devc->voc[voice].current_freq = freq; - freq_to_fnum (freq, &block, &fnum); + freq_to_fnum(freq, &block, &fnum); - /* - * Play note - */ + /* + * Play note + */ - data = fnum & 0xff; /* - * Least significant bits of fnumber - */ - opl3_command (map->ioaddr, FNUM_LOW + map->voice_num, data); + data = fnum & 0xff; /* Least significant bits of fnumber */ + opl3_command(map->ioaddr, FNUM_LOW + map->voice_num, data); - data = 0x20 | ((block & 0x7) << 2) | ((fnum >> 8) & 0x3); - voices[voice].keyon_byte = data; - opl3_command (map->ioaddr, KEYON_BLOCK + map->voice_num, data); - if (voice_mode == 4) - opl3_command (map->ioaddr, KEYON_BLOCK + map->voice_num + 3, data); + data = 0x20 | ((block & 0x7) << 2) | ((fnum >> 8) & 0x3); + devc->voc[voice].keyon_byte = data; + opl3_command(map->ioaddr, KEYON_BLOCK + map->voice_num, data); + if (voice_mode == 4) + opl3_command(map->ioaddr, KEYON_BLOCK + map->voice_num + 3, data); - return 0; + return 0; } static void -freq_to_fnum (int freq, int *block, int *fnum) +freq_to_fnum(int freq, int *block, int *fnum) { - int f, octave; - - /* - * Converts the note frequency to block and fnum values for the FM chip - */ - /* - * First try to compute the block -value (octave) where the note belongs - */ - - f = freq; - - octave = 5; - - if (f == 0) - octave = 0; - else if (f < 261) - { - while (f < 261) - { - octave--; - f <<= 1; + int f, octave; + + /* + * Converts the note frequency to block and fnum values for the FM + * chip + */ + /* + * First try to compute the block -value (octave) where the note + * belongs + */ + + f = freq; + + octave = 5; + + if (f == 0) + octave = 0; + else if (f < 261) { + while (f < 261) { + octave--; + f <<= 1; } - } - else if (f > 493) - { - while (f > 493) - { - octave++; - f >>= 1; + } else if (f > 493) { + while (f > 493) { + octave++; + f >>= 1; } } + if (octave > 7) + octave = 7; - if (octave > 7) - octave = 7; - - *fnum = freq * (1 << (20 - octave)) / 49716; - *block = octave; + *fnum = freq * (1 << (20 - octave)) / 49716; + *block = octave; } static void -opl3_command (int io_addr, unsigned int addr, unsigned int val) +opl3_command(int io_addr, u_int addr, u_int val) { - int i; - - /* - * The original 2-OP synth requires a quite long delay after writing to a - * register. The OPL-3 survives with just two INBs - */ - - OUTB ((unsigned char) (addr & 0xff), io_addr); /* - * Select register - * - */ - - if (!opl3_enabled) - tenmicrosec (); - else - for (i = 0; i < 2; i++) - INB (io_addr); - - OUTB ((unsigned char) (val & 0xff), io_addr + 1); /* - * Write to register - * - */ - - if (!opl3_enabled) - { - tenmicrosec (); - tenmicrosec (); - tenmicrosec (); - } - else - for (i = 0; i < 2; i++) - INB (io_addr); + int i; + + /* + * The original 2-OP synth requires a quite long delay after writing + * to a register. The OPL-3 survives with just two INBs + */ + + outb(io_addr, (u_char) (addr & 0xff)); + + if (!devc->model != 2) + DELAY(10); + else + for (i = 0; i < 2; i++) + inb(io_addr); + + outb(io_addr + 1, (u_char) (val & 0xff)); + + if (devc->model != 2) + DELAY(30); + else + for (i = 0; i < 2; i++) + inb(io_addr); } static void -opl3_reset (int dev) +opl3_reset(int dev) { - int i; + int i; - for (i = 0; i < nr_voices; i++) - { - opl3_command (physical_voices[logical_voices[i]].ioaddr, - KSL_LEVEL + physical_voices[logical_voices[i]].op[0], 0xff); + for (i = 0; i < 18; i++) + devc->lv_map[i] = i; - opl3_command (physical_voices[logical_voices[i]].ioaddr, - KSL_LEVEL + physical_voices[logical_voices[i]].op[1], 0xff); + for (i = 0; i < devc->nr_voice; i++) { + opl3_command(pv_map[devc->lv_map[i]].ioaddr, + KSL_LEVEL + pv_map[devc->lv_map[i]].op[0], 0xff); - if (physical_voices[logical_voices[i]].voice_mode == 4) - { - opl3_command (physical_voices[logical_voices[i]].ioaddr, - KSL_LEVEL + physical_voices[logical_voices[i]].op[2], 0xff); + opl3_command(pv_map[devc->lv_map[i]].ioaddr, + KSL_LEVEL + pv_map[devc->lv_map[i]].op[1], 0xff); - opl3_command (physical_voices[logical_voices[i]].ioaddr, - KSL_LEVEL + physical_voices[logical_voices[i]].op[3], 0xff); - } + if (pv_map[devc->lv_map[i]].voice_mode == 4) { + opl3_command(pv_map[devc->lv_map[i]].ioaddr, + KSL_LEVEL + pv_map[devc->lv_map[i]].op[2], 0xff); - opl3_kill_note (dev, i, 0, 64); + opl3_command(pv_map[devc->lv_map[i]].ioaddr, + KSL_LEVEL + pv_map[devc->lv_map[i]].op[3], 0xff); + } + opl3_kill_note(dev, i, 0, 64); } - if (opl3_enabled) - { - voice_alloc->max_voice = nr_voices = 18; - - for (i = 0; i < 18; i++) - logical_voices[i] = i; + if (devc->model == 2) { + devc->v_alloc->max_voice = devc->nr_voice = 18; - for (i = 0; i < 18; i++) - physical_voices[i].voice_mode = 2; + for (i = 0; i < 18; i++) + pv_map[i].voice_mode = 2; } - } static int -opl3_open (int dev, int mode) +opl3_open(int dev, int mode) { - if (!opl3_ok) - return RET_ERROR (ENXIO); - if (opl3_busy) - return RET_ERROR (EBUSY); - opl3_busy = 1; - - connection_mask = 0x00; /* - * Just 2 OP voices - */ - if (opl3_enabled) - opl3_command (right_address, CONNECTION_SELECT_REGISTER, connection_mask); - return 0; + int i; + + if (devc->busy) + return -(EBUSY); + devc->busy = 1; + + devc->v_alloc->max_voice = devc->nr_voice = (devc->model == 2) ? 18 : 9; + devc->v_alloc->timestamp = 0; + + for (i = 0; i < 18; i++) { + devc->v_alloc->map[i] = 0; + devc->v_alloc->alloc_times[i] = 0; + } + + devc->cmask = 0x00; /* Just 2 OP mode */ + if (devc->model == 2) + opl3_command(devc->right_io, CONNECTION_SELECT_REGISTER, devc->cmask); + return 0; } static void -opl3_close (int dev) +opl3_close(int dev) { - opl3_busy = 0; - voice_alloc->max_voice = nr_voices = opl3_enabled ? 18 : 9; - fm_info.nr_drums = 0; - fm_info.perc_mode = 0; + devc->busy = 0; + devc->v_alloc->max_voice = devc->nr_voice = (devc->model == 2) ? 18 : 9; + + devc->fm_info.nr_drums = 0; + devc->fm_info.perc_mode = 0; - opl3_reset (dev); + opl3_reset(dev); } static void -opl3_hw_control (int dev, unsigned char *event) +opl3_hw_control(int dev, u_char *event) { } static int -opl3_load_patch (int dev, int format, snd_rw_buf * addr, - int offs, int count, int pmgr_flag) +opl3_load_patch(int dev, int format, snd_rw_buf * addr, + int offs, int count, int pmgr_flag) { - struct sbi_instrument ins; + struct sbi_instrument ins; - if (count < sizeof (ins)) - { - printk ("FM Error: Patch record too short\n"); - return RET_ERROR (EINVAL); + if (count < sizeof(ins)) { + printf("FM Error: Patch record too short\n"); + return -(EINVAL); } + if (uiomove(&((char *) &ins)[offs], sizeof(ins) - offs, addr)) { + printf("sb: Bad copyin()!\n"); + }; - COPY_FROM_USER (&((char *) &ins)[offs], (char *) addr, offs, sizeof (ins) - offs); - - if (ins.channel < 0 || ins.channel >= SBFM_MAXINSTR) - { - printk ("FM Error: Invalid instrument number %d\n", ins.channel); - return RET_ERROR (EINVAL); + if (ins.channel < 0 || ins.channel >= SBFM_MAXINSTR) { + printf("FM Error: Invalid instrument number %d\n", ins.channel); + return -(EINVAL); } - ins.key = format; + ins.key = format; - return store_instr (ins.channel, &ins); + return store_instr(ins.channel, &ins); } static void -opl3_panning (int dev, int voice, int pressure) +opl3_panning(int dev, int voice, int pressure) { } static void -opl3_volume_method (int dev, int mode) +opl3_volume_method(int dev, int mode) { } @@ -929,297 +820,313 @@ opl3_volume_method (int dev, int mode) opl3_command (map->ioaddr, AM_VIB + map->op[cell-1], tmp);} static void -opl3_aftertouch (int dev, int voice, int pressure) +opl3_aftertouch(int dev, int voice, int pressure) { - int tmp; - struct sbi_instrument *instr; - struct physical_voice_info *map; + int tmp; + struct sbi_instrument *instr; + struct physical_voice_info *map; - if (voice < 0 || voice >= nr_voices) - return; + if (voice < 0 || voice >= devc->nr_voice) + return; - map = &physical_voices[logical_voices[voice]]; + map = &pv_map[devc->lv_map[voice]]; - DEB (printk ("Aftertouch %d\n", voice)); + DEB(printf("Aftertouch %d\n", voice)); - if (map->voice_mode == 0) - return; + if (map->voice_mode == 0) + return; - /* - * Adjust the amount of vibrato depending the pressure - */ + /* + * Adjust the amount of vibrato depending the pressure + */ - instr = active_instrument[voice]; + instr = devc->act_i[voice]; - if (!instr) - instr = &instrmap[0]; + if (!instr) + instr = &devc->i_map[0]; - if (voices[voice].mode == 4) - { - int connection = ((instr->operators[10] & 0x01) << 1) | (instr->operators[10 + OFFS_4OP] & 0x01); + if (devc->voc[voice].mode == 4) { + int connection = ((instr->operators[10] & 0x01) << 1) | (instr->operators[10 + OFFS_4OP] & 0x01); - switch (connection) - { + switch (connection) { case 0: - SET_VIBRATO (4); - break; + SET_VIBRATO(4); + break; case 1: - SET_VIBRATO (2); - SET_VIBRATO (4); - break; + SET_VIBRATO(2); + SET_VIBRATO(4); + break; case 2: - SET_VIBRATO (1); - SET_VIBRATO (4); - break; + SET_VIBRATO(1); + SET_VIBRATO(4); + break; case 3: - SET_VIBRATO (1); - SET_VIBRATO (3); - SET_VIBRATO (4); - break; + SET_VIBRATO(1); + SET_VIBRATO(3); + SET_VIBRATO(4); + break; } - /* - * Not implemented yet - */ - } - else - { - SET_VIBRATO (1); - - if ((instr->operators[10] & 0x01)) /* - * Additive synthesis - */ - SET_VIBRATO (2); + /* + * Not implemented yet + */ + } else { + SET_VIBRATO(1); + + if ((instr->operators[10] & 0x01)) /* Additive synthesis */ + SET_VIBRATO(2); } } #undef SET_VIBRATO static void -bend_pitch (int dev, int voice, int value) +bend_pitch(int dev, int voice, int value) { - unsigned char data; - int block, fnum, freq; - struct physical_voice_info *map; - - map = &physical_voices[logical_voices[voice]]; - - if (map->voice_mode == 0) - return; - - voices[voice].bender = value; - if (!value) - return; - if (!(voices[voice].keyon_byte & 0x20)) - return; /* - * Not keyed on - */ - - freq = compute_finetune (voices[voice].orig_freq, voices[voice].bender, voices[voice].bender_range); - voices[voice].current_freq = freq; - - freq_to_fnum (freq, &block, &fnum); - - data = fnum & 0xff; /* - * Least significant bits of fnumber - */ - opl3_command (map->ioaddr, FNUM_LOW + map->voice_num, data); - - data = 0x20 | ((block & 0x7) << 2) | ((fnum >> 8) & 0x3); /* - * * - * KEYON|OCTAVE|MS - * - * * bits * * - * of * f-num - * - */ - voices[voice].keyon_byte = data; - opl3_command (map->ioaddr, KEYON_BLOCK + map->voice_num, data); + u_char data; + int block, fnum, freq; + struct physical_voice_info *map; + + map = &pv_map[devc->lv_map[voice]]; + + if (map->voice_mode == 0) + return; + + devc->voc[voice].bender = value; + if (!value) + return; + if (!(devc->voc[voice].keyon_byte & 0x20)) + return; /* Not keyed on */ + + freq = compute_finetune(devc->voc[voice].orig_freq, devc->voc[voice].bender, devc->voc[voice].bender_range); + devc->voc[voice].current_freq = freq; + + freq_to_fnum(freq, &block, &fnum); + + data = fnum & 0xff; /* Least significant bits of fnumber */ + opl3_command(map->ioaddr, FNUM_LOW + map->voice_num, data); + + data = 0x20 | ((block & 0x7) << 2) | ((fnum >> 8) & 0x3); + /* KEYON|OCTAVE|MS bits of f-num */ + devc->voc[voice].keyon_byte = data; + opl3_command(map->ioaddr, KEYON_BLOCK + map->voice_num, data); } static void -opl3_controller (int dev, int voice, int ctrl_num, int value) +opl3_controller(int dev, int voice, int ctrl_num, int value) { - if (voice < 0 || voice >= nr_voices) - return; + if (voice < 0 || voice >= devc->nr_voice) + return; - switch (ctrl_num) - { + switch (ctrl_num) { case CTRL_PITCH_BENDER: - bend_pitch (dev, voice, value); - break; + bend_pitch(dev, voice, value); + break; case CTRL_PITCH_BENDER_RANGE: - voices[voice].bender_range = value; - break; + devc->voc[voice].bender_range = value; + break; + + case CTL_MAIN_VOLUME: + devc->voc[voice].volume = value / 128; + break; } } static int -opl3_patchmgr (int dev, struct patmgr_info *rec) +opl3_patchmgr(int dev, struct patmgr_info * rec) { - return RET_ERROR (EINVAL); + return -(EINVAL); } static void -opl3_bender (int dev, int voice, int value) +opl3_bender(int dev, int voice, int value) { - if (voice < 0 || voice >= nr_voices) - return; + if (voice < 0 || voice >= devc->nr_voice) + return; - bend_pitch (dev, voice, value); + bend_pitch(dev, voice, value - 8192); } static int -opl3_alloc_voice (int dev, int chn, int note, struct voice_alloc_info *alloc) +opl3_alloc_voice(int dev, int chn, int note, struct voice_alloc_info * alloc) { - int i, p, avail_voices; - struct sbi_instrument *instr; - int is4op; - int instr_no; - - if (chn < 0 || chn > 15) - instr_no = 0; - else - instr_no = chn_info[chn].pgm_num; - - instr = &instrmap[instr_no]; - if (instr->channel < 0 || /* Instrument not loaded */ - nr_voices != 12) /* Not in 4 OP mode */ - is4op = 0; - else if (nr_voices == 12) /* 4 OP mode */ - is4op = (instr->key == OPL3_PATCH); - else - is4op = 0; - - if (is4op) - { - p = 0; - avail_voices = 6; - } - else - { - if (nr_voices == 12) /* 4 OP mode. Use the '2 OP only' voices first */ - p = 6; - else - p = 0; - avail_voices = nr_voices; + int i, p, best, first, avail, best_time = 0x7fffffff; + struct sbi_instrument *instr; + int is4op; + int instr_no; + + if (chn < 0 || chn > 15) + instr_no = 0; + else + instr_no = devc->chn_info[chn].pgm_num; + + instr = &devc->i_map[instr_no]; + if (instr->channel < 0 || /* Instrument not loaded */ + devc->nr_voice != 12) /* Not in 4 OP mode */ + is4op = 0; + else if (devc->nr_voice == 12) /* 4 OP mode */ + is4op = (instr->key == OPL3_PATCH); + else + is4op = 0; + + if (is4op) { + first = p = 0; + avail = 6; + } else { + if (devc->nr_voice == 12) /* 4 OP mode. Use the '2 OP + * only' operators first */ + first = p = 6; + else + first = p = 0; + avail = devc->nr_voice; } - /* - * Now try to find a free voice - */ + /* + * Now try to find a free voice + */ + best = first; - for (i = 0; i < avail_voices; i++) - { - if (alloc->map[p] == 0) - { - return p; + for (i = 0; i < avail; i++) { + if (alloc->map[p] == 0) { + return p; } - p = (p + 1) % nr_voices; + if (alloc->alloc_times[p] < best_time) { /* Find oldest playing note */ + best_time = alloc->alloc_times[p]; + best = p; + } + p = (p + 1) % avail; } - /* - * Insert some kind of priority mechanism here. - */ + /* + * Insert some kind of priority mechanism here. + */ + + if (best < 0) + best = 0; + if (best > devc->nr_voice) + best -= devc->nr_voice; - printk ("OPL3: Out of free voices\n"); - return 0; /* All voices in use. Select the first one. */ + return best; /* All devc->voc in use. Select the first + * one. */ +} + +static void +opl3_setup_voice(int dev, int voice, int chn) +{ + struct channel_info *info = + &synth_devs[dev]->chn_info[chn]; + + opl3_set_instr(dev, voice, info->pgm_num); + + devc->voc[voice].bender = info->bender_value; + devc->voc[voice].volume = info->controllers[CTL_MAIN_VOLUME]; } static struct synth_operations opl3_operations = { - &fm_info, - 0, - SYNTH_TYPE_FM, - FM_TYPE_ADLIB, - opl3_open, - opl3_close, - opl3_ioctl, - opl3_kill_note, - opl3_start_note, - opl3_set_instr, - opl3_reset, - opl3_hw_control, - opl3_load_patch, - opl3_aftertouch, - opl3_controller, - opl3_panning, - opl3_volume_method, - opl3_patchmgr, - opl3_bender, - opl3_alloc_voice + NULL, + 0, + SYNTH_TYPE_FM, + FM_TYPE_ADLIB, + opl3_open, + opl3_close, + opl3_ioctl, + opl3_kill_note, + opl3_start_note, + opl3_set_instr, + opl3_reset, + opl3_hw_control, + opl3_load_patch, + opl3_aftertouch, + opl3_controller, + opl3_panning, + opl3_volume_method, + opl3_patchmgr, + opl3_bender, + opl3_alloc_voice, + opl3_setup_voice }; -long -opl3_init (long mem_start) +void +opl3_init(int ioaddr, sound_os_info * osp) { - int i; - - PERMANENT_MALLOC (struct sbi_instrument *, instrmap, - SBFM_MAXINSTR * sizeof (*instrmap), mem_start); - - if (num_synths >= MAX_SYNTH_DEV) - printk ("OPL3 Error: Too many synthesizers\n"); - else - { - synth_devs[num_synths++] = &opl3_operations; - voice_alloc = &opl3_operations.alloc; - chn_info = &opl3_operations.chn_info[0]; + int i; + + if (num_synths >= MAX_SYNTH_DEV) { + printf("OPL3 Error: Too many synthesizers\n"); + return ; + } + if (devc == NULL) { + printf("OPL3: Device control structure not initialized.\n"); + return ; + } + bzero((char *) devc, sizeof(*devc)); + devc->osp = osp; + + devc->nr_voice = 9; + strcpy(devc->fm_info.name, "OPL2-"); + + devc->fm_info.device = 0; + devc->fm_info.synth_type = SYNTH_TYPE_FM; + devc->fm_info.synth_subtype = FM_TYPE_ADLIB; + devc->fm_info.perc_mode = 0; + devc->fm_info.nr_voices = 9; + devc->fm_info.nr_drums = 0; + devc->fm_info.instr_bank_size = SBFM_MAXINSTR; + devc->fm_info.capabilities = 0; + devc->left_io = ioaddr; + devc->right_io = ioaddr + 2; + + if (detected_model <= 2) + devc->model = 1; + else { + devc->model = 2; + if (detected_model == 4) + devc->is_opl4 = 1; } - fm_model = 0; - opl3_ok = 1; - if (opl3_enabled) - { - printk (" <Yamaha OPL-3 FM>"); - fm_model = 2; - voice_alloc->max_voice = nr_voices = 18; - fm_info.nr_drums = 0; - fm_info.capabilities |= SYNTH_CAP_OPL3; -#ifndef SCO - strcpy (fm_info.name, "Yamaha OPL-3"); -#endif + opl3_operations.info = &devc->fm_info; + + synth_devs[num_synths++] = &opl3_operations; + devc->v_alloc = &opl3_operations.alloc; + devc->chn_info = &opl3_operations.chn_info[0]; - for (i = 0; i < 18; i++) - if (physical_voices[i].ioaddr == USE_LEFT) - physical_voices[i].ioaddr = left_address; + if (devc->model == 2) { + if (devc->is_opl4) + conf_printf2("Yamaha OPL4/OPL3 FM", ioaddr, 0, -1, -1); else - physical_voices[i].ioaddr = right_address; - - - opl3_command (right_address, OPL3_MODE_REGISTER, OPL3_ENABLE); /* - * Enable - * OPL-3 - * mode - */ - opl3_command (right_address, CONNECTION_SELECT_REGISTER, 0x00); /* - * Select - * all - * 2-OP - * * - * voices - */ - } - else - { - printk (" <Yamaha 2-OP FM>"); - fm_model = 1; - voice_alloc->max_voice = nr_voices = 9; - fm_info.nr_drums = 0; - - for (i = 0; i < 18; i++) - physical_voices[i].ioaddr = left_address; + conf_printf2("Yamaha OPL3 FM", ioaddr, 0, -1, -1); + + devc->v_alloc->max_voice = devc->nr_voice = 18; + devc->fm_info.nr_drums = 0; + devc->fm_info.capabilities |= SYNTH_CAP_OPL3; + strcpy(devc->fm_info.name, "Yamaha OPL-3"); + + for (i = 0; i < 18; i++) + if (pv_map[i].ioaddr == USE_LEFT) + pv_map[i].ioaddr = devc->left_io; + else + pv_map[i].ioaddr = devc->right_io; + + opl3_command(devc->right_io, OPL3_MODE_REGISTER, OPL3_ENABLE); + opl3_command(devc->right_io, CONNECTION_SELECT_REGISTER, 0x00); + } else { + conf_printf2("Yamaha OPL2 FM", ioaddr, 0, -1, -1); + devc->v_alloc->max_voice = devc->nr_voice = 9; + devc->fm_info.nr_drums = 0; + + for (i = 0; i < 18; i++) + pv_map[i].ioaddr = devc->left_io; }; - already_initialized = 1; - for (i = 0; i < SBFM_MAXINSTR; i++) - instrmap[i].channel = -1; + for (i = 0; i < SBFM_MAXINSTR; i++) + devc->i_map[i].channel = -1; - return mem_start; + return ; } #endif |