diff options
-rw-r--r-- | src/adlmidi_bankmap.h | 1 | ||||
-rw-r--r-- | src/adlmidi_load.cpp | 40 | ||||
-rw-r--r-- | src/adlmidi_midiplay.cpp | 80 | ||||
-rw-r--r-- | src/adlmidi_opl3.cpp | 55 | ||||
-rw-r--r-- | src/adlmidi_private.cpp | 23 | ||||
-rw-r--r-- | src/adlmidi_private.hpp | 29 |
6 files changed, 110 insertions, 118 deletions
diff --git a/src/adlmidi_bankmap.h b/src/adlmidi_bankmap.h index 43921b8..9b71d8f 100644 --- a/src/adlmidi_bankmap.h +++ b/src/adlmidi_bankmap.h @@ -27,6 +27,7 @@ #include <list> #include <utility> #include <stdint.h> +#include <stddef.h> #include "adlmidi_ptr.hpp" diff --git a/src/adlmidi_load.cpp b/src/adlmidi_load.cpp index 54899c0..8deb3b9 100644 --- a/src/adlmidi_load.cpp +++ b/src/adlmidi_load.cpp @@ -72,7 +72,7 @@ bool MIDIplay::LoadBank(const void *data, size_t size) return LoadBank(file); } -static void cvt_WOPLI_to_FMIns(adlinsdata2 &ins, WOPLInstrument &in) +static void cvt_WOPLI_to_FMIns(adlinsdata2 &ins, const WOPLInstrument &in) { ins.voice2_fine_tune = 0.0; int8_t voice2_fine_tune = in.second_voice_detune; @@ -188,40 +188,32 @@ bool MIDIplay::LoadBank(MIDIplay::fileReader &fr) m_setup.HighVibratoMode = -1; m_setup.VolumeModel = ADLMIDI_VolumeModel_AUTO; - /* TODO: Avoid memory reallocation in nearest future! */ - opl.dynamic_melodic_banks.clear(); - opl.dynamic_percussion_banks.clear(); - opl.dynamic_metainstruments.clear(); - opl.dynamic_percussion_offset = 0; - opl.setEmbeddedBank(m_setup.AdlBank); - OPL3::BankMap *slots_banks[2] = { &opl.dynamic_melodic_banks, &opl.dynamic_percussion_banks}; uint16_t slots_counts[2] = {wopl->banks_count_melodic, wopl->banks_count_percussion}; WOPLBank *slots_src_ins[2] = { wopl->banks_melodic, wopl->banks_percussive }; - for(int ss = 0; ss < 2; ss++) + for(unsigned ss = 0; ss < 2; ss++) { - for(int i = 0; i < slots_counts[ss]; i++) + for(unsigned i = 0; i < slots_counts[ss]; i++) { - uint16_t bank = (slots_src_ins[ss][i].bank_midi_msb * 256) + slots_src_ins[ss][i].bank_midi_lsb; - size_t offset = slots_banks[ss]->size(); - (*slots_banks[ss])[bank] = offset; - + unsigned bankno = + (slots_src_ins[ss][i].bank_midi_msb * 256) + + slots_src_ins[ss][i].bank_midi_lsb + + (ss ? OPL3::PercussionTag : 0); + OPL3::Bank &bank = opl.dynamic_banks[bankno]; for(int j = 0; j < 128; j++) { - adlinsdata2 ins; + adlinsdata2 &ins = bank.ins[j]; std::memset(&ins, 0, sizeof(adlinsdata2)); WOPLInstrument &inIns = slots_src_ins[ss][i].ins[j]; cvt_WOPLI_to_FMIns(ins, inIns); - opl.dynamic_metainstruments.push_back(ins); } } } opl.AdlBank = ~0u; // Use dynamic banks! //Percussion offset is count of instruments multipled to count of melodic banks - opl.dynamic_percussion_offset = 128 * wopl->banks_count_melodic; applySetup(); WOPL_Free(wopl); @@ -379,8 +371,7 @@ riffskip: #endif //ADLMIDI_DISABLE_XMI_SUPPORT else if(std::memcmp(HeaderBuf, "CTMF", 4) == 0) { - opl.dynamic_instruments.clear(); - opl.dynamic_metainstruments.clear(); + opl.dynamic_banks.clear(); // Creative Music Format (CMF). // When playing CTMF files, use the following commandline: // adlmidi song8.ctmf -p -v 1 1 0 @@ -402,13 +393,19 @@ riffskip: //std::printf("%u instruments\n", ins_count); for(unsigned i = 0; i < ins_count; ++i) { + unsigned bank = i / 256; + bank = (bank & 127) + ((bank >> 7) << 8); + if(bank > 127 + (127 << 8)) + break; + bank += (i % 256 < 128) ? 0 : OPL3::PercussionTag; + unsigned char InsData[16]; fr.read(InsData, 1, 16); /*std::printf("Ins %3u: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", i, InsData[0],InsData[1],InsData[2],InsData[3], InsData[4],InsData[5],InsData[6],InsData[7], InsData[8],InsData[9],InsData[10],InsData[11], InsData[12],InsData[13],InsData[14],InsData[15]);*/ - struct adldata adl; - struct adlinsdata2 adlins; + adlinsdata2 &adlins = opl.dynamic_banks[bank].ins[i % 128]; + adldata adl; adl.modulator_E862 = ((static_cast<uint32_t>(InsData[8] & 0x07) << 24) & 0xFF000000) //WaveForm | ((static_cast<uint32_t>(InsData[6]) << 16) & 0x00FF0000) //Sustain/Release @@ -430,7 +427,6 @@ riffskip: adlins.tone = 0; adlins.flags = 0; adlins.voice2_fine_tune = 0.0; - opl.dynamic_metainstruments.push_back(adlins); } fr.seeku(mus_start, SEEK_SET); diff --git a/src/adlmidi_midiplay.cpp b/src/adlmidi_midiplay.cpp index 8da4a43..75b5f58 100644 --- a/src/adlmidi_midiplay.cpp +++ b/src/adlmidi_midiplay.cpp @@ -1001,7 +1001,7 @@ bool MIDIplay::realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocity) //Let XG SFX1/SFX2 bank will have LSB==1 (128...255 range in WOPN file) //Let XG Percussion bank will use (0...127 range in WOPN file) bank = (uint16_t)midiins + ((bank == 0x7E00) ? 128 : 0); // MIDI instrument defines the patch - midiins = opl.dynamic_percussion_offset + note; // Percussion instrument + midiins = note; // Percussion instrument isXgPercussion = true; isPercussion = false; } @@ -1010,43 +1010,36 @@ bool MIDIplay::realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocity) if(isPercussion) { bank = (uint16_t)midiins; // MIDI instrument defines the patch - midiins = opl.dynamic_percussion_offset + note; // Percussion instrument + midiins = note; // Percussion instrument } + if(isPercussion || isXgPercussion) + bank += OPL3::PercussionTag; //Set bank bank - if(bank > 0) + const OPL3::Bank *bnk = NULL; + if((bank & ~(uint16_t)OPL3::PercussionTag) > 0) { - if(isPercussion || isXgPercussion) - { - OPL3::BankMap::iterator b = opl.dynamic_percussion_banks.find(bank); - if(b != opl.dynamic_percussion_banks.end()) - midiins += b->second * 128; - else - if(hooks.onDebugMessage) - { - if(!caugh_missing_banks_melodic.count(bank)) - { - hooks.onDebugMessage(hooks.onDebugMessage_userData, "[%i] Playing missing percussion MIDI bank %i (patch %i)", channel, bank, midiins); - caugh_missing_banks_melodic.insert(bank); - } - } - } - else + OPL3::BankMap::iterator b = opl.dynamic_banks.find(bank); + if(b != opl.dynamic_banks.end()) + bnk = &b->second; + + if(!bnk && hooks.onDebugMessage) { - OPL3::BankMap::iterator b = opl.dynamic_melodic_banks.find(bank); - if(b != opl.dynamic_melodic_banks.end()) - midiins += b->second * 128; - else - if(hooks.onDebugMessage) - { - if(!caugh_missing_banks_percussion.count(bank)) - { - hooks.onDebugMessage(hooks.onDebugMessage_userData, "[%i] Playing missing melodic MIDI bank %i (patch %i)", channel, bank, midiins); - caugh_missing_banks_percussion.insert(bank); - } - } + std::set<uint16_t> &missing = (isPercussion || isXgPercussion) ? + caugh_missing_banks_percussion : caugh_missing_banks_melodic; + const char *text = (isPercussion || isXgPercussion) ? + "percussion" : "melodic"; + if(missing.insert(bank).second) + hooks.onDebugMessage(hooks.onDebugMessage_userData, "[%i] Playing missing %s MIDI bank %i (patch %i)", channel, text, bank, midiins); } } + //Or fall back to first bank + if(!bnk) + { + OPL3::BankMap::iterator b = opl.dynamic_banks.find((bank & OPL3::PercussionTag)); + if(b != opl.dynamic_banks.end()) + bnk = &b->second; + } /* if(MidCh%16 == 9 || (midiins != 32 && midiins != 46 && midiins != 48 && midiins != 50)) @@ -1057,8 +1050,7 @@ bool MIDIplay::realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocity) //if(midiins == 56) vol = vol*6/10; // HACK //int meta = banks[opl.AdlBank][midiins]; - size_t meta = opl.GetAdlMetaNumber(midiins); - adlinsdata2 ains = opl.GetAdlMetaIns(meta); + const adlinsdata2 &ains = bnk ? bnk->ins[midiins] : OPL3::emptyInstrument; int16_t tone = note; if(!isPercussion && !isXgPercussion && (bank > 0)) // For non-zero banks @@ -1067,16 +1059,11 @@ bool MIDIplay::realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocity) { if(hooks.onDebugMessage) { - if(!caugh_missing_instruments.count(static_cast<uint8_t>(midiins))) - { + if(caugh_missing_instruments.insert(static_cast<uint8_t>(midiins)).second) hooks.onDebugMessage(hooks.onDebugMessage_userData, "[%i] Caugh a blank instrument %i (offset %i) in the MIDI bank %u", channel, Ch[channel].patch, midiins, bank); - caugh_missing_instruments.insert(static_cast<uint8_t>(midiins)); - } } bank = 0; midiins = midiChan.patch; - meta = opl.GetAdlMetaNumber(midiins); - ains = opl.GetAdlMetaIns(meta); } } @@ -1114,11 +1101,9 @@ bool MIDIplay::realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocity) if(hooks.onDebugMessage) { - if(!caugh_missing_instruments.count(static_cast<uint8_t>(midiins)) && (ains.flags & adlinsdata::Flag_NoSound)) - { + if((ains.flags & adlinsdata::Flag_NoSound) && + caugh_missing_instruments.insert(static_cast<uint8_t>(midiins)).second) hooks.onDebugMessage(hooks.onDebugMessage_userData, "[%i] Playing missing instrument %i", channel, midiins); - caugh_missing_instruments.insert(static_cast<uint8_t>(midiins)); - } } // Allocate AdLib channel (the physical sound channel for the note) @@ -1211,7 +1196,7 @@ bool MIDIplay::realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocity) ir.first->vibrato = midiChan.noteAftertouch[note]; ir.first->tone = tone; ir.first->midiins = midiins; - ir.first->insmeta = meta; + ir.first->ains = &ains; ir.first->chip_channels_count = 0; for(unsigned ccount = 0; ccount < MIDIchannel::NoteInfo::MaxNumPhysChans; ++ccount) @@ -1449,8 +1434,7 @@ void MIDIplay::NoteUpdate(uint16_t MidCh, const int16_t tone = info.tone; const uint8_t vol = info.vol; const int midiins = info.midiins; - const size_t insmeta = info.insmeta; - const adlinsdata2 ains = opl.GetAdlMetaIns(insmeta); + const adlinsdata2 &ains = *info.ains; AdlChannel::Location my_loc; my_loc.MidCh = MidCh; my_loc.note = info.note; @@ -2606,7 +2590,7 @@ ADLMIDI_EXPORT void AdlInstrumentTester::DoNote(int note) OPL3 *opl = P->opl; if(P->adl_ins_list.empty()) FindAdlList(); const unsigned meta = P->adl_ins_list[P->ins_idx]; - const adlinsdata2 ains = opl->GetAdlMetaIns(meta); + const adlinsdata2 ains(adlins[meta]); int tone = (P->cur_gm & 128) ? (P->cur_gm & 127) : (note + 50); if(ains.tone) @@ -2680,7 +2664,7 @@ ADLMIDI_EXPORT void AdlInstrumentTester::NextAdl(int offset) for(unsigned a = 0, n = P->adl_ins_list.size(); a < n; ++a) { const unsigned i = P->adl_ins_list[a]; - const adlinsdata2 ains = opl->GetAdlMetaIns(i); + const adlinsdata2 ains(adlins[i]); char ToneIndication[8] = " "; if(ains.tone) diff --git a/src/adlmidi_opl3.cpp b/src/adlmidi_opl3.cpp index 143c911..f82302c 100644 --- a/src/adlmidi_opl3.cpp +++ b/src/adlmidi_opl3.cpp @@ -129,45 +129,54 @@ static const unsigned short Channels[23] = Ports: ??? */ - -adlinsdata2 OPL3::GetAdlMetaIns(size_t n) +void OPL3::setEmbeddedBank(unsigned int bank) { - return (n & DynamicMetaInstrumentTag) ? - dynamic_metainstruments[n & ~DynamicMetaInstrumentTag] - : adlinsdata2(adlins[n]); -} + AdlBank = bank; + //Embedded banks are supports 128:128 GM set only + dynamic_banks.clear(); -size_t OPL3::GetAdlMetaNumber(size_t midiins) -{ - return (AdlBank == ~0u) ? - (midiins | DynamicMetaInstrumentTag) - : banks[AdlBank][midiins]; + if(bank >= maxAdlBanks()) + return; + + Bank *bank_pair[2] = + { + &dynamic_banks[0], + &dynamic_banks[PercussionTag] + }; + + for(unsigned i = 0; i < 256; ++i) + { + size_t meta = banks[bank][i]; + adlinsdata2 &ins = bank_pair[i / 128]->ins[i % 128]; + ins = adlinsdata2(adlins[meta]); + } } -void OPL3::setEmbeddedBank(unsigned int bank) +static adlinsdata2 makeEmptyInstrument() { - AdlBank = bank; - //Embedded banks are supports 128:128 GM set only - dynamic_percussion_offset = 128; - dynamic_melodic_banks.clear(); - dynamic_percussion_banks.clear(); - dynamic_metainstruments.clear(); + adlinsdata2 ins; + memset(&ins, 0, sizeof(adlinsdata2)); + ins.flags = adlinsdata::Flag_NoSound; + return ins; } +const adlinsdata2 OPL3::emptyInstrument = makeEmptyInstrument(); OPL3::OPL3() : - dynamic_percussion_offset(128), - DynamicInstrumentTag(0x8000u), - DynamicMetaInstrumentTag(0x4000000u), NumCards(1), - AdlBank(0), NumFourOps(0), HighTremoloMode(false), HighVibratoMode(false), AdlPercussionMode(false), m_musicMode(MODE_MIDI), m_volumeScale(VOLUME_Generic) -{} +{ +#ifdef DISABLE_EMBEDDED_BANKS + AdlBank = ~0u; +#else + setEmbeddedBank(0); +#endif +} void OPL3::Poke(size_t card, uint32_t index, uint32_t value) { diff --git a/src/adlmidi_private.cpp b/src/adlmidi_private.cpp index 3d9d9e9..77319d7 100644 --- a/src/adlmidi_private.cpp +++ b/src/adlmidi_private.cpp @@ -34,16 +34,21 @@ int adlRefreshNumCards(ADL_MIDIPlayer *device) if(play->opl.AdlBank == ~0u) { //For custom bank - for(size_t a = 0; a < play->opl.dynamic_metainstruments.size(); ++a) + OPL3::BankMap::iterator it = play->opl.dynamic_banks.begin(); + OPL3::BankMap::iterator end = play->opl.dynamic_banks.end(); + for(; it != end; ++it) { - adlinsdata2 &ins = play->opl.dynamic_metainstruments[a]; - if(ins.flags & adlinsdata::Flag_NoSound) - continue; - - size_t div = (a >= play->opl.dynamic_percussion_offset) ? 1 : 0; - ++n_total[div]; - if(ins.flags & adlinsdata::Flag_Real4op) - ++n_fourop[div]; + uint16_t bank = it->first; + unsigned div = (bank & OPL3::PercussionTag) ? 1 : 0; + for(unsigned i = 0; i < 128; ++i) + { + adlinsdata2 &ins = it->second.ins[i]; + if(ins.flags & adlinsdata::Flag_NoSound) + continue; + if((ins.adl[0] != ins.adl[1]) && ((ins.flags & adlinsdata::Flag_Pseudo4op) == 0)) + ++n_fourop[div]; + ++n_total[div]; + } } } else diff --git a/src/adlmidi_private.hpp b/src/adlmidi_private.hpp index ee73c61..2010b4e 100644 --- a/src/adlmidi_private.hpp +++ b/src/adlmidi_private.hpp @@ -220,22 +220,19 @@ private: std::vector<uint8_t> regBD; friend int adlRefreshNumCards(ADL_MIDIPlayer *device); - //! Meta information about every instrument - std::vector<adlinsdata2> dynamic_metainstruments; // Replaces adlins[] when CMF file - //! Raw instrument data ready to be sent to the chip - std::vector<adldata> dynamic_instruments; // Replaces adl[] when CMF file - size_t dynamic_percussion_offset; - - typedef BasicBankMap<size_t> BankMap; - BankMap dynamic_melodic_banks; - BankMap dynamic_percussion_banks; +public: + struct Bank + { + adlinsdata2 ins[128]; + }; + typedef BasicBankMap<Bank> BankMap; +private: + BankMap dynamic_banks; AdlBankSetup dynamic_bank_setup; - const unsigned DynamicInstrumentTag /* = 0x8000u*/, - DynamicMetaInstrumentTag /* = 0x4000000u*/; - adlinsdata2 GetAdlMetaIns(size_t n); - size_t GetAdlMetaNumber(size_t midiins); public: void setEmbeddedBank(unsigned int bank); + static const adlinsdata2 emptyInstrument; + enum { PercussionTag = 1 << 15 }; //! Total number of running concurrent emulated chips unsigned int NumCards; @@ -530,10 +527,10 @@ public: // Tone selected on noteon: int16_t tone; char ____padding2[4]; - // Patch selected on noteon; index to banks[AdlBank][] + // Patch selected on noteon; index to bank.ins[] size_t midiins; - // Index to physical adlib data structure, adlins[] - size_t insmeta; + // Patch selected + const adlinsdata2 *ains; enum { MaxNumPhysChans = 2, |