aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJP Cimalando <jpcima@users.noreply.github.com>2018-05-17 21:33:28 +0200
committerJP Cimalando <jpcima@users.noreply.github.com>2018-06-02 08:08:40 +0200
commitd7b9439df5d09d121c55a15f2bc25c360deeebe0 (patch)
tree98994c90751ec158de303334204ef5e67cff628d /src
parent9fb6aef78053b6462f2e74fdb750576dbd3eab96 (diff)
downloadlibADLMIDI-d7b9439df5d09d121c55a15f2bc25c360deeebe0.tar.gz
libADLMIDI-d7b9439df5d09d121c55a15f2bc25c360deeebe0.tar.bz2
libADLMIDI-d7b9439df5d09d121c55a15f2bc25c360deeebe0.zip
dynamic instrument API
Diffstat (limited to 'src')
-rw-r--r--src/adldata.hh10
-rw-r--r--src/adlmidi.cpp136
-rw-r--r--src/adlmidi_bankmap.h2
-rw-r--r--src/adlmidi_bankmap.tcc19
-rw-r--r--src/adlmidi_load.cpp79
-rw-r--r--src/adlmidi_private.hpp4
6 files changed, 245 insertions, 5 deletions
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<MIDIplay *>(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<MIDIplay *>(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<uint16_t, OPL3::Bank> 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<OPL3::BankMap::iterator, bool> 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<MIDIplay *>(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<MIDIplay *>(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<MIDIplay *>(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
@@ -137,6 +137,25 @@ inline bool BasicBankMap<T>::iterator::operator!=(const iterator &o) const
}
template <class T>
+void BasicBankMap<T>::iterator::to_ptrs(void *ptrs[3])
+{
+ ptrs[0] = buckets;
+ ptrs[1] = slot;
+ ptrs[2] = (void *)index;
+}
+
+template <class T>
+typename BasicBankMap<T>::iterator
+BasicBankMap<T>::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 <class T>
std::pair<typename BasicBankMap<T>::iterator, bool>
BasicBankMap<T>::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 <class WOPLI>
+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 <class WOPLI>
+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<int8_t>(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<uint8_t>(in.adl[slt].carrier_E862 >> 24);
+ ins.operators[op].susrel_80 = static_cast<uint8_t>(in.adl[slt].carrier_E862 >> 16);
+ ins.operators[op].atdec_60 = static_cast<uint8_t>(in.adl[slt].carrier_E862 >> 8);
+ ins.operators[op].avekf_20 = static_cast<uint8_t>(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<uint8_t>(in.adl[slt].carrier_E862 >> 24);
+ ins.operators[op].susrel_80 = static_cast<uint8_t>(in.adl[slt].carrier_E862 >> 16);
+ ins.operators[op].atdec_60 = static_cast<uint8_t>(in.adl[slt].carrier_E862 >> 8);
+ ins.operators[op].avekf_20 = static_cast<uint8_t>(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<Bank> BankMap;
-private:
BankMap dynamic_banks;
AdlBankSetup dynamic_bank_setup;
public: