diff options
author | Vitaly Novichkov <admin@wohlnet.ru> | 2018-08-31 03:54:16 +0300 |
---|---|---|
committer | Vitaly Novichkov <admin@wohlnet.ru> | 2018-08-31 03:54:16 +0300 |
commit | c7b3199669a7b7e0ba11eb0d94d4e143a5fdd633 (patch) | |
tree | 3777a2b2ada15c9c3478427348acff63ab4642b8 /src | |
parent | 399992184883f76a0cd8909a92c15dea85dc657c (diff) | |
download | libADLMIDI-c7b3199669a7b7e0ba11eb0d94d4e143a5fdd633.tar.gz libADLMIDI-c7b3199669a7b7e0ba11eb0d94d4e143a5fdd633.tar.bz2 libADLMIDI-c7b3199669a7b7e0ba11eb0d94d4e143a5fdd633.zip |
Added high tone frequency extension from OPL3-BE
Diffstat (limited to 'src')
-rw-r--r-- | src/adlmidi_midiplay.cpp | 5 | ||||
-rw-r--r-- | src/adlmidi_opl3.cpp | 93 | ||||
-rw-r--r-- | src/adlmidi_private.hpp | 5 |
3 files changed, 76 insertions, 27 deletions
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<double>(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<uint32_t>(hertz + 0.5); - uint32_t chn = g_channelsMap[cc]; + ftone = octave + static_cast<uint32_t>(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<char>(ChanCat_Rhythm_Bass + (b - 18)) : + (b >= 18) ? static_cast<int>(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 |