From 252e65097e9b8a815485fc03e4358698803f1a73 Mon Sep 17 00:00:00 2001 From: JP Cimalando Date: Wed, 20 Jun 2018 21:45:54 +0200 Subject: basic framework of sysex handling and sequencer support --- src/adlmidi_midiplay.cpp | 178 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 178 insertions(+) (limited to 'src/adlmidi_midiplay.cpp') diff --git a/src/adlmidi_midiplay.cpp b/src/adlmidi_midiplay.cpp index 2f186a6..e0cacfa 100644 --- a/src/adlmidi_midiplay.cpp +++ b/src/adlmidi_midiplay.cpp @@ -680,6 +680,7 @@ bool MIDIplay::buildTrackData() MIDIplay::MIDIplay(unsigned long sampleRate): cmf_percussion_mode(false), + m_sysExDeviceId(0), m_arpeggioCounter(0) #if defined(ADLMIDI_AUDIO_TICK_HANDLER) , m_audioTickCounter(0) @@ -1459,6 +1460,172 @@ void MIDIplay::realTime_BankChange(uint8_t channel, uint16_t bank) Ch[channel].bank_msb = uint8_t((bank >> 8) & 0xFF); } +void MIDIplay::setDeviceId(uint8_t id) +{ + m_sysExDeviceId = id; +} + +bool MIDIplay::realTime_SysEx(const uint8_t *msg, unsigned size) +{ + if(size < 4 || msg[0] != 0xF0 || msg[size - 1] != 0xF7) + return false; + + unsigned manufacturer = msg[1]; + unsigned dev = msg[2]; + msg += 3; + size -= 4; + + switch(manufacturer) + { + default: + break; + case Manufacturer_UniversalNonRealtime: + case Manufacturer_UniversalRealtime: + return doUniversalSysEx( + dev, manufacturer == Manufacturer_UniversalRealtime, msg, size); + case Manufacturer_Roland: + return doRolandSysEx(dev, msg, size); + case Manufacturer_Yamaha: + return doYamahaSysEx(dev, msg, size); + } + + return false; +} + +bool MIDIplay::doUniversalSysEx(unsigned dev, bool realtime, const uint8_t *data, unsigned size) +{ + bool devicematch = dev == 0x7F || dev == m_sysExDeviceId; + if(size < 2 || !devicematch) + return false; + + unsigned address = + (((unsigned)data[0] & 0x7F) << 8) | + (((unsigned)data[1] & 0x7F)); + data += 2; + size -= 2; + + switch(((unsigned)realtime << 16) | address) + { + case (0 << 16) | 0x0901: // GM System On + /*TODO*/ + return true; + case (0 << 16) | 0x0902: // GM System Off + /*TODO*/ + return true; + case (1 << 16) | 0x0401: // MIDI Master Volume + if(size != 2) + break; + unsigned volume = + (((unsigned)data[0] & 0x7F)) | + (((unsigned)data[1] & 0x7F) << 7); + /*TODO*/ + (void)volume; + return true; + } + + return false; +} + +bool MIDIplay::doRolandSysEx(unsigned dev, const uint8_t *data, unsigned size) +{ + bool devicematch = dev == 0x7F || (dev & 0x0F) == m_sysExDeviceId; + if(size < 6 || !devicematch) + return false; + + unsigned model = data[0] & 0x7F; + unsigned mode = data[1] & 0x7F; + unsigned checksum = data[size - 1] & 0x7F; + data += 2; + size -= 3; + +#if !defined(ADLMIDI_SKIP_ROLAND_CHECKSUM) + { + unsigned checkvalue = 0; + for(unsigned i = 0; i < size; ++i) + checkvalue += data[i] & 0x7F; + checkvalue = (128 - (checkvalue & 127)) & 127; + if(checkvalue != checksum) + return false; + } +#endif + + unsigned address = + (((unsigned)data[0] & 0x7F) << 16) | + (((unsigned)data[1] & 0x7F) << 8) | + (((unsigned)data[2] & 0x7F)); + data += 3; + size -= 3; + + if(mode != RolandMode_Send) // don't have MIDI-Out reply ability + return false; + + switch((model << 24) | address) + { + case (RolandModel_GS << 24) | 0x00007F: // System Mode Set + { + if(size != 1 || (dev & 0xF0) != 0x10) + break; + unsigned mode = data[0] & 0x7F; + /*TODO*/ + (void)mode; + return true; + } + case (RolandModel_GS << 24) | 0x40007F: // Mode Set + { + if(size != 1 || (dev & 0xF0) != 0x10) + break; + unsigned value = data[0] & 0x7F; + /*TODO*/ + (void)value; + return true; + } + } + + return false; +} + +bool MIDIplay::doYamahaSysEx(unsigned dev, const uint8_t *data, unsigned size) +{ + bool devicematch = dev == 0x7F || (dev & 0x0F) == m_sysExDeviceId; + if(size < 1 || !devicematch) + return false; + + unsigned model = data[0] & 0x7F; + ++data; + --size; + + switch((model << 8) | (dev & 0xF0)) + { + case (YamahaModel_XG << 8) | 0x10: // parameter change + { + if(size < 3) + break; + + unsigned address = + (((unsigned)data[0] & 0x7F) << 16) | + (((unsigned)data[1] & 0x7F) << 8) | + (((unsigned)data[2] & 0x7F)); + data += 3; + size -= 3; + + switch(address) + { + case 0x00007E: // XG System On + if(size != 1) + break; + unsigned value = data[0] & 0x7F; + /*TODO*/ + (void)value; + return true; + } + + break; + } + } + + return false; +} + void MIDIplay::realTime_panic() { Panic(); @@ -1845,6 +2012,10 @@ MIDIplay::MidiEvent MIDIplay::parseEvent(uint8_t **pptr, uint8_t *end, int &stat evt.isValid = 0; return evt; } + evt.type = MidiEvent::T_SYSEX; + evt.data.clear(); + evt.data.push_back(byte); + std::copy(ptr, ptr + length, std::back_inserter(evt.data)); ptr += (size_t)length; return evt; } @@ -2067,6 +2238,13 @@ void MIDIplay::HandleEvent(size_t tk, const MIDIplay::MidiEvent &evt, int &statu { //std::string data( length?(const char*) &TrackData[tk][CurrentPosition.track[tk].ptr]:0, length ); //UI.PrintLn("SysEx %02X: %u bytes", byte, length/*, data.c_str()*/); +#if 0 + fputs("SysEx:", stderr); + for(size_t i = 0; i < evt.data.size(); ++i) + fprintf(stderr, " %02X", evt.data[i]); + fputc('\n', stderr); +#endif + realTime_SysEx(evt.data.data(), (unsigned)evt.data.size()); return; } -- cgit v1.2.3 From ebee7962d7a2691e38d585dac9b9c0e3d286364c Mon Sep 17 00:00:00 2001 From: Vitaly Novichkov Date: Thu, 21 Jun 2018 09:43:34 +0300 Subject: SysEx: Use `size_t` for size values instead of `unsigned int` --- src/adlmidi_midiplay.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/adlmidi_midiplay.cpp') diff --git a/src/adlmidi_midiplay.cpp b/src/adlmidi_midiplay.cpp index 8b4f27f..ba5b1ef 100644 --- a/src/adlmidi_midiplay.cpp +++ b/src/adlmidi_midiplay.cpp @@ -712,7 +712,7 @@ void MIDIplay::setDeviceId(uint8_t id) m_sysExDeviceId = id; } -bool MIDIplay::realTime_SysEx(const uint8_t *msg, unsigned size) +bool MIDIplay::realTime_SysEx(const uint8_t *msg, size_t size) { if(size < 4 || msg[0] != 0xF0 || msg[size - 1] != 0xF7) return false; @@ -739,7 +739,7 @@ bool MIDIplay::realTime_SysEx(const uint8_t *msg, unsigned size) return false; } -bool MIDIplay::doUniversalSysEx(unsigned dev, bool realtime, const uint8_t *data, unsigned size) +bool MIDIplay::doUniversalSysEx(unsigned dev, bool realtime, const uint8_t *data, size_t size) { bool devicematch = dev == 0x7F || dev == m_sysExDeviceId; if(size < 2 || !devicematch) @@ -773,7 +773,7 @@ bool MIDIplay::doUniversalSysEx(unsigned dev, bool realtime, const uint8_t *data return false; } -bool MIDIplay::doRolandSysEx(unsigned dev, const uint8_t *data, unsigned size) +bool MIDIplay::doRolandSysEx(unsigned dev, const uint8_t *data, size_t size) { bool devicematch = dev == 0x7F || (dev & 0x0F) == m_sysExDeviceId; if(size < 6 || !devicematch) @@ -788,7 +788,7 @@ bool MIDIplay::doRolandSysEx(unsigned dev, const uint8_t *data, unsigned size) #if !defined(ADLMIDI_SKIP_ROLAND_CHECKSUM) { unsigned checkvalue = 0; - for(unsigned i = 0; i < size; ++i) + for(size_t i = 0; i < size; ++i) checkvalue += data[i] & 0x7F; checkvalue = (128 - (checkvalue & 127)) & 127; if(checkvalue != checksum) @@ -831,7 +831,7 @@ bool MIDIplay::doRolandSysEx(unsigned dev, const uint8_t *data, unsigned size) return false; } -bool MIDIplay::doYamahaSysEx(unsigned dev, const uint8_t *data, unsigned size) +bool MIDIplay::doYamahaSysEx(unsigned dev, const uint8_t *data, size_t size) { bool devicematch = dev == 0x7F || (dev & 0x0F) == m_sysExDeviceId; if(size < 1 || !devicematch) -- cgit v1.2.3 From 8075701abfe8e5b1fc6705eb2b1d35b407784c82 Mon Sep 17 00:00:00 2001 From: Vitaly Novichkov Date: Fri, 22 Jun 2018 03:35:06 +0300 Subject: Portamento must use previously played note in a channel like S-YXG50 does --- src/adlmidi_midiplay.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/adlmidi_midiplay.cpp') diff --git a/src/adlmidi_midiplay.cpp b/src/adlmidi_midiplay.cpp index ba5b1ef..089fd43 100644 --- a/src/adlmidi_midiplay.cpp +++ b/src/adlmidi_midiplay.cpp @@ -478,7 +478,8 @@ bool MIDIplay::realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocity) midiChan.portamentoEnable && currentPortamentoRate != HUGE_VAL && !isPercussion && !isXgPercussion; // Record the last note on MIDI channel as source of portamento - midiChan.portamentoSource = portamentoEnable ? (int8_t)note : (int8_t)-1; + midiChan.portamentoSource = static_cast(note); + // midiChan.portamentoSource = portamentoEnable ? (int8_t)note : (int8_t)-1; // Enable gliding on portamento note if (portamentoEnable && currentPortamentoSource >= 0) -- cgit v1.2.3 From be2e41fe5d800520ee50ca93729c8633407fb1fc Mon Sep 17 00:00:00 2001 From: JP Cimalando Date: Fri, 22 Jun 2018 17:30:34 +0200 Subject: handle sysex resets --- src/adlmidi_midiplay.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/adlmidi_midiplay.cpp') diff --git a/src/adlmidi_midiplay.cpp b/src/adlmidi_midiplay.cpp index 089fd43..bd979bd 100644 --- a/src/adlmidi_midiplay.cpp +++ b/src/adlmidi_midiplay.cpp @@ -606,7 +606,7 @@ void MIDIplay::realTime_Controller(uint8_t channel, uint8_t type, uint8_t value) break; case 120: // All sounds off - NoteUpdate_All(channel, Upt_OffMute); + NoteUpdate_All(channel, Upd_OffMute); break; case 123: // All notes off @@ -755,10 +755,10 @@ bool MIDIplay::doUniversalSysEx(unsigned dev, bool realtime, const uint8_t *data switch(((unsigned)realtime << 16) | address) { case (0 << 16) | 0x0901: // GM System On - /*TODO*/ + realTime_ResetState(); return true; case (0 << 16) | 0x0902: // GM System Off - /*TODO*/ + realTime_ResetState(); return true; case (1 << 16) | 0x0401: // MIDI Master Volume if(size != 2) @@ -814,8 +814,8 @@ bool MIDIplay::doRolandSysEx(unsigned dev, const uint8_t *data, size_t size) if(size != 1 || (dev & 0xF0) != 0x10) break; unsigned mode = data[0] & 0x7F; - /*TODO*/ (void)mode; + realTime_ResetState(); return true; } case (RolandModel_GS << 24) | 0x40007F: // Mode Set @@ -823,8 +823,8 @@ bool MIDIplay::doRolandSysEx(unsigned dev, const uint8_t *data, size_t size) if(size != 1 || (dev & 0xF0) != 0x10) break; unsigned value = data[0] & 0x7F; - /*TODO*/ (void)value; + realTime_ResetState(); return true; } } -- cgit v1.2.3 From 16831e97a68049d27329db4630dcfbfa58b1d8fd Mon Sep 17 00:00:00 2001 From: JP Cimalando Date: Fri, 22 Jun 2018 17:58:31 +0200 Subject: handle MIDI master volume --- src/adlmidi_midiplay.cpp | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) (limited to 'src/adlmidi_midiplay.cpp') diff --git a/src/adlmidi_midiplay.cpp b/src/adlmidi_midiplay.cpp index bd979bd..3aa307d 100644 --- a/src/adlmidi_midiplay.cpp +++ b/src/adlmidi_midiplay.cpp @@ -93,6 +93,8 @@ static const uint8_t PercussionMap[256] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; +enum { MasterVolumeDefault = 127 }; + inline bool isXgPercChannel(uint8_t msb, uint8_t lsb) { return (msb == 0x7E || msb == 0x7F) && (lsb == 0); @@ -117,6 +119,7 @@ void MIDIplay::AdlChannel::AddAge(int64_t ms) MIDIplay::MIDIplay(unsigned long sampleRate): cmf_percussion_mode(false), + m_masterVolume(MasterVolumeDefault), m_sysExDeviceId(0), m_arpeggioCounter(0) #if defined(ADLMIDI_AUDIO_TICK_HANDLER) @@ -220,6 +223,7 @@ void MIDIplay::realTime_ResetState() NoteUpdate_All(uint16_t(ch), Upd_All); NoteUpdate_All(uint16_t(ch), Upd_Off); } + m_masterVolume = MasterVolumeDefault; } bool MIDIplay::realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocity) @@ -766,8 +770,9 @@ bool MIDIplay::doUniversalSysEx(unsigned dev, bool realtime, const uint8_t *data unsigned volume = (((unsigned)data[0] & 0x7F)) | (((unsigned)data[1] & 0x7F) << 7); - /*TODO*/ - (void)volume; + m_masterVolume = volume >> 7; + for(size_t ch = 0; ch < Ch.size(); ch++) + NoteUpdate_All(uint16_t(ch), Upd_Volume); return true; } @@ -1029,7 +1034,7 @@ void MIDIplay::NoteUpdate(uint16_t MidCh, case OPL3::VOLUME_Generic: { - volume = vol * Ch[MidCh].volume * Ch[MidCh].expression; + volume = vol * m_masterVolume * Ch[MidCh].volume * Ch[MidCh].expression; /* If the channel has arpeggio, the effective volume of * *this* instrument is actually lower due to timesharing. @@ -1040,10 +1045,10 @@ void MIDIplay::NoteUpdate(uint16_t MidCh, */ //volume = (int)(volume * std::sqrt( (double) ch[c].users.size() )); - // The formula below: SOLVE(V=127^3 * 2^( (A-63.49999) / 8), A) - volume = volume > 8725 ? static_cast(std::log(static_cast(volume)) * 11.541561 + (0.5 - 104.22845)) : 0; - // The incorrect formula below: SOLVE(V=127^3 * (2^(A/63)-1), A) - //opl.Touch_Real(c, volume>11210 ? 91.61112 * std::log(4.8819E-7*volume + 1.0)+0.5 : 0); + // The formula below: SOLVE(V=127^4 * 2^( (A-63.49999) / 8), A) + volume = volume > (8725 * 127) ? static_cast(std::log(static_cast(volume) * (1.0 / 127.0)) * 11.541561 + (0.5 - 104.22845)) : 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); opl.Touch_Real(c, volume, brightness); //opl.Touch(c, volume); @@ -1053,14 +1058,14 @@ void MIDIplay::NoteUpdate(uint16_t MidCh, case OPL3::VOLUME_NATIVE: { volume = vol * Ch[MidCh].volume * Ch[MidCh].expression; - volume = volume * 127 / (127 * 127 * 127) / 2; + volume = volume * m_masterVolume / (127 * 127 * 127) / 2; opl.Touch_Real(c, volume, brightness); } break; case OPL3::VOLUME_DMX: { - volume = 2 * ((Ch[MidCh].volume * Ch[MidCh].expression) * 127 / 16129) + 1; + volume = 2 * (Ch[MidCh].volume * Ch[MidCh].expression * m_masterVolume / 16129) + 1; //volume = 2 * (Ch[MidCh].volume) + 1; volume = (DMX_volume_mapping_table[(vol < 128) ? vol : 127] * volume) >> 9; opl.Touch_Real(c, volume, brightness); @@ -1069,7 +1074,7 @@ void MIDIplay::NoteUpdate(uint16_t MidCh, case OPL3::VOLUME_APOGEE: { - volume = ((Ch[MidCh].volume * Ch[MidCh].expression) * 127 / 16129); + volume = (Ch[MidCh].volume * Ch[MidCh].expression * m_masterVolume / 16129); volume = ((64 * (vol + 0x80)) * volume) >> 15; //volume = ((63 * (vol + 0x80)) * Ch[MidCh].volume) >> 15; opl.Touch_Real(c, volume, brightness); @@ -1078,8 +1083,8 @@ void MIDIplay::NoteUpdate(uint16_t MidCh, case OPL3::VOLUME_9X: { - //volume = 63 - W9X_volume_mapping_table[(((vol * Ch[MidCh].volume /** Ch[MidCh].expression*/) * 127 / 16129 /*2048383*/) >> 2)]; - volume = 63 - W9X_volume_mapping_table[(((vol * Ch[MidCh].volume * Ch[MidCh].expression) * 127 / 2048383) >> 2)]; + //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 * Ch[MidCh].volume * Ch[MidCh].expression * m_masterVolume / 2048383) >> 2)]; //volume = W9X_volume_mapping_table[vol >> 2] + volume; opl.Touch_Real(c, volume, brightness); } -- cgit v1.2.3 From faaab13482d1e8334712232b7f64a59ec8ae6f07 Mon Sep 17 00:00:00 2001 From: JP Cimalando Date: Fri, 22 Jun 2018 18:41:31 +0200 Subject: Yamaha XG reset --- src/adlmidi_midiplay.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/adlmidi_midiplay.cpp') diff --git a/src/adlmidi_midiplay.cpp b/src/adlmidi_midiplay.cpp index 3aa307d..a6fc2a5 100644 --- a/src/adlmidi_midiplay.cpp +++ b/src/adlmidi_midiplay.cpp @@ -867,8 +867,8 @@ bool MIDIplay::doYamahaSysEx(unsigned dev, const uint8_t *data, size_t size) if(size != 1) break; unsigned value = data[0] & 0x7F; - /*TODO*/ (void)value; + realTime_ResetState(); return true; } -- cgit v1.2.3 From 2e88f9b9303ce1b9ef5512d6b84b3bb190dbfe75 Mon Sep 17 00:00:00 2001 From: JP Cimalando Date: Fri, 22 Jun 2018 19:08:17 +0200 Subject: simplify the volume formula --- src/adlmidi_midiplay.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/adlmidi_midiplay.cpp') diff --git a/src/adlmidi_midiplay.cpp b/src/adlmidi_midiplay.cpp index a6fc2a5..5637da4 100644 --- a/src/adlmidi_midiplay.cpp +++ b/src/adlmidi_midiplay.cpp @@ -1046,7 +1046,7 @@ void MIDIplay::NoteUpdate(uint16_t MidCh, //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(std::log(static_cast(volume) * (1.0 / 127.0)) * 11.541561 + (0.5 - 104.22845)) : 0; + volume = volume > (8725 * 127) ? static_cast(std::log(static_cast(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); -- cgit v1.2.3 From 51081828bbc756f81ac4b5c58cd3605a31047f61 Mon Sep 17 00:00:00 2001 From: Vitaly Novichkov Date: Fri, 22 Jun 2018 21:22:44 +0300 Subject: Move `opl.Touch_Real()` call out of volume model switch --- src/adlmidi_midiplay.cpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'src/adlmidi_midiplay.cpp') diff --git a/src/adlmidi_midiplay.cpp b/src/adlmidi_midiplay.cpp index 5637da4..625f8f7 100644 --- a/src/adlmidi_midiplay.cpp +++ b/src/adlmidi_midiplay.cpp @@ -1049,9 +1049,6 @@ void MIDIplay::NoteUpdate(uint16_t MidCh, volume = volume > (8725 * 127) ? static_cast(std::log(static_cast(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); - - opl.Touch_Real(c, volume, brightness); - //opl.Touch(c, volume); } break; @@ -1059,7 +1056,6 @@ void MIDIplay::NoteUpdate(uint16_t MidCh, { volume = vol * Ch[MidCh].volume * Ch[MidCh].expression; volume = volume * m_masterVolume / (127 * 127 * 127) / 2; - opl.Touch_Real(c, volume, brightness); } break; @@ -1068,7 +1064,6 @@ void MIDIplay::NoteUpdate(uint16_t MidCh, volume = 2 * (Ch[MidCh].volume * Ch[MidCh].expression * m_masterVolume / 16129) + 1; //volume = 2 * (Ch[MidCh].volume) + 1; volume = (DMX_volume_mapping_table[(vol < 128) ? vol : 127] * volume) >> 9; - opl.Touch_Real(c, volume, brightness); } break; @@ -1077,7 +1072,6 @@ void MIDIplay::NoteUpdate(uint16_t MidCh, volume = (Ch[MidCh].volume * Ch[MidCh].expression * m_masterVolume / 16129); volume = ((64 * (vol + 0x80)) * volume) >> 15; //volume = ((63 * (vol + 0x80)) * Ch[MidCh].volume) >> 15; - opl.Touch_Real(c, volume, brightness); } break; @@ -1086,11 +1080,12 @@ void MIDIplay::NoteUpdate(uint16_t MidCh, //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 * Ch[MidCh].volume * Ch[MidCh].expression * m_masterVolume / 2048383) >> 2)]; //volume = W9X_volume_mapping_table[vol >> 2] + volume; - opl.Touch_Real(c, volume, brightness); } break; } + opl.Touch_Real(c, volume, brightness); + /* DEBUG ONLY!!! static uint32_t max = 0; -- cgit v1.2.3 From db96b37884c4e32f2d6b7cd1745f829e1c2cb564 Mon Sep 17 00:00:00 2001 From: Vitaly Novichkov Date: Fri, 22 Jun 2018 21:23:01 +0300 Subject: Added some debug message hooks into SysEx processors --- src/adlmidi_midiplay.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'src/adlmidi_midiplay.cpp') diff --git a/src/adlmidi_midiplay.cpp b/src/adlmidi_midiplay.cpp index 625f8f7..336c40c 100644 --- a/src/adlmidi_midiplay.cpp +++ b/src/adlmidi_midiplay.cpp @@ -759,9 +759,13 @@ bool MIDIplay::doUniversalSysEx(unsigned dev, bool realtime, const uint8_t *data switch(((unsigned)realtime << 16) | address) { case (0 << 16) | 0x0901: // GM System On + if(hooks.onDebugMessage) + hooks.onDebugMessage(hooks.onDebugMessage_userData, "SysEx: GM System On"); realTime_ResetState(); return true; case (0 << 16) | 0x0902: // GM System Off + if(hooks.onDebugMessage) + hooks.onDebugMessage(hooks.onDebugMessage_userData, "SysEx: GM System Off"); realTime_ResetState(); return true; case (1 << 16) | 0x0401: // MIDI Master Volume @@ -819,7 +823,9 @@ bool MIDIplay::doRolandSysEx(unsigned dev, const uint8_t *data, size_t size) if(size != 1 || (dev & 0xF0) != 0x10) break; unsigned mode = data[0] & 0x7F; - (void)mode; + ADL_UNUSED(mode); + if(hooks.onDebugMessage) + hooks.onDebugMessage(hooks.onDebugMessage_userData, "SysEx: Caugh Roland System Mode Set: %02X", mode); realTime_ResetState(); return true; } @@ -828,7 +834,9 @@ bool MIDIplay::doRolandSysEx(unsigned dev, const uint8_t *data, size_t size) if(size != 1 || (dev & 0xF0) != 0x10) break; unsigned value = data[0] & 0x7F; - (void)value; + ADL_UNUSED(value); + if(hooks.onDebugMessage) + hooks.onDebugMessage(hooks.onDebugMessage_userData, "SysEx: Caugh Roland Mode Set: %02X", value); realTime_ResetState(); return true; } @@ -867,7 +875,9 @@ bool MIDIplay::doYamahaSysEx(unsigned dev, const uint8_t *data, size_t size) if(size != 1) break; unsigned value = data[0] & 0x7F; - (void)value; + ADL_UNUSED(value); + if(hooks.onDebugMessage) + hooks.onDebugMessage(hooks.onDebugMessage_userData, "SysEx: Caugh Yamaha XG System On: %02X", value); realTime_ResetState(); return true; } -- cgit v1.2.3 From a8fa66e8444da96b39699489bf75587a0ae94721 Mon Sep 17 00:00:00 2001 From: Vitaly Novichkov Date: Fri, 22 Jun 2018 21:30:00 +0300 Subject: Use Generic volume model by default when VM value has received some junk --- src/adlmidi_midiplay.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/adlmidi_midiplay.cpp') diff --git a/src/adlmidi_midiplay.cpp b/src/adlmidi_midiplay.cpp index 336c40c..8a4e8cd 100644 --- a/src/adlmidi_midiplay.cpp +++ b/src/adlmidi_midiplay.cpp @@ -1041,7 +1041,7 @@ void MIDIplay::NoteUpdate(uint16_t MidCh, switch(opl.m_volumeScale) { - + default: case OPL3::VOLUME_Generic: { volume = vol * m_masterVolume * Ch[MidCh].volume * Ch[MidCh].expression; -- cgit v1.2.3 From 2f30eb0596d3fc9788ffe99b72a09ceca596b792 Mon Sep 17 00:00:00 2001 From: Vitaly Novichkov Date: Fri, 22 Jun 2018 22:33:36 +0300 Subject: Fix the typo in "Caught" word in debug messages --- src/adlmidi_midiplay.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/adlmidi_midiplay.cpp') diff --git a/src/adlmidi_midiplay.cpp b/src/adlmidi_midiplay.cpp index 8a4e8cd..eca5282 100644 --- a/src/adlmidi_midiplay.cpp +++ b/src/adlmidi_midiplay.cpp @@ -335,7 +335,7 @@ bool MIDIplay::realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocity) if(hooks.onDebugMessage) { if(caugh_missing_instruments.insert(static_cast(midiins)).second) - hooks.onDebugMessage(hooks.onDebugMessage_userData, "[%i] Caugh a blank instrument %i (offset %i) in the MIDI bank %u", channel, Ch[channel].patch, midiins, bank); + hooks.onDebugMessage(hooks.onDebugMessage_userData, "[%i] Caught a blank instrument %i (offset %i) in the MIDI bank %u", channel, Ch[channel].patch, midiins, bank); } bank = 0; midiins = midiChan.patch; @@ -825,7 +825,7 @@ bool MIDIplay::doRolandSysEx(unsigned dev, const uint8_t *data, size_t size) unsigned mode = data[0] & 0x7F; ADL_UNUSED(mode); if(hooks.onDebugMessage) - hooks.onDebugMessage(hooks.onDebugMessage_userData, "SysEx: Caugh Roland System Mode Set: %02X", mode); + hooks.onDebugMessage(hooks.onDebugMessage_userData, "SysEx: Caught Roland System Mode Set: %02X", mode); realTime_ResetState(); return true; } @@ -836,7 +836,7 @@ bool MIDIplay::doRolandSysEx(unsigned dev, const uint8_t *data, size_t size) unsigned value = data[0] & 0x7F; ADL_UNUSED(value); if(hooks.onDebugMessage) - hooks.onDebugMessage(hooks.onDebugMessage_userData, "SysEx: Caugh Roland Mode Set: %02X", value); + hooks.onDebugMessage(hooks.onDebugMessage_userData, "SysEx: Caught Roland Mode Set: %02X", value); realTime_ResetState(); return true; } @@ -877,7 +877,7 @@ bool MIDIplay::doYamahaSysEx(unsigned dev, const uint8_t *data, size_t size) unsigned value = data[0] & 0x7F; ADL_UNUSED(value); if(hooks.onDebugMessage) - hooks.onDebugMessage(hooks.onDebugMessage_userData, "SysEx: Caugh Yamaha XG System On: %02X", value); + hooks.onDebugMessage(hooks.onDebugMessage_userData, "SysEx: Caught Yamaha XG System On: %02X", value); realTime_ResetState(); return true; } -- cgit v1.2.3 From 159bb5b202cd088db920ccc073d952122dea85ba Mon Sep 17 00:00:00 2001 From: Vitaly Novichkov Date: Fri, 22 Jun 2018 23:25:13 +0300 Subject: Added support for synthesizer mode - in GS mode, RPN XG-related vibrato depth events will be ignored (GS does using NRPN values are stored separately and are NOT handled) - in GS mode ignore LSB value of the bank number --- src/adlmidi_midiplay.cpp | 40 +++++++++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 11 deletions(-) (limited to 'src/adlmidi_midiplay.cpp') diff --git a/src/adlmidi_midiplay.cpp b/src/adlmidi_midiplay.cpp index eca5282..dd5c9bf 100644 --- a/src/adlmidi_midiplay.cpp +++ b/src/adlmidi_midiplay.cpp @@ -121,6 +121,7 @@ MIDIplay::MIDIplay(unsigned long sampleRate): cmf_percussion_mode(false), m_masterVolume(MasterVolumeDefault), m_sysExDeviceId(0), + m_synthMode(Mode_XG), m_arpeggioCounter(0) #if defined(ADLMIDI_AUDIO_TICK_HANDLER) , m_audioTickCounter(0) @@ -262,10 +263,13 @@ bool MIDIplay::realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocity) uint16_t bank = 0; if(midiChan.bank_msb || midiChan.bank_lsb) { - bank = (uint16_t(midiChan.bank_msb) * 256) + uint16_t(midiChan.bank_lsb); + if((m_synthMode & Mode_GS) != 0) //in GS mode ignore LSB + bank = (uint16_t(midiChan.bank_msb) * 256); + else + bank = (uint16_t(midiChan.bank_msb) * 256) + uint16_t(midiChan.bank_lsb); //0x7E00 - XG SFX1/SFX2 channel (16128 signed decimal) //0x7F00 - XG Percussion channel (16256 signed decimal) - if(bank == 0x7E00 || bank == 0x7F00) + if(((m_synthMode & Mode_XG) != 0) && (bank == 0x7E00 || bank == 0x7F00)) { //Let XG SFX1/SFX2 bank will have LSB==1 (128...255 range in WOPN file) //Let XG Percussion bank will use (0...127 range in WOPN file) @@ -761,11 +765,13 @@ bool MIDIplay::doUniversalSysEx(unsigned dev, bool realtime, const uint8_t *data case (0 << 16) | 0x0901: // GM System On if(hooks.onDebugMessage) hooks.onDebugMessage(hooks.onDebugMessage_userData, "SysEx: GM System On"); + m_synthMode = Mode_GM; realTime_ResetState(); return true; case (0 << 16) | 0x0902: // GM System Off if(hooks.onDebugMessage) hooks.onDebugMessage(hooks.onDebugMessage_userData, "SysEx: GM System Off"); + m_synthMode = Mode_XG;//TODO: TEMPORARY, make something RIGHT realTime_ResetState(); return true; case (1 << 16) | 0x0401: // MIDI Master Volume @@ -826,6 +832,7 @@ bool MIDIplay::doRolandSysEx(unsigned dev, const uint8_t *data, size_t size) ADL_UNUSED(mode); if(hooks.onDebugMessage) hooks.onDebugMessage(hooks.onDebugMessage_userData, "SysEx: Caught Roland System Mode Set: %02X", mode); + m_synthMode = Mode_GS; realTime_ResetState(); return true; } @@ -837,6 +844,7 @@ bool MIDIplay::doRolandSysEx(unsigned dev, const uint8_t *data, size_t size) ADL_UNUSED(value); if(hooks.onDebugMessage) hooks.onDebugMessage(hooks.onDebugMessage_userData, "SysEx: Caught Roland Mode Set: %02X", value); + m_synthMode = Mode_GS; realTime_ResetState(); return true; } @@ -878,6 +886,7 @@ bool MIDIplay::doYamahaSysEx(unsigned dev, const uint8_t *data, size_t size) ADL_UNUSED(value); if(hooks.onDebugMessage) hooks.onDebugMessage(hooks.onDebugMessage_userData, "SysEx: Caught Yamaha XG System On: %02X", value); + m_synthMode = Mode_XG; realTime_ResetState(); return true; } @@ -1396,17 +1405,26 @@ void MIDIplay::SetRPN(unsigned MidCh, unsigned value, bool MSB) Ch[MidCh].bendsense_lsb = value; Ch[MidCh].updateBendSensitivity(); break; - case 0x0108 + 1*0x10000 + 1*0x20000: // Vibrato speed - if(value == 64) Ch[MidCh].vibspeed = 1.0; - else if(value < 100) Ch[MidCh].vibspeed = 1.0 / (1.6e-2 * (value ? value : 1)); - else Ch[MidCh].vibspeed = 1.0 / (0.051153846 * value - 3.4965385); - Ch[MidCh].vibspeed *= 2 * 3.141592653 * 5.0; + case 0x0108 + 1*0x10000 + 1*0x20000: + if((m_synthMode & Mode_XG) != 0) // Vibrato speed + { + if(value == 64) Ch[MidCh].vibspeed = 1.0; + else if(value < 100) Ch[MidCh].vibspeed = 1.0 / (1.6e-2 * (value ? value : 1)); + else Ch[MidCh].vibspeed = 1.0 / (0.051153846 * value - 3.4965385); + Ch[MidCh].vibspeed *= 2 * 3.141592653 * 5.0; + } break; - case 0x0109 + 1*0x10000 + 1*0x20000: // Vibrato depth - Ch[MidCh].vibdepth = ((value - 64) * 0.15) * 0.01; + case 0x0109 + 1*0x10000 + 1*0x20000: + if((m_synthMode & Mode_XG) != 0) // Vibrato depth + { + Ch[MidCh].vibdepth = ((value - 64) * 0.15) * 0.01; + } break; - case 0x010A + 1*0x10000 + 1*0x20000: // Vibrato delay in millisecons - Ch[MidCh].vibdelay = value ? int64_t(0.2092 * std::exp(0.0795 * (double)value)) : 0; + case 0x010A + 1*0x10000 + 1*0x20000: + if((m_synthMode & Mode_XG) != 0) // Vibrato delay in millisecons + { + Ch[MidCh].vibdelay = value ? int64_t(0.2092 * std::exp(0.0795 * (double)value)) : 0; + } break; default:/* UI.PrintLn("%s %04X <- %d (%cSB) (ch %u)", "NRPN"+!nrpn, addr, value, "LM"[MSB], MidCh);*/ -- cgit v1.2.3 From de7550a4cc643b37449eb791f09b625bf1af17fb Mon Sep 17 00:00:00 2001 From: Vitaly Novichkov Date: Fri, 22 Jun 2018 23:27:07 +0300 Subject: Added some TODOs [ci skip] --- src/adlmidi_midiplay.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/adlmidi_midiplay.cpp') diff --git a/src/adlmidi_midiplay.cpp b/src/adlmidi_midiplay.cpp index dd5c9bf..3faa299 100644 --- a/src/adlmidi_midiplay.cpp +++ b/src/adlmidi_midiplay.cpp @@ -829,7 +829,7 @@ bool MIDIplay::doRolandSysEx(unsigned dev, const uint8_t *data, size_t size) if(size != 1 || (dev & 0xF0) != 0x10) break; unsigned mode = data[0] & 0x7F; - ADL_UNUSED(mode); + ADL_UNUSED(mode);//TODO: Hook this correctly! if(hooks.onDebugMessage) hooks.onDebugMessage(hooks.onDebugMessage_userData, "SysEx: Caught Roland System Mode Set: %02X", mode); m_synthMode = Mode_GS; @@ -841,7 +841,7 @@ bool MIDIplay::doRolandSysEx(unsigned dev, const uint8_t *data, size_t size) if(size != 1 || (dev & 0xF0) != 0x10) break; unsigned value = data[0] & 0x7F; - ADL_UNUSED(value); + ADL_UNUSED(value);//TODO: Hook this correctly! if(hooks.onDebugMessage) hooks.onDebugMessage(hooks.onDebugMessage_userData, "SysEx: Caught Roland Mode Set: %02X", value); m_synthMode = Mode_GS; @@ -883,7 +883,7 @@ bool MIDIplay::doYamahaSysEx(unsigned dev, const uint8_t *data, size_t size) if(size != 1) break; unsigned value = data[0] & 0x7F; - ADL_UNUSED(value); + ADL_UNUSED(value);//TODO: Hook this correctly! if(hooks.onDebugMessage) hooks.onDebugMessage(hooks.onDebugMessage_userData, "SysEx: Caught Yamaha XG System On: %02X", value); m_synthMode = Mode_XG; -- cgit v1.2.3