aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorVitaly Novichkov <admin@wohlnet.ru>2018-08-31 03:54:16 +0300
committerVitaly Novichkov <admin@wohlnet.ru>2018-08-31 03:54:16 +0300
commitc7b3199669a7b7e0ba11eb0d94d4e143a5fdd633 (patch)
tree3777a2b2ada15c9c3478427348acff63ab4642b8 /src
parent399992184883f76a0cd8909a92c15dea85dc657c (diff)
downloadlibADLMIDI-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.cpp5
-rw-r--r--src/adlmidi_opl3.cpp93
-rw-r--r--src/adlmidi_private.hpp5
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