aboutsummaryrefslogtreecommitdiff
path: root/src/adlmidi_midiplay.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/adlmidi_midiplay.cpp')
-rw-r--r--src/adlmidi_midiplay.cpp277
1 files changed, 138 insertions, 139 deletions
diff --git a/src/adlmidi_midiplay.cpp b/src/adlmidi_midiplay.cpp
index ed7f44a..702ebea 100644
--- a/src/adlmidi_midiplay.cpp
+++ b/src/adlmidi_midiplay.cpp
@@ -117,18 +117,18 @@ inline bool isXgPercChannel(uint8_t msb, uint8_t lsb)
void MIDIplay::AdlChannel::AddAge(int64_t ms)
{
- if(users.empty())
+ if(users_empty())
koff_time_until_neglible =
std::max(int64_t(koff_time_until_neglible - ms), static_cast<int64_t>(-0x1FFFFFFFl));
else
{
koff_time_until_neglible = 0;
- for(users_t::iterator i = users.begin(); i != users.end(); ++i)
+ for(LocationData *i = users_first; i; i = i->next)
{
- i->second.kon_time_until_neglible =
- std::max(i->second.kon_time_until_neglible - ms, static_cast<int64_t>(-0x1FFFFFFFl));
- i->second.vibdelay += ms;
+ i->kon_time_until_neglible =
+ std::max(i->kon_time_until_neglible - ms, static_cast<int64_t>(-0x1FFFFFFFl));
+ i->vibdelay += ms;
}
}
}
@@ -760,6 +760,7 @@ void MIDIplay::applySetup()
ch.resize(opl.NumChannels);
}
+#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER
uint64_t MIDIplay::ReadVarLen(uint8_t **ptr)
{
uint64_t result = 0;
@@ -792,7 +793,6 @@ uint64_t MIDIplay::ReadVarLenEx(uint8_t **ptr, uint8_t *end, bool &ok)
return result;
}
-#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER
double MIDIplay::Tick(double s, double granularity)
{
s *= tempoMultiplier;
@@ -967,10 +967,10 @@ bool MIDIplay::realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocity)
if((opl.m_musicMode == OPL3::MODE_RSXX) && (velocity != 0))
{
// Check if this is just a note after-touch
- MIDIchannel::activenoteiterator i = Ch[channel].activenotes.find(note);
- if(i != Ch[channel].activenotes.end())
+ MIDIchannel::activenoteiterator i = Ch[channel].activenotes_find(note);
+ if(i)
{
- i->second.vol = velocity;
+ i->vol = velocity;
NoteUpdate(channel, i, Upd_Volume);
return false;
}
@@ -1093,10 +1093,10 @@ bool MIDIplay::realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocity)
//uint16_t i[2] = { ains.adlno1, ains.adlno2 };
bool pseudo_4op = ains->flags & adlinsdata::Flag_Pseudo4op;
- MIDIchannel::NoteInfo::Phys voices[2] =
+ MIDIchannel::NoteInfo::Phys voices[MIDIchannel::NoteInfo::MaxNumPhysChans] =
{
- {ains->adlno1, false},
- {ains->adlno2, pseudo_4op}
+ {0, ains->adlno1, false},
+ {0, ains->adlno2, pseudo_4op}
};
if((opl.AdlPercussionMode == 1) && PercussionMap[midiins & 0xFF])
@@ -1112,9 +1112,9 @@ bool MIDIplay::realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocity)
}
// Allocate AdLib channel (the physical sound channel for the note)
- int32_t adlchannel[2] = { -1, -1 };
+ int32_t adlchannel[MIDIchannel::NoteInfo::MaxNumPhysChans] = { -1, -1 };
- for(uint32_t ccount = 0; ccount < 2; ++ccount)
+ for(uint32_t ccount = 0; ccount < MIDIchannel::NoteInfo::MaxNumPhysChans; ++ccount)
{
if(ccount == 1)
{
@@ -1196,19 +1196,20 @@ bool MIDIplay::realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocity)
// Allocate active note for MIDI channel
std::pair<MIDIchannel::activenoteiterator, bool>
- ir = Ch[channel].activenotes.insert(std::make_pair(note, MIDIchannel::NoteInfo()));
- ir.first->second.vol = velocity;
- ir.first->second.tone = tone;
- ir.first->second.midiins = midiins;
- ir.first->second.insmeta = meta;
+ ir = Ch[channel].activenotes_insert(note);
+ ir.first->vol = velocity;
+ ir.first->tone = tone;
+ ir.first->midiins = midiins;
+ ir.first->insmeta = meta;
+ ir.first->chip_channels_count = 0;
- for(unsigned ccount = 0; ccount < 2; ++ccount)
+ for(unsigned ccount = 0; ccount < MIDIchannel::NoteInfo::MaxNumPhysChans; ++ccount)
{
int32_t c = adlchannel[ccount];
if(c < 0)
continue;
uint16_t chipChan = static_cast<uint16_t>(adlchannel[ccount]);
- ir.first->second.phys[chipChan] = voices[ccount];
+ ir.first->phys_ensure_find_or_create(chipChan)->assign(voices[ccount]);
}
NoteUpdate(channel, ir.first, Upd_All | Upd_Patch);
return true;
@@ -1224,13 +1225,13 @@ void MIDIplay::realTime_NoteAfterTouch(uint8_t channel, uint8_t note, uint8_t at
{
channel = channel % 16;
MIDIchannel::activenoteiterator
- i = Ch[channel].activenotes.find(note);
- if(i == Ch[channel].activenotes.end())
+ i = Ch[channel].activenotes_find(note);
+ if(!i)
{
// Ignore touch if note is not active
return;
}
- i->second.vol = 127 - atVal;
+ i->vol = 127 - atVal;
NoteUpdate(channel, i, Upd_Volume);
}
@@ -1239,12 +1240,10 @@ void MIDIplay::realTime_ChannelAfterTouch(uint8_t channel, uint8_t atVal)
// TODO: Verify, is this correct action?
channel = channel % 16;
for(MIDIchannel::activenoteiterator
- i = Ch[channel].activenotes.begin();
- i != Ch[channel].activenotes.end();
- ++i)
+ i = Ch[channel].activenotes_begin(); i; ++i)
{
// Set this pressure to all active notes on the channel
- i->second.vol = 127 - atVal;
+ i->vol = 127 - atVal;
}
NoteUpdate_All(channel, Upd_Volume);
@@ -1436,7 +1435,7 @@ void MIDIplay::NoteUpdate(uint16_t MidCh,
unsigned props_mask,
int32_t select_adlchn)
{
- MIDIchannel::NoteInfo &info = i->second;
+ MIDIchannel::NoteInfo &info = *i;
const int16_t tone = info.tone;
const uint8_t vol = info.vol;
const int midiins = info.midiins;
@@ -1444,38 +1443,32 @@ void MIDIplay::NoteUpdate(uint16_t MidCh,
const adlinsdata &ains = opl.GetAdlMetaIns(insmeta);
AdlChannel::Location my_loc;
my_loc.MidCh = MidCh;
- my_loc.note = i->first;
+ my_loc.note = info.note;
- for(MIDIchannel::NoteInfo::PhysMap::iterator
- jnext = info.phys.begin();
- jnext != info.phys.end();
- )
+ for(unsigned ccount = 0, ctotal = info.chip_channels_count; ccount < ctotal; ccount++)
{
- MIDIchannel::NoteInfo::PhysMap::iterator j(jnext++);
- uint16_t c = j->first;
- const MIDIchannel::NoteInfo::Phys &ins = j->second;
+ const MIDIchannel::NoteInfo::Phys &ins = info.chip_channels[ccount];
+ uint16_t c = ins.chip_chan;
if(select_adlchn >= 0 && c != select_adlchn) continue;
if(props_mask & Upd_Patch)
{
opl.Patch(c, ins.insId);
- AdlChannel::LocationData &d = ch[c].users[my_loc];
- d.sustained = false; // inserts if necessary
- d.vibdelay = 0;
- d.kon_time_until_neglible = ains.ms_sound_kon;
- d.ins = ins;
+ AdlChannel::LocationData *d = ch[c].users_find_or_create(my_loc);
+ if(d) { // inserts if necessary
+ d->sustained = false;
+ d->vibdelay = 0;
+ d->kon_time_until_neglible = ains.ms_sound_kon;
+ d->ins = ins;
+ }
}
}
- for(MIDIchannel::NoteInfo::PhysMap::iterator
- jnext = info.phys.begin();
- jnext != info.phys.end();
- )
+ for(unsigned ccount = 0; ccount < info.chip_channels_count; ccount++)
{
- MIDIchannel::NoteInfo::PhysMap::iterator j(jnext++);
- uint16_t c = j->first;
- const MIDIchannel::NoteInfo::Phys &ins = j->second;
+ const MIDIchannel::NoteInfo::Phys &ins = info.chip_channels[ccount];
+ uint16_t c = ins.chip_chan;
if(select_adlchn >= 0 && c != select_adlchn)
continue;
@@ -1484,15 +1477,15 @@ void MIDIplay::NoteUpdate(uint16_t MidCh,
{
if(Ch[MidCh].sustain == 0)
{
- AdlChannel::users_t::iterator k = ch[c].users.find(my_loc);
+ AdlChannel::LocationData *k = ch[c].users_find(my_loc);
- if(k != ch[c].users.end())
- ch[c].users.erase(k);
+ if(k)
+ ch[c].users_erase(k);
if(hooks.onNote)
hooks.onNote(hooks.onNote_userData, c, tone, midiins, 0, 0.0);
- if(ch[c].users.empty())
+ if(ch[c].users_empty())
{
opl.NoteOff(c);
if(props_mask & Upd_Mute) // Mute the note
@@ -1508,13 +1501,15 @@ void MIDIplay::NoteUpdate(uint16_t MidCh,
{
// Sustain: Forget about the note, but don't key it off.
// Also will avoid overwriting it very soon.
- AdlChannel::LocationData &d = ch[c].users[my_loc];
- d.sustained = true; // note: not erased!
+ AdlChannel::LocationData *d = ch[c].users_find_or_create(my_loc);
+ if(d)
+ d->sustained = true; // note: not erased!
if(hooks.onNote)
hooks.onNote(hooks.onNote_userData, c, tone, midiins, -1, 0.0);
}
- info.phys.erase(j);
+ info.phys_erase_at(&ins); // decrements channel count
+ --ccount; // adjusts index accordingly
continue;
}
@@ -1610,10 +1605,10 @@ void MIDIplay::NoteUpdate(uint16_t MidCh,
if(props_mask & Upd_Pitch)
{
- AdlChannel::LocationData &d = ch[c].users[my_loc];
+ AdlChannel::LocationData *d = ch[c].users_find(my_loc);
// Don't bend a sustained note
- if(!d.sustained)
+ if(!d || !d->sustained)
{
double bend = Ch[MidCh].bend + opl.GetAdlIns(ins.insId).finetune;
double phase = 0.0;
@@ -1623,7 +1618,7 @@ void MIDIplay::NoteUpdate(uint16_t MidCh,
phase = ains.voice2_fine_tune;//0.125; // Detune the note slightly (this is what Doom does)
}
- if(Ch[MidCh].vibrato && d.vibdelay >= Ch[MidCh].vibdelay)
+ if(Ch[MidCh].vibrato && d->vibdelay >= Ch[MidCh].vibdelay)
bend += Ch[MidCh].vibrato * Ch[MidCh].vibdepth * std::sin(Ch[MidCh].vibpos);
#ifdef ADLMIDI_USE_DOSBOX_OPL
@@ -1639,8 +1634,8 @@ void MIDIplay::NoteUpdate(uint16_t MidCh,
}
}
- if(info.phys.empty())
- Ch[MidCh].activenotes.erase(i);
+ if(info.chip_channels_count == 0)
+ Ch[MidCh].activenotes_erase(i);
}
#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER
@@ -2138,35 +2133,32 @@ int64_t MIDIplay::CalculateAdlChannelGoodness(unsigned c, const MIDIchannel::Not
// Same midi-instrument = some stability
//if(c == MidCh) s += 4;
- for(AdlChannel::users_t::const_iterator
- j = ch[c].users.begin();
- j != ch[c].users.end();
- ++j)
+ for (AdlChannel::LocationData *j = ch[c].users_first; j; j = j->next)
{
s -= 4000;
- if(!j->second.sustained)
- s -= j->second.kon_time_until_neglible;
+ if(!j->sustained)
+ s -= j->kon_time_until_neglible;
else
- s -= (j->second.kon_time_until_neglible / 2);
+ s -= (j->kon_time_until_neglible / 2);
- MIDIchannel::activenotemap_t::const_iterator
- k = Ch[j->first.MidCh].activenotes.find(j->first.note);
+ MIDIchannel::activenoteiterator
+ k = const_cast<MIDIchannel &>(Ch[j->loc.MidCh]).activenotes_find(j->loc.note);
- if(k != Ch[j->first.MidCh].activenotes.end())
+ if(k)
{
// Same instrument = good
- if(j->second.ins == ins)
+ if(j->ins == ins)
{
s += 300;
// Arpeggio candidate = even better
- if(j->second.vibdelay < 70
- || j->second.kon_time_until_neglible > 20000)
+ if(j->vibdelay < 70
+ || j->kon_time_until_neglible > 20000)
s += 0;
}
// Percussion is inferior to melody
- s += 50 * (int64_t)(k->second.midiins / 128);
+ s += 50 * (int64_t)(k->midiins / 128);
/*
if(k->second.midiins >= 25
&& k->second.midiins < 40
@@ -2189,14 +2181,11 @@ int64_t MIDIplay::CalculateAdlChannelGoodness(unsigned c, const MIDIchannel::Not
if(opl.four_op_category[c2]
!= opl.four_op_category[c]) continue;
- for(AdlChannel::users_t::const_iterator
- m = ch[c2].users.begin();
- m != ch[c2].users.end();
- ++m)
+ for(AdlChannel::LocationData *m = ch[c2].users_first; m; m = m->next)
{
- if(m->second.sustained) continue;
- if(m->second.vibdelay >= 200) continue;
- if(m->second.ins != j->second.ins) continue;
+ if(m->sustained) continue;
+ if(m->vibdelay >= 200) continue;
+ if(m->ins != j->ins) continue;
n_evacuation_stations += 1;
}
}
@@ -2210,27 +2199,25 @@ int64_t MIDIplay::CalculateAdlChannelGoodness(unsigned c, const MIDIchannel::Not
void MIDIplay::PrepareAdlChannelForNewNote(size_t c, const MIDIchannel::NoteInfo::Phys &ins)
{
- if(ch[c].users.empty()) return; // Nothing to do
+ if(ch[c].users_empty()) return; // Nothing to do
//bool doing_arpeggio = false;
- for(AdlChannel::users_t::iterator
- jnext = ch[c].users.begin();
- jnext != ch[c].users.end();
- )
+ for(AdlChannel::LocationData *jnext = ch[c].users_first; jnext;)
{
- AdlChannel::users_t::iterator j(jnext++);
+ AdlChannel::LocationData *j = jnext;
+ jnext = jnext->next;
- if(!j->second.sustained)
+ if(!j->sustained)
{
// Collision: Kill old note,
// UNLESS we're going to do arpeggio
MIDIchannel::activenoteiterator i
- (Ch[j->first.MidCh].activenotes.find(j->first.note));
+ (Ch[j->loc.MidCh].activenotes_ensure_find(j->loc.note));
// Check if we can do arpeggio.
- if((j->second.vibdelay < 70
- || j->second.kon_time_until_neglible > 20000)
- && j->second.ins == ins)
+ if((j->vibdelay < 70
+ || j->kon_time_until_neglible > 20000)
+ && j->ins == ins)
{
// Do arpeggio together with this note.
//doing_arpeggio = true;
@@ -2249,11 +2236,13 @@ void MIDIplay::PrepareAdlChannelForNewNote(size_t c, const MIDIchannel::NoteInfo
// Keyoff the channel so that it can be retriggered,
// unless the new note will be introduced as just an arpeggio.
- if(ch[c].users.empty())
+ if(ch[c].users_empty())
opl.NoteOff(c);
}
-void MIDIplay::KillOrEvacuate(size_t from_channel, AdlChannel::users_t::iterator j, MIDIplay::MIDIchannel::activenoteiterator i)
+void MIDIplay::KillOrEvacuate(size_t from_channel,
+ AdlChannel::LocationData *j,
+ MIDIplay::MIDIchannel::activenoteiterator i)
{
// Before killing the note, check if it can be
// evacuated to another channel as an arpeggio
@@ -2271,32 +2260,34 @@ void MIDIplay::KillOrEvacuate(size_t from_channel, AdlChannel::users_t::iterator
if(opl.four_op_category[c] != opl.four_op_category[from_channel])
continue;
- for(AdlChannel::users_t::iterator
- m = ch[c].users.begin();
- m != ch[c].users.end();
- ++m)
+ AdlChannel &adlch = ch[c];
+ if(adlch.users_size == AdlChannel::users_max)
+ continue; // no room for more arpeggio on channel
+
+ for(AdlChannel::LocationData *m = adlch.users_first; m; m = m->next)
{
- if(m->second.vibdelay >= 200
- && m->second.kon_time_until_neglible < 10000) continue;
- if(m->second.ins != j->second.ins)
+ if(m->vibdelay >= 200
+ && m->kon_time_until_neglible < 10000) continue;
+ if(m->ins != j->ins)
continue;
if(hooks.onNote)
{
hooks.onNote(hooks.onNote_userData,
(int)from_channel,
- i->second.tone,
- i->second.midiins, 0, 0.0);
+ i->tone,
+ i->midiins, 0, 0.0);
hooks.onNote(hooks.onNote_userData,
(int)c,
- i->second.tone,
- i->second.midiins,
- i->second.vol, 0.0);
+ i->tone,
+ i->midiins,
+ i->vol, 0.0);
}
- i->second.phys.erase(static_cast<uint16_t>(from_channel));
- i->second.phys[cs] = j->second.ins;
- ch[cs].users.insert(*j);
- ch[from_channel].users.erase(j);
+ i->phys_erase(static_cast<uint16_t>(from_channel));
+ i->phys_ensure_find_or_create(cs)->assign(j->ins);
+ if(!ch[cs].users_insert(*j))
+ assert(false);
+ ch[from_channel].users_erase(j);
return;
}
}
@@ -2309,7 +2300,7 @@ void MIDIplay::KillOrEvacuate(size_t from_channel, AdlChannel::users_t::iterator
ins
);*/
// Kill it
- NoteUpdate(j->first.MidCh,
+ NoteUpdate(j->loc.MidCh,
i,
Upd_Off,
static_cast<int32_t>(from_channel));
@@ -2336,27 +2327,25 @@ void MIDIplay::KillSustainingNotes(int32_t MidCh, int32_t this_adlchn)
for(unsigned c = first; c < last; ++c)
{
- if(ch[c].users.empty()) continue; // Nothing to do
+ if(ch[c].users_empty()) continue; // Nothing to do
- for(AdlChannel::users_t::iterator
- jnext = ch[c].users.begin();
- jnext != ch[c].users.end();
- )
+ for(AdlChannel::LocationData *jnext = ch[c].users_first; jnext;)
{
- AdlChannel::users_t::iterator j(jnext++);
+ AdlChannel::LocationData *j = jnext;
+ jnext = jnext->next;
- if((MidCh < 0 || j->first.MidCh == MidCh)
- && j->second.sustained)
+ if((MidCh < 0 || j->loc.MidCh == MidCh)
+ && j->sustained)
{
int midiins = '?';
if(hooks.onNote)
- hooks.onNote(hooks.onNote_userData, (int)c, j->first.note, midiins, 0, 0.0);
- ch[c].users.erase(j);
+ hooks.onNote(hooks.onNote_userData, (int)c, j->loc.note, midiins, 0, 0.0);
+ ch[c].users_erase(j);
}
}
// Keyoff the channel, if there are no users left.
- if(ch[c].users.empty())
+ if(ch[c].users_empty())
opl.NoteOff(c);
}
}
@@ -2402,9 +2391,7 @@ void MIDIplay::SetRPN(unsigned MidCh, unsigned value, bool MSB)
void MIDIplay::NoteUpdate_All(uint16_t MidCh, unsigned props_mask)
{
for(MIDIchannel::activenoteiterator
- i = Ch[MidCh].activenotes.begin();
- i != Ch[MidCh].activenotes.end();
- )
+ i = Ch[MidCh].activenotes_begin(); i;)
{
MIDIchannel::activenoteiterator j(i++);
NoteUpdate(MidCh, j, props_mask);
@@ -2414,9 +2401,9 @@ void MIDIplay::NoteUpdate_All(uint16_t MidCh, unsigned props_mask)
void MIDIplay::NoteOff(uint16_t MidCh, uint8_t note)
{
MIDIchannel::activenoteiterator
- i = Ch[MidCh].activenotes.find(note);
+ i = Ch[MidCh].activenotes_find(note);
- if(i != Ch[MidCh].activenotes.end())
+ if(i)
NoteUpdate(MidCh, i, Upd_Off);
}
@@ -2425,7 +2412,7 @@ void MIDIplay::UpdateVibrato(double amount)
{
for(size_t a = 0, b = Ch.size(); a < b; ++a)
{
- if(Ch[a].vibrato && !Ch[a].activenotes.empty())
+ if(Ch[a].vibrato && !Ch[a].activenotes_empty())
{
NoteUpdate_All(static_cast<uint16_t>(a), Upd_Pitch);
Ch[a].vibpos += amount * Ch[a].vibspeed;
@@ -2447,7 +2434,17 @@ uint64_t MIDIplay::ChooseDevice(const std::string &name)
size_t n = devices.size() * 16;
devices.insert(std::make_pair(name, n));
- Ch.resize(n + 16);
+
+ size_t channelsBefore = Ch.size();
+ size_t channels = n + 16;
+ Ch.resize(channels);
+
+ for(size_t ch = channelsBefore; ch < channels; ++ch) {
+ for(unsigned i = 0; i < 128; ++i) {
+ Ch[ch].activenotes[i].note = i;
+ Ch[ch].activenotes[i].active = false;
+ }
+ }
return n;
}
@@ -2483,11 +2480,11 @@ retry_arpeggio:
if(c > uint32_t(std::numeric_limits<int32_t>::max()))
break;
- size_t n_users = ch[c].users.size();
+ size_t n_users = ch[c].users_size;
if(n_users > 1)
{
- AdlChannel::users_t::const_iterator i = ch[c].users.begin();
+ AdlChannel::LocationData *i = ch[c].users_first;
size_t rate_reduction = 3;
if(n_users >= 3)
@@ -2496,23 +2493,25 @@ retry_arpeggio:
if(n_users >= 4)
rate_reduction = 1;
- std::advance(i, (arpeggio_counter / rate_reduction) % n_users);
+ for(unsigned count = (arpeggio_counter / rate_reduction) % n_users,
+ n = 0; n < count; ++n)
+ i = i->next;
- if(i->second.sustained == false)
+ if(i->sustained == false)
{
- if(i->second.kon_time_until_neglible <= 0l)
+ if(i->kon_time_until_neglible <= 0l)
{
NoteUpdate(
- i->first.MidCh,
- Ch[ i->first.MidCh ].activenotes.find(i->first.note),
+ i->loc.MidCh,
+ Ch[ i->loc.MidCh ].activenotes_ensure_find(i->loc.note),
Upd_Off,
static_cast<int32_t>(c));
goto retry_arpeggio;
}
NoteUpdate(
- i->first.MidCh,
- Ch[ i->first.MidCh ].activenotes.find(i->first.note),
+ i->loc.MidCh,
+ Ch[ i->loc.MidCh ].activenotes_ensure_find(i->loc.note),
Upd_Pitch | Upd_Volume | Upd_Pan,
static_cast<int32_t>(c));
}