From 8bd614ddcb75541711ef287880f08c9f49f139b1 Mon Sep 17 00:00:00 2001 From: JP Cimalando Date: Sat, 25 Aug 2018 20:19:03 +0200 Subject: upgrade timing resolution to the microsecond --- src/adlmidi_midiplay.cpp | 52 ++++++++++++++++++++++++------------------------ src/adlmidi_private.hpp | 22 ++++++++++---------- 2 files changed, 37 insertions(+), 37 deletions(-) (limited to 'src') diff --git a/src/adlmidi_midiplay.cpp b/src/adlmidi_midiplay.cpp index ded81b3..fc5a019 100644 --- a/src/adlmidi_midiplay.cpp +++ b/src/adlmidi_midiplay.cpp @@ -100,19 +100,19 @@ inline bool isXgPercChannel(uint8_t msb, uint8_t lsb) return (msb == 0x7E || msb == 0x7F) && (lsb == 0); } -void MIDIplay::AdlChannel::addAge(int64_t ms) +void MIDIplay::AdlChannel::addAge(int64_t us) { - const int64_t neg = static_cast(-0x1FFFFFFFl); + const int64_t neg = 1000 * static_cast(-0x1FFFFFFFll); if(users_empty()) - koff_time_until_neglible = std::max(int64_t(koff_time_until_neglible - ms), neg); + koff_time_until_neglible_us = std::max(koff_time_until_neglible_us - us, neg); else { - koff_time_until_neglible = 0; + koff_time_until_neglible_us = 0; for(LocationData *i = users_first; i; i = i->next) { if(!i->fixed_sustain) - i->kon_time_until_neglible = std::max(i->kon_time_until_neglible - ms, neg); - i->vibdelay += ms; + i->kon_time_until_neglible_us = std::max(i->kon_time_until_neglible_us - us, neg); + i->vibdelay_us += us; } } } @@ -233,7 +233,7 @@ void MIDIplay::resetMIDI() void MIDIplay::TickIterators(double s) { for(uint16_t c = 0; c < m_synth.m_numChannels; ++c) - m_chipChannels[c].addAge(static_cast(s * 1000.0)); + m_chipChannels[c].addAge(static_cast(s * 1e6)); updateVibrato(s); updateArpeggio(s); #if !defined(ADLMIDI_AUDIO_TICK_HANDLER) @@ -1113,9 +1113,9 @@ void MIDIplay::noteUpdate(size_t midCh, if(d) // inserts if necessary { d->sustained = AdlChannel::LocationData::Sustain_None; - d->vibdelay = 0; + d->vibdelay_us = 0; d->fixed_sustain = (ains.ms_sound_kon == static_cast(adlNoteOnMaxTime)); - d->kon_time_until_neglible = ains.ms_sound_kon; + d->kon_time_until_neglible_us = 1000 * ains.ms_sound_kon; d->ins = ins; } } @@ -1147,11 +1147,11 @@ void MIDIplay::noteUpdate(size_t midCh, if(props_mask & Upd_Mute) // Mute the note { m_synth.touchNote(c, 0); - m_chipChannels[c].koff_time_until_neglible = 0; + m_chipChannels[c].koff_time_until_neglible_us = 0; } else { - m_chipChannels[c].koff_time_until_neglible = ains.ms_sound_koff; + m_chipChannels[c].koff_time_until_neglible_us = 1000 * ains.ms_sound_koff; } } } @@ -1279,7 +1279,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 >= m_midiChannels[midCh].vibdelay)) + if(vibrato && (!d || d->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 @@ -1321,7 +1321,8 @@ void MIDIplay::setErrorString(const std::string &err) int64_t MIDIplay::calculateChipChannelGoodness(size_t c, const MIDIchannel::NoteInfo::Phys &ins) const { - int64_t s = (m_synth.m_musicMode != OPL3::MODE_CMF) ? -m_chipChannels[c].koff_time_until_neglible : 0; + int64_t koff_ms = m_chipChannels[c].koff_time_until_neglible_us / 1000; + int64_t s = (m_synth.m_musicMode != OPL3::MODE_CMF) ? -koff_ms : 0; // Same midi-instrument = some stability //if(c == MidCh) s += 4; @@ -1329,10 +1330,9 @@ int64_t MIDIplay::calculateChipChannelGoodness(size_t c, const MIDIchannel::Note { s -= 4000; - if(j->sustained == AdlChannel::LocationData::Sustain_None) - s -= j->kon_time_until_neglible; - else - s -= (j->kon_time_until_neglible / 2); + int64_t kon_ms = j->kon_time_until_neglible_us / 1000; + s -= (j->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); @@ -1344,8 +1344,8 @@ int64_t MIDIplay::calculateChipChannelGoodness(size_t c, const MIDIchannel::Note { s += 300; // Arpeggio candidate = even better - if(j->vibdelay < 70 - || j->kon_time_until_neglible > 20000) + if(j->vibdelay_us < 70000 + || j->kon_time_until_neglible_us > 20000000) s += 0; } @@ -1376,7 +1376,7 @@ int64_t MIDIplay::calculateChipChannelGoodness(size_t c, const MIDIchannel::Note for(AdlChannel::LocationData *m = m_chipChannels[c2].users_first; m; m = m->next) { if(m->sustained != AdlChannel::LocationData::Sustain_None) continue; - if(m->vibdelay >= 200) continue; + if(m->vibdelay_us >= 200000) continue; if(m->ins != j->ins) continue; n_evacuation_stations += 1; } @@ -1407,8 +1407,8 @@ void MIDIplay::prepareChipChannelForNewNote(size_t c, const MIDIchannel::NoteInf (m_midiChannels[j->loc.MidCh].activenotes_ensure_find(j->loc.note)); // Check if we can do arpeggio. - if((j->vibdelay < 70 - || j->kon_time_until_neglible > 20000) + if((j->vibdelay_us < 70000 + || j->kon_time_until_neglible_us > 20000000) && j->ins == ins) { // Do arpeggio together with this note. @@ -1458,8 +1458,8 @@ void MIDIplay::killOrEvacuate(size_t from_channel, for(AdlChannel::LocationData *m = adlch.users_first; m; m = m->next) { - if(m->vibdelay >= 200 - && m->kon_time_until_neglible < 10000) continue; + if(m->vibdelay_us >= 200000 + && m->kon_time_until_neglible_us < 10000000) continue; if(m->ins != j->ins) continue; if(hooks.onNote) @@ -1596,7 +1596,7 @@ void MIDIplay::setRPN(size_t midCh, unsigned value, bool MSB) case 0x010A + 1*0x10000 + 1*0x20000: if((m_synthMode & Mode_XG) != 0) // Vibrato delay in millisecons { - m_midiChannels[midCh].vibdelay = value ? int64_t(0.2092 * std::exp(0.0795 * (double)value)) : 0; + m_midiChannels[midCh].vibdelay_us = value ? int64_t(209.2 * std::exp(0.0795 * (double)value)) : 0; } break; default:/* UI.PrintLn("%s %04X <- %d (%cSB) (ch %u)", @@ -1702,7 +1702,7 @@ retry_arpeggio: if(i->sustained == AdlChannel::LocationData::Sustain_None) { - if(i->kon_time_until_neglible <= 0l) + if(i->kon_time_until_neglible_us <= 0) { noteUpdate( i->loc.MidCh, diff --git a/src/adlmidi_private.hpp b/src/adlmidi_private.hpp index f719f01..0b7994a 100644 --- a/src/adlmidi_private.hpp +++ b/src/adlmidi_private.hpp @@ -558,7 +558,7 @@ public: //! Vibrato depth value vibdepth; //! Vibrato delay time - int64_t vibdelay; + int64_t vibdelay_us; //! Last LSB part of RPN value received uint8_t lastlrpn, //! Last MSB poart of RPN value received @@ -801,7 +801,7 @@ public: noteAfterTouchInUse = false; vibspeed = 2 * 3.141592653 * 5.0; vibdepth = 0.5 / 127; - vibdelay = 0; + vibdelay_us = 0; panning = 64; portamento = 0; portamentoEnable = false; @@ -866,12 +866,12 @@ public: //! Has fixed sustain, don't iterate "on" timeout bool fixed_sustain; //! Timeout until note will be allowed to be killed by channel manager while it is on - int64_t kon_time_until_neglible; - int64_t vibdelay; + int64_t kon_time_until_neglible_us; + int64_t vibdelay_us; }; //! Time left until sounding will be muted after key off - int64_t koff_time_until_neglible; + int64_t koff_time_until_neglible_us; enum { users_max = 128 }; LocationData *users_first, *users_free_cells; @@ -888,12 +888,12 @@ public: void users_assign(const LocationData *users, size_t count); // For channel allocation: - AdlChannel(): koff_time_until_neglible(0) + AdlChannel(): koff_time_until_neglible_us(0) { users_clear(); } - AdlChannel(const AdlChannel &oth): koff_time_until_neglible(oth.koff_time_until_neglible) + AdlChannel(const AdlChannel &oth): koff_time_until_neglible_us(oth.koff_time_until_neglible_us) { if(oth.users_first) { @@ -906,16 +906,16 @@ public: AdlChannel &operator=(const AdlChannel &oth) { - koff_time_until_neglible = oth.koff_time_until_neglible; + koff_time_until_neglible_us = oth.koff_time_until_neglible_us; users_assign(oth.users_first, oth.users_size); return *this; } /** - * @brief Increases age of active note in milliseconds time - * @param ms Amount time in milliseconds + * @brief Increases age of active note in microseconds time + * @param us Amount time in microseconds */ - void addAge(int64_t ms); + void addAge(int64_t us); }; #ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER -- cgit v1.2.3 From ab65e333342b59deea859e07bf57a9a6dee97de3 Mon Sep 17 00:00:00 2001 From: JP Cimalando Date: Mon, 27 Aug 2018 09:30:14 +0200 Subject: early koff update to prevent a bad reuse of channel --- src/adlmidi_midiplay.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'src') diff --git a/src/adlmidi_midiplay.cpp b/src/adlmidi_midiplay.cpp index fc5a019..49aa119 100644 --- a/src/adlmidi_midiplay.cpp +++ b/src/adlmidi_midiplay.cpp @@ -578,6 +578,15 @@ bool MIDIplay::realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocity) } noteUpdate(channel, ir.first, Upd_All | Upd_Patch); + + for(unsigned ccount = 0; ccount < MIDIchannel::NoteInfo::MaxNumPhysChans; ++ccount) + { + int32_t c = adlchannel[ccount]; + if(c < 0) + continue; + m_chipChannels[c].addAge(0); + } + return true; } -- cgit v1.2.3 From 55bee6c3f34ab15eab6bd843d9aab78a175486cf Mon Sep 17 00:00:00 2001 From: JP Cimalando Date: Mon, 27 Aug 2018 22:56:52 +0200 Subject: reassign the channel categories after num4ops was decreased --- src/adlmidi_opl3.cpp | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/adlmidi_opl3.cpp b/src/adlmidi_opl3.cpp index 5ea2053..19cd952 100644 --- a/src/adlmidi_opl3.cpp +++ b/src/adlmidi_opl3.cpp @@ -452,31 +452,39 @@ void OPL3::silenceAll() // Silence all OPL channels. void OPL3::updateChannelCategories() { - uint32_t fours = m_numFourOps; + const uint32_t fours = m_numFourOps; - for(size_t chip = 0; chip < m_numChips; ++chip) + for(uint32_t chip = 0, fours_left = fours; chip < m_numChips; ++chip) { m_regBD[chip] = (m_deepTremoloMode * 0x80 + m_deepVibratoMode * 0x40 + m_rhythmMode * 0x20); writeRegI(chip, 0x0BD, m_regBD[chip]); - uint32_t fours_this_chip = std::min(fours, static_cast(6u)); + uint32_t fours_this_chip = std::min(fours_left, static_cast(6u)); writeRegI(chip, 0x104, (1 << fours_this_chip) - 1); - fours -= fours_this_chip; + fours_left -= fours_this_chip; } - // Mark all channels that are reserved for four-operator function - if(m_rhythmMode == 1) + if(!m_rhythmMode) + { + for(size_t a = 0, n = m_numChips; a < n; ++a) + { + for(size_t b = 0; b < 23; ++b) + m_channelCategory[a * 23 + b] = + (b >= 18) ? ChanCat_Rhythm_Slave : ChanCat_Regular; + } + } + else { - for(size_t a = 0; a < m_numChips; ++a) + for(size_t a = 0, n = m_numChips; a < n; ++a) { - for(size_t b = 0; b < 5; ++b) - m_channelCategory[a * 23 + 18 + b] = static_cast(b + 3); - for(size_t b = 0; b < 3; ++b) - m_channelCategory[a * 23 + 6 + b] = ChanCat_Rhythm_Slave; + for(size_t b = 0; b < 23; ++b) + m_channelCategory[a * 23 + b] = + (b >= 18) ? static_cast(ChanCat_Rhythm_Bass + (b - 18)) : + (b >= 6 && b < 9) ? ChanCat_Rhythm_Slave : ChanCat_Regular; } } - size_t nextfour = 0; - for(size_t a = 0; a < m_numFourOps; ++a) + uint32_t nextfour = 0; + for(uint32_t a = 0; a < fours; ++a) { m_channelCategory[nextfour] = ChanCat_4op_Master; m_channelCategory[nextfour + 3] = ChanCat_4op_Slave; -- cgit v1.2.3 From 399992184883f76a0cd8909a92c15dea85dc657c Mon Sep 17 00:00:00 2001 From: Vitaly Novichkov Date: Tue, 28 Aug 2018 01:31:08 +0300 Subject: Little beautifying --- src/adlmidi_opl3.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/adlmidi_opl3.cpp b/src/adlmidi_opl3.cpp index 19cd952..e127568 100644 --- a/src/adlmidi_opl3.cpp +++ b/src/adlmidi_opl3.cpp @@ -468,8 +468,10 @@ void OPL3::updateChannelCategories() for(size_t a = 0, n = m_numChips; a < n; ++a) { for(size_t b = 0; b < 23; ++b) + { m_channelCategory[a * 23 + b] = (b >= 18) ? ChanCat_Rhythm_Slave : ChanCat_Regular; + } } } else @@ -477,9 +479,11 @@ void OPL3::updateChannelCategories() for(size_t a = 0, n = m_numChips; a < n; ++a) { for(size_t b = 0; b < 23; ++b) + { m_channelCategory[a * 23 + b] = (b >= 18) ? static_cast(ChanCat_Rhythm_Bass + (b - 18)) : (b >= 6 && b < 9) ? ChanCat_Rhythm_Slave : ChanCat_Regular; + } } } -- cgit v1.2.3 From 6c495486cdd3c3c8f5c3c945e79233128a7479f9 Mon Sep 17 00:00:00 2001 From: JP Cimalando Date: Tue, 28 Aug 2018 04:28:20 +0200 Subject: XMI: fix the VLQ reading procedure --- src/cvt_xmi2mid.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/cvt_xmi2mid.hpp b/src/cvt_xmi2mid.hpp index decb25c..e8d9dbf 100644 --- a/src/cvt_xmi2mid.hpp +++ b/src/cvt_xmi2mid.hpp @@ -640,7 +640,7 @@ static int xmi2mid_GetVLQ2(struct xmi2mid_xmi_ctx *ctx, uint32_t *quant) { int32_t data; *quant = 0; - for (i = 0; i < 4; i++) { + for (i = 0; xmi2mid_getsrcpos(ctx) != xmi2mid_getsrcsize(ctx); ++i) { data = xmi2mid_read1(ctx); if (data & 0x80) { xmi2mid_skipsrc(ctx, -1); -- cgit v1.2.3 From 66d2b296616663603a64d4196bfd00f9c5f039da Mon Sep 17 00:00:00 2001 From: JP Cimalando Date: Tue, 28 Aug 2018 10:26:21 +0200 Subject: sequencer: enable end silence skipping --- src/midi_sequencer_impl.hpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'src') diff --git a/src/midi_sequencer_impl.hpp b/src/midi_sequencer_impl.hpp index 0fe6192..e54c7ee 100644 --- a/src/midi_sequencer_impl.hpp +++ b/src/midi_sequencer_impl.hpp @@ -614,6 +614,19 @@ bool BW_MidiSequencer::buildSmfTrackData(const std::vector } } +#ifdef ENABLE_END_SILENCE_SKIPPING + //Have track end on its own row? Clear any delay on the row before + if(event.subtype == MidiEvent::ST_ENDTRACK && evtPos.events.size() == 1) + { + if (!m_trackData[tk].empty()) + { + MidiTrackRow &previous = m_trackData[tk].back(); + previous.delay = 0; + previous.timeDelay = 0; + } + } +#endif + if((evtPos.delay > 0) || (event.subtype == MidiEvent::ST_ENDTRACK)) { evtPos.absPos = abs_position; -- cgit v1.2.3 From 57ef547b460843c0864e14ae4ce0fcf1f901a9d7 Mon Sep 17 00:00:00 2001 From: Wohlstand Date: Tue, 28 Aug 2018 13:20:16 +0300 Subject: Small warning fix --- src/adlmidi_opl3.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/adlmidi_opl3.cpp b/src/adlmidi_opl3.cpp index e127568..c98469f 100644 --- a/src/adlmidi_opl3.cpp +++ b/src/adlmidi_opl3.cpp @@ -481,7 +481,7 @@ void OPL3::updateChannelCategories() for(size_t b = 0; b < 23; ++b) { m_channelCategory[a * 23 + b] = - (b >= 18) ? static_cast(ChanCat_Rhythm_Bass + (b - 18)) : + (b >= 18) ? static_cast(ChanCat_Rhythm_Bass + (b - 18)) : (b >= 6 && b < 9) ? ChanCat_Rhythm_Slave : ChanCat_Regular; } } -- cgit v1.2.3 From 33fefba831f691f0448db49599f9798a04bcb06f Mon Sep 17 00:00:00 2001 From: JP Cimalando Date: Wed, 29 Aug 2018 04:18:21 +0200 Subject: fix the miswritten name of Jamie O'Connell --- src/adldata.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/adldata.cpp b/src/adldata.cpp index 6606e1f..0e5b43f 100644 --- a/src/adldata.cpp +++ b/src/adldata.cpp @@ -9449,7 +9449,7 @@ const char* const banknames[76] = "TMB (Shadow Warrior)", "DMX (Raptor)", "OP3 (Modded GMOPL by Wohlstand)", - "SB (Jammey O'Connel's bank)", + "SB (Jamie O'Connell's bank)", "TMB (Default bank of Apgee Sound System)", "WOPL (4op bank by James Alan Nguyen and Wohlstand)", "TMB (Blood)", @@ -10882,7 +10882,7 @@ const AdlBankSetup adlbanksetup[75] = {3, 0, 0, 0, 0}, //Bank 63, TMB (Shadow Warrior) {2, 0, 0, 0, 0}, //Bank 64, DMX (Raptor) {3, 0, 0, 0, 0}, //Bank 65, OP3 (Modded GMOPL by Wohlstand) - {3, 0, 0, 0, 0}, //Bank 66, SB (Jammey O'Connel's bank) + {3, 0, 0, 0, 0}, //Bank 66, SB (Jamie O'Connell's bank) {3, 0, 0, 0, 0}, //Bank 67, TMB (Default bank of Apgee Sound System) {0, 1, 1, 0, 0}, //Bank 68, WOPL (4op bank by James Alan Nguyen and Wohlstand) {3, 0, 0, 0, 0}, //Bank 69, TMB (Blood) -- cgit v1.2.3 From 7ccbb3a40a80637a130f499bb914bbafbcd71646 Mon Sep 17 00:00:00 2001 From: JP Cimalando Date: Wed, 29 Aug 2018 04:20:29 +0200 Subject: fix a typo about Apogee Sound System --- src/adldata.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/adldata.cpp b/src/adldata.cpp index 0e5b43f..b7fd3a1 100644 --- a/src/adldata.cpp +++ b/src/adldata.cpp @@ -9450,7 +9450,7 @@ const char* const banknames[76] = "DMX (Raptor)", "OP3 (Modded GMOPL by Wohlstand)", "SB (Jamie O'Connell's bank)", - "TMB (Default bank of Apgee Sound System)", + "TMB (Default bank of Apogee Sound System)", "WOPL (4op bank by James Alan Nguyen and Wohlstand)", "TMB (Blood)", "TMB (Lee)", @@ -10883,7 +10883,7 @@ const AdlBankSetup adlbanksetup[75] = {2, 0, 0, 0, 0}, //Bank 64, DMX (Raptor) {3, 0, 0, 0, 0}, //Bank 65, OP3 (Modded GMOPL by Wohlstand) {3, 0, 0, 0, 0}, //Bank 66, SB (Jamie O'Connell's bank) - {3, 0, 0, 0, 0}, //Bank 67, TMB (Default bank of Apgee Sound System) + {3, 0, 0, 0, 0}, //Bank 67, TMB (Default bank of Apogee Sound System) {0, 1, 1, 0, 0}, //Bank 68, WOPL (4op bank by James Alan Nguyen and Wohlstand) {3, 0, 0, 0, 0}, //Bank 69, TMB (Blood) {3, 0, 0, 0, 0}, //Bank 70, TMB (Lee) -- cgit v1.2.3 From 0d9bc6794e57526af28ce45a57d91ec78e39b354 Mon Sep 17 00:00:00 2001 From: JP Cimalando Date: Thu, 30 Aug 2018 07:49:14 +0200 Subject: API to return 4op channels to the original count --- src/adlmidi.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/adlmidi.cpp b/src/adlmidi.cpp index c7c5cf3..26a21e4 100644 --- a/src/adlmidi.cpp +++ b/src/adlmidi.cpp @@ -351,6 +351,10 @@ ADLMIDI_EXPORT int adl_setNumFourOpsChn(ADL_MIDIPlayer *device, int ops4) { if(!device) return -1; + + if(ops4 == -1) + return adlRefreshNumCards(device); + MidiPlayer *play = GET_MIDI_PLAYER(device); if((unsigned int)ops4 > 6 * play->m_setup.numChips) { @@ -364,7 +368,7 @@ ADLMIDI_EXPORT int adl_setNumFourOpsChn(ADL_MIDIPlayer *device, int ops4) play->m_synth.m_numFourOps = play->m_setup.numFourOps; play->m_synth.updateChannelCategories(); - return 0; //adlRefreshNumCards(device); + return 0; } ADLMIDI_EXPORT int adl_getNumFourOpsChn(struct ADL_MIDIPlayer *device) -- cgit v1.2.3 From 13e4cb1528f36d3514fa6d7f26eb4028194c5b07 Mon Sep 17 00:00:00 2001 From: JP Cimalando Date: Thu, 30 Aug 2018 11:01:42 +0200 Subject: fix a case of miscalculation and infinite loop --- src/adlmidi_midiplay.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/adlmidi_midiplay.cpp b/src/adlmidi_midiplay.cpp index 49aa119..f405489 100644 --- a/src/adlmidi_midiplay.cpp +++ b/src/adlmidi_midiplay.cpp @@ -1599,7 +1599,7 @@ void MIDIplay::setRPN(size_t midCh, unsigned value, bool MSB) case 0x0109 + 1*0x10000 + 1*0x20000: if((m_synthMode & Mode_XG) != 0) // Vibrato depth { - m_midiChannels[midCh].vibdepth = ((value - 64) * 0.15) * 0.01; + m_midiChannels[midCh].vibdepth = (((int)value - 64) * 0.15) * 0.01; } break; case 0x010A + 1*0x10000 + 1*0x20000: -- cgit v1.2.3 From c7b3199669a7b7e0ba11eb0d94d4e143a5fdd633 Mon Sep 17 00:00:00 2001 From: Vitaly Novichkov Date: Fri, 31 Aug 2018 03:54:16 +0300 Subject: Added high tone frequency extension from OPL3-BE --- src/adlmidi_midiplay.cpp | 5 +-- src/adlmidi_opl3.cpp | 93 ++++++++++++++++++++++++++++++++++++------------ src/adlmidi_private.hpp | 5 +-- 3 files changed, 76 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/src/adlmidi_midiplay.cpp b/src/adlmidi_midiplay.cpp index 49aa119..cdd4086 100644 --- a/src/adlmidi_midiplay.cpp +++ b/src/adlmidi_midiplay.cpp @@ -1133,7 +1133,8 @@ void MIDIplay::noteUpdate(size_t midCh, for(unsigned ccount = 0; ccount < info.chip_channels_count; ccount++) { const MIDIchannel::NoteInfo::Phys &ins = info.chip_channels[ccount]; - uint16_t c = ins.chip_chan; + uint16_t c = ins.chip_chan; + uint16_t c_slave = info.chip_channels[1].chip_chan; if(select_adlchn >= 0 && c != select_adlchn) continue; @@ -1292,7 +1293,7 @@ void MIDIplay::noteUpdate(size_t midCh, bend += static_cast(vibrato) * m_midiChannels[midCh].vibdepth * std::sin(m_midiChannels[midCh].vibpos); #define BEND_COEFFICIENT 172.4387 - m_synth.noteOn(c, BEND_COEFFICIENT * std::exp(0.057762265 * (currentTone + bend + phase))); + m_synth.noteOn(c, c_slave, BEND_COEFFICIENT * std::exp(0.057762265 * (currentTone + bend + phase))); #undef BEND_COEFFICIENT if(hooks.onNote) hooks.onNote(hooks.onNote_userData, c, noteTone, midiins, vol, midibend); diff --git a/src/adlmidi_opl3.cpp b/src/adlmidi_opl3.cpp index e127568..7ec1fd6 100644 --- a/src/adlmidi_opl3.cpp +++ b/src/adlmidi_opl3.cpp @@ -263,40 +263,85 @@ void OPL3::noteOff(size_t c) writeRegI(chip, 0xB0 + g_channelsMap[cc], m_keyBlockFNumCache[c] & 0xDF); } -void OPL3::noteOn(size_t c, double hertz) // Hertz range: 0..131071 +void OPL3::noteOn(size_t c1, size_t c2, double hertz) // Hertz range: 0..131071 { - size_t chip = c / 23, cc = c % 23; - uint32_t octave = 0; + size_t chip = c1 / 23, cc1 = c1 % 23, cc2 = c2 % 23; + uint32_t octave = 0, ftone = 0, mul_offset = 0; if(hertz < 0) return; - while(hertz >= 1023.5) + //Basic range until max of octaves reaching + while((hertz >= 1023.5) && (octave < 0x1C00)) + { + hertz /= 2.0; // Calculate octave + octave += 0x400; + } + //Extended range, rely on frequency multiplication increment + while(hertz >= 1022.75) { - hertz /= 2.0; // Calculate octave - if(octave < 0x1C00) - octave += 0x400; + hertz /= 2.0; // Calculate octave + mul_offset++; } - octave += static_cast(hertz + 0.5); - uint32_t chn = g_channelsMap[cc]; + ftone = octave + static_cast(hertz + 0.5); + uint32_t chn = g_channelsMap[cc1]; + const adldata &patch1 = m_insCache[c1]; + const adldata &patch2 = m_insCache[c2 < m_insCache.size() ? c2 : 0]; - if(cc >= 18) + if(cc1 < 18) { - m_regBD[chip ] |= (0x10 >> (cc - 18)); - writeRegI(chip , 0x0BD, m_regBD[chip ]); - //x |= 0x800; // for test + ftone += 0x2000u; /* Key-ON [KON] */ + + const bool natural_4op = (m_channelCategory[c1] == ChanCat_4op_Master); + const size_t opsCount = natural_4op ? 4 : 2; + const uint16_t op_addr[4] = + { + g_operatorsMap[cc1 * 2 + 0], g_operatorsMap[cc1 * 2 + 1], + g_operatorsMap[cc2 * 2 + 0], g_operatorsMap[cc2 * 2 + 1] + }; + const uint32_t ops[4] = + { + patch1.modulator_E862 & 0xFF, + patch1.carrier_E862 & 0xFF, + patch2.modulator_E862 & 0xFF, + patch2.carrier_E862 & 0xFF + }; + + for(size_t op = 0; op < opsCount; op++) + { + if((op > 0) && (op_addr[op] == 0xFFF)) + break; + if(mul_offset > 0) + { + uint32_t dt = ops[op] & 0xF0; + uint32_t mul = ops[op] & 0x0F; + if((mul + mul_offset) > 0x0F) + { + mul_offset = 0; + mul = 0x0F; + } + writeRegI(chip, 0x20 + op_addr[op], (dt | (mul + mul_offset)) & 0xFF); + } + else + { + writeRegI(chip, 0x20 + op_addr[op], ops[op] & 0xFF); + } + } } - else + + if(chn != 0xFFF) { - octave += 0x2000u; /* Key-ON [KON] */ + writeRegI(chip , 0xA0 + chn, (ftone & 0xFF)); + writeRegI(chip , 0xB0 + chn, (ftone >> 8)); + m_keyBlockFNumCache[c1] = (ftone >> 8); } - if(chn != 0xFFF) + if(cc1 >= 18) { - writeRegI(chip , 0xA0 + chn, (octave & 0xFF)); - writeRegI(chip , 0xB0 + chn, (octave >> 8)); - m_keyBlockFNumCache[c] = (octave >> 8); + m_regBD[chip ] |= (0x10 >> (cc1 - 18)); + writeRegI(chip , 0x0BD, m_regBD[chip ]); + //x |= 0x800; // for test } } @@ -312,15 +357,17 @@ void OPL3::touchNote(size_t c, uint8_t volume, uint8_t brightness) uint8_t x = adli.modulator_40, y = adli.carrier_40; uint32_t mode = 1; // 2-op AM - if(m_channelCategory[c] == 0 || m_channelCategory[c] == 3) + if(m_channelCategory[c] == ChanCat_Regular || + m_channelCategory[c] == ChanCat_Rhythm_Bass) { mode = adli.feedconn & 1; // 2-op FM or 2-op AM } - else if(m_channelCategory[c] == 1 || m_channelCategory[c] == 2) + else if(m_channelCategory[c] == ChanCat_4op_Master || + m_channelCategory[c] == ChanCat_4op_Slave) { const adldata *i0, *i1; - if(m_channelCategory[c] == 1) + if(m_channelCategory[c] == ChanCat_4op_Master) { i0 = &adli; i1 = &m_insCache[c + 3]; @@ -481,7 +528,7 @@ void OPL3::updateChannelCategories() for(size_t b = 0; b < 23; ++b) { m_channelCategory[a * 23 + b] = - (b >= 18) ? static_cast(ChanCat_Rhythm_Bass + (b - 18)) : + (b >= 18) ? static_cast(ChanCat_Rhythm_Bass + (b - 18)) : (b >= 6 && b < 9) ? ChanCat_Rhythm_Slave : ChanCat_Regular; } } diff --git a/src/adlmidi_private.hpp b/src/adlmidi_private.hpp index 0b7994a..2fc12a4 100644 --- a/src/adlmidi_private.hpp +++ b/src/adlmidi_private.hpp @@ -399,10 +399,11 @@ public: /** * @brief On the note in specified chip channel with specified frequency of the tone - * @param c Channel of chip (Emulated chip choosing by next formula: [c = ch + (chipId * 23)]) + * @param c1 Channel of chip [or master 4-op channel] (Emulated chip choosing by next formula: [c = ch + (chipId * 23)]) + * @param c2 Slave 4-op channel of chip, unused for 2op (Emulated chip choosing by next formula: [c = ch + (chipId * 23)]) * @param hertz Frequency of the tone in hertzes */ - void noteOn(size_t c, double hertz); + void noteOn(size_t c1, size_t c2, double hertz); /** * @brief Change setup of instrument in specified chip channel -- cgit v1.2.3