diff options
Diffstat (limited to 'src/adlmidi_midiplay.cpp')
-rw-r--r-- | src/adlmidi_midiplay.cpp | 277 |
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)); } |