aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVitaly Novichkov <admin@wohlnet.ru>2018-06-02 01:41:28 +0300
committerVitaly Novichkov <admin@wohlnet.ru>2018-06-02 01:41:28 +0300
commit9fb6aef78053b6462f2e74fdb750576dbd3eab96 (patch)
tree6c1e0a504da727fb6ec699d930b8b8ee6883c027
parenta983e9325269a1d1abebeaa104c862041e315598 (diff)
parentbfd80e89d91a1f014ee8c7bf8996aecfbc257975 (diff)
downloadlibADLMIDI-9fb6aef78053b6462f2e74fdb750576dbd3eab96.tar.gz
libADLMIDI-9fb6aef78053b6462f2e74fdb750576dbd3eab96.tar.bz2
libADLMIDI-9fb6aef78053b6462f2e74fdb750576dbd3eab96.zip
Merge branch 'banks3-rebase'
-rw-r--r--src/adlmidi_bankmap.h1
-rw-r--r--src/adlmidi_load.cpp40
-rw-r--r--src/adlmidi_midiplay.cpp260
-rw-r--r--src/adlmidi_opl3.cpp81
-rw-r--r--src/adlmidi_private.cpp23
-rw-r--r--src/adlmidi_private.hpp32
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,