#define BANK_MAX 64 #define BANK_KEEP 0x01 #define BANK_UNKN 0x02 typedef struct _bank_voice bank_voice; typedef struct _bank_key bank_key; typedef struct _bank_channel bank_channel; typedef struct _bank_handle bank_handle; struct _bank_voice { bank_channel *channel; opl3_channel *opl; uint8_t note; uint8_t op; int16_t detune; bank_voice *pair; }; struct _bank_key { uint8_t note; uint8_t velocity; bank_voice *voice; }; struct _bank_channel { bank_handle *bank; bank_key keys[BANK_MAX]; uint8_t notes[128]; uint8_t keyindex; uint8_t active; uint16_t pbank; int8_t pan; uint8_t volume; int16_t pitch; uint8_t program; bank_instr *instr; uint8_t ch_num; }; struct _bank_handle { bank_channel channel[16]; bank_voice *voices; bank_instr *bdata; uint16_t voiceindex; uint16_t v_avail; uint16_t v_used; uint8_t flags; int8_t velo_func; }; void bank_reset(opl3_chip *chip, bank_handle *bank) { uint16_t voices = chip->n_voices; uint8_t flags = bank->flags; int8_t velo_func = bank->velo_func; bank_instr *instr = bank->bdata; uint8_t *bankdata = (uint8_t*)bank; bankdata += sizeof(bank_handle); memset(bank, 0, sizeof(bank_handle)); bank->voices = (bank_voice*)bankdata; bank->v_avail = voices; bank->flags = flags; bank->velo_func = velo_func; bank->bdata = instr; for(int h = 0; h < 16; h++) { bank_channel *channel = &bank->channel[h]; channel->bank = bank; memset(channel->notes, 0xff, 128); channel->volume = 127; channel->pbank = (h == 9) ? 128 : 0; channel->instr = &bank->bdata[(h == 9) ? 128 : 0]; channel->ch_num = h; } for(int h = 0; h < voices; h++) { bank_voice *voice = &bank->voices[h]; voice->channel = NULL; voice->opl = &chip->channel[h]; voice->note = 0xff; voice->op = b_op2; voice->detune = 0; voice->pair = &bank->voices[h+(((h & 1) == 0) ? 1 : -1)]; } } bank_handle *bank_alloc(opl3_chip *chip, bank_instr *instr, uint8_t keep, uint8_t useunkn, int8_t velofunc) { uint8_t *bankdata = malloc(sizeof(bank_handle) + (sizeof(bank_voice) * chip->n_voices)); bank_handle *bank = (bank_handle*)bankdata; bank->flags = (keep ? BANK_KEEP : 0) | (useunkn ? BANK_UNKN : 0); bank->velo_func = velofunc; bank->bdata = instr; bank_reset(chip, bank); return bank; } static const uint32_t bank_notes[] = { 8175, 8661, 9177, 9722, 10300, 10913, 11562, 12249, 12978, 13750, 14567, 15433, 16351, 17323, 18354, 19445, 20601, 21826, 23124, 24499, 25956, 27500, 29135, 30867, 32703, 34647, 36708, 38890, 41203, 43653, 46249, 48999, 51913, 55000, 58270, 61735, 65406, 69295, 73416, 77781, 82406, 87307, 92498, 97998, 103826, 110000, 116540, 123470, 130812, 138591, 146832, 155563, 164813, 174614, 184997, 195997, 207652, 220000, 233081, 246941, 261625, 277182, 293664, 311126, 329627, 349228, 369994, 391995, 415304, 440000, 466163, 493883, 523251, 554365, 587329, 622253, 659255, 698456, 739988, 783990, 830609, 880000, 932327, 987766, 1046502, 1108730, 1174659, 1244507, 1318510, 1396912, 1479977, 1567981, 1661218, 1760000, 1864655, 1975533, 2093004, 2217461, 2349318, 2489015, 2637020, 2793825, 2959955, 3135963, 3322437, 3520000, 3729310, 3951066, 4186009, 4434922, 4698636, 4978031, 5274040, 5587651, 5919910, 6271926, 6644875, 7040000, 7458620, 7902132, 8372018, 8869844, 9397272, 9956063, 10548081, 11175303, 11839821, 12543853 }; static const uint32_t opl3_maxfreq[] = { 48503, 97006, 194013, 388026, 776053, 1552107, 3104215, 6208431 }; uint8_t bank_getnote(bank_channel *ch, uint8_t key, uint8_t id, uint8_t drum, bank_instr *instr) { int16_t note = (int16_t)key; if(instr->fixed /* || drum */) { note = ((int16_t)instr->percnum) + instr->channels[id].offset; } else { note += instr->channels[id].offset; } note = note < 0 ? 0 : note; note = note > 127 ? 127 : note; return (uint8_t)note; } static void OPL3_ChannelFreqHz(opl3_channel *channel, uint32_t freq) { uint32_t block = 0; while(opl3_maxfreq[block] < freq) { block++; if(block == 8) { break; } } if(block == 8) { OPL3_ChannelFreq(channel, 7, 1023); return; } double f_num = ((double)freq) / 1000.0 * pow(2.0, (20.0-((double)block))) / 49716.0; OPL3_ChannelFreq(channel, block, (uint32_t)f_num); } #define BANK_PBRANGE 2.0 uint32_t bank_getfreq(uint8_t key, int16_t pitch, int16_t detune) { double pfrq = pow(2.0, ((((double)pitch) / 8191.0 * BANK_PBRANGE) + (((double)detune) / 100.0)) / 12.0); double freq = ((double)bank_notes[key]) * pfrq; return (uint32_t)freq; } static void OPL3_ChannelNote(opl3_channel *channel, uint8_t key, int16_t pitch, int16_t detune) { OPL3_ChannelFreqHz(channel, bank_getfreq(key, pitch, detune)); } #define BANK_VELOFUNC(x, n) (1.0-log(1.0+((1.0-pow(x,n))*(M_E-1.0)))) uint32_t bank_getlevel(int8_t function, uint8_t velocity, uint8_t volume, int8_t pan) { double lvl = ((function == -128) ? 1.0 : (function ? BANK_VELOFUNC(((double)velocity)/127.0, function < 0 ? (0.1+(1.0-((((double)(-function))-1.0)/126.0))*9.9) : (1.0+((((double)function)-1.0)/126.0)*9.0)) : (((double)velocity)/127.0))) * (((double)volume)/127.0) * (1.0-(0.9*((double)pan)/63.0)); // fprintf(stderr, "%d===%d-->%.2f\n", function, velocity, lvl); lvl *= 65536.0; return (uint32_t)lvl; } static void OPL3_ChannelLevelPan(opl3_channel *channel, int8_t function, uint8_t velocity, uint8_t volume, int8_t pan) { OPL3_ChannelOutput(channel, 0, bank_getlevel(function, velocity, volume, pan)); OPL3_ChannelOutput(channel, 1, bank_getlevel(function, velocity, volume, -pan)); } void bank_release_voice(bank_handle *bank, bank_channel *ch, bank_voice *voice) { if(voice->note == 0xff) { return; } OPL3_ChannelKeyOff(voice->opl); voice->note = 0xff; if(voice->op == b_op22) { voice->pair->note = 0xff; OPL3_ChannelKeyOff(voice->pair->opl); bank->v_used -= 2; } else if(voice->op == b_op4) { voice->pair->note = 0xff; bank->v_used -= 2; } else { bank->v_used -= 1; } } bank_voice *bank_release_key(bank_channel *ch, uint8_t note) { if(ch->active == 0) { return NULL; } if(ch->notes[note] == 0xff) { return NULL; } bank_key *key = &ch->keys[ch->notes[note]]; ch->notes[note] = 0xff; ch->active -= 1; if(key->voice) { bank_release_voice(ch->bank, ch, key->voice); } key->velocity = 0; return key->voice; } void bank_init_voice(opl3_channel *channel, bank_instr *instr, uint8_t id) { OPL3_Channel4Op(channel, instr->op == b_op4); for(int o = 0; o < ((instr->op == b_op4) ? 4 : 2); o++) { bank_pair *pair = &instr->channels[(instr->op == b_op4) ? (o >> 1) : id]; bank_operator *op = &pair->ops[o & 1]; opl3_slot *slot = (o >= 2) ? (channel->pair->slots[o & 1]) : (channel->slots[o & 1]); OPL3_SlotFlags(slot, op->tremolo, op->vibrato, op->sustaining, op->ksr); OPL3_SlotMult(slot, op->mult); OPL3_SlotKSL(slot, op->ksl); OPL3_SlotLevel(slot, op->level); OPL3_SlotADSR(slot, op->attack, op->decay, op->sustain, op->release); OPL3_SlotWaveform(slot, op->waveform); if((o & 1) == 1) { opl3_channel *chn = (o >= 2) ? channel->pair : channel; OPL3_ChannelFeedback(chn, pair->feedback); OPL3_ChannelAM(chn, pair->am); } } } bank_voice *bank_get_voice(bank_handle *bank, bank_channel *ch, uint8_t note, uint8_t velocity) { bank_instr *instr = ch->instr; if(ch->pbank == 128) { instr += note; } else if((ch->pbank != 0) && (!(bank->flags & BANK_UNKN))) { return NULL; } if(instr->op == b_op0) { return NULL; } if(bank->v_used == bank->v_avail) { if(bank->flags & BANK_KEEP) { return NULL; } if((instr->op != b_op2) && ((bank->voiceindex & 1) != 0)) { bank->voiceindex += 1; if(bank->voiceindex >= bank->v_avail) { bank->voiceindex = 0; } } bank_release_key(bank->voices[bank->voiceindex].channel, bank->voices[bank->voiceindex].note); } else if((instr->op != b_op2) && ((bank->voiceindex & 1) != 0)) { bank->voiceindex += 1; if(bank->voiceindex >= bank->v_avail) { bank->voiceindex = 0; } } uint8_t vi = bank->voiceindex; while((bank->voices[bank->voiceindex].note != 0xff) || ((instr->op != b_op2) && (bank->voices[bank->voiceindex+1].note != 0xff))) { bank->voiceindex += (instr->op != b_op2) ? 2 : 1; if(bank->voiceindex >= bank->v_avail) { bank->voiceindex = 0; } if(vi == bank->voiceindex) { if(bank->flags & BANK_KEEP) { return NULL; } bank_release_key(bank->voices[bank->voiceindex].channel, bank->voices[bank->voiceindex].note); if((instr->op != b_op2) && (bank->voices[bank->voiceindex+1].note != 0xff)) { bank_release_key(bank->voices[bank->voiceindex+1].channel, bank->voices[bank->voiceindex+1].note); } break; } } bank_voice *voice = &bank->voices[bank->voiceindex]; if((instr->op == b_op2) && (voice->op == b_op4)) { int16_t offset = ((int16_t)bank->voiceindex) + (((bank->voiceindex & 1) == 0) ? 1 : -1); bank_voice *voice2 = &bank->voices[offset]; if(voice2->note == 0xff) { OPL3_ChannelOutput(voice2->opl, 0, 0); OPL3_ChannelOutput(voice2->opl, 1, 0); } } bank->voiceindex += (instr->op != b_op2) ? 2 : 1; if(bank->voiceindex >= bank->v_avail) { bank->voiceindex = 0; } voice->channel = ch; voice->note = note; voice->op = instr->op; voice->detune = instr->channels[0].detune; bank_init_voice(voice->opl, instr, 0); if(voice->op == b_op22) { voice->pair->channel = ch; voice->pair->note = note; voice->pair->op = b_op22; voice->pair->detune = instr->channels[1].detune; bank_init_voice(voice->pair->opl, instr, 1); OPL3_ChannelNote(voice->opl, bank_getnote(ch, note, 0, ch->pbank == 128, instr), ch->pitch, voice->detune); OPL3_ChannelNote(voice->pair->opl, bank_getnote(ch, note, 1, ch->pbank == 128, instr), ch->pitch, voice->pair->detune); OPL3_ChannelLevelPan(voice->opl, bank->velo_func, velocity, ch->volume, ch->pan); OPL3_ChannelLevelPan(voice->pair->opl, bank->velo_func, velocity, ch->volume, ch->pan); OPL3_ChannelKeyOn(voice->opl); OPL3_ChannelKeyOn(voice->pair->opl); bank->v_used += 2; } else if(voice->op == b_op4) { voice->pair->channel = ch; voice->pair->note = note; voice->pair->op = b_op4; OPL3_ChannelNote(voice->opl, bank_getnote(ch, note, 0, ch->pbank == 128, instr), ch->pitch, voice->detune); OPL3_ChannelLevelPan(voice->opl, bank->velo_func, velocity, ch->volume, ch->pan); OPL3_ChannelKeyOn(voice->opl); bank->v_used += 2; } else { OPL3_ChannelNote(voice->opl, bank_getnote(ch, note, 0, ch->pbank == 128, instr), ch->pitch, voice->detune); OPL3_ChannelLevelPan(voice->opl, bank->velo_func, velocity, ch->volume, ch->pan); OPL3_ChannelKeyOn(voice->opl); bank->v_used += 1; } return voice; } bank_voice *bank_press_key(bank_channel *ch, uint8_t note, uint8_t velocity) { if(ch->notes[note] != 0xff) { bank_release_key(ch, note); } if(ch->active == BANK_MAX) { return NULL; } uint8_t ki = ch->keyindex; while(ch->keys[ch->keyindex].velocity != 0) { ch->keyindex += 1; if(ch->keyindex == BANK_MAX) { ch->keyindex = 0; } if(ki == ch->keyindex) { return NULL; } } bank_voice *voice = bank_get_voice(ch->bank, ch, note, velocity); ch->notes[note] = ch->keyindex; ch->active += 1; bank_key *key = &ch->keys[ch->keyindex]; key->note = note; key->velocity = velocity; key->voice = voice; return voice; } void bank_notesoff(bank_channel *ch) { for(int h = 0; (h < BANK_MAX) && (ch->active > 0); h++) { bank_release_key(ch, h); } } void bank_progupdate(bank_channel *ch, opl3_chip *chip) { bank_notesoff(ch); uint16_t id = ch->program; if(ch->pbank == 128) { id = 128; } else if((ch->pbank != 0) && (!(ch->bank->flags & BANK_UNKN))) { id = 0; } ch->instr = (ch->bank->bdata)+id; } void bank_levelupdate(bank_channel *ch, opl3_chip *chip) { uint8_t done = 0; for(int h = 0; (h < BANK_MAX) && (done < ch->active); h++) { bank_key *key = (ch->keys)+h; if((key->velocity == 0) || (key->voice == NULL)) { continue; } OPL3_ChannelLevelPan(key->voice->opl, ch->bank->velo_func, key->velocity, ch->volume, ch->pan); if(key->voice->op == b_op22) { OPL3_ChannelLevelPan(key->voice->pair->opl, ch->bank->velo_func, key->velocity, ch->volume, ch->pan); } done++; } } void bank_frequpdate(bank_channel *ch, opl3_chip *chip) { uint8_t done = 0; for(int h = 0; (h < BANK_MAX) && (done < ch->active); h++) { bank_key *key = (ch->keys)+h; if((key->velocity == 0) || (key->voice == NULL)) { continue; } OPL3_ChannelNote(key->voice->opl, bank_getnote(ch, key->note, 0, ch->pbank == 128, ch->instr), ch->pitch, key->voice->detune); if(key->voice->op == b_op22) { OPL3_ChannelNote(key->voice->pair->opl, bank_getnote(ch, key->note, 1, ch->pbank == 128, ch->instr), ch->pitch, key->voice->pair->detune); } done++; } } void bank_noteon(bank_handle *bank, opl3_chip *chip, uint8_t channel, uint8_t key, uint8_t velocity) { bank_channel *ch = &bank->channel[channel]; // if((ch->pbank == 128) && ((key < 35) || (key > 81))) { // return; // } bank_press_key(ch, key, velocity); } void bank_noteoff(bank_handle *bank, opl3_chip *chip, uint8_t channel, uint8_t key, uint8_t velocity) { bank_channel *ch = &bank->channel[channel]; // if((ch->pbank == 128) && ((key < 35) || (key > 81))) { // return; // } bank_release_key(ch, key); } void bank_progchange(bank_handle *bank, opl3_chip *chip, uint8_t channel, uint8_t program) { bank_channel *ch = &bank->channel[channel]; ch->program = program; bank_progupdate(ch, chip); } void bank_pitchbend(bank_handle *bank, opl3_chip *chip, uint8_t channel, int16_t pitch) { bank_channel *ch = &bank->channel[channel]; ch->pitch = pitch; bank_frequpdate(ch, chip); } void bank_control(bank_handle *bank, opl3_chip *chip, uint8_t channel, uint8_t control, uint8_t value) { bank_channel *ch = &bank->channel[channel]; switch(control) { case 0x00: // bank MSB // if((channel == 9) && (value == 0)) { // ch->pbank = 128; // } // else { if(channel != 9) { ch->pbank &= 0x007f; ch->pbank |= (((uint16_t)value) << 7) & 0x3f80; } bank_progupdate(ch, chip); break; case 0x20: // bank LSB // if((channel == 9) && (value == 0)) { // ch->pbank = 128; // } // else { if(channel != 9) { ch->pbank &= 0x3f80; ch->pbank |= ((uint16_t)value) & 0x007f; } bank_progupdate(ch, chip); break; case 0x07: // volume MSB ch->volume = value; bank_levelupdate(ch, chip); break; case 0x0a: // pan MSB ch->pan = ((int8_t)value) - 64; bank_levelupdate(ch, chip); break; case 0x79: // reset ch->pbank = (channel == 9) ? 128 : 0; ch->volume = 127; ch->pan = 0; bank_progupdate(ch, chip); bank_levelupdate(ch, chip); break; case 0x7b: // all off bank_notesoff(ch); break; } } void bank_alloff(bank_handle *bank) { for(int h = 0; h < 16; h++) { bank_notesoff(&bank->channel[h]); } }