From 5ebf40cd10d59c5e11ea744cc7b6075ee4c1bc90 Mon Sep 17 00:00:00 2001 From: Wohlstand Date: Tue, 7 Nov 2017 02:40:13 +0300 Subject: Custom WOPL now supports multiple banks Feel free to create something like GS or XG bank :wink: --- src/adlmidi.cpp | 8 ++++---- src/adlmidi_load.cpp | 43 ++++++++++++++++++++++++------------------- src/adlmidi_midiplay.cpp | 27 +++++++++++++++++++++++---- src/adlmidi_opl3.cpp | 17 +++++++++++++---- src/adlmidi_private.hpp | 22 ++++++++++++++-------- 5 files changed, 78 insertions(+), 39 deletions(-) (limited to 'src') diff --git a/src/adlmidi.cpp b/src/adlmidi.cpp index dc9c980..8ee5996 100644 --- a/src/adlmidi.cpp +++ b/src/adlmidi.cpp @@ -93,10 +93,7 @@ ADLMIDI_EXPORT int adl_setBank(ADL_MIDIPlayer *device, int bank) bankno = 0; MIDIplay *play = reinterpret_cast(device->adl_midiPlayer); - play->m_setup.AdlBank = static_cast(bankno); - play->opl.AdlBank = play->m_setup.AdlBank; - - if(play->m_setup.AdlBank >= NumBanks) + if(static_cast(bankno) >= NumBanks) { std::stringstream s; s << "bank number may only be 0.." << (NumBanks - 1) << ".\n"; @@ -104,6 +101,9 @@ ADLMIDI_EXPORT int adl_setBank(ADL_MIDIPlayer *device, int bank) return -1; } + play->m_setup.AdlBank = static_cast(bankno); + play->opl.setEmbeddedBank(play->m_setup.AdlBank); + return adlRefreshNumCards(device); #endif } diff --git a/src/adlmidi_load.cpp b/src/adlmidi_load.cpp index 76765dc..9b28810 100644 --- a/src/adlmidi_load.cpp +++ b/src/adlmidi_load.cpp @@ -241,6 +241,9 @@ bool MIDIplay::LoadBank(MIDIplay::fileReader &fr) //6'th byte reserved for ADLMIDI's default volume model m_setup.VolumeModel = (int)head[5]; + opl.dynamic_melodic_banks.clear(); + opl.dynamic_percussion_banks.clear(); + if(version >= 2)//Read bank meta-entries { for(uint16_t i = 0; i < count_melodic_banks; i++) @@ -251,6 +254,9 @@ bool MIDIplay::LoadBank(MIDIplay::fileReader &fr) errorStringOut = "Custom bank: Fail to read melodic bank meta-data!"; return false; } + uint16_t bank = uint16_t(bank_meta[33]) * 256 + uint16_t(bank_meta[32]); + size_t offset = opl.dynamic_melodic_banks.size(); + opl.dynamic_melodic_banks[bank] = offset; //strncpy(bankMeta.name, char_p(bank_meta), 32); //bankMeta.lsb = bank_meta[32]; //bankMeta.msb = bank_meta[33]; @@ -264,15 +270,16 @@ bool MIDIplay::LoadBank(MIDIplay::fileReader &fr) errorStringOut = "Custom bank: Fail to read melodic bank meta-data!"; return false; } + uint16_t bank = uint16_t(bank_meta[33]) * 256 + uint16_t(bank_meta[32]); + size_t offset = opl.dynamic_percussion_banks.size(); + opl.dynamic_percussion_banks[bank] = offset; //strncpy(bankMeta.name, char_p(bank_meta), 32); //bankMeta.lsb = bank_meta[32]; //bankMeta.msb = bank_meta[33]; } } - opl.AdlBank = m_setup.AdlBank; - opl.dynamic_metainstruments.clear(); - opl.dynamic_instruments.clear(); + opl.setEmbeddedBank(m_setup.AdlBank); uint16_t total = 128 * count_melodic_banks; bool readPercussion = false; @@ -284,28 +291,24 @@ tryAgain: memset(&ins, 0, sizeof(WOPL_Inst)); if(!readInstrument(fr, ins, readPercussion)) { - opl.dynamic_metainstruments.clear(); - opl.dynamic_instruments.clear(); + opl.setEmbeddedBank(m_setup.AdlBank); errorStringOut = "Custom bank: Fail to read instrument!"; return false; } - if(i < 128) //Only first bank! + /* + * 0..127 - melodic, 128...255 - percussion. + * TODO: Make separated melodic and drum arrays and make MIDI bank ID support + */ + ins.adlins.adlno1 = static_cast(opl.dynamic_instruments.size() | opl.DynamicInstrumentTag); + opl.dynamic_instruments.push_back(ins.op[0]); + ins.adlins.adlno2 = ins.adlins.adlno1; + if(ins.fourOps) { - /* - * 0..127 - melodic, 128...255 - percussion. - * TODO: Make separated melodic and drum arrays and make MIDI bank ID support - */ - ins.adlins.adlno1 = static_cast(opl.dynamic_instruments.size() | opl.DynamicInstrumentTag); - opl.dynamic_instruments.push_back(ins.op[0]); - ins.adlins.adlno2 = ins.adlins.adlno1; - if(ins.fourOps) - { - ins.adlins.adlno2 = static_cast(opl.dynamic_instruments.size() | opl.DynamicInstrumentTag); - opl.dynamic_instruments.push_back(ins.op[1]); - } - opl.dynamic_metainstruments.push_back(ins.adlins); + ins.adlins.adlno2 = static_cast(opl.dynamic_instruments.size() | opl.DynamicInstrumentTag); + opl.dynamic_instruments.push_back(ins.op[1]); } + opl.dynamic_metainstruments.push_back(ins.adlins); } if(!readPercussion) @@ -316,6 +319,8 @@ tryAgain: } opl.AdlBank = ~0u; // Use dynamic banks! + //Percussion offset is count of instruments multipled to count of melodic banks + opl.dynamic_percussion_offset = 128 * count_melodic_banks; return true; } diff --git a/src/adlmidi_midiplay.cpp b/src/adlmidi_midiplay.cpp index 7d1ba75..8794d9f 100644 --- a/src/adlmidi_midiplay.cpp +++ b/src/adlmidi_midiplay.cpp @@ -866,10 +866,29 @@ bool MIDIplay::realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocity) if(velocity == 0) return false; - uint8_t midiins = Ch[channel].patch; + size_t midiins = Ch[channel].patch; + bool isPercussion = (channel % 16 == 9); - if(channel % 16 == 9) - midiins = 128 + note; // Percussion instrument + if(isPercussion) + midiins = opl.dynamic_percussion_offset + note; // Percussion instrument + + //Set bank bank + if(Ch[channel].bank_msb || Ch[channel].bank_lsb) + { + uint16_t bank = (uint16_t(Ch[channel].bank_msb) * 256) + uint16_t(Ch[channel].bank_lsb); + if(isPercussion) + { + OPL3::BankMap::iterator b = opl.dynamic_percussion_banks.find(bank); + if(b != opl.dynamic_percussion_banks.end()) + midiins += b->second * 128; + } + else + { + OPL3::BankMap::iterator b = opl.dynamic_melodic_banks.find(bank); + if(b != opl.dynamic_melodic_banks.end()) + midiins += b->second * 128; + } + } /* if(MidCh%16 == 9 || (midiins != 32 && midiins != 46 && midiins != 48 && midiins != 50)) @@ -921,7 +940,7 @@ bool MIDIplay::realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocity) */ //int meta = banks[opl.AdlBank][midiins]; - const uint32_t meta = opl.GetAdlMetaNumber(midiins); + const size_t meta = opl.GetAdlMetaNumber(midiins); const adlinsdata &ains = opl.GetAdlMetaIns(meta); int16_t tone = note; diff --git a/src/adlmidi_opl3.cpp b/src/adlmidi_opl3.cpp index ce26ba6..9db3803 100644 --- a/src/adlmidi_opl3.cpp +++ b/src/adlmidi_opl3.cpp @@ -115,30 +115,39 @@ static const unsigned short Channels[23] = */ -const adlinsdata &OPL3::GetAdlMetaIns(unsigned n) +const adlinsdata &OPL3::GetAdlMetaIns(size_t n) { return (n & DynamicMetaInstrumentTag) ? dynamic_metainstruments[n & ~DynamicMetaInstrumentTag] : adlins[n]; } -unsigned OPL3::GetAdlMetaNumber(unsigned midiins) +size_t OPL3::GetAdlMetaNumber(size_t midiins) { return (AdlBank == ~0u) ? (midiins | DynamicMetaInstrumentTag) : banks[AdlBank][midiins]; } - const adldata &OPL3::GetAdlIns(size_t insno) { return (insno & DynamicInstrumentTag) ? dynamic_instruments[insno & ~DynamicInstrumentTag] - : adl[insno]; + : adl[insno]; +} + +void OPL3::setEmbeddedBank(unsigned int bank) +{ + AdlBank = bank; + //Embedded banks are supports 128:128 GM set only + dynamic_percussion_offset = 128; + dynamic_melodic_banks.clear(); + dynamic_percussion_banks.clear(); } OPL3::OPL3() : + dynamic_percussion_offset(128), DynamicInstrumentTag(0x8000u), DynamicMetaInstrumentTag(0x4000000u), NumCards(1), diff --git a/src/adlmidi_private.hpp b/src/adlmidi_private.hpp index 698dad5..dbea5e6 100644 --- a/src/adlmidi_private.hpp +++ b/src/adlmidi_private.hpp @@ -141,8 +141,9 @@ public: }; class MIDIplay; -struct OPL3 +class OPL3 { +public: friend class MIDIplay; uint32_t NumChannels; char ____padding[4]; @@ -162,13 +163,19 @@ private: friend int adlRefreshNumCards(ADL_MIDIPlayer *device); std::vector dynamic_metainstruments; // Replaces adlins[] when CMF file std::vector dynamic_instruments; // Replaces adl[] when CMF file + size_t dynamic_percussion_offset; + typedef std::map BankMap; + BankMap dynamic_melodic_banks; + BankMap dynamic_percussion_banks; const unsigned DynamicInstrumentTag /* = 0x8000u*/, DynamicMetaInstrumentTag /* = 0x4000000u*/; public: - const adlinsdata &GetAdlMetaIns(unsigned n); - unsigned GetAdlMetaNumber(unsigned midiins); + const adlinsdata &GetAdlMetaIns(size_t n); + size_t GetAdlMetaNumber(size_t midiins); const adldata &GetAdlIns(size_t insno); + void setEmbeddedBank(unsigned int bank); + //! Total number of running concurrent emulated chips unsigned int NumCards; //! Currently running embedded bank number. "~0" means usign of the custom bank. @@ -446,14 +453,14 @@ public: { // Current pressure uint8_t vol; - // Tone selected on noteon: char ____padding[1]; + // Tone selected on noteon: int16_t tone; + char ____padding2[4]; // Patch selected on noteon; index to banks[AdlBank][] - uint8_t midiins; + size_t midiins; // Index to physical adlib data structure, adlins[] - char ____padding2[3]; - uint32_t insmeta; + size_t insmeta; struct Phys { //! ins, inde to adl[] @@ -471,7 +478,6 @@ public: } }; typedef std::map PhysMap; - char ____padding3[4]; // List of OPL3 channels it is currently occupying. std::map phys; }; -- cgit v1.2.3