aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/adlmidi.h6
-rw-r--r--src/adlmidi.cpp21
-rw-r--r--src/adlmidi_midiplay.cpp257
-rw-r--r--src/adlmidi_private.hpp51
-rw-r--r--src/adlmidi_sequencer.cpp5
-rw-r--r--src/midi_sequencer_impl.hpp53
-rw-r--r--utils/vlc_codec/libadlmidi.c5
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);