aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/adlmidi_cvt.hpp11
-rw-r--r--src/adlmidi_midiplay.cpp111
-rw-r--r--src/adlmidi_midiplay.hpp3
-rw-r--r--src/adlmidi_opl3.cpp201
-rw-r--r--src/adlmidi_opl3.hpp10
-rw-r--r--src/cvt_mus2mid.hpp6
6 files changed, 197 insertions, 145 deletions
diff --git a/src/adlmidi_cvt.hpp b/src/adlmidi_cvt.hpp
index cb16eb0..3b2e07d 100644
--- a/src/adlmidi_cvt.hpp
+++ b/src/adlmidi_cvt.hpp
@@ -29,15 +29,12 @@ template <class WOPLI>
static void cvt_generic_to_FMIns(adlinsdata2 &ins, const WOPLI &in)
{
ins.voice2_fine_tune = 0.0;
- int8_t voice2_fine_tune = in.second_voice_detune;
+ int voice2_fine_tune = in.second_voice_detune;
+
if(voice2_fine_tune != 0)
{
- if(voice2_fine_tune == 1)
- ins.voice2_fine_tune = 0.000025;
- else if(voice2_fine_tune == -1)
- ins.voice2_fine_tune = -0.000025;
- else
- ins.voice2_fine_tune = voice2_fine_tune * (15.625 / 1000.0);
+ // Simulate behavior of DMX second voice detune
+ ins.voice2_fine_tune = (double)(((voice2_fine_tune + 128) >> 1) - 64) / 32.0;
}
ins.midi_velocity_offset = in.midi_velocity_offset;
diff --git a/src/adlmidi_midiplay.cpp b/src/adlmidi_midiplay.cpp
index 697a264..559ed69 100644
--- a/src/adlmidi_midiplay.cpp
+++ b/src/adlmidi_midiplay.cpp
@@ -29,38 +29,6 @@
// Minimum life time of percussion notes
static const double drum_note_min_time = 0.03;
-
-// Mapping from MIDI volume level to OPL level value.
-
-static const uint_fast32_t DMX_volume_mapping_table[128] =
-{
- 0, 1, 3, 5, 6, 8, 10, 11,
- 13, 14, 16, 17, 19, 20, 22, 23,
- 25, 26, 27, 29, 30, 32, 33, 34,
- 36, 37, 39, 41, 43, 45, 47, 49,
- 50, 52, 54, 55, 57, 59, 60, 61,
- 63, 64, 66, 67, 68, 69, 71, 72,
- 73, 74, 75, 76, 77, 79, 80, 81,
- 82, 83, 84, 84, 85, 86, 87, 88,
- 89, 90, 91, 92, 92, 93, 94, 95,
- 96, 96, 97, 98, 99, 99, 100, 101,
- 101, 102, 103, 103, 104, 105, 105, 106,
- 107, 107, 108, 109, 109, 110, 110, 111,
- 112, 112, 113, 113, 114, 114, 115, 115,
- 116, 117, 117, 118, 118, 119, 119, 120,
- 120, 121, 121, 122, 122, 123, 123, 123,
- 124, 124, 125, 125, 126, 126, 127, 127,
-};
-
-static const uint_fast32_t W9X_volume_mapping_table[32] =
-{
- 63, 63, 40, 36, 32, 28, 23, 21,
- 19, 17, 15, 14, 13, 12, 11, 10,
- 9, 8, 7, 6, 5, 5, 4, 4,
- 3, 3, 2, 2, 1, 1, 0, 0
-};
-
-
//static const char MIDIsymbols[256+1] =
//"PPPPPPhcckmvmxbd" // Ins 0-15
//"oooooahoGGGGGGGG" // Ins 16-31
@@ -110,7 +78,6 @@ void MIDIplay::AdlChannel::addAge(int64_t us)
MIDIplay::MIDIplay(unsigned long sampleRate):
m_cmfPercussionMode(false),
- m_masterVolume(MasterVolumeDefault),
m_sysExDeviceId(0),
m_synthMode(Mode_XG),
m_arpeggioCounter(0)
@@ -224,7 +191,8 @@ void MIDIplay::partialReset()
void MIDIplay::resetMIDI()
{
- m_masterVolume = MasterVolumeDefault;
+ Synth &synth = *m_synth;
+ synth.m_masterVolume = MasterVolumeDefault;
m_sysExDeviceId = 0;
m_synthMode = Mode_XG;
m_arpeggioCounter = 0;
@@ -299,7 +267,7 @@ void MIDIplay::realTime_ResetState()
noteUpdateAll(uint16_t(ch), Upd_All);
noteUpdateAll(uint16_t(ch), Upd_Off);
}
- m_masterVolume = MasterVolumeDefault;
+ synth.m_masterVolume = MasterVolumeDefault;
}
bool MIDIplay::realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocity)
@@ -969,7 +937,8 @@ bool MIDIplay::doUniversalSysEx(unsigned dev, bool realtime, const uint8_t *data
unsigned volume =
(((unsigned)data[0] & 0x7F)) |
(((unsigned)data[1] & 0x7F) << 7);
- m_masterVolume = static_cast<uint8_t>(volume >> 7);
+ if(m_synth.get())
+ m_synth->m_masterVolume = static_cast<uint8_t>(volume >> 7);
for(size_t ch = 0; ch < m_midiChannels.size(); ch++)
noteUpdateAll(uint16_t(ch), Upd_Volume);
return true;
@@ -1245,7 +1214,7 @@ void MIDIplay::noteUpdate(size_t midCh,
synth.noteOff(c);
if(props_mask & Upd_Mute) // Mute the note
{
- synth.touchNote(c, 0);
+ synth.touchNote(c, 0, 0, 0);
m_chipChannels[c].koff_time_until_neglible_us = 0;
}
else
@@ -1275,9 +1244,9 @@ void MIDIplay::noteUpdate(size_t midCh,
if(props_mask & Upd_Volume)
{
- uint_fast32_t volume;
- bool is_percussion = (midCh == 9) || m_midiChannels[midCh].is_xg_percussion;
- uint_fast32_t brightness = is_percussion ? 127 : m_midiChannels[midCh].brightness;
+ const MIDIchannel &ch = m_midiChannels[midCh];
+ bool is_percussion = (midCh == 9) || ch.is_xg_percussion;
+ uint_fast32_t brightness = is_percussion ? 127 : ch.brightness;
if(!m_setup.fullRangeBrightnessCC74)
{
@@ -1288,63 +1257,11 @@ void MIDIplay::noteUpdate(size_t midCh,
brightness *= 2;
}
- switch(synth.m_volumeScale)
- {
- default:
- case Synth::VOLUME_Generic:
- {
- volume = vol * m_masterVolume * m_midiChannels[midCh].volume * m_midiChannels[midCh].expression;
-
- /* If the channel has arpeggio, the effective volume of
- * *this* instrument is actually lower due to timesharing.
- * To compensate, add extra volume that corresponds to the
- * time this note is *not* heard.
- * Empirical tests however show that a full equal-proportion
- * increment sounds wrong. Therefore, using the square root.
- */
- //volume = (int)(volume * std::sqrt( (double) ch[c].users.size() ));
-
- // The formula below: SOLVE(V=127^4 * 2^( (A-63.49999) / 8), A)
- volume = volume > (8725 * 127) ? static_cast<uint_fast32_t>(std::log(static_cast<double>(volume)) * 11.541560327111707 - 1.601379199767093e+02) : 0;
- // The incorrect formula below: SOLVE(V=127^4 * (2^(A/63)-1), A)
- //opl.Touch_Real(c, volume>(11210*127) ? 91.61112 * std::log((4.8819E-7/127)*volume + 1.0)+0.5 : 0);
- }
- break;
-
- case Synth::VOLUME_NATIVE:
- {
- volume = vol * m_midiChannels[midCh].volume * m_midiChannels[midCh].expression;
- // volume = volume * m_masterVolume / (127 * 127 * 127) / 2;
- volume = (volume * m_masterVolume) / 4096766;
- }
- break;
-
- case Synth::VOLUME_DMX:
- {
- volume = (m_midiChannels[midCh].volume * m_midiChannels[midCh].expression * m_masterVolume) / 16129;
- volume = (DMX_volume_mapping_table[volume] + 1) << 1;
- volume = (DMX_volume_mapping_table[(vol < 128) ? vol : 127] * volume) >> 9;
- }
- break;
-
- case Synth::VOLUME_APOGEE:
- {
- volume = (m_midiChannels[midCh].volume * m_midiChannels[midCh].expression * m_masterVolume / 16129);
- volume = ((64 * (vol + 0x80)) * volume) >> 15;
- //volume = ((63 * (vol + 0x80)) * Ch[MidCh].volume) >> 15;
- }
- break;
-
- case Synth::VOLUME_9X:
- {
- //volume = 63 - W9X_volume_mapping_table[(((vol * Ch[MidCh].volume /** Ch[MidCh].expression*/) * m_masterVolume / 16129 /*2048383*/) >> 2)];
- volume = 63 - W9X_volume_mapping_table[((vol * m_midiChannels[midCh].volume * m_midiChannels[midCh].expression * m_masterVolume / 2048383) >> 2)];
- //volume = W9X_volume_mapping_table[vol >> 2] + volume;
- }
- break;
- }
-
- synth.touchNote(c, static_cast<uint8_t>(volume), static_cast<uint8_t>(brightness));
+ synth.touchNote(c,
+ vol,
+ ch.volume,
+ ch.expression,
+ static_cast<uint8_t>(brightness));
/* DEBUG ONLY!!!
static uint32_t max = 0;
diff --git a/src/adlmidi_midiplay.hpp b/src/adlmidi_midiplay.hpp
index 9cf35b1..f7732fe 100644
--- a/src/adlmidi_midiplay.hpp
+++ b/src/adlmidi_midiplay.hpp
@@ -538,9 +538,6 @@ public:
//! CMF Rhythm mode
bool m_cmfPercussionMode;
- //! Master volume, controlled via SysEx
- uint8_t m_masterVolume;
-
//! SysEx device ID
uint8_t m_sysExDeviceId;
diff --git a/src/adlmidi_opl3.cpp b/src/adlmidi_opl3.cpp
index 09e1a19..7938710 100644
--- a/src/adlmidi_opl3.cpp
+++ b/src/adlmidi_opl3.cpp
@@ -195,6 +195,41 @@ static const uint16_t g_channelsMapPan[NUM_OF_CHANNELS] =
Ports: ???
*/
+// Mapping from MIDI volume level to OPL level value.
+
+static const uint_fast32_t DMX_volume_mapping_table[128] =
+{
+ 0, 1, 3, 5, 6, 8, 10, 11,
+ 13, 14, 16, 17, 19, 20, 22, 23,
+ 25, 26, 27, 29, 30, 32, 33, 34,
+ 36, 37, 39, 41, 43, 45, 47, 49,
+ 50, 52, 54, 55, 57, 59, 60, 61,
+ 63, 64, 66, 67, 68, 69, 71, 72,
+ 73, 74, 75, 76, 77, 79, 80, 81,
+ 82, 83, 84, 84, 85, 86, 87, 88,
+ 89, 90, 91, 92, 92, 93, 94, 95,
+ 96, 96, 97, 98, 99, 99, 100, 101,
+ 101, 102, 103, 103, 104, 105, 105, 106,
+ 107, 107, 108, 109, 109, 110, 110, 111,
+ 112, 112, 113, 113, 114, 114, 115, 115,
+ 116, 117, 117, 118, 118, 119, 119, 120,
+ 120, 121, 121, 122, 122, 123, 123, 123,
+ 124, 124, 125, 125, 126, 126, 127, 127,
+};
+
+static const uint_fast32_t W9X_volume_mapping_table[32] =
+{
+ 63, 63, 40, 36, 32, 28, 23, 21,
+ 19, 17, 15, 14, 13, 12, 11, 10,
+ 9, 8, 7, 6, 5, 5, 4, 4,
+ 3, 3, 2, 2, 1, 1, 0, 0
+};
+
+enum
+{
+ MasterVolumeDefault = 127
+};
+
enum
{
OPL_PANNING_LEFT = 0x10,
@@ -202,6 +237,8 @@ enum
OPL_PANNING_BOTH = 0x30
};
+
+
static adlinsdata2 makeEmptyInstrument()
{
adlinsdata2 ins;
@@ -219,6 +256,7 @@ OPL3::OPL3() :
m_deepVibratoMode(false),
m_rhythmMode(false),
m_softPanning(false),
+ m_masterVolume(MasterVolumeDefault),
m_musicMode(MODE_MIDI),
m_volumeScale(VOLUME_Generic)
{
@@ -486,11 +524,12 @@ void OPL3::noteOn(size_t c1, size_t c2, double hertz) // Hertz range: 0..131071
}
}
-void OPL3::touchNote(size_t c, uint8_t volume, uint8_t brightness)
+void OPL3::touchNote(size_t c,
+ uint_fast32_t velocity,
+ uint_fast32_t channelVolume,
+ uint_fast32_t channelExpression,
+ uint8_t brightness)
{
- if(volume > 63)
- volume = 63;
-
size_t chip = c / NUM_OF_CHANNELS, cc = c % NUM_OF_CHANNELS;
const adldata &adli = m_insCache[c];
size_t cmf_offset = ((m_musicMode == MODE_CMF) && cc >= OPL3_CHANNELS_RHYTHM_BASE) ? 10 : 0;
@@ -499,6 +538,94 @@ 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
+ uint_fast32_t kslMod = x & 0xC0;
+ uint_fast32_t kslCar = y & 0xC0;
+ uint_fast32_t tlMod = x & 63;
+ uint_fast32_t tlCar = y & 63;
+
+ uint_fast32_t modulator;
+ uint_fast32_t carrier;
+
+ uint_fast32_t volume;
+
+ bool do_modulator;
+ bool do_carrier;
+
+ static const bool do_ops[10][2] =
+ {
+ { false, true }, /* 2 op FM */
+ { true, true }, /* 2 op AM */
+ { false, false }, /* 4 op FM-FM ops 1&2 */
+ { true, false }, /* 4 op AM-FM ops 1&2 */
+ { false, true }, /* 4 op FM-AM ops 1&2 */
+ { true, false }, /* 4 op AM-AM ops 1&2 */
+ { false, true }, /* 4 op FM-FM ops 3&4 */
+ { false, true }, /* 4 op AM-FM ops 3&4 */
+ { false, true }, /* 4 op FM-AM ops 3&4 */
+ { true, true } /* 4 op AM-AM ops 3&4 */
+ };
+
+
+ switch(m_volumeScale)
+ {
+ default:
+ case Synth::VOLUME_Generic:
+ {
+ volume = velocity * m_masterVolume * channelVolume * channelExpression;
+
+ /* If the channel has arpeggio, the effective volume of
+ * *this* instrument is actually lower due to timesharing.
+ * To compensate, add extra volume that corresponds to the
+ * time this note is *not* heard.
+ * Empirical tests however show that a full equal-proportion
+ * increment sounds wrong. Therefore, using the square root.
+ */
+ //volume = (int)(volume * std::sqrt( (double) ch[c].users.size() ));
+
+ // The formula below: SOLVE(V=127^4 * 2^( (A-63.49999) / 8), A)
+ volume = volume > (8725 * 127) ? static_cast<uint_fast32_t>(std::log(static_cast<double>(volume)) * 11.541560327111707 - 1.601379199767093e+02) : 0;
+ // The incorrect formula below: SOLVE(V=127^4 * (2^(A/63)-1), A)
+ //opl.Touch_Real(c, volume>(11210*127) ? 91.61112 * std::log((4.8819E-7/127)*volume + 1.0)+0.5 : 0);
+ }
+ break;
+
+ case Synth::VOLUME_NATIVE:
+ {
+ volume = velocity * channelVolume * channelExpression;
+ // volume = volume * m_masterVolume / (127 * 127 * 127) / 2;
+ volume = (volume * m_masterVolume) / 4096766;
+ }
+ break;
+
+ case Synth::VOLUME_DMX:
+ {
+ volume = (channelVolume * channelExpression * m_masterVolume) / 16129;
+ volume = (DMX_volume_mapping_table[volume] + 1) << 1;
+ volume = (DMX_volume_mapping_table[(velocity < 128) ? velocity : 127] * volume) >> 9;
+ }
+ break;
+
+ case Synth::VOLUME_APOGEE:
+ {
+ volume = (channelVolume * channelExpression * m_masterVolume / 16129);
+ volume = ((64 * (velocity + 0x80)) * volume) >> 15;
+ //volume = ((63 * (velocity + 0x80)) * Ch[MidCh].volume) >> 15;
+ }
+ break;
+
+ case Synth::VOLUME_9X:
+ {
+ //volume = 63 - W9X_volume_mapping_table[(((velocity * Ch[MidCh].volume /** Ch[MidCh].expression*/) * m_masterVolume / 16129 /*2048383*/) >> 2)];
+ volume = 63 - W9X_volume_mapping_table[((velocity * channelVolume * channelExpression * m_masterVolume / 2048383) >> 2)];
+ //volume = W9X_volume_mapping_table[vol >> 2] + volume;
+ }
+ break;
+ }
+
+ if(volume > 63)
+ volume = 63;
+
+
if(m_channelCategory[c] == ChanCat_Regular ||
m_channelCategory[c] == ChanCat_Rhythm_Bass)
{
@@ -525,50 +652,58 @@ void OPL3::touchNote(size_t c, uint8_t volume, uint8_t brightness)
mode += (i0->feedconn & 1) + (i1->feedconn & 1) * 2;
}
- static const bool do_ops[10][2] =
- {
- { false, true }, /* 2 op FM */
- { true, true }, /* 2 op AM */
- { false, false }, /* 4 op FM-FM ops 1&2 */
- { true, false }, /* 4 op AM-FM ops 1&2 */
- { false, true }, /* 4 op FM-AM ops 1&2 */
- { true, false }, /* 4 op AM-AM ops 1&2 */
- { false, true }, /* 4 op FM-FM ops 3&4 */
- { false, true }, /* 4 op AM-FM ops 3&4 */
- { false, true }, /* 4 op FM-AM ops 3&4 */
- { true, true } /* 4 op AM-AM ops 3&4 */
- };
if(m_musicMode == MODE_RSXX)
{
- if(o1 != 0xFFF)
- writeRegI(chip, 0x40 + o1, x);
- if(o2 != 0xFFF)
- writeRegI(chip, 0x40 + o2, y - volume / 2);
+ tlCar -= volume / 2;
+ }
+ else if(m_volumeScale == Synth::VOLUME_DMX && mode <= 1)
+ {
+ do_modulator = do_ops[mode][ 0 ] || m_scaleModulators;
+
+ tlCar = (63 - volume);
+
+ if(do_modulator)
+ {
+ if(tlMod < tlCar)
+ tlMod = tlCar;
+ }
+
+ if(brightness != 127)
+ {
+ brightness = static_cast<uint8_t>(::round(127.0 * ::sqrt((static_cast<double>(brightness)) * (1.0 / 127.0))) / 2.0);
+ if(!do_modulator)
+ tlMod = 63 - brightness + (brightness * tlMod) / 63;
+ }
}
else
{
- bool do_modulator = do_ops[ mode ][ 0 ] || m_scaleModulators;
- bool do_carrier = do_ops[ mode ][ 1 ] || m_scaleModulators;
+ do_modulator = do_ops[ mode ][ 0 ] || m_scaleModulators;
+ do_carrier = do_ops[ mode ][ 1 ] || m_scaleModulators;
- uint32_t modulator = do_modulator ? (x | 63) - volume + volume * (x & 63) / 63 : x;
- uint32_t carrier = do_carrier ? (y | 63) - volume + volume * (y & 63) / 63 : y;
+ if(do_modulator)
+ tlMod = 63 - volume + (volume * tlMod) / 63;
+ if(do_carrier)
+ tlCar = 63 - volume + (volume * tlCar) / 63;
if(brightness != 127)
{
brightness = static_cast<uint8_t>(::round(127.0 * ::sqrt((static_cast<double>(brightness)) * (1.0 / 127.0))) / 2.0);
if(!do_modulator)
- modulator = (modulator | 63) - brightness + brightness * (modulator & 63) / 63;
+ tlMod = 63 - brightness + (brightness * tlMod) / 63;
if(!do_carrier)
- carrier = (carrier | 63) - brightness + brightness * (carrier & 63) / 63;
+ tlCar = 63 - brightness + (brightness * tlCar) / 63;
}
-
- if(o1 != 0xFFF)
- writeRegI(chip, 0x40 + o1, modulator);
- if(o2 != 0xFFF)
- writeRegI(chip, 0x40 + o2, carrier);
}
+ modulator = (kslMod & 0xC0) | (tlMod & 63);
+ carrier = (kslCar & 0xC0) | (tlCar & 63);
+
+ if(o1 != 0xFFF)
+ writeRegI(chip, 0x40 + o1, modulator);
+ if(o2 != 0xFFF)
+ writeRegI(chip, 0x40 + o2, carrier);
+
// Correct formula (ST3, AdPlug):
// 63-((63-(instrvol))/63)*chanvol
// Reduces to (tested identical):
@@ -640,7 +775,7 @@ void OPL3::silenceAll() // Silence all OPL channels.
for(size_t c = 0; c < m_numChannels; ++c)
{
noteOff(c);
- touchNote(c, 0);
+ touchNote(c, 0, 0, 0);
}
}
diff --git a/src/adlmidi_opl3.hpp b/src/adlmidi_opl3.hpp
index b97b5d3..a12069e 100644
--- a/src/adlmidi_opl3.hpp
+++ b/src/adlmidi_opl3.hpp
@@ -110,6 +110,8 @@ public:
bool m_runAtPcmRate;
//! Enable soft panning
bool m_softPanning;
+ //! Master volume, controlled via SysEx (0...127)
+ uint8_t m_masterVolume;
//! Just a padding. Reserved.
char _padding2[3];
@@ -249,10 +251,14 @@ public:
/**
* @brief Change setup of instrument in specified chip channel
* @param c Channel of chip (Emulated chip choosing by next formula: [c = ch + (chipId * 23)])
- * @param volume Volume level (from 0 to 63)
+ * @param volume Volume level (from 0 to 127)
* @param brightness CC74 Brightness level (from 0 to 127)
*/
- void touchNote(size_t c, uint8_t volume, uint8_t brightness = 127);
+ void touchNote(size_t c,
+ uint_fast32_t velocity,
+ uint_fast32_t channelVolume = 127,
+ uint_fast32_t channelExpression = 127,
+ uint8_t brightness = 127);
/**
* @brief Set the instrument into specified chip channel
diff --git a/src/cvt_mus2mid.hpp b/src/cvt_mus2mid.hpp
index 4b07b0d..fcd586d 100644
--- a/src/cvt_mus2mid.hpp
+++ b/src/cvt_mus2mid.hpp
@@ -307,11 +307,11 @@ static int Convert_mus2midi(uint8_t *in, uint32_t insize,
mus2mid_write1(&ctx, (MUS_TEMPO & 0x0000ff00) >> 8);
mus2mid_write1(&ctx, (MUS_TEMPO & 0x00ff0000) >> 16);
- /* Percussions channel starts out at full volume */
+ /* Percussions channel starts out at volume 100 */
mus2mid_write1(&ctx, 0x00);
mus2mid_write1(&ctx, 0xB9);
mus2mid_write1(&ctx, 0x07);
- mus2mid_write1(&ctx, 127);
+ mus2mid_write1(&ctx, 100);
/* get current position in source, and end of position */
cur = in + header.scoreStart;
@@ -340,7 +340,7 @@ static int Convert_mus2midi(uint8_t *in, uint32_t insize,
if (channelMap[channel] < 0) {
*out_local++ = 0xB0 + currentChannel;
*out_local++ = 0x07;
- *out_local++ = 127;
+ *out_local++ = 100;
*out_local++ = 0x00;
channelMap[channel] = currentChannel++;
if (currentChannel == 9)