162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) by Uros Bizjak <uros@kss-loka.si> 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Midi synth routines for OPL2/OPL3/OPL4 FM 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#undef DEBUG_ALLOC 962306a36Sopenharmony_ci#undef DEBUG_MIDI 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include "opl3_voice.h" 1262306a36Sopenharmony_ci#include <sound/asoundef.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_cistatic void snd_opl3_note_off_unsafe(void *p, int note, int vel, 1562306a36Sopenharmony_ci struct snd_midi_channel *chan); 1662306a36Sopenharmony_ci/* 1762306a36Sopenharmony_ci * The next table looks magical, but it certainly is not. Its values have 1862306a36Sopenharmony_ci * been calculated as table[i]=8*log(i/64)/log(2) with an obvious exception 1962306a36Sopenharmony_ci * for i=0. This log-table converts a linear volume-scaling (0..127) to a 2062306a36Sopenharmony_ci * logarithmic scaling as present in the FM-synthesizer chips. so : Volume 2162306a36Sopenharmony_ci * 64 = 0 db = relative volume 0 and: Volume 32 = -6 db = relative 2262306a36Sopenharmony_ci * volume -8 it was implemented as a table because it is only 128 bytes and 2362306a36Sopenharmony_ci * it saves a lot of log() calculations. (Rob Hooft <hooft@chem.ruu.nl>) 2462306a36Sopenharmony_ci */ 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistatic const char opl3_volume_table[128] = 2762306a36Sopenharmony_ci{ 2862306a36Sopenharmony_ci -63, -48, -40, -35, -32, -29, -27, -26, 2962306a36Sopenharmony_ci -24, -23, -21, -20, -19, -18, -18, -17, 3062306a36Sopenharmony_ci -16, -15, -15, -14, -13, -13, -12, -12, 3162306a36Sopenharmony_ci -11, -11, -10, -10, -10, -9, -9, -8, 3262306a36Sopenharmony_ci -8, -8, -7, -7, -7, -6, -6, -6, 3362306a36Sopenharmony_ci -5, -5, -5, -5, -4, -4, -4, -4, 3462306a36Sopenharmony_ci -3, -3, -3, -3, -2, -2, -2, -2, 3562306a36Sopenharmony_ci -2, -1, -1, -1, -1, 0, 0, 0, 3662306a36Sopenharmony_ci 0, 0, 0, 1, 1, 1, 1, 1, 3762306a36Sopenharmony_ci 1, 2, 2, 2, 2, 2, 2, 2, 3862306a36Sopenharmony_ci 3, 3, 3, 3, 3, 3, 3, 4, 3962306a36Sopenharmony_ci 4, 4, 4, 4, 4, 4, 4, 5, 4062306a36Sopenharmony_ci 5, 5, 5, 5, 5, 5, 5, 5, 4162306a36Sopenharmony_ci 6, 6, 6, 6, 6, 6, 6, 6, 4262306a36Sopenharmony_ci 6, 7, 7, 7, 7, 7, 7, 7, 4362306a36Sopenharmony_ci 7, 7, 7, 8, 8, 8, 8, 8 4462306a36Sopenharmony_ci}; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_civoid snd_opl3_calc_volume(unsigned char *volbyte, int vel, 4762306a36Sopenharmony_ci struct snd_midi_channel *chan) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci int oldvol, newvol, n; 5062306a36Sopenharmony_ci int volume; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci volume = (vel * chan->gm_volume * chan->gm_expression) / (127*127); 5362306a36Sopenharmony_ci if (volume > 127) 5462306a36Sopenharmony_ci volume = 127; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci oldvol = OPL3_TOTAL_LEVEL_MASK - (*volbyte & OPL3_TOTAL_LEVEL_MASK); 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci newvol = opl3_volume_table[volume] + oldvol; 5962306a36Sopenharmony_ci if (newvol > OPL3_TOTAL_LEVEL_MASK) 6062306a36Sopenharmony_ci newvol = OPL3_TOTAL_LEVEL_MASK; 6162306a36Sopenharmony_ci else if (newvol < 0) 6262306a36Sopenharmony_ci newvol = 0; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci n = OPL3_TOTAL_LEVEL_MASK - (newvol & OPL3_TOTAL_LEVEL_MASK); 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci *volbyte = (*volbyte & OPL3_KSL_MASK) | (n & OPL3_TOTAL_LEVEL_MASK); 6762306a36Sopenharmony_ci} 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci/* 7062306a36Sopenharmony_ci * Converts the note frequency to block and fnum values for the FM chip 7162306a36Sopenharmony_ci */ 7262306a36Sopenharmony_cistatic const short opl3_note_table[16] = 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci 305, 323, /* for pitch bending, -2 semitones */ 7562306a36Sopenharmony_ci 343, 363, 385, 408, 432, 458, 485, 514, 544, 577, 611, 647, 7662306a36Sopenharmony_ci 686, 726 /* for pitch bending, +2 semitones */ 7762306a36Sopenharmony_ci}; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cistatic void snd_opl3_calc_pitch(unsigned char *fnum, unsigned char *blocknum, 8062306a36Sopenharmony_ci int note, struct snd_midi_channel *chan) 8162306a36Sopenharmony_ci{ 8262306a36Sopenharmony_ci int block = ((note / 12) & 0x07) - 1; 8362306a36Sopenharmony_ci int idx = (note % 12) + 2; 8462306a36Sopenharmony_ci int freq; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci if (chan->midi_pitchbend) { 8762306a36Sopenharmony_ci int pitchbend = chan->midi_pitchbend; 8862306a36Sopenharmony_ci int segment; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci if (pitchbend < -0x2000) 9162306a36Sopenharmony_ci pitchbend = -0x2000; 9262306a36Sopenharmony_ci if (pitchbend > 0x1FFF) 9362306a36Sopenharmony_ci pitchbend = 0x1FFF; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci segment = pitchbend / 0x1000; 9662306a36Sopenharmony_ci freq = opl3_note_table[idx+segment]; 9762306a36Sopenharmony_ci freq += ((opl3_note_table[idx+segment+1] - freq) * 9862306a36Sopenharmony_ci (pitchbend % 0x1000)) / 0x1000; 9962306a36Sopenharmony_ci } else { 10062306a36Sopenharmony_ci freq = opl3_note_table[idx]; 10162306a36Sopenharmony_ci } 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci *fnum = (unsigned char) freq; 10462306a36Sopenharmony_ci *blocknum = ((freq >> 8) & OPL3_FNUM_HIGH_MASK) | 10562306a36Sopenharmony_ci ((block << 2) & OPL3_BLOCKNUM_MASK); 10662306a36Sopenharmony_ci} 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci#ifdef DEBUG_ALLOC 11062306a36Sopenharmony_cistatic void debug_alloc(struct snd_opl3 *opl3, char *s, int voice) { 11162306a36Sopenharmony_ci int i; 11262306a36Sopenharmony_ci char *str = "x.24"; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci printk(KERN_DEBUG "time %.5i: %s [%.2i]: ", opl3->use_time, s, voice); 11562306a36Sopenharmony_ci for (i = 0; i < opl3->max_voices; i++) 11662306a36Sopenharmony_ci printk(KERN_CONT "%c", *(str + opl3->voices[i].state + 1)); 11762306a36Sopenharmony_ci printk(KERN_CONT "\n"); 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci#endif 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci/* 12262306a36Sopenharmony_ci * Get a FM voice (channel) to play a note on. 12362306a36Sopenharmony_ci */ 12462306a36Sopenharmony_cistatic int opl3_get_voice(struct snd_opl3 *opl3, int instr_4op, 12562306a36Sopenharmony_ci struct snd_midi_channel *chan) { 12662306a36Sopenharmony_ci int chan_4op_1; /* first voice for 4op instrument */ 12762306a36Sopenharmony_ci int chan_4op_2; /* second voice for 4op instrument */ 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci struct snd_opl3_voice *vp, *vp2; 13062306a36Sopenharmony_ci unsigned int voice_time; 13162306a36Sopenharmony_ci int i; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci#ifdef DEBUG_ALLOC 13462306a36Sopenharmony_ci char *alloc_type[3] = { "FREE ", "CHEAP ", "EXPENSIVE" }; 13562306a36Sopenharmony_ci#endif 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci /* This is our "allocation cost" table */ 13862306a36Sopenharmony_ci enum { 13962306a36Sopenharmony_ci FREE = 0, CHEAP, EXPENSIVE, END 14062306a36Sopenharmony_ci }; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci /* Keeps track of what we are finding */ 14362306a36Sopenharmony_ci struct best { 14462306a36Sopenharmony_ci unsigned int time; 14562306a36Sopenharmony_ci int voice; 14662306a36Sopenharmony_ci } best[END]; 14762306a36Sopenharmony_ci struct best *bp; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci for (i = 0; i < END; i++) { 15062306a36Sopenharmony_ci best[i].time = (unsigned int)(-1); /* XXX MAX_?INT really */ 15162306a36Sopenharmony_ci best[i].voice = -1; 15262306a36Sopenharmony_ci } 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci /* Look through all the channels for the most suitable. */ 15562306a36Sopenharmony_ci for (i = 0; i < opl3->max_voices; i++) { 15662306a36Sopenharmony_ci vp = &opl3->voices[i]; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci if (vp->state == SNDRV_OPL3_ST_NOT_AVAIL) 15962306a36Sopenharmony_ci /* skip unavailable channels, allocated by 16062306a36Sopenharmony_ci drum voices or by bounded 4op voices) */ 16162306a36Sopenharmony_ci continue; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci voice_time = vp->time; 16462306a36Sopenharmony_ci bp = best; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci chan_4op_1 = ((i < 3) || (i > 8 && i < 12)); 16762306a36Sopenharmony_ci chan_4op_2 = ((i > 2 && i < 6) || (i > 11 && i < 15)); 16862306a36Sopenharmony_ci if (instr_4op) { 16962306a36Sopenharmony_ci /* allocate 4op voice */ 17062306a36Sopenharmony_ci /* skip channels unavailable to 4op instrument */ 17162306a36Sopenharmony_ci if (!chan_4op_1) 17262306a36Sopenharmony_ci continue; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci if (vp->state) 17562306a36Sopenharmony_ci /* kill one voice, CHEAP */ 17662306a36Sopenharmony_ci bp++; 17762306a36Sopenharmony_ci /* get state of bounded 2op channel 17862306a36Sopenharmony_ci to be allocated for 4op instrument */ 17962306a36Sopenharmony_ci vp2 = &opl3->voices[i + 3]; 18062306a36Sopenharmony_ci if (vp2->state == SNDRV_OPL3_ST_ON_2OP) { 18162306a36Sopenharmony_ci /* kill two voices, EXPENSIVE */ 18262306a36Sopenharmony_ci bp++; 18362306a36Sopenharmony_ci voice_time = max(voice_time, vp2->time); 18462306a36Sopenharmony_ci } 18562306a36Sopenharmony_ci } else { 18662306a36Sopenharmony_ci /* allocate 2op voice */ 18762306a36Sopenharmony_ci if ((chan_4op_1) || (chan_4op_2)) 18862306a36Sopenharmony_ci /* use bounded channels for 2op, CHEAP */ 18962306a36Sopenharmony_ci bp++; 19062306a36Sopenharmony_ci else if (vp->state) 19162306a36Sopenharmony_ci /* kill one voice on 2op channel, CHEAP */ 19262306a36Sopenharmony_ci bp++; 19362306a36Sopenharmony_ci /* raise kill cost to EXPENSIVE for all channels */ 19462306a36Sopenharmony_ci if (vp->state) 19562306a36Sopenharmony_ci bp++; 19662306a36Sopenharmony_ci } 19762306a36Sopenharmony_ci if (voice_time < bp->time) { 19862306a36Sopenharmony_ci bp->time = voice_time; 19962306a36Sopenharmony_ci bp->voice = i; 20062306a36Sopenharmony_ci } 20162306a36Sopenharmony_ci } 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci for (i = 0; i < END; i++) { 20462306a36Sopenharmony_ci if (best[i].voice >= 0) { 20562306a36Sopenharmony_ci#ifdef DEBUG_ALLOC 20662306a36Sopenharmony_ci printk(KERN_DEBUG "%s %iop allocation on voice %i\n", 20762306a36Sopenharmony_ci alloc_type[i], instr_4op ? 4 : 2, 20862306a36Sopenharmony_ci best[i].voice); 20962306a36Sopenharmony_ci#endif 21062306a36Sopenharmony_ci return best[i].voice; 21162306a36Sopenharmony_ci } 21262306a36Sopenharmony_ci } 21362306a36Sopenharmony_ci /* not found */ 21462306a36Sopenharmony_ci return -1; 21562306a36Sopenharmony_ci} 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci/* ------------------------------ */ 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci/* 22062306a36Sopenharmony_ci * System timer interrupt function 22162306a36Sopenharmony_ci */ 22262306a36Sopenharmony_civoid snd_opl3_timer_func(struct timer_list *t) 22362306a36Sopenharmony_ci{ 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci struct snd_opl3 *opl3 = from_timer(opl3, t, tlist); 22662306a36Sopenharmony_ci unsigned long flags; 22762306a36Sopenharmony_ci int again = 0; 22862306a36Sopenharmony_ci int i; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci spin_lock_irqsave(&opl3->voice_lock, flags); 23162306a36Sopenharmony_ci for (i = 0; i < opl3->max_voices; i++) { 23262306a36Sopenharmony_ci struct snd_opl3_voice *vp = &opl3->voices[i]; 23362306a36Sopenharmony_ci if (vp->state > 0 && vp->note_off_check) { 23462306a36Sopenharmony_ci if (vp->note_off == jiffies) 23562306a36Sopenharmony_ci snd_opl3_note_off_unsafe(opl3, vp->note, 0, 23662306a36Sopenharmony_ci vp->chan); 23762306a36Sopenharmony_ci else 23862306a36Sopenharmony_ci again++; 23962306a36Sopenharmony_ci } 24062306a36Sopenharmony_ci } 24162306a36Sopenharmony_ci spin_unlock_irqrestore(&opl3->voice_lock, flags); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci spin_lock_irqsave(&opl3->sys_timer_lock, flags); 24462306a36Sopenharmony_ci if (again) 24562306a36Sopenharmony_ci mod_timer(&opl3->tlist, jiffies + 1); /* invoke again */ 24662306a36Sopenharmony_ci else 24762306a36Sopenharmony_ci opl3->sys_timer_status = 0; 24862306a36Sopenharmony_ci spin_unlock_irqrestore(&opl3->sys_timer_lock, flags); 24962306a36Sopenharmony_ci} 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci/* 25262306a36Sopenharmony_ci * Start system timer 25362306a36Sopenharmony_ci */ 25462306a36Sopenharmony_cistatic void snd_opl3_start_timer(struct snd_opl3 *opl3) 25562306a36Sopenharmony_ci{ 25662306a36Sopenharmony_ci unsigned long flags; 25762306a36Sopenharmony_ci spin_lock_irqsave(&opl3->sys_timer_lock, flags); 25862306a36Sopenharmony_ci if (! opl3->sys_timer_status) { 25962306a36Sopenharmony_ci mod_timer(&opl3->tlist, jiffies + 1); 26062306a36Sopenharmony_ci opl3->sys_timer_status = 1; 26162306a36Sopenharmony_ci } 26262306a36Sopenharmony_ci spin_unlock_irqrestore(&opl3->sys_timer_lock, flags); 26362306a36Sopenharmony_ci} 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci/* ------------------------------ */ 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_cistatic const int snd_opl3_oss_map[MAX_OPL3_VOICES] = { 26962306a36Sopenharmony_ci 0, 1, 2, 9, 10, 11, 6, 7, 8, 15, 16, 17, 3, 4 ,5, 12, 13, 14 27062306a36Sopenharmony_ci}; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci/* 27362306a36Sopenharmony_ci * Start a note. 27462306a36Sopenharmony_ci */ 27562306a36Sopenharmony_civoid snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan) 27662306a36Sopenharmony_ci{ 27762306a36Sopenharmony_ci struct snd_opl3 *opl3; 27862306a36Sopenharmony_ci int instr_4op; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci int voice; 28162306a36Sopenharmony_ci struct snd_opl3_voice *vp, *vp2; 28262306a36Sopenharmony_ci unsigned short connect_mask; 28362306a36Sopenharmony_ci unsigned char connection; 28462306a36Sopenharmony_ci unsigned char vol_op[4]; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci int extra_prg = 0; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci unsigned short reg_side; 28962306a36Sopenharmony_ci unsigned char op_offset; 29062306a36Sopenharmony_ci unsigned char voice_offset; 29162306a36Sopenharmony_ci unsigned short opl3_reg; 29262306a36Sopenharmony_ci unsigned char reg_val; 29362306a36Sopenharmony_ci unsigned char prg, bank; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci int key = note; 29662306a36Sopenharmony_ci unsigned char fnum, blocknum; 29762306a36Sopenharmony_ci int i; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci struct fm_patch *patch; 30062306a36Sopenharmony_ci struct fm_instrument *fm; 30162306a36Sopenharmony_ci unsigned long flags; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci opl3 = p; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci#ifdef DEBUG_MIDI 30662306a36Sopenharmony_ci snd_printk(KERN_DEBUG "Note on, ch %i, inst %i, note %i, vel %i\n", 30762306a36Sopenharmony_ci chan->number, chan->midi_program, note, vel); 30862306a36Sopenharmony_ci#endif 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci /* in SYNTH mode, application takes care of voices */ 31162306a36Sopenharmony_ci /* in SEQ mode, drum voice numbers are notes on drum channel */ 31262306a36Sopenharmony_ci if (opl3->synth_mode == SNDRV_OPL3_MODE_SEQ) { 31362306a36Sopenharmony_ci if (chan->drum_channel) { 31462306a36Sopenharmony_ci /* percussion instruments are located in bank 128 */ 31562306a36Sopenharmony_ci bank = 128; 31662306a36Sopenharmony_ci prg = note; 31762306a36Sopenharmony_ci } else { 31862306a36Sopenharmony_ci bank = chan->gm_bank_select; 31962306a36Sopenharmony_ci prg = chan->midi_program; 32062306a36Sopenharmony_ci } 32162306a36Sopenharmony_ci } else { 32262306a36Sopenharmony_ci /* Prepare for OSS mode */ 32362306a36Sopenharmony_ci if (chan->number >= MAX_OPL3_VOICES) 32462306a36Sopenharmony_ci return; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci /* OSS instruments are located in bank 127 */ 32762306a36Sopenharmony_ci bank = 127; 32862306a36Sopenharmony_ci prg = chan->midi_program; 32962306a36Sopenharmony_ci } 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci spin_lock_irqsave(&opl3->voice_lock, flags); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci if (use_internal_drums) { 33462306a36Sopenharmony_ci snd_opl3_drum_switch(opl3, note, vel, 1, chan); 33562306a36Sopenharmony_ci spin_unlock_irqrestore(&opl3->voice_lock, flags); 33662306a36Sopenharmony_ci return; 33762306a36Sopenharmony_ci } 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci __extra_prg: 34062306a36Sopenharmony_ci patch = snd_opl3_find_patch(opl3, prg, bank, 0); 34162306a36Sopenharmony_ci if (!patch) { 34262306a36Sopenharmony_ci spin_unlock_irqrestore(&opl3->voice_lock, flags); 34362306a36Sopenharmony_ci return; 34462306a36Sopenharmony_ci } 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci fm = &patch->inst; 34762306a36Sopenharmony_ci switch (patch->type) { 34862306a36Sopenharmony_ci case FM_PATCH_OPL2: 34962306a36Sopenharmony_ci instr_4op = 0; 35062306a36Sopenharmony_ci break; 35162306a36Sopenharmony_ci case FM_PATCH_OPL3: 35262306a36Sopenharmony_ci if (opl3->hardware >= OPL3_HW_OPL3) { 35362306a36Sopenharmony_ci instr_4op = 1; 35462306a36Sopenharmony_ci break; 35562306a36Sopenharmony_ci } 35662306a36Sopenharmony_ci fallthrough; 35762306a36Sopenharmony_ci default: 35862306a36Sopenharmony_ci spin_unlock_irqrestore(&opl3->voice_lock, flags); 35962306a36Sopenharmony_ci return; 36062306a36Sopenharmony_ci } 36162306a36Sopenharmony_ci#ifdef DEBUG_MIDI 36262306a36Sopenharmony_ci snd_printk(KERN_DEBUG " --> OPL%i instrument: %s\n", 36362306a36Sopenharmony_ci instr_4op ? 3 : 2, patch->name); 36462306a36Sopenharmony_ci#endif 36562306a36Sopenharmony_ci /* in SYNTH mode, application takes care of voices */ 36662306a36Sopenharmony_ci /* in SEQ mode, allocate voice on free OPL3 channel */ 36762306a36Sopenharmony_ci if (opl3->synth_mode == SNDRV_OPL3_MODE_SEQ) { 36862306a36Sopenharmony_ci voice = opl3_get_voice(opl3, instr_4op, chan); 36962306a36Sopenharmony_ci } else { 37062306a36Sopenharmony_ci /* remap OSS voice */ 37162306a36Sopenharmony_ci voice = snd_opl3_oss_map[chan->number]; 37262306a36Sopenharmony_ci } 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci if (voice < 0) { 37562306a36Sopenharmony_ci spin_unlock_irqrestore(&opl3->voice_lock, flags); 37662306a36Sopenharmony_ci return; 37762306a36Sopenharmony_ci } 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci if (voice < MAX_OPL2_VOICES) { 38062306a36Sopenharmony_ci /* Left register block for voices 0 .. 8 */ 38162306a36Sopenharmony_ci reg_side = OPL3_LEFT; 38262306a36Sopenharmony_ci voice_offset = voice; 38362306a36Sopenharmony_ci connect_mask = (OPL3_LEFT_4OP_0 << voice_offset) & 0x07; 38462306a36Sopenharmony_ci } else { 38562306a36Sopenharmony_ci /* Right register block for voices 9 .. 17 */ 38662306a36Sopenharmony_ci reg_side = OPL3_RIGHT; 38762306a36Sopenharmony_ci voice_offset = voice - MAX_OPL2_VOICES; 38862306a36Sopenharmony_ci connect_mask = (OPL3_RIGHT_4OP_0 << voice_offset) & 0x38; 38962306a36Sopenharmony_ci } 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci /* kill voice on channel */ 39262306a36Sopenharmony_ci vp = &opl3->voices[voice]; 39362306a36Sopenharmony_ci if (vp->state > 0) { 39462306a36Sopenharmony_ci opl3_reg = reg_side | (OPL3_REG_KEYON_BLOCK + voice_offset); 39562306a36Sopenharmony_ci reg_val = vp->keyon_reg & ~OPL3_KEYON_BIT; 39662306a36Sopenharmony_ci opl3->command(opl3, opl3_reg, reg_val); 39762306a36Sopenharmony_ci } 39862306a36Sopenharmony_ci if (instr_4op) { 39962306a36Sopenharmony_ci vp2 = &opl3->voices[voice + 3]; 40062306a36Sopenharmony_ci if (vp2->state > 0) { 40162306a36Sopenharmony_ci opl3_reg = reg_side | (OPL3_REG_KEYON_BLOCK + 40262306a36Sopenharmony_ci voice_offset + 3); 40362306a36Sopenharmony_ci reg_val = vp->keyon_reg & ~OPL3_KEYON_BIT; 40462306a36Sopenharmony_ci opl3->command(opl3, opl3_reg, reg_val); 40562306a36Sopenharmony_ci } 40662306a36Sopenharmony_ci } 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci /* set connection register */ 40962306a36Sopenharmony_ci if (instr_4op) { 41062306a36Sopenharmony_ci if ((opl3->connection_reg ^ connect_mask) & connect_mask) { 41162306a36Sopenharmony_ci opl3->connection_reg |= connect_mask; 41262306a36Sopenharmony_ci /* set connection bit */ 41362306a36Sopenharmony_ci opl3_reg = OPL3_RIGHT | OPL3_REG_CONNECTION_SELECT; 41462306a36Sopenharmony_ci opl3->command(opl3, opl3_reg, opl3->connection_reg); 41562306a36Sopenharmony_ci } 41662306a36Sopenharmony_ci } else { 41762306a36Sopenharmony_ci if ((opl3->connection_reg ^ ~connect_mask) & connect_mask) { 41862306a36Sopenharmony_ci opl3->connection_reg &= ~connect_mask; 41962306a36Sopenharmony_ci /* clear connection bit */ 42062306a36Sopenharmony_ci opl3_reg = OPL3_RIGHT | OPL3_REG_CONNECTION_SELECT; 42162306a36Sopenharmony_ci opl3->command(opl3, opl3_reg, opl3->connection_reg); 42262306a36Sopenharmony_ci } 42362306a36Sopenharmony_ci } 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci#ifdef DEBUG_MIDI 42662306a36Sopenharmony_ci snd_printk(KERN_DEBUG " --> setting OPL3 connection: 0x%x\n", 42762306a36Sopenharmony_ci opl3->connection_reg); 42862306a36Sopenharmony_ci#endif 42962306a36Sopenharmony_ci /* 43062306a36Sopenharmony_ci * calculate volume depending on connection 43162306a36Sopenharmony_ci * between FM operators (see include/opl3.h) 43262306a36Sopenharmony_ci */ 43362306a36Sopenharmony_ci for (i = 0; i < (instr_4op ? 4 : 2); i++) 43462306a36Sopenharmony_ci vol_op[i] = fm->op[i].ksl_level; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci connection = fm->feedback_connection[0] & 0x01; 43762306a36Sopenharmony_ci if (instr_4op) { 43862306a36Sopenharmony_ci connection <<= 1; 43962306a36Sopenharmony_ci connection |= fm->feedback_connection[1] & 0x01; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci snd_opl3_calc_volume(&vol_op[3], vel, chan); 44262306a36Sopenharmony_ci switch (connection) { 44362306a36Sopenharmony_ci case 0x03: 44462306a36Sopenharmony_ci snd_opl3_calc_volume(&vol_op[2], vel, chan); 44562306a36Sopenharmony_ci fallthrough; 44662306a36Sopenharmony_ci case 0x02: 44762306a36Sopenharmony_ci snd_opl3_calc_volume(&vol_op[0], vel, chan); 44862306a36Sopenharmony_ci break; 44962306a36Sopenharmony_ci case 0x01: 45062306a36Sopenharmony_ci snd_opl3_calc_volume(&vol_op[1], vel, chan); 45162306a36Sopenharmony_ci } 45262306a36Sopenharmony_ci } else { 45362306a36Sopenharmony_ci snd_opl3_calc_volume(&vol_op[1], vel, chan); 45462306a36Sopenharmony_ci if (connection) 45562306a36Sopenharmony_ci snd_opl3_calc_volume(&vol_op[0], vel, chan); 45662306a36Sopenharmony_ci } 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci /* Program the FM voice characteristics */ 45962306a36Sopenharmony_ci for (i = 0; i < (instr_4op ? 4 : 2); i++) { 46062306a36Sopenharmony_ci#ifdef DEBUG_MIDI 46162306a36Sopenharmony_ci snd_printk(KERN_DEBUG " --> programming operator %i\n", i); 46262306a36Sopenharmony_ci#endif 46362306a36Sopenharmony_ci op_offset = snd_opl3_regmap[voice_offset][i]; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci /* Set OPL3 AM_VIB register of requested voice/operator */ 46662306a36Sopenharmony_ci reg_val = fm->op[i].am_vib; 46762306a36Sopenharmony_ci opl3_reg = reg_side | (OPL3_REG_AM_VIB + op_offset); 46862306a36Sopenharmony_ci opl3->command(opl3, opl3_reg, reg_val); 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci /* Set OPL3 KSL_LEVEL register of requested voice/operator */ 47162306a36Sopenharmony_ci reg_val = vol_op[i]; 47262306a36Sopenharmony_ci opl3_reg = reg_side | (OPL3_REG_KSL_LEVEL + op_offset); 47362306a36Sopenharmony_ci opl3->command(opl3, opl3_reg, reg_val); 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci /* Set OPL3 ATTACK_DECAY register of requested voice/operator */ 47662306a36Sopenharmony_ci reg_val = fm->op[i].attack_decay; 47762306a36Sopenharmony_ci opl3_reg = reg_side | (OPL3_REG_ATTACK_DECAY + op_offset); 47862306a36Sopenharmony_ci opl3->command(opl3, opl3_reg, reg_val); 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci /* Set OPL3 SUSTAIN_RELEASE register of requested voice/operator */ 48162306a36Sopenharmony_ci reg_val = fm->op[i].sustain_release; 48262306a36Sopenharmony_ci opl3_reg = reg_side | (OPL3_REG_SUSTAIN_RELEASE + op_offset); 48362306a36Sopenharmony_ci opl3->command(opl3, opl3_reg, reg_val); 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci /* Select waveform */ 48662306a36Sopenharmony_ci reg_val = fm->op[i].wave_select; 48762306a36Sopenharmony_ci opl3_reg = reg_side | (OPL3_REG_WAVE_SELECT + op_offset); 48862306a36Sopenharmony_ci opl3->command(opl3, opl3_reg, reg_val); 48962306a36Sopenharmony_ci } 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci /* Set operator feedback and 2op inter-operator connection */ 49262306a36Sopenharmony_ci reg_val = fm->feedback_connection[0]; 49362306a36Sopenharmony_ci /* Set output voice connection */ 49462306a36Sopenharmony_ci reg_val |= OPL3_STEREO_BITS; 49562306a36Sopenharmony_ci if (chan->gm_pan < 43) 49662306a36Sopenharmony_ci reg_val &= ~OPL3_VOICE_TO_RIGHT; 49762306a36Sopenharmony_ci if (chan->gm_pan > 85) 49862306a36Sopenharmony_ci reg_val &= ~OPL3_VOICE_TO_LEFT; 49962306a36Sopenharmony_ci opl3_reg = reg_side | (OPL3_REG_FEEDBACK_CONNECTION + voice_offset); 50062306a36Sopenharmony_ci opl3->command(opl3, opl3_reg, reg_val); 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci if (instr_4op) { 50362306a36Sopenharmony_ci /* Set 4op inter-operator connection */ 50462306a36Sopenharmony_ci reg_val = fm->feedback_connection[1] & OPL3_CONNECTION_BIT; 50562306a36Sopenharmony_ci /* Set output voice connection */ 50662306a36Sopenharmony_ci reg_val |= OPL3_STEREO_BITS; 50762306a36Sopenharmony_ci if (chan->gm_pan < 43) 50862306a36Sopenharmony_ci reg_val &= ~OPL3_VOICE_TO_RIGHT; 50962306a36Sopenharmony_ci if (chan->gm_pan > 85) 51062306a36Sopenharmony_ci reg_val &= ~OPL3_VOICE_TO_LEFT; 51162306a36Sopenharmony_ci opl3_reg = reg_side | (OPL3_REG_FEEDBACK_CONNECTION + 51262306a36Sopenharmony_ci voice_offset + 3); 51362306a36Sopenharmony_ci opl3->command(opl3, opl3_reg, reg_val); 51462306a36Sopenharmony_ci } 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci /* 51762306a36Sopenharmony_ci * Special treatment of percussion notes for fm: 51862306a36Sopenharmony_ci * Requested pitch is really program, and pitch for 51962306a36Sopenharmony_ci * device is whatever was specified in the patch library. 52062306a36Sopenharmony_ci */ 52162306a36Sopenharmony_ci if (fm->fix_key) 52262306a36Sopenharmony_ci note = fm->fix_key; 52362306a36Sopenharmony_ci /* 52462306a36Sopenharmony_ci * use transpose if defined in patch library 52562306a36Sopenharmony_ci */ 52662306a36Sopenharmony_ci if (fm->trnsps) 52762306a36Sopenharmony_ci note += (fm->trnsps - 64); 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci snd_opl3_calc_pitch(&fnum, &blocknum, note, chan); 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci /* Set OPL3 FNUM_LOW register of requested voice */ 53262306a36Sopenharmony_ci opl3_reg = reg_side | (OPL3_REG_FNUM_LOW + voice_offset); 53362306a36Sopenharmony_ci opl3->command(opl3, opl3_reg, fnum); 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci opl3->voices[voice].keyon_reg = blocknum; 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci /* Set output sound flag */ 53862306a36Sopenharmony_ci blocknum |= OPL3_KEYON_BIT; 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci#ifdef DEBUG_MIDI 54162306a36Sopenharmony_ci snd_printk(KERN_DEBUG " --> trigger voice %i\n", voice); 54262306a36Sopenharmony_ci#endif 54362306a36Sopenharmony_ci /* Set OPL3 KEYON_BLOCK register of requested voice */ 54462306a36Sopenharmony_ci opl3_reg = reg_side | (OPL3_REG_KEYON_BLOCK + voice_offset); 54562306a36Sopenharmony_ci opl3->command(opl3, opl3_reg, blocknum); 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci /* kill note after fixed duration (in centiseconds) */ 54862306a36Sopenharmony_ci if (fm->fix_dur) { 54962306a36Sopenharmony_ci opl3->voices[voice].note_off = jiffies + 55062306a36Sopenharmony_ci (fm->fix_dur * HZ) / 100; 55162306a36Sopenharmony_ci snd_opl3_start_timer(opl3); 55262306a36Sopenharmony_ci opl3->voices[voice].note_off_check = 1; 55362306a36Sopenharmony_ci } else 55462306a36Sopenharmony_ci opl3->voices[voice].note_off_check = 0; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci /* get extra pgm, but avoid possible loops */ 55762306a36Sopenharmony_ci extra_prg = (extra_prg) ? 0 : fm->modes; 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci /* do the bookkeeping */ 56062306a36Sopenharmony_ci vp->time = opl3->use_time++; 56162306a36Sopenharmony_ci vp->note = key; 56262306a36Sopenharmony_ci vp->chan = chan; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci if (instr_4op) { 56562306a36Sopenharmony_ci vp->state = SNDRV_OPL3_ST_ON_4OP; 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci vp2 = &opl3->voices[voice + 3]; 56862306a36Sopenharmony_ci vp2->time = opl3->use_time++; 56962306a36Sopenharmony_ci vp2->note = key; 57062306a36Sopenharmony_ci vp2->chan = chan; 57162306a36Sopenharmony_ci vp2->state = SNDRV_OPL3_ST_NOT_AVAIL; 57262306a36Sopenharmony_ci } else { 57362306a36Sopenharmony_ci if (vp->state == SNDRV_OPL3_ST_ON_4OP) { 57462306a36Sopenharmony_ci /* 4op killed by 2op, release bounded voice */ 57562306a36Sopenharmony_ci vp2 = &opl3->voices[voice + 3]; 57662306a36Sopenharmony_ci vp2->time = opl3->use_time++; 57762306a36Sopenharmony_ci vp2->state = SNDRV_OPL3_ST_OFF; 57862306a36Sopenharmony_ci } 57962306a36Sopenharmony_ci vp->state = SNDRV_OPL3_ST_ON_2OP; 58062306a36Sopenharmony_ci } 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci#ifdef DEBUG_ALLOC 58362306a36Sopenharmony_ci debug_alloc(opl3, "note on ", voice); 58462306a36Sopenharmony_ci#endif 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci /* allocate extra program if specified in patch library */ 58762306a36Sopenharmony_ci if (extra_prg) { 58862306a36Sopenharmony_ci if (extra_prg > 128) { 58962306a36Sopenharmony_ci bank = 128; 59062306a36Sopenharmony_ci /* percussions start at 35 */ 59162306a36Sopenharmony_ci prg = extra_prg - 128 + 35 - 1; 59262306a36Sopenharmony_ci } else { 59362306a36Sopenharmony_ci bank = 0; 59462306a36Sopenharmony_ci prg = extra_prg - 1; 59562306a36Sopenharmony_ci } 59662306a36Sopenharmony_ci#ifdef DEBUG_MIDI 59762306a36Sopenharmony_ci snd_printk(KERN_DEBUG " *** allocating extra program\n"); 59862306a36Sopenharmony_ci#endif 59962306a36Sopenharmony_ci goto __extra_prg; 60062306a36Sopenharmony_ci } 60162306a36Sopenharmony_ci spin_unlock_irqrestore(&opl3->voice_lock, flags); 60262306a36Sopenharmony_ci} 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_cistatic void snd_opl3_kill_voice(struct snd_opl3 *opl3, int voice) 60562306a36Sopenharmony_ci{ 60662306a36Sopenharmony_ci unsigned short reg_side; 60762306a36Sopenharmony_ci unsigned char voice_offset; 60862306a36Sopenharmony_ci unsigned short opl3_reg; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci struct snd_opl3_voice *vp, *vp2; 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci if (snd_BUG_ON(voice >= MAX_OPL3_VOICES)) 61362306a36Sopenharmony_ci return; 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci vp = &opl3->voices[voice]; 61662306a36Sopenharmony_ci if (voice < MAX_OPL2_VOICES) { 61762306a36Sopenharmony_ci /* Left register block for voices 0 .. 8 */ 61862306a36Sopenharmony_ci reg_side = OPL3_LEFT; 61962306a36Sopenharmony_ci voice_offset = voice; 62062306a36Sopenharmony_ci } else { 62162306a36Sopenharmony_ci /* Right register block for voices 9 .. 17 */ 62262306a36Sopenharmony_ci reg_side = OPL3_RIGHT; 62362306a36Sopenharmony_ci voice_offset = voice - MAX_OPL2_VOICES; 62462306a36Sopenharmony_ci } 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci /* kill voice */ 62762306a36Sopenharmony_ci#ifdef DEBUG_MIDI 62862306a36Sopenharmony_ci snd_printk(KERN_DEBUG " --> kill voice %i\n", voice); 62962306a36Sopenharmony_ci#endif 63062306a36Sopenharmony_ci opl3_reg = reg_side | (OPL3_REG_KEYON_BLOCK + voice_offset); 63162306a36Sopenharmony_ci /* clear Key ON bit */ 63262306a36Sopenharmony_ci opl3->command(opl3, opl3_reg, vp->keyon_reg); 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci /* do the bookkeeping */ 63562306a36Sopenharmony_ci vp->time = opl3->use_time++; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci if (vp->state == SNDRV_OPL3_ST_ON_4OP) { 63862306a36Sopenharmony_ci vp2 = &opl3->voices[voice + 3]; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci vp2->time = opl3->use_time++; 64162306a36Sopenharmony_ci vp2->state = SNDRV_OPL3_ST_OFF; 64262306a36Sopenharmony_ci } 64362306a36Sopenharmony_ci vp->state = SNDRV_OPL3_ST_OFF; 64462306a36Sopenharmony_ci#ifdef DEBUG_ALLOC 64562306a36Sopenharmony_ci debug_alloc(opl3, "note off", voice); 64662306a36Sopenharmony_ci#endif 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci} 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci/* 65162306a36Sopenharmony_ci * Release a note in response to a midi note off. 65262306a36Sopenharmony_ci */ 65362306a36Sopenharmony_cistatic void snd_opl3_note_off_unsafe(void *p, int note, int vel, 65462306a36Sopenharmony_ci struct snd_midi_channel *chan) 65562306a36Sopenharmony_ci{ 65662306a36Sopenharmony_ci struct snd_opl3 *opl3; 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci int voice; 65962306a36Sopenharmony_ci struct snd_opl3_voice *vp; 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci opl3 = p; 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci#ifdef DEBUG_MIDI 66462306a36Sopenharmony_ci snd_printk(KERN_DEBUG "Note off, ch %i, inst %i, note %i\n", 66562306a36Sopenharmony_ci chan->number, chan->midi_program, note); 66662306a36Sopenharmony_ci#endif 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci if (opl3->synth_mode == SNDRV_OPL3_MODE_SEQ) { 66962306a36Sopenharmony_ci if (chan->drum_channel && use_internal_drums) { 67062306a36Sopenharmony_ci snd_opl3_drum_switch(opl3, note, vel, 0, chan); 67162306a36Sopenharmony_ci return; 67262306a36Sopenharmony_ci } 67362306a36Sopenharmony_ci /* this loop will hopefully kill all extra voices, because 67462306a36Sopenharmony_ci they are grouped by the same channel and note values */ 67562306a36Sopenharmony_ci for (voice = 0; voice < opl3->max_voices; voice++) { 67662306a36Sopenharmony_ci vp = &opl3->voices[voice]; 67762306a36Sopenharmony_ci if (vp->state > 0 && vp->chan == chan && vp->note == note) { 67862306a36Sopenharmony_ci snd_opl3_kill_voice(opl3, voice); 67962306a36Sopenharmony_ci } 68062306a36Sopenharmony_ci } 68162306a36Sopenharmony_ci } else { 68262306a36Sopenharmony_ci /* remap OSS voices */ 68362306a36Sopenharmony_ci if (chan->number < MAX_OPL3_VOICES) { 68462306a36Sopenharmony_ci voice = snd_opl3_oss_map[chan->number]; 68562306a36Sopenharmony_ci snd_opl3_kill_voice(opl3, voice); 68662306a36Sopenharmony_ci } 68762306a36Sopenharmony_ci } 68862306a36Sopenharmony_ci} 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_civoid snd_opl3_note_off(void *p, int note, int vel, 69162306a36Sopenharmony_ci struct snd_midi_channel *chan) 69262306a36Sopenharmony_ci{ 69362306a36Sopenharmony_ci struct snd_opl3 *opl3 = p; 69462306a36Sopenharmony_ci unsigned long flags; 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci spin_lock_irqsave(&opl3->voice_lock, flags); 69762306a36Sopenharmony_ci snd_opl3_note_off_unsafe(p, note, vel, chan); 69862306a36Sopenharmony_ci spin_unlock_irqrestore(&opl3->voice_lock, flags); 69962306a36Sopenharmony_ci} 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci/* 70262306a36Sopenharmony_ci * key pressure change 70362306a36Sopenharmony_ci */ 70462306a36Sopenharmony_civoid snd_opl3_key_press(void *p, int note, int vel, struct snd_midi_channel *chan) 70562306a36Sopenharmony_ci{ 70662306a36Sopenharmony_ci#ifdef DEBUG_MIDI 70762306a36Sopenharmony_ci snd_printk(KERN_DEBUG "Key pressure, ch#: %i, inst#: %i\n", 70862306a36Sopenharmony_ci chan->number, chan->midi_program); 70962306a36Sopenharmony_ci#endif 71062306a36Sopenharmony_ci} 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci/* 71362306a36Sopenharmony_ci * terminate note 71462306a36Sopenharmony_ci */ 71562306a36Sopenharmony_civoid snd_opl3_terminate_note(void *p, int note, struct snd_midi_channel *chan) 71662306a36Sopenharmony_ci{ 71762306a36Sopenharmony_ci#ifdef DEBUG_MIDI 71862306a36Sopenharmony_ci snd_printk(KERN_DEBUG "Terminate note, ch#: %i, inst#: %i\n", 71962306a36Sopenharmony_ci chan->number, chan->midi_program); 72062306a36Sopenharmony_ci#endif 72162306a36Sopenharmony_ci} 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_cistatic void snd_opl3_update_pitch(struct snd_opl3 *opl3, int voice) 72462306a36Sopenharmony_ci{ 72562306a36Sopenharmony_ci unsigned short reg_side; 72662306a36Sopenharmony_ci unsigned char voice_offset; 72762306a36Sopenharmony_ci unsigned short opl3_reg; 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci unsigned char fnum, blocknum; 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci struct snd_opl3_voice *vp; 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci if (snd_BUG_ON(voice >= MAX_OPL3_VOICES)) 73462306a36Sopenharmony_ci return; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci vp = &opl3->voices[voice]; 73762306a36Sopenharmony_ci if (vp->chan == NULL) 73862306a36Sopenharmony_ci return; /* not allocated? */ 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci if (voice < MAX_OPL2_VOICES) { 74162306a36Sopenharmony_ci /* Left register block for voices 0 .. 8 */ 74262306a36Sopenharmony_ci reg_side = OPL3_LEFT; 74362306a36Sopenharmony_ci voice_offset = voice; 74462306a36Sopenharmony_ci } else { 74562306a36Sopenharmony_ci /* Right register block for voices 9 .. 17 */ 74662306a36Sopenharmony_ci reg_side = OPL3_RIGHT; 74762306a36Sopenharmony_ci voice_offset = voice - MAX_OPL2_VOICES; 74862306a36Sopenharmony_ci } 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci snd_opl3_calc_pitch(&fnum, &blocknum, vp->note, vp->chan); 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci /* Set OPL3 FNUM_LOW register of requested voice */ 75362306a36Sopenharmony_ci opl3_reg = reg_side | (OPL3_REG_FNUM_LOW + voice_offset); 75462306a36Sopenharmony_ci opl3->command(opl3, opl3_reg, fnum); 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci vp->keyon_reg = blocknum; 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci /* Set output sound flag */ 75962306a36Sopenharmony_ci blocknum |= OPL3_KEYON_BIT; 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci /* Set OPL3 KEYON_BLOCK register of requested voice */ 76262306a36Sopenharmony_ci opl3_reg = reg_side | (OPL3_REG_KEYON_BLOCK + voice_offset); 76362306a36Sopenharmony_ci opl3->command(opl3, opl3_reg, blocknum); 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci vp->time = opl3->use_time++; 76662306a36Sopenharmony_ci} 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci/* 76962306a36Sopenharmony_ci * Update voice pitch controller 77062306a36Sopenharmony_ci */ 77162306a36Sopenharmony_cistatic void snd_opl3_pitch_ctrl(struct snd_opl3 *opl3, struct snd_midi_channel *chan) 77262306a36Sopenharmony_ci{ 77362306a36Sopenharmony_ci int voice; 77462306a36Sopenharmony_ci struct snd_opl3_voice *vp; 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci unsigned long flags; 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci spin_lock_irqsave(&opl3->voice_lock, flags); 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci if (opl3->synth_mode == SNDRV_OPL3_MODE_SEQ) { 78162306a36Sopenharmony_ci for (voice = 0; voice < opl3->max_voices; voice++) { 78262306a36Sopenharmony_ci vp = &opl3->voices[voice]; 78362306a36Sopenharmony_ci if (vp->state > 0 && vp->chan == chan) { 78462306a36Sopenharmony_ci snd_opl3_update_pitch(opl3, voice); 78562306a36Sopenharmony_ci } 78662306a36Sopenharmony_ci } 78762306a36Sopenharmony_ci } else { 78862306a36Sopenharmony_ci /* remap OSS voices */ 78962306a36Sopenharmony_ci if (chan->number < MAX_OPL3_VOICES) { 79062306a36Sopenharmony_ci voice = snd_opl3_oss_map[chan->number]; 79162306a36Sopenharmony_ci snd_opl3_update_pitch(opl3, voice); 79262306a36Sopenharmony_ci } 79362306a36Sopenharmony_ci } 79462306a36Sopenharmony_ci spin_unlock_irqrestore(&opl3->voice_lock, flags); 79562306a36Sopenharmony_ci} 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci/* 79862306a36Sopenharmony_ci * Deal with a controller type event. This includes all types of 79962306a36Sopenharmony_ci * control events, not just the midi controllers 80062306a36Sopenharmony_ci */ 80162306a36Sopenharmony_civoid snd_opl3_control(void *p, int type, struct snd_midi_channel *chan) 80262306a36Sopenharmony_ci{ 80362306a36Sopenharmony_ci struct snd_opl3 *opl3; 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci opl3 = p; 80662306a36Sopenharmony_ci#ifdef DEBUG_MIDI 80762306a36Sopenharmony_ci snd_printk(KERN_DEBUG "Controller, TYPE = %i, ch#: %i, inst#: %i\n", 80862306a36Sopenharmony_ci type, chan->number, chan->midi_program); 80962306a36Sopenharmony_ci#endif 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci switch (type) { 81262306a36Sopenharmony_ci case MIDI_CTL_MSB_MODWHEEL: 81362306a36Sopenharmony_ci if (chan->control[MIDI_CTL_MSB_MODWHEEL] > 63) 81462306a36Sopenharmony_ci opl3->drum_reg |= OPL3_VIBRATO_DEPTH; 81562306a36Sopenharmony_ci else 81662306a36Sopenharmony_ci opl3->drum_reg &= ~OPL3_VIBRATO_DEPTH; 81762306a36Sopenharmony_ci opl3->command(opl3, OPL3_LEFT | OPL3_REG_PERCUSSION, 81862306a36Sopenharmony_ci opl3->drum_reg); 81962306a36Sopenharmony_ci break; 82062306a36Sopenharmony_ci case MIDI_CTL_E2_TREMOLO_DEPTH: 82162306a36Sopenharmony_ci if (chan->control[MIDI_CTL_E2_TREMOLO_DEPTH] > 63) 82262306a36Sopenharmony_ci opl3->drum_reg |= OPL3_TREMOLO_DEPTH; 82362306a36Sopenharmony_ci else 82462306a36Sopenharmony_ci opl3->drum_reg &= ~OPL3_TREMOLO_DEPTH; 82562306a36Sopenharmony_ci opl3->command(opl3, OPL3_LEFT | OPL3_REG_PERCUSSION, 82662306a36Sopenharmony_ci opl3->drum_reg); 82762306a36Sopenharmony_ci break; 82862306a36Sopenharmony_ci case MIDI_CTL_PITCHBEND: 82962306a36Sopenharmony_ci snd_opl3_pitch_ctrl(opl3, chan); 83062306a36Sopenharmony_ci break; 83162306a36Sopenharmony_ci } 83262306a36Sopenharmony_ci} 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci/* 83562306a36Sopenharmony_ci * NRPN events 83662306a36Sopenharmony_ci */ 83762306a36Sopenharmony_civoid snd_opl3_nrpn(void *p, struct snd_midi_channel *chan, 83862306a36Sopenharmony_ci struct snd_midi_channel_set *chset) 83962306a36Sopenharmony_ci{ 84062306a36Sopenharmony_ci#ifdef DEBUG_MIDI 84162306a36Sopenharmony_ci snd_printk(KERN_DEBUG "NRPN, ch#: %i, inst#: %i\n", 84262306a36Sopenharmony_ci chan->number, chan->midi_program); 84362306a36Sopenharmony_ci#endif 84462306a36Sopenharmony_ci} 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci/* 84762306a36Sopenharmony_ci * receive sysex 84862306a36Sopenharmony_ci */ 84962306a36Sopenharmony_civoid snd_opl3_sysex(void *p, unsigned char *buf, int len, 85062306a36Sopenharmony_ci int parsed, struct snd_midi_channel_set *chset) 85162306a36Sopenharmony_ci{ 85262306a36Sopenharmony_ci#ifdef DEBUG_MIDI 85362306a36Sopenharmony_ci snd_printk(KERN_DEBUG "SYSEX\n"); 85462306a36Sopenharmony_ci#endif 85562306a36Sopenharmony_ci} 856