From 298160f0154a05030681a208a247e2ed309f89db Mon Sep 17 00:00:00 2001 From: JP Cimalando Date: Sat, 10 Nov 2018 16:59:35 +0100 Subject: linked list structure + users --- src/adlmidi_midiplay.cpp | 306 +++++++++++++++-------------------------------- 1 file changed, 95 insertions(+), 211 deletions(-) (limited to 'src/adlmidi_midiplay.cpp') diff --git a/src/adlmidi_midiplay.cpp b/src/adlmidi_midiplay.cpp index 1a20e9e..62c7ee3 100644 --- a/src/adlmidi_midiplay.cpp +++ b/src/adlmidi_midiplay.cpp @@ -106,7 +106,7 @@ inline bool isXgPercChannel(uint8_t msb, uint8_t lsb) void MIDIplay::AdlChannel::addAge(int64_t us) { const int64_t neg = 1000 * static_cast(-0x1FFFFFFFll); - if(users_empty()) + if(users.empty()) { koff_time_until_neglible_us = std::max(koff_time_until_neglible_us - us, neg); if(koff_time_until_neglible_us < 0) @@ -115,11 +115,12 @@ void MIDIplay::AdlChannel::addAge(int64_t us) else { koff_time_until_neglible_us = 0; - for(LocationData *i = users_first; i; i = i->next) + for(users_iterator i = users.begin(); !i.is_end(); ++i) { - if(!i->fixed_sustain) - i->kon_time_until_neglible_us = std::max(i->kon_time_until_neglible_us - us, neg); - i->vibdelay_us += us; + LocationData &d = i->value; + if(!d.fixed_sustain) + d.kon_time_until_neglible_us = std::max(d.kon_time_until_neglible_us - us, neg); + d.vibdelay_us += us; } } } @@ -1147,14 +1148,15 @@ void MIDIplay::noteUpdate(size_t midCh, if(props_mask & Upd_Patch) { synth.setPatch(c, ins.ains); - AdlChannel::LocationData *d = m_chipChannels[c].users_find_or_create(my_loc); - if(d) // inserts if necessary + AdlChannel::users_iterator i = m_chipChannels[c].find_or_create_user(my_loc); + if(!i.is_end()) // inserts if necessary { - d->sustained = AdlChannel::LocationData::Sustain_None; - d->vibdelay_us = 0; - d->fixed_sustain = (ains.ms_sound_kon == static_cast(adlNoteOnMaxTime)); - d->kon_time_until_neglible_us = 1000 * ains.ms_sound_kon; - d->ins = ins; + AdlChannel::LocationData &d = i->value; + d.sustained = AdlChannel::LocationData::Sustain_None; + d.vibdelay_us = 0; + d.fixed_sustain = (ains.ms_sound_kon == static_cast(adlNoteOnMaxTime)); + d.kon_time_until_neglible_us = 1000 * ains.ms_sound_kon; + d.ins = ins; } } } @@ -1172,15 +1174,15 @@ void MIDIplay::noteUpdate(size_t midCh, { if(!m_midiChannels[midCh].sustain) { - AdlChannel::LocationData *k = m_chipChannels[c].users_find(my_loc); - bool do_erase_user = (k && ((k->sustained & AdlChannel::LocationData::Sustain_Sostenuto) == 0)); + AdlChannel::users_iterator k = m_chipChannels[c].find_user(my_loc); + bool do_erase_user = (!k.is_end() && ((k->value.sustained & AdlChannel::LocationData::Sustain_Sostenuto) == 0)); if(do_erase_user) - m_chipChannels[c].users_erase(k); + m_chipChannels[c].users.erase(k); if(hooks.onNote) hooks.onNote(hooks.onNote_userData, c, noteTone, midiins, 0, 0.0); - if(do_erase_user && m_chipChannels[c].users_empty()) + if(do_erase_user && m_chipChannels[c].users.empty()) { synth.noteOff(c); if(props_mask & Upd_Mute) // Mute the note @@ -1198,9 +1200,9 @@ void MIDIplay::noteUpdate(size_t midCh, { // Sustain: Forget about the note, but don't key it off. // Also will avoid overwriting it very soon. - AdlChannel::LocationData *d = m_chipChannels[c].users_find_or_create(my_loc); - if(d) - d->sustained |= AdlChannel::LocationData::Sustain_Pedal; // note: not erased! + AdlChannel::users_iterator d = m_chipChannels[c].find_or_create_user(my_loc); + if(!d.is_end()) + d->value.sustained |= AdlChannel::LocationData::Sustain_Pedal; // note: not erased! if(hooks.onNote) hooks.onNote(hooks.onNote_userData, c, noteTone, midiins, -1, 0.0); } @@ -1302,10 +1304,10 @@ void MIDIplay::noteUpdate(size_t midCh, if(props_mask & Upd_Pitch) { - AdlChannel::LocationData *d = m_chipChannels[c].users_find(my_loc); + AdlChannel::users_iterator d = m_chipChannels[c].find_user(my_loc); // Don't bend a sustained note - if(!d || (d->sustained == AdlChannel::LocationData::Sustain_None)) + if(d.is_end() || (d->value.sustained == AdlChannel::LocationData::Sustain_None)) { double midibend = m_midiChannels[midCh].bend * m_midiChannels[midCh].bendsense; double bend = midibend + ins.ains.finetune; @@ -1318,7 +1320,7 @@ void MIDIplay::noteUpdate(size_t midCh, phase = ains.voice2_fine_tune;//0.125; // Detune the note slightly (this is what Doom does) } - if(vibrato && (!d || d->vibdelay_us >= m_midiChannels[midCh].vibdelay_us)) + if(vibrato && (d.is_end() || d->value.vibdelay_us >= m_midiChannels[midCh].vibdelay_us)) bend += static_cast(vibrato) * m_midiChannels[midCh].vibdepth * std::sin(m_midiChannels[midCh].vibpos); #define BEND_COEFFICIENT 172.4387 @@ -1366,7 +1368,7 @@ int64_t MIDIplay::calculateChipChannelGoodness(size_t c, const MIDIchannel::Note int64_t s = -koff_ms; // Rate channel with a releasing note - if(s < 0 && chan.users_empty()) + if(s < 0 && chan.users.empty()) { s -= 40000; // If it's same instrument, better chance to get it when no free channels @@ -1376,26 +1378,27 @@ int64_t MIDIplay::calculateChipChannelGoodness(size_t c, const MIDIchannel::Note } // Same midi-instrument = some stability - for(AdlChannel::LocationData *j = chan.users_first; j; j = j->next) + for(AdlChannel::const_users_iterator j = chan.users.begin(); !j.is_end(); ++j) { + const AdlChannel::LocationData &jd = j->value; s -= 4000000; - int64_t kon_ms = j->kon_time_until_neglible_us / 1000; - s -= (j->sustained == AdlChannel::LocationData::Sustain_None) ? + int64_t kon_ms = jd.kon_time_until_neglible_us / 1000; + s -= (jd.sustained == AdlChannel::LocationData::Sustain_None) ? kon_ms : (kon_ms / 2); MIDIchannel::activenoteiterator - k = const_cast(m_midiChannels[j->loc.MidCh]).activenotes_find(j->loc.note); + k = const_cast(m_midiChannels[jd.loc.MidCh]).activenotes_find(jd.loc.note); if(k) { // Same instrument = good - if(j->ins == ins) + if(jd.ins == ins) { s += 300; // Arpeggio candidate = even better - if(j->vibdelay_us < 70000 - || j->kon_time_until_neglible_us > 20000000) + if(jd.vibdelay_us < 70000 + || jd.kon_time_until_neglible_us > 20000000) s += 10; } @@ -1423,11 +1426,12 @@ int64_t MIDIplay::calculateChipChannelGoodness(size_t c, const MIDIchannel::Note if(synth.m_channelCategory[c2] != synth.m_channelCategory[c]) continue; - for(AdlChannel::LocationData *m = m_chipChannels[c2].users_first; m; m = m->next) + for(AdlChannel::const_users_iterator m = m_chipChannels[c2].users.begin(); !m.is_end(); ++m) { - if(m->sustained != AdlChannel::LocationData::Sustain_None) continue; - if(m->vibdelay_us >= 200000) continue; - if(m->ins != j->ins) continue; + const AdlChannel::LocationData &md = m->value; + if(md.sustained != AdlChannel::LocationData::Sustain_None) continue; + if(md.vibdelay_us >= 200000) continue; + if(md.ins != jd.ins) continue; n_evacuation_stations += 1; } } @@ -1441,27 +1445,28 @@ int64_t MIDIplay::calculateChipChannelGoodness(size_t c, const MIDIchannel::Note void MIDIplay::prepareChipChannelForNewNote(size_t c, const MIDIchannel::NoteInfo::Phys &ins) { - if(m_chipChannels[c].users_empty()) return; // Nothing to do + if(m_chipChannels[c].users.empty()) return; // Nothing to do Synth &synth = *m_synth; //bool doing_arpeggio = false; - for(AdlChannel::LocationData *jnext = m_chipChannels[c].users_first; jnext;) + for(AdlChannel::users_iterator jnext = m_chipChannels[c].users.begin(); !jnext.is_end();) { - AdlChannel::LocationData *j = jnext; - jnext = jnext->next; + AdlChannel::users_iterator j = jnext; + AdlChannel::LocationData &jd = jnext->value; + ++jnext; - if(j->sustained == AdlChannel::LocationData::Sustain_None) + if(jd.sustained == AdlChannel::LocationData::Sustain_None) { // Collision: Kill old note, // UNLESS we're going to do arpeggio MIDIchannel::activenoteiterator i - (m_midiChannels[j->loc.MidCh].activenotes_ensure_find(j->loc.note)); + (m_midiChannels[jd.loc.MidCh].activenotes_ensure_find(jd.loc.note)); // Check if we can do arpeggio. - if((j->vibdelay_us < 70000 - || j->kon_time_until_neglible_us > 20000000) - && j->ins == ins) + if((jd.vibdelay_us < 70000 + || jd.kon_time_until_neglible_us > 20000000) + && jd.ins == ins) { // Do arpeggio together with this note. //doing_arpeggio = true; @@ -1480,16 +1485,17 @@ void MIDIplay::prepareChipChannelForNewNote(size_t c, const MIDIchannel::NoteInf // Keyoff the channel so that it can be retriggered, // unless the new note will be introduced as just an arpeggio. - if(m_chipChannels[c].users_empty()) + if(m_chipChannels[c].users.empty()) synth.noteOff(c); } void MIDIplay::killOrEvacuate(size_t from_channel, - AdlChannel::LocationData *j, + AdlChannel::users_iterator j, MIDIplay::MIDIchannel::activenoteiterator i) { Synth &synth = *m_synth; uint32_t maxChannels = ADL_MAX_CHIPS * 18; + AdlChannel::LocationData &jd = j->value; // Before killing the note, check if it can be // evacuated to another channel as an arpeggio @@ -1508,14 +1514,16 @@ void MIDIplay::killOrEvacuate(size_t from_channel, continue; AdlChannel &adlch = m_chipChannels[c]; - if(adlch.users_size == AdlChannel::users_max) + if(adlch.users.size() == adlch.users.capacity()) continue; // no room for more arpeggio on channel - for(AdlChannel::LocationData *m = adlch.users_first; m; m = m->next) + for(AdlChannel::users_iterator m = adlch.users.begin(); !m.is_end(); ++m) { - if(m->vibdelay_us >= 200000 - && m->kon_time_until_neglible_us < 10000000) continue; - if(m->ins != j->ins) + AdlChannel::LocationData &mv = m->value; + + if(mv.vibdelay_us >= 200000 + && mv.kon_time_until_neglible_us < 10000000) continue; + if(mv.ins != jd.ins) continue; if(hooks.onNote) { @@ -1531,10 +1539,9 @@ void MIDIplay::killOrEvacuate(size_t from_channel, } i->phys_erase(static_cast(from_channel)); - i->phys_ensure_find_or_create(cs)->assign(j->ins); - if(!m_chipChannels[cs].users_insert(*j)) - assert(false); - m_chipChannels[from_channel].users_erase(j); + i->phys_ensure_find_or_create(cs)->assign(jd.ins); + m_chipChannels[cs].users.push_back(jd); + m_chipChannels[from_channel].users.erase(j); return; } } @@ -1547,7 +1554,7 @@ void MIDIplay::killOrEvacuate(size_t from_channel, ins );*/ // Kill it - noteUpdate(j->loc.MidCh, + noteUpdate(jd.loc.MidCh, i, Upd_Off, static_cast(from_channel)); @@ -1575,28 +1582,29 @@ void MIDIplay::killSustainingNotes(int32_t midCh, int32_t this_adlchn, uint32_t for(uint32_t c = first; c < last; ++c) { - if(m_chipChannels[c].users_empty()) + if(m_chipChannels[c].users.empty()) continue; // Nothing to do - for(AdlChannel::LocationData *jnext = m_chipChannels[c].users_first; jnext;) + for(AdlChannel::users_iterator jnext = m_chipChannels[c].users.begin(); !jnext.is_end();) { - AdlChannel::LocationData *j = jnext; - jnext = jnext->next; + AdlChannel::users_iterator j = jnext; + AdlChannel::LocationData &jd = j->value; + ++jnext; - if((midCh < 0 || j->loc.MidCh == midCh) - && ((j->sustained & sustain_type) != 0)) + if((midCh < 0 || jd.loc.MidCh == midCh) + && ((jd.sustained & sustain_type) != 0)) { int midiins = '?'; if(hooks.onNote) - hooks.onNote(hooks.onNote_userData, (int)c, j->loc.note, midiins, 0, 0.0); - j->sustained &= ~sustain_type; - if(j->sustained == AdlChannel::LocationData::Sustain_None) - m_chipChannels[c].users_erase(j);//Remove only when note is clean from any holders + hooks.onNote(hooks.onNote_userData, (int)c, jd.loc.note, midiins, 0, 0.0); + jd.sustained &= ~sustain_type; + if(jd.sustained == AdlChannel::LocationData::Sustain_None) + m_chipChannels[c].users.erase(j);//Remove only when note is clean from any holders } } // Keyoff the channel, if there are no users left. - if(m_chipChannels[c].users_empty()) + if(m_chipChannels[c].users.empty()) synth.noteOff(c); } } @@ -1607,15 +1615,16 @@ void MIDIplay::markSostenutoNotes(int32_t midCh) uint32_t first = 0, last = synth.m_numChannels; for(uint32_t c = first; c < last; ++c) { - if(m_chipChannels[c].users_empty()) + if(m_chipChannels[c].users.empty()) continue; // Nothing to do - for(AdlChannel::LocationData *jnext = m_chipChannels[c].users_first; jnext;) + for(AdlChannel::users_iterator jnext = m_chipChannels[c].users.begin(); !jnext.is_end();) { - AdlChannel::LocationData *j = jnext; - jnext = jnext->next; - if((j->loc.MidCh == midCh) && (j->sustained == AdlChannel::LocationData::Sustain_None)) - j->sustained |= AdlChannel::LocationData::Sustain_Sostenuto; + AdlChannel::users_iterator j = jnext; + AdlChannel::LocationData &jd = j->value; + ++jnext; + if((jd.loc.MidCh == midCh) && (jd.sustained == AdlChannel::LocationData::Sustain_None)) + jd.sustained |= AdlChannel::LocationData::Sustain_Sostenuto; } } } @@ -1743,11 +1752,11 @@ retry_arpeggio: if(c > uint32_t(std::numeric_limits::max())) break; - size_t n_users = m_chipChannels[c].users_size; + size_t n_users = m_chipChannels[c].users.size(); if(n_users > 1) { - AdlChannel::LocationData *i = m_chipChannels[c].users_first; + AdlChannel::users_iterator i = m_chipChannels[c].users.begin(); size_t rate_reduction = 3; if(n_users >= 3) @@ -1758,23 +1767,24 @@ retry_arpeggio: for(size_t count = (m_arpeggioCounter / rate_reduction) % n_users, n = 0; n < count; ++n) - i = i->next; + ++i; - if(i->sustained == AdlChannel::LocationData::Sustain_None) + AdlChannel::LocationData &d = i->value; + if(d.sustained == AdlChannel::LocationData::Sustain_None) { - if(i->kon_time_until_neglible_us <= 0) + if(d.kon_time_until_neglible_us <= 0) { noteUpdate( - i->loc.MidCh, - m_midiChannels[ i->loc.MidCh ].activenotes_ensure_find(i->loc.note), + d.loc.MidCh, + m_midiChannels[ d.loc.MidCh ].activenotes_ensure_find(d.loc.note), Upd_Off, static_cast(c)); goto retry_arpeggio; } noteUpdate( - i->loc.MidCh, - m_midiChannels[ i->loc.MidCh ].activenotes_ensure_find(i->loc.note), + d.loc.MidCh, + m_midiChannels[ d.loc.MidCh ].activenotes_ensure_find(d.loc.note), Upd_Pitch | Upd_Volume | Upd_Pan, static_cast(c)); } @@ -1827,8 +1837,8 @@ void MIDIplay::describeChannels(char *str, char *attr, size_t size) { const AdlChannel &adlChannel = m_chipChannels[index]; - AdlChannel::LocationData *loc = adlChannel.users_first; - if(!loc) // off + AdlChannel::const_users_iterator loc = adlChannel.users.begin(); + if(loc.is_end()) // off { str[index] = '-'; } @@ -1854,8 +1864,8 @@ void MIDIplay::describeChannels(char *str, char *attr, size_t size) } uint8_t attribute = 0; - if (loc) // 4-bit color index of MIDI channel - attribute |= (uint8_t)(loc->loc.MidCh & 0xF); + if (!loc.is_end()) // 4-bit color index of MIDI channel + attribute |= (uint8_t)(loc->value.loc.MidCh & 0xF); attr[index] = (char)attribute; ++index; @@ -2094,129 +2104,3 @@ ADLMIDI_EXPORT bool AdlInstrumentTester::HandleInputChar(char ch) } #endif /* ADLMIDI_DISABLE_CPP_EXTRAS */ - -// Implement the user map data structure. - -bool MIDIplay::AdlChannel::users_empty() const -{ - return !users_first; -} - -MIDIplay::AdlChannel::LocationData *MIDIplay::AdlChannel::users_find(Location loc) -{ - LocationData *user = NULL; - for(LocationData *curr = users_first; !user && curr; curr = curr->next) - if(curr->loc == loc) - user = curr; - return user; -} - -MIDIplay::AdlChannel::LocationData *MIDIplay::AdlChannel::users_allocate() -{ - // remove free cells front - LocationData *user = users_free_cells; - if(!user) - return NULL; - users_free_cells = user->next; - if(users_free_cells) - users_free_cells->prev = NULL; - // add to users front - if(users_first) - users_first->prev = user; - user->prev = NULL; - user->next = users_first; - users_first = user; - ++users_size; - return user; -} - -MIDIplay::AdlChannel::LocationData *MIDIplay::AdlChannel::users_find_or_create(Location loc) -{ - LocationData *user = users_find(loc); - 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->loc = loc; - } - return user; -} - -MIDIplay::AdlChannel::LocationData *MIDIplay::AdlChannel::users_insert(const LocationData &x) -{ - LocationData *user = users_find(x.loc); - if(!user) - { - user = users_allocate(); - if(!user) - return NULL; - LocationData *prev = user->prev, *next = user->next; - *user = x; - user->prev = prev; - user->next = next; - } - return user; -} - -void MIDIplay::AdlChannel::users_erase(LocationData *user) -{ - if(user->prev) - user->prev->next = user->next; - if(user->next) - user->next->prev = user->prev; - if(user == users_first) - users_first = user->next; - user->prev = NULL; - user->next = users_free_cells; - users_free_cells = user; - --users_size; -} - -void MIDIplay::AdlChannel::users_clear() -{ - users_first = NULL; - users_free_cells = users_cells; - users_size = 0; - for(size_t i = 0; i < users_max; ++i) - { - users_cells[i].prev = (i > 0) ? &users_cells[i - 1] : NULL; - users_cells[i].next = (i + 1 < users_max) ? &users_cells[i + 1] : NULL; - } -} - -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) - { - // self assignment - assert(users_size == count); - return; - } - users_clear(); - const LocationData *src_cell = users; - // move to the last - if(src_cell) - { - while(src_cell->next) - src_cell = src_cell->next; - } - // push cell copies in reverse order - 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; - src_cell = src_cell->prev; - } - assert(users_size == count); -} -- cgit v1.2.3