diff options
-rw-r--r-- | include/adlmidi.h | 6 | ||||
-rw-r--r-- | src/adlmidi.cpp | 21 | ||||
-rw-r--r-- | src/adlmidi_midiplay.cpp | 257 | ||||
-rw-r--r-- | src/adlmidi_private.hpp | 51 | ||||
-rw-r--r-- | src/adlmidi_sequencer.cpp | 5 | ||||
-rw-r--r-- | src/midi_sequencer_impl.hpp | 53 | ||||
-rw-r--r-- | utils/vlc_codec/libadlmidi.c | 5 |
7 files changed, 351 insertions, 47 deletions
diff --git a/include/adlmidi.h b/include/adlmidi.h index fe1f590..8bb0bf1 100644 --- a/include/adlmidi.h +++ b/include/adlmidi.h @@ -237,6 +237,9 @@ extern const char *adl_errorInfo(struct ADL_MIDIPlayer *device); /*Initialize ADLMIDI Player device*/ extern struct ADL_MIDIPlayer *adl_init(long sample_rate); +/*Set 4-bit device identifier*/ +extern int adl_setDeviceIdentifier(struct ADL_MIDIPlayer *device, unsigned id); + /*Load MIDI file from File System*/ extern int adl_openFile(struct ADL_MIDIPlayer *device, const char *filePath); @@ -364,6 +367,9 @@ extern void adl_rt_bankChangeMSB(struct ADL_MIDIPlayer *device, ADL_UInt8 channe /*Change bank by absolute signed value*/ extern void adl_rt_bankChange(struct ADL_MIDIPlayer *device, ADL_UInt8 channel, ADL_SInt16 bank); +/*Perform a system exclusive message*/ +extern int adl_rt_systemExclusive(struct ADL_MIDIPlayer *device, const ADL_UInt8 *msg, size_t size); + /**Hooks**/ diff --git a/src/adlmidi.cpp b/src/adlmidi.cpp index efd716c..c3c07a7 100644 --- a/src/adlmidi.cpp +++ b/src/adlmidi.cpp @@ -68,6 +68,17 @@ ADLMIDI_EXPORT struct ADL_MIDIPlayer *adl_init(long sample_rate) return midi_device; } +ADLMIDI_EXPORT int adl_setDeviceIdentifier(ADL_MIDIPlayer *device, unsigned id) +{ + if(!device || id > 0x0f) + return -1; + MIDIplay *play = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer); + if(!play) + return -1; + play->setDeviceId(id); + return 0; +} + ADLMIDI_EXPORT int adl_setNumChips(ADL_MIDIPlayer *device, int numCards) { if(device == NULL) @@ -1330,3 +1341,13 @@ ADLMIDI_EXPORT void adl_rt_bankChange(struct ADL_MIDIPlayer *device, ADL_UInt8 c return; player->realTime_BankChange(channel, (uint16_t)bank); } + +ADLMIDI_EXPORT int adl_rt_systemExclusive(struct ADL_MIDIPlayer *device, const ADL_UInt8 *msg, size_t size) +{ + if(!device) + return -1; + MIDIplay *player = reinterpret_cast<MIDIplay *>(device->adl_midiPlayer); + if(!player) + return -1; + return player->realTime_SysEx(msg, size); +} diff --git a/src/adlmidi_midiplay.cpp b/src/adlmidi_midiplay.cpp index 56078fb..3faa299 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,9 @@ void MIDIplay::AdlChannel::AddAge(int64_t ms) 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) @@ -219,6 +224,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) @@ -257,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) @@ -330,7 +339,7 @@ bool MIDIplay::realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocity) if(hooks.onDebugMessage) { if(caugh_missing_instruments.insert(static_cast<uint8_t>(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; @@ -605,7 +614,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 @@ -707,6 +716,188 @@ 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, size_t 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, size_t 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 + 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 + if(size != 2) + break; + unsigned volume = + (((unsigned)data[0] & 0x7F)) | + (((unsigned)data[1] & 0x7F) << 7); + m_masterVolume = volume >> 7; + for(size_t ch = 0; ch < Ch.size(); ch++) + NoteUpdate_All(uint16_t(ch), Upd_Volume); + return true; + } + + return false; +} + +bool MIDIplay::doRolandSysEx(unsigned dev, const uint8_t *data, size_t 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(size_t 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; + 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; + realTime_ResetState(); + return true; + } + case (RolandModel_GS << 24) | 0x40007F: // Mode Set + { + if(size != 1 || (dev & 0xF0) != 0x10) + break; + unsigned value = data[0] & 0x7F; + 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; + realTime_ResetState(); + return true; + } + } + + return false; +} + +bool MIDIplay::doYamahaSysEx(unsigned dev, const uint8_t *data, size_t 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; + 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; + realTime_ResetState(); + return true; + } + + break; + } + } + + return false; +} + void MIDIplay::realTime_panic() { Panic(); @@ -859,10 +1050,10 @@ void MIDIplay::NoteUpdate(uint16_t MidCh, switch(opl.m_volumeScale) { - + default: 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. @@ -873,52 +1064,47 @@ 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<uint32_t>(std::log(static_cast<double>(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); - - opl.Touch_Real(c, volume, brightness); - //opl.Touch(c, volume); + // The formula below: SOLVE(V=127^4 * 2^( (A-63.49999) / 8), A) + volume = volume > (8725 * 127) ? static_cast<uint32_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 OPL3::VOLUME_NATIVE: { volume = vol * Ch[MidCh].volume * Ch[MidCh].expression; - volume = volume * 127 / (127 * 127 * 127) / 2; - opl.Touch_Real(c, volume, brightness); + volume = volume * m_masterVolume / (127 * 127 * 127) / 2; } 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); } break; 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); } break; 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); } break; } + opl.Touch_Real(c, volume, brightness); + /* DEBUG ONLY!!! static uint32_t max = 0; @@ -1219,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);*/ diff --git a/src/adlmidi_private.hpp b/src/adlmidi_private.hpp index 058a431..ec194c6 100644 --- a/src/adlmidi_private.hpp +++ b/src/adlmidi_private.hpp @@ -723,6 +723,17 @@ public: std::vector<MIDIchannel> Ch; bool cmf_percussion_mode; + uint8_t m_masterVolume; + uint8_t m_sysExDeviceId; + + enum SynthMode + { + Mode_GM = 0x00, + Mode_GS = 0x01, + Mode_XG = 0x02, + Mode_GM2 = 0x04, + }; + uint32_t m_synthMode; MIDIEventHooks hooks; @@ -901,6 +912,20 @@ public: void realTime_BankChange(uint8_t channel, uint16_t bank); /** + * @brief Sets the Device identifier + * @param id 7-bit Device identifier + */ + void setDeviceId(uint8_t id); + + /** + * @brief System Exclusive message + * @param msg Raw SysEx Message + * @param size Length of SysEx message + * @return true if message was passed successfully. False on any errors + */ + bool realTime_SysEx(const uint8_t *msg, size_t size); + + /** * @brief Turn off all notes and mute the sound of releasing notes */ void realTime_panic(); @@ -934,6 +959,30 @@ public: private: enum { + Manufacturer_Roland = 0x41, + Manufacturer_Yamaha = 0x43, + Manufacturer_UniversalNonRealtime = 0x7E, + Manufacturer_UniversalRealtime = 0x7F + }; + enum + { + RolandMode_Request = 0x11, + RolandMode_Send = 0x12 + }; + enum + { + RolandModel_GS = 0x42, + RolandModel_SC55 = 0x45, + YamahaModel_XG = 0x4C + }; + + bool doUniversalSysEx(unsigned dev, bool realtime, const uint8_t *data, size_t size); + bool doRolandSysEx(unsigned dev, const uint8_t *data, size_t size); + bool doYamahaSysEx(unsigned dev, const uint8_t *data, size_t size); + +private: + enum + { Upd_Patch = 0x1, Upd_Pan = 0x2, Upd_Volume = 0x4, @@ -941,7 +990,7 @@ private: Upd_All = Upd_Pan + Upd_Volume + Upd_Pitch, Upd_Off = 0x20, Upd_Mute = 0x40, - Upt_OffMute = Upd_Off + Upd_Mute + Upd_OffMute = Upd_Off + Upd_Mute }; void NoteUpdate(uint16_t MidCh, diff --git a/src/adlmidi_sequencer.cpp b/src/adlmidi_sequencer.cpp index fcc1380..b8bf3dd 100644 --- a/src/adlmidi_sequencer.cpp +++ b/src/adlmidi_sequencer.cpp @@ -79,10 +79,7 @@ static void rtPitchBend(void *userdata, uint8_t channel, uint8_t msb, uint8_t ls static void rtSysEx(void *userdata, const uint8_t *msg, size_t size) { MIDIplay *context = reinterpret_cast<MIDIplay *>(userdata); - ADL_UNUSED(context); - ADL_UNUSED(msg); - ADL_UNUSED(size); - /* TODO: pass SysEx HERE! */ + context->realTime_SysEx(msg, size); } diff --git a/src/midi_sequencer_impl.hpp b/src/midi_sequencer_impl.hpp index b3bfefa..0e71c2a 100644 --- a/src/midi_sequencer_impl.hpp +++ b/src/midi_sequencer_impl.hpp @@ -26,6 +26,8 @@ #include <stdio.h> #include <memory> #include <cstring> +#include <iterator> // std::back_inserter +#include <algorithm> // std::copy #include <set> #include <assert.h> @@ -158,31 +160,48 @@ void BW_MidiSequencer::MidiTrackRow::clear() void BW_MidiSequencer::MidiTrackRow::sortEvents(bool *noteStates) { typedef std::vector<MidiEvent> EvtArr; + EvtArr sysEx; EvtArr metas; EvtArr noteOffs; EvtArr controllers; EvtArr anyOther; - metas.reserve(events.size()); - noteOffs.reserve(events.size()); - controllers.reserve(events.size()); - anyOther.reserve(events.size()); - for(size_t i = 0; i < events.size(); i++) { if(events[i].type == MidiEvent::T_NOTEOFF) + { + if(noteOffs.capacity() == 0) + noteOffs.reserve(events.size()); noteOffs.push_back(events[i]); + } + else if(events[i].type == MidiEvent::T_SYSEX || + events[i].type == MidiEvent::T_SYSEX2) + { + if(sysEx.capacity() == 0) + sysEx.reserve(events.size()); + sysEx.push_back(events[i]); + } else if((events[i].type == MidiEvent::T_CTRLCHANGE) || (events[i].type == MidiEvent::T_PATCHCHANGE) || (events[i].type == MidiEvent::T_WHEEL) || (events[i].type == MidiEvent::T_CHANAFTTOUCH)) { + if(controllers.capacity() == 0) + controllers.reserve(events.size()); controllers.push_back(events[i]); } else if((events[i].type == MidiEvent::T_SPECIAL) && (events[i].subtype == MidiEvent::ST_MARKER)) + { + if(metas.capacity() == 0) + metas.reserve(events.size()); metas.push_back(events[i]); + } else + { + if(anyOther.capacity() == 0) + anyOther.reserve(events.size()); anyOther.push_back(events[i]); + } } /* @@ -244,10 +263,16 @@ void BW_MidiSequencer::MidiTrackRow::sortEvents(bool *noteStates) /***********************************************************************************/ events.clear(); - events.insert(events.end(), noteOffs.begin(), noteOffs.end()); - events.insert(events.end(), metas.begin(), metas.end()); - events.insert(events.end(), controllers.begin(), controllers.end()); - events.insert(events.end(), anyOther.begin(), anyOther.end()); + if(!sysEx.empty()) + events.insert(events.end(), sysEx.begin(), sysEx.end()); + if(!noteOffs.empty()) + events.insert(events.end(), noteOffs.begin(), noteOffs.end()); + if(!metas.empty()) + events.insert(events.end(), metas.begin(), metas.end()); + if(!controllers.empty()) + events.insert(events.end(), controllers.begin(), controllers.end()); + if(!anyOther.empty()) + events.insert(events.end(), anyOther.begin(), anyOther.end()); } BW_MidiSequencer::BW_MidiSequencer() : @@ -919,6 +944,10 @@ BW_MidiSequencer::MidiEvent BW_MidiSequencer::parseEvent(const uint8_t **pptr, c 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; } @@ -1120,6 +1149,12 @@ void BW_MidiSequencer::handleEvent(size_t tk, const BW_MidiSequencer::MidiEvent { //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 + std::fputs("SysEx:", stderr); + for(size_t i = 0; i < evt.data.size(); ++i) + std::fprintf(stderr, " %02X", evt.data[i]); + std::fputc('\n', stderr); +#endif m_interface->rt_systemExclusive(m_interface->rtUserData, evt.data.data(), evt.data.size()); return; } diff --git a/utils/vlc_codec/libadlmidi.c b/utils/vlc_codec/libadlmidi.c index efc2bb8..24a519e 100644 --- a/utils/vlc_codec/libadlmidi.c +++ b/utils/vlc_codec/libadlmidi.c @@ -257,8 +257,9 @@ static block_t *DecodeBlock (decoder_t *p_dec, block_t **pp_block) msg_Warn (p_dec, "fragmented SysEx not implemented"); goto drop; } - //fluid_synth_sysex (p_sys->synth, (char *)p_block->p_buffer + 1, - // p_block->i_buffer - 2, NULL, NULL, NULL, 0); + adl_rt_systemExclusive(p_sys->synth, + (const ADL_UInt8 *)p_block->p_buffer + 1, + p_block->i_buffer - 2); break; case 0xF: adl_rt_resetState(p_sys->synth); |