1*1da177e4SLinus Torvalds /* 2*1da177e4SLinus Torvalds * Copyright (c) by Uros Bizjak <uros@kss-loka.si> 3*1da177e4SLinus Torvalds * 4*1da177e4SLinus Torvalds * Midi synth routines for OPL2/OPL3/OPL4 FM 5*1da177e4SLinus Torvalds * 6*1da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify 7*1da177e4SLinus Torvalds * it under the terms of the GNU General Public License as published by 8*1da177e4SLinus Torvalds * the Free Software Foundation; either version 2 of the License, or 9*1da177e4SLinus Torvalds * (at your option) any later version. 10*1da177e4SLinus Torvalds * 11*1da177e4SLinus Torvalds * This program is distributed in the hope that it will be useful, 12*1da177e4SLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of 13*1da177e4SLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14*1da177e4SLinus Torvalds * GNU General Public License for more details. 15*1da177e4SLinus Torvalds * 16*1da177e4SLinus Torvalds * You should have received a copy of the GNU General Public License 17*1da177e4SLinus Torvalds * along with this program; if not, write to the Free Software 18*1da177e4SLinus Torvalds * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19*1da177e4SLinus Torvalds * 20*1da177e4SLinus Torvalds */ 21*1da177e4SLinus Torvalds 22*1da177e4SLinus Torvalds #undef DEBUG_ALLOC 23*1da177e4SLinus Torvalds #undef DEBUG_MIDI 24*1da177e4SLinus Torvalds 25*1da177e4SLinus Torvalds #include "opl3_voice.h" 26*1da177e4SLinus Torvalds #include <sound/asoundef.h> 27*1da177e4SLinus Torvalds 28*1da177e4SLinus Torvalds extern char snd_opl3_regmap[MAX_OPL2_VOICES][4]; 29*1da177e4SLinus Torvalds 30*1da177e4SLinus Torvalds extern int use_internal_drums; 31*1da177e4SLinus Torvalds 32*1da177e4SLinus Torvalds /* 33*1da177e4SLinus Torvalds * The next table looks magical, but it certainly is not. Its values have 34*1da177e4SLinus Torvalds * been calculated as table[i]=8*log(i/64)/log(2) with an obvious exception 35*1da177e4SLinus Torvalds * for i=0. This log-table converts a linear volume-scaling (0..127) to a 36*1da177e4SLinus Torvalds * logarithmic scaling as present in the FM-synthesizer chips. so : Volume 37*1da177e4SLinus Torvalds * 64 = 0 db = relative volume 0 and: Volume 32 = -6 db = relative 38*1da177e4SLinus Torvalds * volume -8 it was implemented as a table because it is only 128 bytes and 39*1da177e4SLinus Torvalds * it saves a lot of log() calculations. (Rob Hooft <hooft@chem.ruu.nl>) 40*1da177e4SLinus Torvalds */ 41*1da177e4SLinus Torvalds 42*1da177e4SLinus Torvalds static char opl3_volume_table[128] = 43*1da177e4SLinus Torvalds { 44*1da177e4SLinus Torvalds -63, -48, -40, -35, -32, -29, -27, -26, 45*1da177e4SLinus Torvalds -24, -23, -21, -20, -19, -18, -18, -17, 46*1da177e4SLinus Torvalds -16, -15, -15, -14, -13, -13, -12, -12, 47*1da177e4SLinus Torvalds -11, -11, -10, -10, -10, -9, -9, -8, 48*1da177e4SLinus Torvalds -8, -8, -7, -7, -7, -6, -6, -6, 49*1da177e4SLinus Torvalds -5, -5, -5, -5, -4, -4, -4, -4, 50*1da177e4SLinus Torvalds -3, -3, -3, -3, -2, -2, -2, -2, 51*1da177e4SLinus Torvalds -2, -1, -1, -1, -1, 0, 0, 0, 52*1da177e4SLinus Torvalds 0, 0, 0, 1, 1, 1, 1, 1, 53*1da177e4SLinus Torvalds 1, 2, 2, 2, 2, 2, 2, 2, 54*1da177e4SLinus Torvalds 3, 3, 3, 3, 3, 3, 3, 4, 55*1da177e4SLinus Torvalds 4, 4, 4, 4, 4, 4, 4, 5, 56*1da177e4SLinus Torvalds 5, 5, 5, 5, 5, 5, 5, 5, 57*1da177e4SLinus Torvalds 6, 6, 6, 6, 6, 6, 6, 6, 58*1da177e4SLinus Torvalds 6, 7, 7, 7, 7, 7, 7, 7, 59*1da177e4SLinus Torvalds 7, 7, 7, 8, 8, 8, 8, 8 60*1da177e4SLinus Torvalds }; 61*1da177e4SLinus Torvalds 62*1da177e4SLinus Torvalds void snd_opl3_calc_volume(unsigned char *volbyte, int vel, 63*1da177e4SLinus Torvalds snd_midi_channel_t *chan) 64*1da177e4SLinus Torvalds { 65*1da177e4SLinus Torvalds int oldvol, newvol, n; 66*1da177e4SLinus Torvalds int volume; 67*1da177e4SLinus Torvalds 68*1da177e4SLinus Torvalds volume = (vel * chan->gm_volume * chan->gm_expression) / (127*127); 69*1da177e4SLinus Torvalds if (volume > 127) 70*1da177e4SLinus Torvalds volume = 127; 71*1da177e4SLinus Torvalds 72*1da177e4SLinus Torvalds oldvol = OPL3_TOTAL_LEVEL_MASK - (*volbyte & OPL3_TOTAL_LEVEL_MASK); 73*1da177e4SLinus Torvalds 74*1da177e4SLinus Torvalds newvol = opl3_volume_table[volume] + oldvol; 75*1da177e4SLinus Torvalds if (newvol > OPL3_TOTAL_LEVEL_MASK) 76*1da177e4SLinus Torvalds newvol = OPL3_TOTAL_LEVEL_MASK; 77*1da177e4SLinus Torvalds else if (newvol < 0) 78*1da177e4SLinus Torvalds newvol = 0; 79*1da177e4SLinus Torvalds 80*1da177e4SLinus Torvalds n = OPL3_TOTAL_LEVEL_MASK - (newvol & OPL3_TOTAL_LEVEL_MASK); 81*1da177e4SLinus Torvalds 82*1da177e4SLinus Torvalds *volbyte = (*volbyte & OPL3_KSL_MASK) | (n & OPL3_TOTAL_LEVEL_MASK); 83*1da177e4SLinus Torvalds } 84*1da177e4SLinus Torvalds 85*1da177e4SLinus Torvalds /* 86*1da177e4SLinus Torvalds * Converts the note frequency to block and fnum values for the FM chip 87*1da177e4SLinus Torvalds */ 88*1da177e4SLinus Torvalds static short opl3_note_table[16] = 89*1da177e4SLinus Torvalds { 90*1da177e4SLinus Torvalds 305, 323, /* for pitch bending, -2 semitones */ 91*1da177e4SLinus Torvalds 343, 363, 385, 408, 432, 458, 485, 514, 544, 577, 611, 647, 92*1da177e4SLinus Torvalds 686, 726 /* for pitch bending, +2 semitones */ 93*1da177e4SLinus Torvalds }; 94*1da177e4SLinus Torvalds 95*1da177e4SLinus Torvalds static void snd_opl3_calc_pitch(unsigned char *fnum, unsigned char *blocknum, 96*1da177e4SLinus Torvalds int note, snd_midi_channel_t *chan) 97*1da177e4SLinus Torvalds { 98*1da177e4SLinus Torvalds int block = ((note / 12) & 0x07) - 1; 99*1da177e4SLinus Torvalds int idx = (note % 12) + 2; 100*1da177e4SLinus Torvalds int freq; 101*1da177e4SLinus Torvalds 102*1da177e4SLinus Torvalds if (chan->midi_pitchbend) { 103*1da177e4SLinus Torvalds int pitchbend = chan->midi_pitchbend; 104*1da177e4SLinus Torvalds int segment; 105*1da177e4SLinus Torvalds 106*1da177e4SLinus Torvalds if (pitchbend > 0x1FFF) 107*1da177e4SLinus Torvalds pitchbend = 0x1FFF; 108*1da177e4SLinus Torvalds 109*1da177e4SLinus Torvalds segment = pitchbend / 0x1000; 110*1da177e4SLinus Torvalds freq = opl3_note_table[idx+segment]; 111*1da177e4SLinus Torvalds freq += ((opl3_note_table[idx+segment+1] - freq) * 112*1da177e4SLinus Torvalds (pitchbend % 0x1000)) / 0x1000; 113*1da177e4SLinus Torvalds } else { 114*1da177e4SLinus Torvalds freq = opl3_note_table[idx]; 115*1da177e4SLinus Torvalds } 116*1da177e4SLinus Torvalds 117*1da177e4SLinus Torvalds *fnum = (unsigned char) freq; 118*1da177e4SLinus Torvalds *blocknum = ((freq >> 8) & OPL3_FNUM_HIGH_MASK) | 119*1da177e4SLinus Torvalds ((block << 2) & OPL3_BLOCKNUM_MASK); 120*1da177e4SLinus Torvalds } 121*1da177e4SLinus Torvalds 122*1da177e4SLinus Torvalds 123*1da177e4SLinus Torvalds #ifdef DEBUG_ALLOC 124*1da177e4SLinus Torvalds static void debug_alloc(opl3_t *opl3, char *s, int voice) { 125*1da177e4SLinus Torvalds int i; 126*1da177e4SLinus Torvalds char *str = "x.24"; 127*1da177e4SLinus Torvalds 128*1da177e4SLinus Torvalds printk("time %.5i: %s [%.2i]: ", opl3->use_time, s, voice); 129*1da177e4SLinus Torvalds for (i = 0; i < opl3->max_voices; i++) 130*1da177e4SLinus Torvalds printk("%c", *(str + opl3->voices[i].state + 1)); 131*1da177e4SLinus Torvalds printk("\n"); 132*1da177e4SLinus Torvalds } 133*1da177e4SLinus Torvalds #endif 134*1da177e4SLinus Torvalds 135*1da177e4SLinus Torvalds /* 136*1da177e4SLinus Torvalds * Get a FM voice (channel) to play a note on. 137*1da177e4SLinus Torvalds */ 138*1da177e4SLinus Torvalds static int opl3_get_voice(opl3_t *opl3, int instr_4op, 139*1da177e4SLinus Torvalds snd_midi_channel_t *chan) { 140*1da177e4SLinus Torvalds int chan_4op_1; /* first voice for 4op instrument */ 141*1da177e4SLinus Torvalds int chan_4op_2; /* second voice for 4op instrument */ 142*1da177e4SLinus Torvalds 143*1da177e4SLinus Torvalds snd_opl3_voice_t *vp, *vp2; 144*1da177e4SLinus Torvalds unsigned int voice_time; 145*1da177e4SLinus Torvalds int i; 146*1da177e4SLinus Torvalds 147*1da177e4SLinus Torvalds #ifdef DEBUG_ALLOC 148*1da177e4SLinus Torvalds char *alloc_type[3] = { "FREE ", "CHEAP ", "EXPENSIVE" }; 149*1da177e4SLinus Torvalds #endif 150*1da177e4SLinus Torvalds 151*1da177e4SLinus Torvalds /* This is our "allocation cost" table */ 152*1da177e4SLinus Torvalds enum { 153*1da177e4SLinus Torvalds FREE = 0, CHEAP, EXPENSIVE, END 154*1da177e4SLinus Torvalds }; 155*1da177e4SLinus Torvalds 156*1da177e4SLinus Torvalds /* Keeps track of what we are finding */ 157*1da177e4SLinus Torvalds struct best { 158*1da177e4SLinus Torvalds unsigned int time; 159*1da177e4SLinus Torvalds int voice; 160*1da177e4SLinus Torvalds } best[END]; 161*1da177e4SLinus Torvalds struct best *bp; 162*1da177e4SLinus Torvalds 163*1da177e4SLinus Torvalds for (i = 0; i < END; i++) { 164*1da177e4SLinus Torvalds best[i].time = (unsigned int)(-1); /* XXX MAX_?INT really */; 165*1da177e4SLinus Torvalds best[i].voice = -1; 166*1da177e4SLinus Torvalds } 167*1da177e4SLinus Torvalds 168*1da177e4SLinus Torvalds /* Look through all the channels for the most suitable. */ 169*1da177e4SLinus Torvalds for (i = 0; i < opl3->max_voices; i++) { 170*1da177e4SLinus Torvalds vp = &opl3->voices[i]; 171*1da177e4SLinus Torvalds 172*1da177e4SLinus Torvalds if (vp->state == SNDRV_OPL3_ST_NOT_AVAIL) 173*1da177e4SLinus Torvalds /* skip unavailable channels, allocated by 174*1da177e4SLinus Torvalds drum voices or by bounded 4op voices) */ 175*1da177e4SLinus Torvalds continue; 176*1da177e4SLinus Torvalds 177*1da177e4SLinus Torvalds voice_time = vp->time; 178*1da177e4SLinus Torvalds bp = best; 179*1da177e4SLinus Torvalds 180*1da177e4SLinus Torvalds chan_4op_1 = ((i < 3) || (i > 8 && i < 12)); 181*1da177e4SLinus Torvalds chan_4op_2 = ((i > 2 && i < 6) || (i > 11 && i < 15)); 182*1da177e4SLinus Torvalds if (instr_4op) { 183*1da177e4SLinus Torvalds /* allocate 4op voice */ 184*1da177e4SLinus Torvalds /* skip channels unavailable to 4op instrument */ 185*1da177e4SLinus Torvalds if (!chan_4op_1) 186*1da177e4SLinus Torvalds continue; 187*1da177e4SLinus Torvalds 188*1da177e4SLinus Torvalds if (vp->state) 189*1da177e4SLinus Torvalds /* kill one voice, CHEAP */ 190*1da177e4SLinus Torvalds bp++; 191*1da177e4SLinus Torvalds /* get state of bounded 2op channel 192*1da177e4SLinus Torvalds to be allocated for 4op instrument */ 193*1da177e4SLinus Torvalds vp2 = &opl3->voices[i + 3]; 194*1da177e4SLinus Torvalds if (vp2->state == SNDRV_OPL3_ST_ON_2OP) { 195*1da177e4SLinus Torvalds /* kill two voices, EXPENSIVE */ 196*1da177e4SLinus Torvalds bp++; 197*1da177e4SLinus Torvalds voice_time = (voice_time > vp->time) ? 198*1da177e4SLinus Torvalds voice_time : vp->time; 199*1da177e4SLinus Torvalds } 200*1da177e4SLinus Torvalds } else { 201*1da177e4SLinus Torvalds /* allocate 2op voice */ 202*1da177e4SLinus Torvalds if ((chan_4op_1) || (chan_4op_2)) 203*1da177e4SLinus Torvalds /* use bounded channels for 2op, CHEAP */ 204*1da177e4SLinus Torvalds bp++; 205*1da177e4SLinus Torvalds else if (vp->state) 206*1da177e4SLinus Torvalds /* kill one voice on 2op channel, CHEAP */ 207*1da177e4SLinus Torvalds bp++; 208*1da177e4SLinus Torvalds /* raise kill cost to EXPENSIVE for all channels */ 209*1da177e4SLinus Torvalds if (vp->state) 210*1da177e4SLinus Torvalds bp++; 211*1da177e4SLinus Torvalds } 212*1da177e4SLinus Torvalds if (voice_time < bp->time) { 213*1da177e4SLinus Torvalds bp->time = voice_time; 214*1da177e4SLinus Torvalds bp->voice = i; 215*1da177e4SLinus Torvalds } 216*1da177e4SLinus Torvalds } 217*1da177e4SLinus Torvalds 218*1da177e4SLinus Torvalds for (i = 0; i < END; i++) { 219*1da177e4SLinus Torvalds if (best[i].voice >= 0) { 220*1da177e4SLinus Torvalds #ifdef DEBUG_ALLOC 221*1da177e4SLinus Torvalds printk("%s %iop allocation on voice %i\n", 222*1da177e4SLinus Torvalds alloc_type[i], instr_4op ? 4 : 2, 223*1da177e4SLinus Torvalds best[i].voice); 224*1da177e4SLinus Torvalds #endif 225*1da177e4SLinus Torvalds return best[i].voice; 226*1da177e4SLinus Torvalds } 227*1da177e4SLinus Torvalds } 228*1da177e4SLinus Torvalds /* not found */ 229*1da177e4SLinus Torvalds return -1; 230*1da177e4SLinus Torvalds } 231*1da177e4SLinus Torvalds 232*1da177e4SLinus Torvalds /* ------------------------------ */ 233*1da177e4SLinus Torvalds 234*1da177e4SLinus Torvalds /* 235*1da177e4SLinus Torvalds * System timer interrupt function 236*1da177e4SLinus Torvalds */ 237*1da177e4SLinus Torvalds void snd_opl3_timer_func(unsigned long data) 238*1da177e4SLinus Torvalds { 239*1da177e4SLinus Torvalds 240*1da177e4SLinus Torvalds opl3_t *opl3 = (opl3_t *)data; 241*1da177e4SLinus Torvalds int again = 0; 242*1da177e4SLinus Torvalds int i; 243*1da177e4SLinus Torvalds 244*1da177e4SLinus Torvalds spin_lock(&opl3->sys_timer_lock); 245*1da177e4SLinus Torvalds for (i = 0; i < opl3->max_voices; i++) { 246*1da177e4SLinus Torvalds snd_opl3_voice_t *vp = &opl3->voices[i]; 247*1da177e4SLinus Torvalds if (vp->state > 0 && vp->note_off_check) { 248*1da177e4SLinus Torvalds if (vp->note_off == jiffies) 249*1da177e4SLinus Torvalds snd_opl3_note_off(opl3, vp->note, 0, vp->chan); 250*1da177e4SLinus Torvalds else 251*1da177e4SLinus Torvalds again++; 252*1da177e4SLinus Torvalds } 253*1da177e4SLinus Torvalds } 254*1da177e4SLinus Torvalds if (again) { 255*1da177e4SLinus Torvalds opl3->tlist.expires = jiffies + 1; /* invoke again */ 256*1da177e4SLinus Torvalds add_timer(&opl3->tlist); 257*1da177e4SLinus Torvalds } else { 258*1da177e4SLinus Torvalds opl3->sys_timer_status = 0; 259*1da177e4SLinus Torvalds } 260*1da177e4SLinus Torvalds spin_unlock(&opl3->sys_timer_lock); 261*1da177e4SLinus Torvalds } 262*1da177e4SLinus Torvalds 263*1da177e4SLinus Torvalds /* 264*1da177e4SLinus Torvalds * Start system timer 265*1da177e4SLinus Torvalds */ 266*1da177e4SLinus Torvalds static void snd_opl3_start_timer(opl3_t *opl3) 267*1da177e4SLinus Torvalds { 268*1da177e4SLinus Torvalds unsigned long flags; 269*1da177e4SLinus Torvalds spin_lock_irqsave(&opl3->sys_timer_lock, flags); 270*1da177e4SLinus Torvalds if (! opl3->sys_timer_status) { 271*1da177e4SLinus Torvalds opl3->tlist.expires = jiffies + 1; 272*1da177e4SLinus Torvalds add_timer(&opl3->tlist); 273*1da177e4SLinus Torvalds opl3->sys_timer_status = 1; 274*1da177e4SLinus Torvalds } 275*1da177e4SLinus Torvalds spin_unlock_irqrestore(&opl3->sys_timer_lock, flags); 276*1da177e4SLinus Torvalds } 277*1da177e4SLinus Torvalds 278*1da177e4SLinus Torvalds /* ------------------------------ */ 279*1da177e4SLinus Torvalds 280*1da177e4SLinus Torvalds 281*1da177e4SLinus Torvalds static int snd_opl3_oss_map[MAX_OPL3_VOICES] = { 282*1da177e4SLinus Torvalds 0, 1, 2, 9, 10, 11, 6, 7, 8, 15, 16, 17, 3, 4 ,5, 12, 13, 14 283*1da177e4SLinus Torvalds }; 284*1da177e4SLinus Torvalds 285*1da177e4SLinus Torvalds /* 286*1da177e4SLinus Torvalds * Start a note. 287*1da177e4SLinus Torvalds */ 288*1da177e4SLinus Torvalds void snd_opl3_note_on(void *p, int note, int vel, snd_midi_channel_t *chan) 289*1da177e4SLinus Torvalds { 290*1da177e4SLinus Torvalds opl3_t *opl3; 291*1da177e4SLinus Torvalds snd_seq_instr_t wanted; 292*1da177e4SLinus Torvalds snd_seq_kinstr_t *kinstr; 293*1da177e4SLinus Torvalds int instr_4op; 294*1da177e4SLinus Torvalds 295*1da177e4SLinus Torvalds int voice; 296*1da177e4SLinus Torvalds snd_opl3_voice_t *vp, *vp2; 297*1da177e4SLinus Torvalds unsigned short connect_mask; 298*1da177e4SLinus Torvalds unsigned char connection; 299*1da177e4SLinus Torvalds unsigned char vol_op[4]; 300*1da177e4SLinus Torvalds 301*1da177e4SLinus Torvalds int extra_prg = 0; 302*1da177e4SLinus Torvalds 303*1da177e4SLinus Torvalds unsigned short reg_side; 304*1da177e4SLinus Torvalds unsigned char op_offset; 305*1da177e4SLinus Torvalds unsigned char voice_offset; 306*1da177e4SLinus Torvalds unsigned short opl3_reg; 307*1da177e4SLinus Torvalds unsigned char reg_val; 308*1da177e4SLinus Torvalds 309*1da177e4SLinus Torvalds int key = note; 310*1da177e4SLinus Torvalds unsigned char fnum, blocknum; 311*1da177e4SLinus Torvalds int i; 312*1da177e4SLinus Torvalds 313*1da177e4SLinus Torvalds fm_instrument_t *fm; 314*1da177e4SLinus Torvalds unsigned long flags; 315*1da177e4SLinus Torvalds 316*1da177e4SLinus Torvalds opl3 = p; 317*1da177e4SLinus Torvalds 318*1da177e4SLinus Torvalds #ifdef DEBUG_MIDI 319*1da177e4SLinus Torvalds snd_printk("Note on, ch %i, inst %i, note %i, vel %i\n", 320*1da177e4SLinus Torvalds chan->number, chan->midi_program, note, vel); 321*1da177e4SLinus Torvalds #endif 322*1da177e4SLinus Torvalds wanted.cluster = 0; 323*1da177e4SLinus Torvalds wanted.std = SNDRV_SEQ_INSTR_TYPE2_OPL2_3; 324*1da177e4SLinus Torvalds 325*1da177e4SLinus Torvalds /* in SYNTH mode, application takes care of voices */ 326*1da177e4SLinus Torvalds /* in SEQ mode, drum voice numbers are notes on drum channel */ 327*1da177e4SLinus Torvalds if (opl3->synth_mode == SNDRV_OPL3_MODE_SEQ) { 328*1da177e4SLinus Torvalds if (chan->drum_channel) { 329*1da177e4SLinus Torvalds /* percussion instruments are located in bank 128 */ 330*1da177e4SLinus Torvalds wanted.bank = 128; 331*1da177e4SLinus Torvalds wanted.prg = note; 332*1da177e4SLinus Torvalds } else { 333*1da177e4SLinus Torvalds wanted.bank = chan->gm_bank_select; 334*1da177e4SLinus Torvalds wanted.prg = chan->midi_program; 335*1da177e4SLinus Torvalds } 336*1da177e4SLinus Torvalds } else { 337*1da177e4SLinus Torvalds /* Prepare for OSS mode */ 338*1da177e4SLinus Torvalds if (chan->number >= MAX_OPL3_VOICES) 339*1da177e4SLinus Torvalds return; 340*1da177e4SLinus Torvalds 341*1da177e4SLinus Torvalds /* OSS instruments are located in bank 127 */ 342*1da177e4SLinus Torvalds wanted.bank = 127; 343*1da177e4SLinus Torvalds wanted.prg = chan->midi_program; 344*1da177e4SLinus Torvalds } 345*1da177e4SLinus Torvalds 346*1da177e4SLinus Torvalds spin_lock_irqsave(&opl3->voice_lock, flags); 347*1da177e4SLinus Torvalds 348*1da177e4SLinus Torvalds if (use_internal_drums) { 349*1da177e4SLinus Torvalds snd_opl3_drum_switch(opl3, note, vel, 1, chan); 350*1da177e4SLinus Torvalds spin_unlock_irqrestore(&opl3->voice_lock, flags); 351*1da177e4SLinus Torvalds return; 352*1da177e4SLinus Torvalds } 353*1da177e4SLinus Torvalds 354*1da177e4SLinus Torvalds __extra_prg: 355*1da177e4SLinus Torvalds kinstr = snd_seq_instr_find(opl3->ilist, &wanted, 1, 0); 356*1da177e4SLinus Torvalds if (kinstr == NULL) { 357*1da177e4SLinus Torvalds spin_unlock_irqrestore(&opl3->voice_lock, flags); 358*1da177e4SLinus Torvalds return; 359*1da177e4SLinus Torvalds } 360*1da177e4SLinus Torvalds 361*1da177e4SLinus Torvalds fm = KINSTR_DATA(kinstr); 362*1da177e4SLinus Torvalds 363*1da177e4SLinus Torvalds switch (fm->type) { 364*1da177e4SLinus Torvalds case FM_PATCH_OPL2: 365*1da177e4SLinus Torvalds instr_4op = 0; 366*1da177e4SLinus Torvalds break; 367*1da177e4SLinus Torvalds case FM_PATCH_OPL3: 368*1da177e4SLinus Torvalds if (opl3->hardware >= OPL3_HW_OPL3) { 369*1da177e4SLinus Torvalds instr_4op = 1; 370*1da177e4SLinus Torvalds break; 371*1da177e4SLinus Torvalds } 372*1da177e4SLinus Torvalds default: 373*1da177e4SLinus Torvalds snd_seq_instr_free_use(opl3->ilist, kinstr); 374*1da177e4SLinus Torvalds spin_unlock_irqrestore(&opl3->voice_lock, flags); 375*1da177e4SLinus Torvalds return; 376*1da177e4SLinus Torvalds } 377*1da177e4SLinus Torvalds 378*1da177e4SLinus Torvalds #ifdef DEBUG_MIDI 379*1da177e4SLinus Torvalds snd_printk(" --> OPL%i instrument: %s\n", 380*1da177e4SLinus Torvalds instr_4op ? 3 : 2, kinstr->name); 381*1da177e4SLinus Torvalds #endif 382*1da177e4SLinus Torvalds /* in SYNTH mode, application takes care of voices */ 383*1da177e4SLinus Torvalds /* in SEQ mode, allocate voice on free OPL3 channel */ 384*1da177e4SLinus Torvalds if (opl3->synth_mode == SNDRV_OPL3_MODE_SEQ) { 385*1da177e4SLinus Torvalds voice = opl3_get_voice(opl3, instr_4op, chan); 386*1da177e4SLinus Torvalds } else { 387*1da177e4SLinus Torvalds /* remap OSS voice */ 388*1da177e4SLinus Torvalds voice = snd_opl3_oss_map[chan->number]; 389*1da177e4SLinus Torvalds } 390*1da177e4SLinus Torvalds 391*1da177e4SLinus Torvalds if (voice < MAX_OPL2_VOICES) { 392*1da177e4SLinus Torvalds /* Left register block for voices 0 .. 8 */ 393*1da177e4SLinus Torvalds reg_side = OPL3_LEFT; 394*1da177e4SLinus Torvalds voice_offset = voice; 395*1da177e4SLinus Torvalds connect_mask = (OPL3_LEFT_4OP_0 << voice_offset) & 0x07; 396*1da177e4SLinus Torvalds } else { 397*1da177e4SLinus Torvalds /* Right register block for voices 9 .. 17 */ 398*1da177e4SLinus Torvalds reg_side = OPL3_RIGHT; 399*1da177e4SLinus Torvalds voice_offset = voice - MAX_OPL2_VOICES; 400*1da177e4SLinus Torvalds connect_mask = (OPL3_RIGHT_4OP_0 << voice_offset) & 0x38; 401*1da177e4SLinus Torvalds } 402*1da177e4SLinus Torvalds 403*1da177e4SLinus Torvalds /* kill voice on channel */ 404*1da177e4SLinus Torvalds vp = &opl3->voices[voice]; 405*1da177e4SLinus Torvalds if (vp->state > 0) { 406*1da177e4SLinus Torvalds opl3_reg = reg_side | (OPL3_REG_KEYON_BLOCK + voice_offset); 407*1da177e4SLinus Torvalds reg_val = vp->keyon_reg & ~OPL3_KEYON_BIT; 408*1da177e4SLinus Torvalds opl3->command(opl3, opl3_reg, reg_val); 409*1da177e4SLinus Torvalds } 410*1da177e4SLinus Torvalds if (instr_4op) { 411*1da177e4SLinus Torvalds vp2 = &opl3->voices[voice + 3]; 412*1da177e4SLinus Torvalds if (vp->state > 0) { 413*1da177e4SLinus Torvalds opl3_reg = reg_side | (OPL3_REG_KEYON_BLOCK + 414*1da177e4SLinus Torvalds voice_offset + 3); 415*1da177e4SLinus Torvalds reg_val = vp->keyon_reg & ~OPL3_KEYON_BIT; 416*1da177e4SLinus Torvalds opl3->command(opl3, opl3_reg, reg_val); 417*1da177e4SLinus Torvalds } 418*1da177e4SLinus Torvalds } 419*1da177e4SLinus Torvalds 420*1da177e4SLinus Torvalds /* set connection register */ 421*1da177e4SLinus Torvalds if (instr_4op) { 422*1da177e4SLinus Torvalds if ((opl3->connection_reg ^ connect_mask) & connect_mask) { 423*1da177e4SLinus Torvalds opl3->connection_reg |= connect_mask; 424*1da177e4SLinus Torvalds /* set connection bit */ 425*1da177e4SLinus Torvalds opl3_reg = OPL3_RIGHT | OPL3_REG_CONNECTION_SELECT; 426*1da177e4SLinus Torvalds opl3->command(opl3, opl3_reg, opl3->connection_reg); 427*1da177e4SLinus Torvalds } 428*1da177e4SLinus Torvalds } else { 429*1da177e4SLinus Torvalds if ((opl3->connection_reg ^ ~connect_mask) & connect_mask) { 430*1da177e4SLinus Torvalds opl3->connection_reg &= ~connect_mask; 431*1da177e4SLinus Torvalds /* clear connection bit */ 432*1da177e4SLinus Torvalds opl3_reg = OPL3_RIGHT | OPL3_REG_CONNECTION_SELECT; 433*1da177e4SLinus Torvalds opl3->command(opl3, opl3_reg, opl3->connection_reg); 434*1da177e4SLinus Torvalds } 435*1da177e4SLinus Torvalds } 436*1da177e4SLinus Torvalds 437*1da177e4SLinus Torvalds #ifdef DEBUG_MIDI 438*1da177e4SLinus Torvalds snd_printk(" --> setting OPL3 connection: 0x%x\n", 439*1da177e4SLinus Torvalds opl3->connection_reg); 440*1da177e4SLinus Torvalds #endif 441*1da177e4SLinus Torvalds /* 442*1da177e4SLinus Torvalds * calculate volume depending on connection 443*1da177e4SLinus Torvalds * between FM operators (see include/opl3.h) 444*1da177e4SLinus Torvalds */ 445*1da177e4SLinus Torvalds for (i = 0; i < (instr_4op ? 4 : 2); i++) 446*1da177e4SLinus Torvalds vol_op[i] = fm->op[i].ksl_level; 447*1da177e4SLinus Torvalds 448*1da177e4SLinus Torvalds connection = fm->feedback_connection[0] & 0x01; 449*1da177e4SLinus Torvalds if (instr_4op) { 450*1da177e4SLinus Torvalds connection <<= 1; 451*1da177e4SLinus Torvalds connection |= fm->feedback_connection[1] & 0x01; 452*1da177e4SLinus Torvalds 453*1da177e4SLinus Torvalds snd_opl3_calc_volume(&vol_op[3], vel, chan); 454*1da177e4SLinus Torvalds switch (connection) { 455*1da177e4SLinus Torvalds case 0x03: 456*1da177e4SLinus Torvalds snd_opl3_calc_volume(&vol_op[2], vel, chan); 457*1da177e4SLinus Torvalds /* fallthru */ 458*1da177e4SLinus Torvalds case 0x02: 459*1da177e4SLinus Torvalds snd_opl3_calc_volume(&vol_op[0], vel, chan); 460*1da177e4SLinus Torvalds break; 461*1da177e4SLinus Torvalds case 0x01: 462*1da177e4SLinus Torvalds snd_opl3_calc_volume(&vol_op[1], vel, chan); 463*1da177e4SLinus Torvalds } 464*1da177e4SLinus Torvalds } else { 465*1da177e4SLinus Torvalds snd_opl3_calc_volume(&vol_op[1], vel, chan); 466*1da177e4SLinus Torvalds if (connection) 467*1da177e4SLinus Torvalds snd_opl3_calc_volume(&vol_op[0], vel, chan); 468*1da177e4SLinus Torvalds } 469*1da177e4SLinus Torvalds 470*1da177e4SLinus Torvalds /* Program the FM voice characteristics */ 471*1da177e4SLinus Torvalds for (i = 0; i < (instr_4op ? 4 : 2); i++) { 472*1da177e4SLinus Torvalds #ifdef DEBUG_MIDI 473*1da177e4SLinus Torvalds snd_printk(" --> programming operator %i\n", i); 474*1da177e4SLinus Torvalds #endif 475*1da177e4SLinus Torvalds op_offset = snd_opl3_regmap[voice_offset][i]; 476*1da177e4SLinus Torvalds 477*1da177e4SLinus Torvalds /* Set OPL3 AM_VIB register of requested voice/operator */ 478*1da177e4SLinus Torvalds reg_val = fm->op[i].am_vib; 479*1da177e4SLinus Torvalds opl3_reg = reg_side | (OPL3_REG_AM_VIB + op_offset); 480*1da177e4SLinus Torvalds opl3->command(opl3, opl3_reg, reg_val); 481*1da177e4SLinus Torvalds 482*1da177e4SLinus Torvalds /* Set OPL3 KSL_LEVEL register of requested voice/operator */ 483*1da177e4SLinus Torvalds reg_val = vol_op[i]; 484*1da177e4SLinus Torvalds opl3_reg = reg_side | (OPL3_REG_KSL_LEVEL + op_offset); 485*1da177e4SLinus Torvalds opl3->command(opl3, opl3_reg, reg_val); 486*1da177e4SLinus Torvalds 487*1da177e4SLinus Torvalds /* Set OPL3 ATTACK_DECAY register of requested voice/operator */ 488*1da177e4SLinus Torvalds reg_val = fm->op[i].attack_decay; 489*1da177e4SLinus Torvalds opl3_reg = reg_side | (OPL3_REG_ATTACK_DECAY + op_offset); 490*1da177e4SLinus Torvalds opl3->command(opl3, opl3_reg, reg_val); 491*1da177e4SLinus Torvalds 492*1da177e4SLinus Torvalds /* Set OPL3 SUSTAIN_RELEASE register of requested voice/operator */ 493*1da177e4SLinus Torvalds reg_val = fm->op[i].sustain_release; 494*1da177e4SLinus Torvalds opl3_reg = reg_side | (OPL3_REG_SUSTAIN_RELEASE + op_offset); 495*1da177e4SLinus Torvalds opl3->command(opl3, opl3_reg, reg_val); 496*1da177e4SLinus Torvalds 497*1da177e4SLinus Torvalds /* Select waveform */ 498*1da177e4SLinus Torvalds reg_val = fm->op[i].wave_select; 499*1da177e4SLinus Torvalds opl3_reg = reg_side | (OPL3_REG_WAVE_SELECT + op_offset); 500*1da177e4SLinus Torvalds opl3->command(opl3, opl3_reg, reg_val); 501*1da177e4SLinus Torvalds } 502*1da177e4SLinus Torvalds 503*1da177e4SLinus Torvalds /* Set operator feedback and 2op inter-operator connection */ 504*1da177e4SLinus Torvalds reg_val = fm->feedback_connection[0]; 505*1da177e4SLinus Torvalds /* Set output voice connection */ 506*1da177e4SLinus Torvalds reg_val |= OPL3_STEREO_BITS; 507*1da177e4SLinus Torvalds if (chan->gm_pan < 43) 508*1da177e4SLinus Torvalds reg_val &= ~OPL3_VOICE_TO_RIGHT; 509*1da177e4SLinus Torvalds if (chan->gm_pan > 85) 510*1da177e4SLinus Torvalds reg_val &= ~OPL3_VOICE_TO_LEFT; 511*1da177e4SLinus Torvalds opl3_reg = reg_side | (OPL3_REG_FEEDBACK_CONNECTION + voice_offset); 512*1da177e4SLinus Torvalds opl3->command(opl3, opl3_reg, reg_val); 513*1da177e4SLinus Torvalds 514*1da177e4SLinus Torvalds if (instr_4op) { 515*1da177e4SLinus Torvalds /* Set 4op inter-operator connection */ 516*1da177e4SLinus Torvalds reg_val = fm->feedback_connection[1] & OPL3_CONNECTION_BIT; 517*1da177e4SLinus Torvalds /* Set output voice connection */ 518*1da177e4SLinus Torvalds reg_val |= OPL3_STEREO_BITS; 519*1da177e4SLinus Torvalds if (chan->gm_pan < 43) 520*1da177e4SLinus Torvalds reg_val &= ~OPL3_VOICE_TO_RIGHT; 521*1da177e4SLinus Torvalds if (chan->gm_pan > 85) 522*1da177e4SLinus Torvalds reg_val &= ~OPL3_VOICE_TO_LEFT; 523*1da177e4SLinus Torvalds opl3_reg = reg_side | (OPL3_REG_FEEDBACK_CONNECTION + 524*1da177e4SLinus Torvalds voice_offset + 3); 525*1da177e4SLinus Torvalds opl3->command(opl3, opl3_reg, reg_val); 526*1da177e4SLinus Torvalds } 527*1da177e4SLinus Torvalds 528*1da177e4SLinus Torvalds /* 529*1da177e4SLinus Torvalds * Special treatment of percussion notes for fm: 530*1da177e4SLinus Torvalds * Requested pitch is really program, and pitch for 531*1da177e4SLinus Torvalds * device is whatever was specified in the patch library. 532*1da177e4SLinus Torvalds */ 533*1da177e4SLinus Torvalds if (fm->fix_key) 534*1da177e4SLinus Torvalds note = fm->fix_key; 535*1da177e4SLinus Torvalds /* 536*1da177e4SLinus Torvalds * use transpose if defined in patch library 537*1da177e4SLinus Torvalds */ 538*1da177e4SLinus Torvalds if (fm->trnsps) 539*1da177e4SLinus Torvalds note += (fm->trnsps - 64); 540*1da177e4SLinus Torvalds 541*1da177e4SLinus Torvalds snd_opl3_calc_pitch(&fnum, &blocknum, note, chan); 542*1da177e4SLinus Torvalds 543*1da177e4SLinus Torvalds /* Set OPL3 FNUM_LOW register of requested voice */ 544*1da177e4SLinus Torvalds opl3_reg = reg_side | (OPL3_REG_FNUM_LOW + voice_offset); 545*1da177e4SLinus Torvalds opl3->command(opl3, opl3_reg, fnum); 546*1da177e4SLinus Torvalds 547*1da177e4SLinus Torvalds opl3->voices[voice].keyon_reg = blocknum; 548*1da177e4SLinus Torvalds 549*1da177e4SLinus Torvalds /* Set output sound flag */ 550*1da177e4SLinus Torvalds blocknum |= OPL3_KEYON_BIT; 551*1da177e4SLinus Torvalds 552*1da177e4SLinus Torvalds #ifdef DEBUG_MIDI 553*1da177e4SLinus Torvalds snd_printk(" --> trigger voice %i\n", voice); 554*1da177e4SLinus Torvalds #endif 555*1da177e4SLinus Torvalds /* Set OPL3 KEYON_BLOCK register of requested voice */ 556*1da177e4SLinus Torvalds opl3_reg = reg_side | (OPL3_REG_KEYON_BLOCK + voice_offset); 557*1da177e4SLinus Torvalds opl3->command(opl3, opl3_reg, blocknum); 558*1da177e4SLinus Torvalds 559*1da177e4SLinus Torvalds /* kill note after fixed duration (in centiseconds) */ 560*1da177e4SLinus Torvalds if (fm->fix_dur) { 561*1da177e4SLinus Torvalds opl3->voices[voice].note_off = jiffies + 562*1da177e4SLinus Torvalds (fm->fix_dur * HZ) / 100; 563*1da177e4SLinus Torvalds snd_opl3_start_timer(opl3); 564*1da177e4SLinus Torvalds opl3->voices[voice].note_off_check = 1; 565*1da177e4SLinus Torvalds } else 566*1da177e4SLinus Torvalds opl3->voices[voice].note_off_check = 0; 567*1da177e4SLinus Torvalds 568*1da177e4SLinus Torvalds /* get extra pgm, but avoid possible loops */ 569*1da177e4SLinus Torvalds extra_prg = (extra_prg) ? 0 : fm->modes; 570*1da177e4SLinus Torvalds 571*1da177e4SLinus Torvalds snd_seq_instr_free_use(opl3->ilist, kinstr); 572*1da177e4SLinus Torvalds 573*1da177e4SLinus Torvalds /* do the bookkeeping */ 574*1da177e4SLinus Torvalds vp->time = opl3->use_time++; 575*1da177e4SLinus Torvalds vp->note = key; 576*1da177e4SLinus Torvalds vp->chan = chan; 577*1da177e4SLinus Torvalds 578*1da177e4SLinus Torvalds if (instr_4op) { 579*1da177e4SLinus Torvalds vp->state = SNDRV_OPL3_ST_ON_4OP; 580*1da177e4SLinus Torvalds 581*1da177e4SLinus Torvalds vp2 = &opl3->voices[voice + 3]; 582*1da177e4SLinus Torvalds vp2->time = opl3->use_time++; 583*1da177e4SLinus Torvalds vp2->note = key; 584*1da177e4SLinus Torvalds vp2->chan = chan; 585*1da177e4SLinus Torvalds vp2->state = SNDRV_OPL3_ST_NOT_AVAIL; 586*1da177e4SLinus Torvalds } else { 587*1da177e4SLinus Torvalds if (vp->state == SNDRV_OPL3_ST_ON_4OP) { 588*1da177e4SLinus Torvalds /* 4op killed by 2op, release bounded voice */ 589*1da177e4SLinus Torvalds vp2 = &opl3->voices[voice + 3]; 590*1da177e4SLinus Torvalds vp2->time = opl3->use_time++; 591*1da177e4SLinus Torvalds vp2->state = SNDRV_OPL3_ST_OFF; 592*1da177e4SLinus Torvalds } 593*1da177e4SLinus Torvalds vp->state = SNDRV_OPL3_ST_ON_2OP; 594*1da177e4SLinus Torvalds } 595*1da177e4SLinus Torvalds 596*1da177e4SLinus Torvalds #ifdef DEBUG_ALLOC 597*1da177e4SLinus Torvalds debug_alloc(opl3, "note on ", voice); 598*1da177e4SLinus Torvalds #endif 599*1da177e4SLinus Torvalds 600*1da177e4SLinus Torvalds /* allocate extra program if specified in patch library */ 601*1da177e4SLinus Torvalds if (extra_prg) { 602*1da177e4SLinus Torvalds if (extra_prg > 128) { 603*1da177e4SLinus Torvalds wanted.bank = 128; 604*1da177e4SLinus Torvalds /* percussions start at 35 */ 605*1da177e4SLinus Torvalds wanted.prg = extra_prg - 128 + 35 - 1; 606*1da177e4SLinus Torvalds } else { 607*1da177e4SLinus Torvalds wanted.bank = 0; 608*1da177e4SLinus Torvalds wanted.prg = extra_prg - 1; 609*1da177e4SLinus Torvalds } 610*1da177e4SLinus Torvalds #ifdef DEBUG_MIDI 611*1da177e4SLinus Torvalds snd_printk(" *** allocating extra program\n"); 612*1da177e4SLinus Torvalds #endif 613*1da177e4SLinus Torvalds goto __extra_prg; 614*1da177e4SLinus Torvalds } 615*1da177e4SLinus Torvalds spin_unlock_irqrestore(&opl3->voice_lock, flags); 616*1da177e4SLinus Torvalds } 617*1da177e4SLinus Torvalds 618*1da177e4SLinus Torvalds static void snd_opl3_kill_voice(opl3_t *opl3, int voice) 619*1da177e4SLinus Torvalds { 620*1da177e4SLinus Torvalds unsigned short reg_side; 621*1da177e4SLinus Torvalds unsigned char voice_offset; 622*1da177e4SLinus Torvalds unsigned short opl3_reg; 623*1da177e4SLinus Torvalds 624*1da177e4SLinus Torvalds snd_opl3_voice_t *vp, *vp2; 625*1da177e4SLinus Torvalds 626*1da177e4SLinus Torvalds snd_assert(voice < MAX_OPL3_VOICES, return); 627*1da177e4SLinus Torvalds 628*1da177e4SLinus Torvalds vp = &opl3->voices[voice]; 629*1da177e4SLinus Torvalds if (voice < MAX_OPL2_VOICES) { 630*1da177e4SLinus Torvalds /* Left register block for voices 0 .. 8 */ 631*1da177e4SLinus Torvalds reg_side = OPL3_LEFT; 632*1da177e4SLinus Torvalds voice_offset = voice; 633*1da177e4SLinus Torvalds } else { 634*1da177e4SLinus Torvalds /* Right register block for voices 9 .. 17 */ 635*1da177e4SLinus Torvalds reg_side = OPL3_RIGHT; 636*1da177e4SLinus Torvalds voice_offset = voice - MAX_OPL2_VOICES; 637*1da177e4SLinus Torvalds } 638*1da177e4SLinus Torvalds 639*1da177e4SLinus Torvalds /* kill voice */ 640*1da177e4SLinus Torvalds #ifdef DEBUG_MIDI 641*1da177e4SLinus Torvalds snd_printk(" --> kill voice %i\n", voice); 642*1da177e4SLinus Torvalds #endif 643*1da177e4SLinus Torvalds opl3_reg = reg_side | (OPL3_REG_KEYON_BLOCK + voice_offset); 644*1da177e4SLinus Torvalds /* clear Key ON bit */ 645*1da177e4SLinus Torvalds opl3->command(opl3, opl3_reg, vp->keyon_reg); 646*1da177e4SLinus Torvalds 647*1da177e4SLinus Torvalds /* do the bookkeeping */ 648*1da177e4SLinus Torvalds vp->time = opl3->use_time++; 649*1da177e4SLinus Torvalds 650*1da177e4SLinus Torvalds if (vp->state == SNDRV_OPL3_ST_ON_4OP) { 651*1da177e4SLinus Torvalds vp2 = &opl3->voices[voice + 3]; 652*1da177e4SLinus Torvalds 653*1da177e4SLinus Torvalds vp2->time = opl3->use_time++; 654*1da177e4SLinus Torvalds vp2->state = SNDRV_OPL3_ST_OFF; 655*1da177e4SLinus Torvalds } 656*1da177e4SLinus Torvalds vp->state = SNDRV_OPL3_ST_OFF; 657*1da177e4SLinus Torvalds #ifdef DEBUG_ALLOC 658*1da177e4SLinus Torvalds debug_alloc(opl3, "note off", voice); 659*1da177e4SLinus Torvalds #endif 660*1da177e4SLinus Torvalds 661*1da177e4SLinus Torvalds } 662*1da177e4SLinus Torvalds 663*1da177e4SLinus Torvalds /* 664*1da177e4SLinus Torvalds * Release a note in response to a midi note off. 665*1da177e4SLinus Torvalds */ 666*1da177e4SLinus Torvalds void snd_opl3_note_off(void *p, int note, int vel, snd_midi_channel_t *chan) 667*1da177e4SLinus Torvalds { 668*1da177e4SLinus Torvalds opl3_t *opl3; 669*1da177e4SLinus Torvalds 670*1da177e4SLinus Torvalds int voice; 671*1da177e4SLinus Torvalds snd_opl3_voice_t *vp; 672*1da177e4SLinus Torvalds 673*1da177e4SLinus Torvalds unsigned long flags; 674*1da177e4SLinus Torvalds 675*1da177e4SLinus Torvalds opl3 = p; 676*1da177e4SLinus Torvalds 677*1da177e4SLinus Torvalds #ifdef DEBUG_MIDI 678*1da177e4SLinus Torvalds snd_printk("Note off, ch %i, inst %i, note %i\n", 679*1da177e4SLinus Torvalds chan->number, chan->midi_program, note); 680*1da177e4SLinus Torvalds #endif 681*1da177e4SLinus Torvalds 682*1da177e4SLinus Torvalds spin_lock_irqsave(&opl3->voice_lock, flags); 683*1da177e4SLinus Torvalds 684*1da177e4SLinus Torvalds if (opl3->synth_mode == SNDRV_OPL3_MODE_SEQ) { 685*1da177e4SLinus Torvalds if (chan->drum_channel && use_internal_drums) { 686*1da177e4SLinus Torvalds snd_opl3_drum_switch(opl3, note, vel, 0, chan); 687*1da177e4SLinus Torvalds spin_unlock_irqrestore(&opl3->voice_lock, flags); 688*1da177e4SLinus Torvalds return; 689*1da177e4SLinus Torvalds } 690*1da177e4SLinus Torvalds /* this loop will hopefully kill all extra voices, because 691*1da177e4SLinus Torvalds they are grouped by the same channel and note values */ 692*1da177e4SLinus Torvalds for (voice = 0; voice < opl3->max_voices; voice++) { 693*1da177e4SLinus Torvalds vp = &opl3->voices[voice]; 694*1da177e4SLinus Torvalds if (vp->state > 0 && vp->chan == chan && vp->note == note) { 695*1da177e4SLinus Torvalds snd_opl3_kill_voice(opl3, voice); 696*1da177e4SLinus Torvalds } 697*1da177e4SLinus Torvalds } 698*1da177e4SLinus Torvalds } else { 699*1da177e4SLinus Torvalds /* remap OSS voices */ 700*1da177e4SLinus Torvalds if (chan->number < MAX_OPL3_VOICES) { 701*1da177e4SLinus Torvalds voice = snd_opl3_oss_map[chan->number]; 702*1da177e4SLinus Torvalds snd_opl3_kill_voice(opl3, voice); 703*1da177e4SLinus Torvalds } 704*1da177e4SLinus Torvalds } 705*1da177e4SLinus Torvalds spin_unlock_irqrestore(&opl3->voice_lock, flags); 706*1da177e4SLinus Torvalds } 707*1da177e4SLinus Torvalds 708*1da177e4SLinus Torvalds /* 709*1da177e4SLinus Torvalds * key pressure change 710*1da177e4SLinus Torvalds */ 711*1da177e4SLinus Torvalds void snd_opl3_key_press(void *p, int note, int vel, snd_midi_channel_t *chan) 712*1da177e4SLinus Torvalds { 713*1da177e4SLinus Torvalds opl3_t *opl3; 714*1da177e4SLinus Torvalds 715*1da177e4SLinus Torvalds opl3 = p; 716*1da177e4SLinus Torvalds #ifdef DEBUG_MIDI 717*1da177e4SLinus Torvalds snd_printk("Key pressure, ch#: %i, inst#: %i\n", 718*1da177e4SLinus Torvalds chan->number, chan->midi_program); 719*1da177e4SLinus Torvalds #endif 720*1da177e4SLinus Torvalds } 721*1da177e4SLinus Torvalds 722*1da177e4SLinus Torvalds /* 723*1da177e4SLinus Torvalds * terminate note 724*1da177e4SLinus Torvalds */ 725*1da177e4SLinus Torvalds void snd_opl3_terminate_note(void *p, int note, snd_midi_channel_t *chan) 726*1da177e4SLinus Torvalds { 727*1da177e4SLinus Torvalds opl3_t *opl3; 728*1da177e4SLinus Torvalds 729*1da177e4SLinus Torvalds opl3 = p; 730*1da177e4SLinus Torvalds #ifdef DEBUG_MIDI 731*1da177e4SLinus Torvalds snd_printk("Terminate note, ch#: %i, inst#: %i\n", 732*1da177e4SLinus Torvalds chan->number, chan->midi_program); 733*1da177e4SLinus Torvalds #endif 734*1da177e4SLinus Torvalds } 735*1da177e4SLinus Torvalds 736*1da177e4SLinus Torvalds static void snd_opl3_update_pitch(opl3_t *opl3, int voice) 737*1da177e4SLinus Torvalds { 738*1da177e4SLinus Torvalds unsigned short reg_side; 739*1da177e4SLinus Torvalds unsigned char voice_offset; 740*1da177e4SLinus Torvalds unsigned short opl3_reg; 741*1da177e4SLinus Torvalds 742*1da177e4SLinus Torvalds unsigned char fnum, blocknum; 743*1da177e4SLinus Torvalds 744*1da177e4SLinus Torvalds snd_opl3_voice_t *vp; 745*1da177e4SLinus Torvalds 746*1da177e4SLinus Torvalds snd_assert(voice < MAX_OPL3_VOICES, return); 747*1da177e4SLinus Torvalds 748*1da177e4SLinus Torvalds vp = &opl3->voices[voice]; 749*1da177e4SLinus Torvalds if (vp->chan == NULL) 750*1da177e4SLinus Torvalds return; /* not allocated? */ 751*1da177e4SLinus Torvalds 752*1da177e4SLinus Torvalds if (voice < MAX_OPL2_VOICES) { 753*1da177e4SLinus Torvalds /* Left register block for voices 0 .. 8 */ 754*1da177e4SLinus Torvalds reg_side = OPL3_LEFT; 755*1da177e4SLinus Torvalds voice_offset = voice; 756*1da177e4SLinus Torvalds } else { 757*1da177e4SLinus Torvalds /* Right register block for voices 9 .. 17 */ 758*1da177e4SLinus Torvalds reg_side = OPL3_RIGHT; 759*1da177e4SLinus Torvalds voice_offset = voice - MAX_OPL2_VOICES; 760*1da177e4SLinus Torvalds } 761*1da177e4SLinus Torvalds 762*1da177e4SLinus Torvalds snd_opl3_calc_pitch(&fnum, &blocknum, vp->note, vp->chan); 763*1da177e4SLinus Torvalds 764*1da177e4SLinus Torvalds /* Set OPL3 FNUM_LOW register of requested voice */ 765*1da177e4SLinus Torvalds opl3_reg = reg_side | (OPL3_REG_FNUM_LOW + voice_offset); 766*1da177e4SLinus Torvalds opl3->command(opl3, opl3_reg, fnum); 767*1da177e4SLinus Torvalds 768*1da177e4SLinus Torvalds vp->keyon_reg = blocknum; 769*1da177e4SLinus Torvalds 770*1da177e4SLinus Torvalds /* Set output sound flag */ 771*1da177e4SLinus Torvalds blocknum |= OPL3_KEYON_BIT; 772*1da177e4SLinus Torvalds 773*1da177e4SLinus Torvalds /* Set OPL3 KEYON_BLOCK register of requested voice */ 774*1da177e4SLinus Torvalds opl3_reg = reg_side | (OPL3_REG_KEYON_BLOCK + voice_offset); 775*1da177e4SLinus Torvalds opl3->command(opl3, opl3_reg, blocknum); 776*1da177e4SLinus Torvalds 777*1da177e4SLinus Torvalds vp->time = opl3->use_time++; 778*1da177e4SLinus Torvalds } 779*1da177e4SLinus Torvalds 780*1da177e4SLinus Torvalds /* 781*1da177e4SLinus Torvalds * Update voice pitch controller 782*1da177e4SLinus Torvalds */ 783*1da177e4SLinus Torvalds static void snd_opl3_pitch_ctrl(opl3_t *opl3, snd_midi_channel_t *chan) 784*1da177e4SLinus Torvalds { 785*1da177e4SLinus Torvalds int voice; 786*1da177e4SLinus Torvalds snd_opl3_voice_t *vp; 787*1da177e4SLinus Torvalds 788*1da177e4SLinus Torvalds unsigned long flags; 789*1da177e4SLinus Torvalds 790*1da177e4SLinus Torvalds spin_lock_irqsave(&opl3->voice_lock, flags); 791*1da177e4SLinus Torvalds 792*1da177e4SLinus Torvalds if (opl3->synth_mode == SNDRV_OPL3_MODE_SEQ) { 793*1da177e4SLinus Torvalds for (voice = 0; voice < opl3->max_voices; voice++) { 794*1da177e4SLinus Torvalds vp = &opl3->voices[voice]; 795*1da177e4SLinus Torvalds if (vp->state > 0 && vp->chan == chan) { 796*1da177e4SLinus Torvalds snd_opl3_update_pitch(opl3, voice); 797*1da177e4SLinus Torvalds } 798*1da177e4SLinus Torvalds } 799*1da177e4SLinus Torvalds } else { 800*1da177e4SLinus Torvalds /* remap OSS voices */ 801*1da177e4SLinus Torvalds if (chan->number < MAX_OPL3_VOICES) { 802*1da177e4SLinus Torvalds voice = snd_opl3_oss_map[chan->number]; 803*1da177e4SLinus Torvalds snd_opl3_update_pitch(opl3, voice); 804*1da177e4SLinus Torvalds } 805*1da177e4SLinus Torvalds } 806*1da177e4SLinus Torvalds spin_unlock_irqrestore(&opl3->voice_lock, flags); 807*1da177e4SLinus Torvalds } 808*1da177e4SLinus Torvalds 809*1da177e4SLinus Torvalds /* 810*1da177e4SLinus Torvalds * Deal with a controler type event. This includes all types of 811*1da177e4SLinus Torvalds * control events, not just the midi controllers 812*1da177e4SLinus Torvalds */ 813*1da177e4SLinus Torvalds void snd_opl3_control(void *p, int type, snd_midi_channel_t *chan) 814*1da177e4SLinus Torvalds { 815*1da177e4SLinus Torvalds opl3_t *opl3; 816*1da177e4SLinus Torvalds 817*1da177e4SLinus Torvalds opl3 = p; 818*1da177e4SLinus Torvalds #ifdef DEBUG_MIDI 819*1da177e4SLinus Torvalds snd_printk("Controller, TYPE = %i, ch#: %i, inst#: %i\n", 820*1da177e4SLinus Torvalds type, chan->number, chan->midi_program); 821*1da177e4SLinus Torvalds #endif 822*1da177e4SLinus Torvalds 823*1da177e4SLinus Torvalds switch (type) { 824*1da177e4SLinus Torvalds case MIDI_CTL_MSB_MODWHEEL: 825*1da177e4SLinus Torvalds if (chan->control[MIDI_CTL_MSB_MODWHEEL] > 63) 826*1da177e4SLinus Torvalds opl3->drum_reg |= OPL3_VIBRATO_DEPTH; 827*1da177e4SLinus Torvalds else 828*1da177e4SLinus Torvalds opl3->drum_reg &= ~OPL3_VIBRATO_DEPTH; 829*1da177e4SLinus Torvalds opl3->command(opl3, OPL3_LEFT | OPL3_REG_PERCUSSION, 830*1da177e4SLinus Torvalds opl3->drum_reg); 831*1da177e4SLinus Torvalds break; 832*1da177e4SLinus Torvalds case MIDI_CTL_E2_TREMOLO_DEPTH: 833*1da177e4SLinus Torvalds if (chan->control[MIDI_CTL_E2_TREMOLO_DEPTH] > 63) 834*1da177e4SLinus Torvalds opl3->drum_reg |= OPL3_TREMOLO_DEPTH; 835*1da177e4SLinus Torvalds else 836*1da177e4SLinus Torvalds opl3->drum_reg &= ~OPL3_TREMOLO_DEPTH; 837*1da177e4SLinus Torvalds opl3->command(opl3, OPL3_LEFT | OPL3_REG_PERCUSSION, 838*1da177e4SLinus Torvalds opl3->drum_reg); 839*1da177e4SLinus Torvalds break; 840*1da177e4SLinus Torvalds case MIDI_CTL_PITCHBEND: 841*1da177e4SLinus Torvalds snd_opl3_pitch_ctrl(opl3, chan); 842*1da177e4SLinus Torvalds break; 843*1da177e4SLinus Torvalds } 844*1da177e4SLinus Torvalds } 845*1da177e4SLinus Torvalds 846*1da177e4SLinus Torvalds /* 847*1da177e4SLinus Torvalds * NRPN events 848*1da177e4SLinus Torvalds */ 849*1da177e4SLinus Torvalds void snd_opl3_nrpn(void *p, snd_midi_channel_t *chan, 850*1da177e4SLinus Torvalds snd_midi_channel_set_t *chset) 851*1da177e4SLinus Torvalds { 852*1da177e4SLinus Torvalds opl3_t *opl3; 853*1da177e4SLinus Torvalds 854*1da177e4SLinus Torvalds opl3 = p; 855*1da177e4SLinus Torvalds #ifdef DEBUG_MIDI 856*1da177e4SLinus Torvalds snd_printk("NRPN, ch#: %i, inst#: %i\n", 857*1da177e4SLinus Torvalds chan->number, chan->midi_program); 858*1da177e4SLinus Torvalds #endif 859*1da177e4SLinus Torvalds } 860*1da177e4SLinus Torvalds 861*1da177e4SLinus Torvalds /* 862*1da177e4SLinus Torvalds * receive sysex 863*1da177e4SLinus Torvalds */ 864*1da177e4SLinus Torvalds void snd_opl3_sysex(void *p, unsigned char *buf, int len, 865*1da177e4SLinus Torvalds int parsed, snd_midi_channel_set_t *chset) 866*1da177e4SLinus Torvalds { 867*1da177e4SLinus Torvalds opl3_t *opl3; 868*1da177e4SLinus Torvalds 869*1da177e4SLinus Torvalds opl3 = p; 870*1da177e4SLinus Torvalds #ifdef DEBUG_MIDI 871*1da177e4SLinus Torvalds snd_printk("SYSEX\n"); 872*1da177e4SLinus Torvalds #endif 873*1da177e4SLinus Torvalds } 874