diff options
-rw-r--r-- | README.md | 1 | ||||
-rw-r--r-- | src/adlmidi_midiplay.cpp | 40 | ||||
-rw-r--r-- | src/adlmidi_private.hpp | 21 |
3 files changed, 41 insertions, 21 deletions
@@ -142,6 +142,7 @@ To build that example you will need to have installed SDL2 library. * Fixed incorrect 4-op counter which is still catch 4-op instruments on 2-op banks * Fixed an incorrect processing of auto-flags * Fixed incorrect initial MIDI tempo when MIDI file doesn't includes the tempo event + * Channel and Note Aftertouch features are now supported correctly! Aftertouch is the tremolo / vibrato, NOT A VOLUME! ## 1.3.2 2018-04-24 * Added ability to disable MUS and XMI converters diff --git a/src/adlmidi_midiplay.cpp b/src/adlmidi_midiplay.cpp index 0ecb023..c6bc198 100644 --- a/src/adlmidi_midiplay.cpp +++ b/src/adlmidi_midiplay.cpp @@ -976,6 +976,9 @@ void MIDIplay::realTime_ResetState() bool MIDIplay::realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocity) { + if(note >= 128) + note = 128; + if((opl.m_musicMode == OPL3::MODE_RSXX) && (velocity != 0)) { // Check if this is just a note after-touch @@ -998,14 +1001,16 @@ bool MIDIplay::realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocity) if(velocity == 0) return false; - size_t midiins = Ch[channel].patch; + MIDIchannel &midiChan = Ch[channel]; + + size_t midiins = midiChan.patch; bool isPercussion = (channel % 16 == 9); bool isXgPercussion = false; uint16_t bank = 0; - if(Ch[channel].bank_msb || Ch[channel].bank_lsb) + if(midiChan.bank_msb || midiChan.bank_lsb) { - bank = (uint16_t(Ch[channel].bank_msb) * 256) + uint16_t(Ch[channel].bank_lsb); + 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) @@ -1086,7 +1091,7 @@ bool MIDIplay::realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocity) } } bank = 0; - midiins = Ch[channel].patch; + midiins = midiChan.patch; meta = opl.GetAdlMetaNumber(midiins); ains = opl.GetAdlMetaIns(meta); } @@ -1199,7 +1204,7 @@ bool MIDIplay::realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocity) if(hooks.onDebugMessage) hooks.onDebugMessage(hooks.onDebugMessage_userData, "ignored unplaceable note [bank %i, inst %i, note %i, MIDI channel %i]", - bank, Ch[channel].patch, note, channel); + bank, midiChan.patch, note, channel); continue; // Could not play this note. Ignore it. } @@ -1218,8 +1223,9 @@ bool MIDIplay::realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocity) // Allocate active note for MIDI channel std::pair<MIDIchannel::activenoteiterator, bool> - ir = Ch[channel].activenotes_insert(note); + ir = midiChan.activenotes_insert(note); ir.first->vol = velocity; + ir.first->vibrato = midiChan.noteAftertouch[note]; ir.first->tone = tone; ir.first->midiins = midiins; ir.first->insmeta = meta; @@ -1246,24 +1252,20 @@ void MIDIplay::realTime_NoteOff(uint8_t channel, uint8_t note) void MIDIplay::realTime_NoteAfterTouch(uint8_t channel, uint8_t note, uint8_t atVal) { channel = channel % 16; + MIDIchannel &chan = Ch[channel]; MIDIchannel::activenoteiterator i = Ch[channel].activenotes_find(note); if(i) { - i->vol = 127 - atVal; - NoteUpdate(channel, i, Upd_Volume); + i->vibrato = atVal; } + chan.noteAftertouch[note % 128] = atVal; + chan.noteAfterTouchInUse = (std::memcmp(chan.noteAftertouch, chan.noteAftertouch_Zero, 128) != 0); } void MIDIplay::realTime_ChannelAfterTouch(uint8_t channel, uint8_t atVal) { - // TODO: Verify, is this correct action? channel = channel % 16; - for(MIDIchannel::activenoteiterator i = Ch[channel].activenotes_begin(); i; ++i) - { - // Set this pressure to all active notes on the channel - i->vol = 127 - atVal; - } - NoteUpdate_All(channel, Upd_Volume); + Ch[channel].aftertouch = atVal; } void MIDIplay::realTime_Controller(uint8_t channel, uint8_t type, uint8_t value) @@ -1633,14 +1635,16 @@ void MIDIplay::NoteUpdate(uint16_t MidCh, { double bend = Ch[MidCh].bend + ins.ains.finetune; double phase = 0.0; + uint8_t vibrato = std::max(Ch[MidCh].vibrato, Ch[MidCh].aftertouch); + vibrato = std::max(vibrato, i->vibrato); if((ains.flags & adlinsdata::Flag_Pseudo4op) && ins.pseudo4op) { phase = ains.voice2_fine_tune;//0.125; // Detune the note slightly (this is what Doom does) } - if(Ch[MidCh].vibrato && (!d || d->vibdelay >= Ch[MidCh].vibdelay)) - bend += Ch[MidCh].vibrato * Ch[MidCh].vibdepth * std::sin(Ch[MidCh].vibpos); + if(vibrato && (!d || d->vibdelay >= Ch[MidCh].vibdelay)) + bend += static_cast<double>(vibrato) * Ch[MidCh].vibdepth * std::sin(Ch[MidCh].vibpos); #ifdef ADLMIDI_USE_DOSBOX_OPL #define BEND_COEFFICIENT 172.00093 @@ -2453,7 +2457,7 @@ void MIDIplay::UpdateVibrato(double amount) { for(size_t a = 0, b = Ch.size(); a < b; ++a) { - if(Ch[a].vibrato && !Ch[a].activenotes_empty()) + if(Ch[a].hasVibrato() && !Ch[a].activenotes_empty()) { NoteUpdate_All(static_cast<uint16_t>(a), Upd_Pitch); Ch[a].vibpos += amount * Ch[a].vibspeed; diff --git a/src/adlmidi_private.hpp b/src/adlmidi_private.hpp index b20a2b4..0e3affe 100644 --- a/src/adlmidi_private.hpp +++ b/src/adlmidi_private.hpp @@ -505,7 +505,13 @@ public: uint8_t bank_lsb, bank_msb; uint8_t patch; uint8_t volume, expression; - uint8_t panning, vibrato, sustain; + uint8_t panning, vibrato, aftertouch, sustain; + //! Per note Aftertouch values + uint8_t noteAftertouch[128]; + //! Zero-filled array. Is used to compare with note aftertouch range + uint8_t noteAftertouch_Zero[128]; + //! Is note aftertouch has any non-zero value + bool noteAfterTouchInUse; char ____padding[6]; double bend, bendsense; int bendsense_lsb, bendsense_msb; @@ -521,7 +527,8 @@ public: bool active; // Current pressure uint8_t vol; - char ____padding[1]; + // Note vibrato (a part of Note Aftertouch feature) + uint8_t vibrato; // Tone selected on noteon: int16_t tone; char ____padding2[4]; @@ -617,7 +624,7 @@ public: for(++ptr; ptr && !ptr->active;) ptr = (ptr->note == 127) ? 0 : (ptr + 1); return *this; - }; + } activenoteiterator operator++(int) { activenoteiterator pos = *this; @@ -708,6 +715,10 @@ public: expression = 127; sustain = 0; vibrato = 0; + aftertouch = 0; + std::memset(noteAftertouch, 0, 128); + std::memset(noteAftertouch_Zero, 0, 128); + noteAfterTouchInUse = false; vibspeed = 2 * 3.141592653 * 5.0; vibdepth = 0.5 / 127; vibdelay = 0; @@ -715,6 +726,10 @@ public: portamento = 0; brightness = 127; } + bool hasVibrato() + { + return (vibrato > 0) || (aftertouch > 0) || noteAfterTouchInUse; + } void updateBendSensitivity() { int cent = bendsense_msb * 100 + bendsense_lsb; |