oplplayer/bank.h
2025-03-20 11:02:57 +01:00

487 lines
No EOL
15 KiB
C

#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]);
}
}