diff options
author | Vitaly Novichkov <admin@wohlnet.ru> | 2018-06-02 01:41:28 +0300 |
---|---|---|
committer | Vitaly Novichkov <admin@wohlnet.ru> | 2018-06-02 01:41:28 +0300 |
commit | 9fb6aef78053b6462f2e74fdb750576dbd3eab96 (patch) | |
tree | 6c1e0a504da727fb6ec699d930b8b8ee6883c027 | |
parent | a983e9325269a1d1abebeaa104c862041e315598 (diff) | |
parent | bfd80e89d91a1f014ee8c7bf8996aecfbc257975 (diff) | |
download | libADLMIDI-9fb6aef78053b6462f2e74fdb750576dbd3eab96.tar.gz libADLMIDI-9fb6aef78053b6462f2e74fdb750576dbd3eab96.tar.bz2 libADLMIDI-9fb6aef78053b6462f2e74fdb750576dbd3eab96.zip |
Merge branch 'banks3-rebase'
-rw-r--r-- | src/adlmidi_bankmap.h | 1 | ||||
-rw-r--r-- | src/adlmidi_load.cpp | 40 | ||||
-rw-r--r-- | src/adlmidi_midiplay.cpp | 260 | ||||
-rw-r--r-- | src/adlmidi_opl3.cpp | 81 | ||||
-rw-r--r-- | src/adlmidi_private.cpp | 23 | ||||
-rw-r--r-- | src/adlmidi_private.hpp | 32 |
6 files changed, 209 insertions, 228 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..07bcc6a 100644 --- a/src/adlmidi_midiplay.cpp +++ b/src/adlmidi_midiplay.cpp @@ -205,7 +205,9 @@ void MIDIplay::MidiTrackRow::sortEvents(bool *noteStates) j = noteOffs.erase(j); markAsOn.erase(note_i); continue; - } else { + } + else + { //When same row has many note-offs on same row //that means a zero-length note follows previous note //it must be shuted down @@ -434,17 +436,17 @@ bool MIDIplay::buildTrackData() if(track.empty()) continue;//Empty track is useless! - #ifdef DEBUG_TIME_CALCULATION +#ifdef DEBUG_TIME_CALCULATION std::fprintf(stdout, "\n============Track %" PRIuPTR "=============\n", tk); std::fflush(stdout); - #endif +#endif MidiTrackRow *posPrev = &(*(track.begin()));//First element for(MidiTrackQueue::iterator it = track.begin(); it != track.end(); it++) { - #ifdef DEBUG_TIME_CALCULATION +#ifdef DEBUG_TIME_CALCULATION bool tempoChanged = false; - #endif +#endif MidiTrackRow &pos = *it; if((posPrev != &pos) && //Skip first event (!tempos.empty()) && //Only when in-track tempo events are available @@ -490,9 +492,9 @@ bool MIDIplay::buildTrackData() //Apply next tempo currentTempo = points[j].tempo; - #ifdef DEBUG_TIME_CALCULATION +#ifdef DEBUG_TIME_CALCULATION tempoChanged = true; - #endif +#endif } //Then calculate time between last tempo change point and end point TempoChangePoint tailTempo = points.back(); @@ -535,10 +537,10 @@ bool MIDIplay::buildTrackData() loopEndTime = pos.time; } - #ifdef DEBUG_TIME_CALCULATION +#ifdef DEBUG_TIME_CALCULATION std::fprintf(stdout, "= %10" PRId64 " = %10f%s\n", pos.absPos, pos.time, tempoChanged ? " <----TEMPO CHANGED" : ""); std::fflush(stdout); - #endif +#endif abs_position += pos.delay; posPrev = &pos; @@ -558,7 +560,7 @@ bool MIDIplay::buildTrackData() //Resolve "hell of all times" of too short drum notes: //move too short percussion note-offs far far away as possible /********************************************************************************/ - #if 1 //Use this to record WAVEs for comparison before/after implementing of this +#if 1 //Use this to record WAVEs for comparison before/after implementing of this if(opl.m_musicMode == OPL3::MODE_MIDI)//Percussion fix is needed for MIDI only, not for IMF/RSXX or CMF { //! Minimal real time in seconds @@ -608,8 +610,8 @@ bool MIDIplay::buildTrackData() } bool percussion = (et->channel == 9) || - banks[et->channel] == 0x7E00 || //XG SFX1/SFX2 channel (16128 signed decimal) - banks[et->channel] == 0x7F00; //XG Percussion channel (16256 signed decimal) + banks[et->channel] == 0x7E00 || //XG SFX1/SFX2 channel (16128 signed decimal) + banks[et->channel] == 0x7F00; //XG Percussion channel (16256 signed decimal) if(!percussion) continue; @@ -670,7 +672,7 @@ bool MIDIplay::buildTrackData() #undef DRUM_NOTE_MIN_TIME #undef DRUM_NOTE_MIN_TICKS } - #endif +#endif return true; } @@ -728,17 +730,17 @@ void MIDIplay::applySetup() opl.dynamic_bank_setup = adlbanksetup[m_setup.AdlBank]; opl.HighTremoloMode = m_setup.HighTremoloMode < 0 ? - opl.dynamic_bank_setup.deepTremolo : - (bool)m_setup.HighTremoloMode; + opl.dynamic_bank_setup.deepTremolo : + (bool)m_setup.HighTremoloMode; opl.HighVibratoMode = m_setup.HighVibratoMode < 0 ? - opl.dynamic_bank_setup.deepVibrato : - (bool)m_setup.HighVibratoMode; + opl.dynamic_bank_setup.deepVibrato : + (bool)m_setup.HighVibratoMode; opl.AdlPercussionMode = m_setup.AdlPercussionMode < 0 ? - opl.dynamic_bank_setup.adLibPercussions : - (bool)m_setup.AdlPercussionMode; + opl.dynamic_bank_setup.adLibPercussions : + (bool)m_setup.AdlPercussionMode; opl.ScaleModulators = m_setup.ScaleModulators < 0 ? - opl.dynamic_bank_setup.scaleModulators : - (bool)m_setup.ScaleModulators; + opl.dynamic_bank_setup.scaleModulators : + (bool)m_setup.ScaleModulators; if(m_setup.LogarithmicVolumes) opl.ChangeVolumeRangesModel(ADLMIDI_VolumeModel_NativeOPL3); opl.m_musicMode = OPL3::MODE_MIDI; @@ -791,9 +793,9 @@ uint64_t MIDIplay::ReadVarLenEx(uint8_t **ptr, uint8_t *end, bool &ok) double MIDIplay::Tick(double s, double granularity) { s *= tempoMultiplier; - #ifdef ENABLE_BEGIN_SILENCE_SKIPPING +#ifdef ENABLE_BEGIN_SILENCE_SKIPPING if(CurrentPositionNew.began) - #endif +#endif CurrentPositionNew.wait -= s; CurrentPositionNew.absTimePosition += s; @@ -822,7 +824,7 @@ double MIDIplay::Tick(double s, double granularity) return CurrentPositionNew.wait; } -#endif +#endif /* ADLMIDI_DISABLE_MIDI_SEQUENCER */ void MIDIplay::TickIteratos(double s) { @@ -939,7 +941,7 @@ void MIDIplay::setTempo(double tempo) { tempoMultiplier = tempo; } -#endif +#endif /* ADLMIDI_DISABLE_MIDI_SEQUENCER */ void MIDIplay::realTime_ResetState() { @@ -987,7 +989,7 @@ bool MIDIplay::realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocity) MIDIchannel &midiChan = Ch[channel]; size_t midiins = midiChan.patch; - bool isPercussion = (channel % 16 == 9); + bool isPercussion = (channel % 16 == 9); bool isXgPercussion = false; uint16_t bank = 0; @@ -1001,7 +1003,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 +1012,43 @@ 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; + + const adlinsdata2 *ains = &OPL3::emptyInstrument; //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) + ains = &bnk->ins[midiins]; + else if(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(ains->flags & adlinsdata::Flag_NoSound) + { + OPL3::BankMap::iterator b = opl.dynamic_banks.find(bank & OPL3::PercussionTag); + if(b != opl.dynamic_banks.end()) + bnk = &b->second; + + if(bnk) + ains = &bnk->ins[midiins]; + } /* if(MidCh%16 == 9 || (midiins != 32 && midiins != 46 && midiins != 48 && midiins != 50)) @@ -1057,68 +1059,59 @@ 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); int16_t tone = note; if(!isPercussion && !isXgPercussion && (bank > 0)) // For non-zero banks { - if(ains.flags & adlinsdata::Flag_NoSound) + if(ains->flags & adlinsdata::Flag_NoSound) { 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); } } - if(ains.tone) + if(ains->tone) { - /*if(ains.tone < 20) - tone += ains.tone; + /*if(ains->tone < 20) + tone += ains->tone; else*/ - if(ains.tone < 128) - tone = ains.tone; + if(ains->tone < 128) + tone = ains->tone; else - tone -= ains.tone - 128; + tone -= ains->tone - 128; } - //uint16_t i[2] = { ains.adlno1, ains.adlno2 }; - bool pseudo_4op = ains.flags & adlinsdata::Flag_Pseudo4op; + //uint16_t i[2] = { ains->adlno1, ains->adlno2 }; + bool pseudo_4op = ains->flags & adlinsdata::Flag_Pseudo4op; #ifndef __WATCOMC__ MIDIchannel::NoteInfo::Phys voices[MIDIchannel::NoteInfo::MaxNumPhysChans] = { - {0, ains.adl[0], false}, - {0, ains.adl[1], pseudo_4op} + {0, ains->adl[0], false}, + {0, ains->adl[1], pseudo_4op} }; #else /* Unfortunately, WatCom can't brace-initialize structure that incluses structure fields */ MIDIchannel::NoteInfo::Phys voices[MIDIchannel::NoteInfo::MaxNumPhysChans]; voices[0].chip_chan = 0; - voices[0].ains = ains.adl[0]; + voices[0].ains = ains->adl[0]; voices[0].pseudo4op = false; voices[1].chip_chan = 0; - voices[1].ains = ains.adl[1]; + voices[1].ains = ains->adl[1]; voices[1].pseudo4op = pseudo_4op; -#endif +#endif /* __WATCOMC__ */ if((opl.AdlPercussionMode == 1) && PercussionMap[midiins & 0xFF]) voices[1] = voices[0];//i[1] = i[0]; 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 +1204,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 +1442,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; @@ -1466,7 +1458,8 @@ void MIDIplay::NoteUpdate(uint16_t MidCh, { opl.Patch(c, ins.ains); AdlChannel::LocationData *d = ch[c].users_find_or_create(my_loc); - if(d) { // inserts if necessary + if(d) // inserts if necessary + { d->sustained = false; d->vibdelay = 0; d->kon_time_until_neglible = ains.ms_sound_kon; @@ -1502,7 +1495,9 @@ void MIDIplay::NoteUpdate(uint16_t MidCh, { opl.Touch_Real(c, 0); ch[c].koff_time_until_neglible = 0; - } else { + } + else + { ch[c].koff_time_until_neglible = ains.ms_sound_koff; } } @@ -1637,11 +1632,11 @@ void MIDIplay::NoteUpdate(uint16_t MidCh, if(vibrato && (!d || d->vibdelay >= Ch[MidCh].vibdelay)) bend += static_cast<double>(vibrato) * Ch[MidCh].vibdepth * std::sin(Ch[MidCh].vibpos); - #ifdef ADLMIDI_USE_DOSBOX_OPL -#define BEND_COEFFICIENT 172.00093 - #else -#define BEND_COEFFICIENT 172.4387 - #endif +#ifdef ADLMIDI_USE_DOSBOX_OPL +# define BEND_COEFFICIENT 172.00093 +#else +# define BEND_COEFFICIENT 172.4387 +#endif opl.NoteOn(c, BEND_COEFFICIENT * std::exp(0.057762265 * (tone + bend + phase))); #undef BEND_COEFFICIENT if(hooks.onNote) @@ -1666,9 +1661,9 @@ bool MIDIplay::ProcessEventsNew(bool isSeek) const size_t TrackCount = CurrentPositionNew.track.size(); const PositionNew RowBeginPosition(CurrentPositionNew); - #ifdef DEBUG_TIME_CALCULATION +#ifdef DEBUG_TIME_CALCULATION double maxTime = 0.0; - #endif +#endif for(size_t tk = 0; tk < TrackCount; ++tk) { @@ -1686,10 +1681,10 @@ bool MIDIplay::ProcessEventsNew(bool isSeek) for(size_t i = 0; i < track.pos->events.size(); i++) { const MidiEvent &evt = track.pos->events[i]; - #ifdef ENABLE_BEGIN_SILENCE_SKIPPING +#ifdef ENABLE_BEGIN_SILENCE_SKIPPING if(!CurrentPositionNew.began && (evt.type == MidiEvent::T_NOTEON)) CurrentPositionNew.began = true; - #endif +#endif if(isSeek && (evt.type == MidiEvent::T_NOTEON)) continue; HandleEvent(tk, evt, track.status); @@ -1697,10 +1692,10 @@ bool MIDIplay::ProcessEventsNew(bool isSeek) break;//Stop event handling on catching loopEnd event! } - #ifdef DEBUG_TIME_CALCULATION +#ifdef DEBUG_TIME_CALCULATION if(maxTime < track.pos->time) maxTime = track.pos->time; - #endif +#endif // Read next event time (unless the track just ended) if(track.status >= 0) { @@ -1710,11 +1705,11 @@ bool MIDIplay::ProcessEventsNew(bool isSeek) } } - #ifdef DEBUG_TIME_CALCULATION +#ifdef DEBUG_TIME_CALCULATION std::fprintf(stdout, " \r"); std::fprintf(stdout, "Time: %10f; Audio: %10f\r", maxTime, CurrentPositionNew.absTimePosition); std::fflush(stdout); - #endif +#endif // Find shortest delay from all track uint64_t shortest = 0; @@ -1738,9 +1733,9 @@ bool MIDIplay::ProcessEventsNew(bool isSeek) fraction<uint64_t> t = shortest * Tempo; - #ifdef ENABLE_BEGIN_SILENCE_SKIPPING +#ifdef ENABLE_BEGIN_SILENCE_SKIPPING if(CurrentPositionNew.began) - #endif +#endif CurrentPositionNew.wait += t.value(); //if(shortest > 0) UI.PrintLn("Delay %ld (%g)", shortest, (double)t.valuel()); @@ -1766,9 +1761,7 @@ bool MIDIplay::ProcessEventsNew(bool isSeek) return true;//Has events in queue } -#endif -#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER MIDIplay::MidiEvent MIDIplay::parseEvent(uint8_t **pptr, uint8_t *end, int &status) { uint8_t *&ptr = *pptr; @@ -1987,7 +1980,7 @@ MIDIplay::MidiEvent MIDIplay::parseEvent(uint8_t **pptr, uint8_t *end, int &stat return evt; } -#endif +#endif /* ADLMIDI_DISABLE_MIDI_SEQUENCER */ const std::string &MIDIplay::getErrorString() { @@ -2076,7 +2069,7 @@ void MIDIplay::HandleEvent(size_t tk, const MIDIplay::MidiEvent &evt, int &statu v |= 0x30; //std::printf("OPL poke %02X, %02X\n", i, v); //std::fflush(stdout); - opl.PokeN(0, i, v); + opl.Poke(0, i, v); return; } @@ -2156,7 +2149,7 @@ void MIDIplay::HandleEvent(size_t tk, const MIDIplay::MidiEvent &evt, int &statu } } } -#endif +#endif /* ADLMIDI_DISABLE_MIDI_SEQUENCER */ int64_t MIDIplay::CalculateAdlChannelGoodness(unsigned c, const MIDIchannel::NoteInfo::Phys &ins, uint16_t) const { @@ -2164,7 +2157,7 @@ int64_t MIDIplay::CalculateAdlChannelGoodness(unsigned c, const MIDIchannel::Not // Same midi-instrument = some stability //if(c == MidCh) s += 4; - for (AdlChannel::LocationData *j = ch[c].users_first; j; j = j->next) + for(AdlChannel::LocationData *j = ch[c].users_first; j; j = j->next) { s -= 4000; @@ -2478,9 +2471,9 @@ void MIDIplay::UpdateArpeggio(double) // amount = amount of time passed { // If there is an adlib channel that has multiple notes // simulated on the same channel, arpeggio them. - #if 0 +#if 0 const unsigned desired_arpeggio_rate = 40; // Hz (upper limit) - #if 1 +# if 1 static unsigned cache = 0; amount = amount; // Ignore amount. Assume we get a constant rate. cache += MaxSamplesAtTime * desired_arpeggio_rate; @@ -2488,15 +2481,15 @@ void MIDIplay::UpdateArpeggio(double) // amount = amount of time passed if(cache < PCM_RATE) return; cache %= PCM_RATE; - #else +# else static double arpeggio_cache = 0; arpeggio_cache += amount * desired_arpeggio_rate; if(arpeggio_cache < 1.0) return; arpeggio_cache = 0.0; - #endif - #endif +# endif +#endif static unsigned arpeggio_counter = 0; ++arpeggio_counter; @@ -2520,7 +2513,7 @@ retry_arpeggio: rate_reduction = 1; for(unsigned count = (arpeggio_counter / rate_reduction) % n_users, - n = 0; n < count; ++n) + n = 0; n < count; ++n) i = i->next; if(i->sustained == false) @@ -2606,7 +2599,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) @@ -2661,12 +2654,12 @@ ADLMIDI_EXPORT void AdlInstrumentTester::NextGM(int offset) ADLMIDI_EXPORT void AdlInstrumentTester::NextAdl(int offset) { - OPL3 *opl = P->opl; + //OPL3 *opl = P->opl; if(P->adl_ins_list.empty()) FindAdlList(); const unsigned NumBanks = (unsigned)adl_getBanksCount(); P->ins_idx = (uint32_t)((int32_t)P->ins_idx + (int32_t)P->adl_ins_list.size() + offset) % P->adl_ins_list.size(); - #if 0 +#if 0 UI.Color(15); std::fflush(stderr); std::printf("SELECTED G%c%d\t%s\n", @@ -2675,12 +2668,12 @@ ADLMIDI_EXPORT void AdlInstrumentTester::NextAdl(int offset) std::fflush(stdout); UI.Color(7); std::fflush(stderr); - #endif +#endif 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) @@ -2735,9 +2728,9 @@ ADLMIDI_EXPORT bool AdlInstrumentTester::HandleInputChar(char ch) NextGM(+1); break; case 3: - #if !((!defined(__WIN32__) || defined(__CYGWIN__)) && !defined(__DJGPP__)) +#if !((!defined(__WIN32__) || defined(__CYGWIN__)) && !defined(__DJGPP__)) case 27: - #endif +#endif return false; default: const char *p = std::strchr(notes, ch); @@ -2747,7 +2740,7 @@ ADLMIDI_EXPORT bool AdlInstrumentTester::HandleInputChar(char ch) return true; } -#endif//ADLMIDI_DISABLE_CPP_EXTRAS +#endif /* ADLMIDI_DISABLE_CPP_EXTRAS */ // Implement the user map data structure. @@ -2787,13 +2780,15 @@ MIDIplay::AdlChannel::LocationData *MIDIplay::AdlChannel::users_allocate() MIDIplay::AdlChannel::LocationData *MIDIplay::AdlChannel::users_find_or_create(Location loc) { LocationData *user = users_find(loc); - if(!user) { + if(!user) + { user = users_allocate(); if(!user) return NULL; LocationData *prev = user->prev, *next = user->next; *user = LocationData(); - user->prev = prev; user->next = next; + user->prev = prev; + user->next = next; user->loc = loc; } return user; @@ -2809,7 +2804,8 @@ MIDIplay::AdlChannel::LocationData *MIDIplay::AdlChannel::users_insert(const Loc return NULL; LocationData *prev = user->prev, *next = user->next; *user = x; - user->prev = prev; user->next = next; + user->prev = prev; + user->next = next; } return user; } @@ -2844,7 +2840,8 @@ void MIDIplay::AdlChannel::users_assign(const LocationData *users, size_t count) { ADL_UNUSED(count);//Avoid warning for release builds assert(count <= users_max); - if(users == users_first && users) { + if(users == users_first && users) + { // self assignment assert(users_size == count); return; @@ -2852,17 +2849,20 @@ void MIDIplay::AdlChannel::users_assign(const LocationData *users, size_t count) users_clear(); const LocationData *src_cell = users; // move to the last - if(src_cell) { + if(src_cell) + { while(src_cell->next) src_cell = src_cell->next; } // push cell copies in reverse order - while(src_cell) { + while(src_cell) + { LocationData *dst_cell = users_allocate(); assert(dst_cell); LocationData *prev = dst_cell->prev, *next = dst_cell->next; *dst_cell = *src_cell; - dst_cell->prev = prev; dst_cell->next = next; + dst_cell->prev = prev; + dst_cell->next = next; src_cell = src_cell->prev; } assert(users_size == count); diff --git a/src/adlmidi_opl3.cpp b/src/adlmidi_opl3.cpp index 143c911..b4db049 100644 --- a/src/adlmidi_opl3.cpp +++ b/src/adlmidi_opl3.cpp @@ -129,73 +129,56 @@ 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 >= static_cast<unsigned int>(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) -{} - -void OPL3::Poke(size_t card, uint32_t index, uint32_t value) { - #ifdef ADLMIDI_HW_OPL - (void)card; - unsigned o = index >> 8; - unsigned port = OPLBase + o * 2; - - #ifdef __DJGPP__ - outportb(port, index); - for(unsigned c = 0; c < 6; ++c) inportb(port); - outportb(port + 1, value); - for(unsigned c = 0; c < 35; ++c) inportb(port); - #endif//__DJGPP__ - - #ifdef __WATCOMC__ - outp(port, index); - for(uint16_t c = 0; c < 6; ++c) inp(port); - outp(port + 1, value); - for(uint16_t c = 0; c < 35; ++c) inp(port); - #endif//__WATCOMC__ - - #else//ADLMIDI_HW_OPL - cardsOP2[card]->writeReg(static_cast<uint16_t>(index), static_cast<uint8_t>(value)); - #endif//ADLMIDI_HW_OPL +#ifdef DISABLE_EMBEDDED_BANKS + AdlBank = ~0u; +#else + setEmbeddedBank(0); +#endif } -void OPL3::PokeN(size_t card, uint16_t index, uint8_t value) +void OPL3::Poke(size_t card, uint16_t index, uint8_t value) { #ifdef ADLMIDI_HW_OPL (void)card; @@ -560,7 +543,7 @@ void OPL3::Reset(int emulator, unsigned long PCM_RATE) for(unsigned a = 0; a < 18; ++a) Poke(i, 0xB0 + Channels[a], 0x00); for(unsigned a = 0; a < sizeof(data) / sizeof(*data); a += 2) - PokeN(i, data[a], static_cast<uint8_t>(data[a + 1])); + Poke(i, data[a], static_cast<uint8_t>(data[a + 1])); Poke(i, 0x0BD, regBD[i] = (HighTremoloMode * 0x80 + HighVibratoMode * 0x40 + AdlPercussionMode * 0x20)); 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..8e3b158 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; @@ -284,8 +281,7 @@ public: // 7 = percussion Hihat // 8 = percussion slave - void Poke(size_t card, uint32_t index, uint32_t value); - void PokeN(size_t card, uint16_t index, uint8_t value); + void Poke(size_t card, uint16_t index, uint8_t value); void NoteOff(size_t c); void NoteOn(unsigned c, double hertz); @@ -530,10 +526,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, |