From d7b9439df5d09d121c55a15f2bc25c360deeebe0 Mon Sep 17 00:00:00 2001 From: JP Cimalando Date: Thu, 17 May 2018 21:33:28 +0200 Subject: dynamic instrument API --- src/adldata.hh | 10 ++++ src/adlmidi.cpp | 136 ++++++++++++++++++++++++++++++++++++++++++++++++ src/adlmidi_bankmap.h | 2 + src/adlmidi_bankmap.tcc | 19 +++++++ src/adlmidi_load.cpp | 79 ++++++++++++++++++++++++++-- src/adlmidi_private.hpp | 4 +- 6 files changed, 245 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/adldata.hh b/src/adldata.hh index 65fd6bd..2ac469f 100644 --- a/src/adldata.hh +++ b/src/adldata.hh @@ -104,4 +104,14 @@ inline adlinsdata2::adlinsdata2(const adlinsdata &d) adl[1] = ::adl[d.adlno2]; } +/** + * @brief Convert external instrument to internal instrument + */ +void cvt_ADLI_to_FMIns(adlinsdata2 &dst, const struct ADL_Instrument &src); + +/** + * @brief Convert internal instrument to external instrument + */ +void cvt_FMIns_to_ADLI(struct ADL_Instrument &dst, const adlinsdata2 &src); + #endif //ADLDATA_H diff --git a/src/adlmidi.cpp b/src/adlmidi.cpp index c6402e1..f9891a8 100644 --- a/src/adlmidi.cpp +++ b/src/adlmidi.cpp @@ -143,6 +143,142 @@ ADLMIDI_EXPORT const char *const *adl_getBankNames() return banknames; } +ADLMIDI_EXPORT int adl_reserveBanks(ADL_MIDIPlayer *device, unsigned banks) +{ + if(!device) + return -1; + MIDIplay *play = reinterpret_cast(device->adl_midiPlayer); + OPL3::BankMap &map = play->opl.dynamic_banks; + map.reserve(banks); + return (int)map.capacity(); +} + +ADLMIDI_EXPORT int adl_getBank(ADL_MIDIPlayer *device, const ADL_BankId *idp, int flags, ADL_Bank *bank) +{ + if(!device || !idp || !bank) + return -1; + + ADL_BankId id = *idp; + if(id.lsb > 127 || id.msb > 127 || id.percussive > 1) + return -1; + unsigned idnumber = (id.msb << 8) | id.lsb | (id.percussive ? OPL3::PercussionTag : 0); + + MIDIplay *play = reinterpret_cast(device->adl_midiPlayer); + OPL3::BankMap &map = play->opl.dynamic_banks; + + OPL3::BankMap::iterator it; + if(!(flags & ADLMIDI_Bank_Create)) + { + it = map.find(idnumber); + if(it == map.end()) + return -1; + } + else + { + std::pair value; + value.first = idnumber; + memset(&value.second, 0, sizeof(value.second)); + for (unsigned i = 0; i < 128; ++i) + value.second.ins[i].flags = adlinsdata::Flag_NoSound; + + std::pair ir; + if(flags & ADLMIDI_Bank_CreateRt) + { + ir = map.insert(value, OPL3::BankMap::do_not_expand_t()); + if(ir.first == map.end()) + return -1; + } + else + ir = map.insert(value); + it = ir.first; + } + + it.to_ptrs(bank->pointer); + return 0; +} + +ADLMIDI_EXPORT int adl_getBankId(ADL_MIDIPlayer *device, const ADL_Bank *bank, ADL_BankId *id) +{ + if(!device || !bank) + return -1; + + OPL3::BankMap::iterator it = OPL3::BankMap::iterator::from_ptrs(bank->pointer); + unsigned idnumber = it->first; + id->msb = (idnumber >> 8) & 127; + id->lsb = idnumber & 127; + id->percussive = (idnumber & OPL3::PercussionTag) ? 1 : 0; + return 0; +} + +ADLMIDI_EXPORT int adl_removeBank(ADL_MIDIPlayer *device, ADL_Bank *bank) +{ + if(!device || !bank) + return -1; + + MIDIplay *play = reinterpret_cast(device->adl_midiPlayer); + OPL3::BankMap &map = play->opl.dynamic_banks; + OPL3::BankMap::iterator it = OPL3::BankMap::iterator::from_ptrs(bank->pointer); + size_t size = map.size(); + map.erase(it); + return (map.size() != size) ? 0 : -1; +} + +ADLMIDI_EXPORT int adl_getFirstBank(ADL_MIDIPlayer *device, ADL_Bank *bank) +{ + if(!device) + return -1; + + MIDIplay *play = reinterpret_cast(device->adl_midiPlayer); + OPL3::BankMap &map = play->opl.dynamic_banks; + + OPL3::BankMap::iterator it = map.begin(); + if(it == map.end()) + return -1; + + it.to_ptrs(bank->pointer); + return 0; +} + +ADLMIDI_EXPORT int adl_getNextBank(ADL_MIDIPlayer *device, ADL_Bank *bank) +{ + if(!device) + return -1; + + MIDIplay *play = reinterpret_cast(device->adl_midiPlayer); + OPL3::BankMap &map = play->opl.dynamic_banks; + + OPL3::BankMap::iterator it = OPL3::BankMap::iterator::from_ptrs(bank->pointer); + if(++it == map.end()) + return -1; + + it.to_ptrs(bank->pointer); + return 0; +} + +ADLMIDI_EXPORT int adl_getInstrument(ADL_MIDIPlayer *device, const ADL_Bank *bank, unsigned index, ADL_Instrument *ins) +{ + if(!device || !bank || index > 127 || !ins) + return 1; + + OPL3::BankMap::iterator it = OPL3::BankMap::iterator::from_ptrs(bank->pointer); + cvt_FMIns_to_ADLI(*ins, it->second.ins[index]); + ins->version = 0; + return 0; +} + +ADLMIDI_EXPORT int adl_setInstrument(ADL_MIDIPlayer *device, ADL_Bank *bank, unsigned index, const ADL_Instrument *ins) +{ + if(!device || !bank || index > 127 || !ins) + return 1; + + if(ins->version != 0) + return 1; + + OPL3::BankMap::iterator it = OPL3::BankMap::iterator::from_ptrs(bank->pointer); + cvt_ADLI_to_FMIns(it->second.ins[index], *ins); + return 0; +} + ADLMIDI_EXPORT int adl_setNumFourOpsChn(ADL_MIDIPlayer *device, int ops4) { if(!device) diff --git a/src/adlmidi_bankmap.h b/src/adlmidi_bankmap.h index 9b71d8f..178a1c1 100644 --- a/src/adlmidi_bankmap.h +++ b/src/adlmidi_bankmap.h @@ -85,6 +85,8 @@ public: iterator &operator++(); bool operator==(const iterator &o) const; bool operator!=(const iterator &o) const; + void to_ptrs(void *ptrs[3]); + static iterator from_ptrs(void *const ptrs[3]); private: Slot **buckets; Slot *slot; diff --git a/src/adlmidi_bankmap.tcc b/src/adlmidi_bankmap.tcc index 938192d..9303f0d 100644 --- a/src/adlmidi_bankmap.tcc +++ b/src/adlmidi_bankmap.tcc @@ -136,6 +136,25 @@ inline bool BasicBankMap::iterator::operator!=(const iterator &o) const return !operator==(o); } +template +void BasicBankMap::iterator::to_ptrs(void *ptrs[3]) +{ + ptrs[0] = buckets; + ptrs[1] = slot; + ptrs[2] = (void *)index; +} + +template +typename BasicBankMap::iterator +BasicBankMap::iterator::from_ptrs(void *const ptrs[3]) +{ + iterator it; + it.buckets = (Slot **)ptrs[0]; + it.slot = (Slot *)ptrs[1]; + it.index = (size_t)ptrs[2]; + return it; +} + template std::pair::iterator, bool> BasicBankMap::insert(const value_type &value) diff --git a/src/adlmidi_load.cpp b/src/adlmidi_load.cpp index 8deb3b9..ac9d51a 100644 --- a/src/adlmidi_load.cpp +++ b/src/adlmidi_load.cpp @@ -72,7 +72,8 @@ bool MIDIplay::LoadBank(const void *data, size_t size) return LoadBank(file); } -static void cvt_WOPLI_to_FMIns(adlinsdata2 &ins, const WOPLInstrument &in) +template +static void cvt_generic_to_FMIns(adlinsdata2 &ins, const WOPLI &in) { ins.voice2_fine_tune = 0.0; int8_t voice2_fine_tune = in.second_voice_detune; @@ -83,7 +84,7 @@ static void cvt_WOPLI_to_FMIns(adlinsdata2 &ins, const WOPLInstrument &in) else if(voice2_fine_tune == -1) ins.voice2_fine_tune = -0.000025; else - ins.voice2_fine_tune = ((voice2_fine_tune * 15.625) / 1000.0); + ins.voice2_fine_tune = voice2_fine_tune * (15.625 / 1000.0); } ins.tone = in.percussion_key_number; @@ -114,7 +115,8 @@ static void cvt_WOPLI_to_FMIns(adlinsdata2 &ins, const WOPLInstrument &in) ins.adl[0].feedconn = in.fb_conn1_C0; if(!fourOps) ins.adl[1] = ins.adl[0]; - else { + else + { ins.adl[1].finetune = in.note_offset2; ins.adl[1].feedconn = in.fb_conn2_C0; } @@ -123,6 +125,75 @@ static void cvt_WOPLI_to_FMIns(adlinsdata2 &ins, const WOPLInstrument &in) ins.ms_sound_koff = in.delay_off_ms; } +template +static void cvt_FMIns_to_generic(WOPLI &ins, const adlinsdata2 &in) +{ + ins.second_voice_detune = 0; + double voice2_fine_tune = in.voice2_fine_tune; + if(voice2_fine_tune != 0) + { + if(voice2_fine_tune > 0 && voice2_fine_tune <= 0.000025) + ins.second_voice_detune = 1; + else if(voice2_fine_tune < 0 && voice2_fine_tune >= -0.000025) + ins.second_voice_detune = -1; + else + { + long value = lround(voice2_fine_tune * (1000.0 / 15.625)); + value = (value < -128) ? -128 : value; + value = (value > +127) ? +127 : value; + ins.second_voice_detune = static_cast(value); + } + } + + ins.percussion_key_number = in.tone; + bool fourOps = (in.flags & adlinsdata::Flag_Pseudo4op) || in.adl[0] != in.adl[1]; + ins.inst_flags = fourOps ? WOPL_Ins_4op : 0; + ins.inst_flags|= (in.flags & adlinsdata::Flag_Pseudo4op) ? WOPL_Ins_Pseudo4op : 0; + ins.inst_flags|= (in.flags & adlinsdata::Flag_NoSound) ? WOPL_Ins_IsBlank : 0; + + for(size_t op = 0, slt = 0; op < (fourOps ? 4 : 2); op++, slt++) + { + ins.operators[op].waveform_E0 = static_cast(in.adl[slt].carrier_E862 >> 24); + ins.operators[op].susrel_80 = static_cast(in.adl[slt].carrier_E862 >> 16); + ins.operators[op].atdec_60 = static_cast(in.adl[slt].carrier_E862 >> 8); + ins.operators[op].avekf_20 = static_cast(in.adl[slt].carrier_E862 >> 0); + ins.operators[op].ksl_l_40 = in.adl[slt].carrier_40; + + op++; + ins.operators[op].waveform_E0 = static_cast(in.adl[slt].carrier_E862 >> 24); + ins.operators[op].susrel_80 = static_cast(in.adl[slt].carrier_E862 >> 16); + ins.operators[op].atdec_60 = static_cast(in.adl[slt].carrier_E862 >> 8); + ins.operators[op].avekf_20 = static_cast(in.adl[slt].carrier_E862 >> 0); + ins.operators[op].ksl_l_40 = in.adl[slt].carrier_40; + } + + ins.note_offset1 = in.adl[0].finetune; + ins.fb_conn1_C0 = in.adl[0].feedconn; + if(!fourOps) + { + ins.operators[2] = ins.operators[0]; + ins.operators[3] = ins.operators[1]; + } + else + { + ins.note_offset2 = in.adl[1].finetune; + ins.fb_conn2_C0 = in.adl[1].feedconn; + } + + ins.delay_on_ms = in.ms_sound_kon; + ins.delay_off_ms = in.ms_sound_koff; +} + +void cvt_ADLI_to_FMIns(adlinsdata2 &ins, const ADL_Instrument &in) +{ + return cvt_generic_to_FMIns(ins, in); +} + +void cvt_FMIns_to_ADLI(ADL_Instrument &ins, const adlinsdata2 &in) +{ + cvt_FMIns_to_generic(ins, in); +} + bool MIDIplay::LoadBank(MIDIplay::fileReader &fr) { int err = 0; @@ -207,7 +278,7 @@ bool MIDIplay::LoadBank(MIDIplay::fileReader &fr) 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); + cvt_generic_to_FMIns(ins, inIns); } } } diff --git a/src/adlmidi_private.hpp b/src/adlmidi_private.hpp index 8e3b158..63b4854 100644 --- a/src/adlmidi_private.hpp +++ b/src/adlmidi_private.hpp @@ -35,6 +35,9 @@ # endif #endif +// Require declarations of unstable API for extern "C" +#define ADLMIDI_UNSTABLE_API + #ifdef _WIN32 #define NOMINMAX #endif @@ -226,7 +229,6 @@ public: adlinsdata2 ins[128]; }; typedef BasicBankMap BankMap; -private: BankMap dynamic_banks; AdlBankSetup dynamic_bank_setup; public: -- cgit v1.2.3