mirror of
https://github.com/fabiangreffrath/woof.git
synced 2025-09-22 03:12:00 -04:00
winmidi: Enable SysEx messages from MIDI files (#822)
* winmidi: Enable SysEx messages from MIDI files * Remove unused variable * Discard incomplete SysEx messages when a song loops * Write all 0xF0 SysEx messages, ignore all 0xF7 SysEx messages * Remove extra delay after reset * Remove `winmm_allow_sysex` * Don't use compound literal
This commit is contained in:
parent
e4a18d4aeb
commit
e88086684c
384
src/i_winmusic.c
384
src/i_winmusic.c
@ -34,7 +34,6 @@ int winmm_reset_type = 2;
|
||||
int winmm_reset_delay = 100;
|
||||
int winmm_reverb_level = 40;
|
||||
int winmm_chorus_level = 0;
|
||||
int winmm_allow_sysex = 0;
|
||||
|
||||
static byte gs_reset[] = {
|
||||
0xF0, 0x41, 0x10, 0x42, 0x12, 0x40, 0x00, 0x7F, 0x00, 0x41, 0xF7
|
||||
@ -52,8 +51,18 @@ static byte xg_system_on[] = {
|
||||
0xF0, 0x43, 0x10, 0x4C, 0x00, 0x00, 0x7E, 0x00, 0xF7
|
||||
};
|
||||
|
||||
static int timediv;
|
||||
static int tempo;
|
||||
static byte master_volume_msg[] = {
|
||||
0xF0, 0x7F, 0x7F, 0x04, 0x01, 0x7F, 0x7F, 0xF7
|
||||
};
|
||||
|
||||
#define DEFAULT_MASTER_VOLUME 16383
|
||||
static unsigned int master_volume = DEFAULT_MASTER_VOLUME;
|
||||
static int last_volume = -1;
|
||||
static float volume_factor = 1.0f;
|
||||
static boolean update_volume = false;
|
||||
|
||||
static DWORD timediv;
|
||||
static DWORD tempo;
|
||||
|
||||
static HMIDISTRM hMidiStream;
|
||||
static MIDIHDR MidiStreamHdr;
|
||||
@ -88,14 +97,6 @@ typedef struct
|
||||
|
||||
static win_midi_song_t song;
|
||||
|
||||
static float volume_factor = 1.0f;
|
||||
|
||||
static boolean update_volume = false;
|
||||
|
||||
// Save the last volume for each MIDI channel.
|
||||
|
||||
static int channel_volume[MIDI_CHANNELS_PER_TRACK];
|
||||
|
||||
#define BUFFER_INITIAL_SIZE 1024
|
||||
|
||||
typedef struct
|
||||
@ -111,7 +112,7 @@ static buffer_t buffer;
|
||||
|
||||
#define STREAM_MAX_EVENTS 4
|
||||
|
||||
#define MAKE_EVT(a, b, c, d) ((uint32_t)((a) | ((b) << 8) | ((c) << 16) | ((d) << 24)))
|
||||
#define MAKE_EVT(a, b, c, d) ((DWORD)((a) | ((b) << 8) | ((c) << 16) | ((d) << 24)))
|
||||
|
||||
#define PADDED_SIZE(x) (((x) + sizeof(DWORD) - 1) & ~(sizeof(DWORD) - 1))
|
||||
|
||||
@ -209,19 +210,19 @@ static void StreamOut(void)
|
||||
}
|
||||
}
|
||||
|
||||
static void SendShortMsg(int type, int param1, int param2)
|
||||
static void SendShortMsg(int time, int status, int channel, int param1, int param2)
|
||||
{
|
||||
native_event_t native_event;
|
||||
native_event.dwDeltaTime = 0;
|
||||
native_event.dwDeltaTime = time;
|
||||
native_event.dwStreamID = 0;
|
||||
native_event.dwEvent = MAKE_EVT(type, param1, param2, MEVT_SHORTMSG);
|
||||
native_event.dwEvent = MAKE_EVT(status | channel, param1, param2, MEVT_SHORTMSG);
|
||||
WriteBuffer((byte *)&native_event, sizeof(native_event_t));
|
||||
}
|
||||
|
||||
static void SendLongMsg(const byte *ptr, int length)
|
||||
static void SendLongMsg(int time, const byte *ptr, int length)
|
||||
{
|
||||
native_event_t native_event;
|
||||
native_event.dwDeltaTime = 0;
|
||||
native_event.dwDeltaTime = time;
|
||||
native_event.dwStreamID = 0;
|
||||
native_event.dwEvent = MAKE_EVT(length, 0, 0, MEVT_LONGMSG);
|
||||
WriteBuffer((byte *)&native_event, sizeof(native_event_t));
|
||||
@ -229,8 +230,10 @@ static void SendLongMsg(const byte *ptr, int length)
|
||||
WriteBufferPad();
|
||||
}
|
||||
|
||||
static void SendDelayMsg(int ticks)
|
||||
static void SendDelayMsg(void)
|
||||
{
|
||||
// Convert ms to ticks (see "Standard MIDI Files 1.0" page 14).
|
||||
int ticks = (float)winmm_reset_delay * 1000 * timediv / tempo + 0.5f;
|
||||
native_event_t native_event;
|
||||
native_event.dwDeltaTime = ticks;
|
||||
native_event.dwStreamID = 0;
|
||||
@ -238,6 +241,23 @@ static void SendDelayMsg(int ticks)
|
||||
WriteBuffer((byte *)&native_event, sizeof(native_event_t));
|
||||
}
|
||||
|
||||
static void UpdateTempo(int time)
|
||||
{
|
||||
native_event_t native_event;
|
||||
native_event.dwDeltaTime = time;
|
||||
native_event.dwStreamID = 0;
|
||||
native_event.dwEvent = MAKE_EVT(tempo, 0, 0, MEVT_TEMPO);
|
||||
WriteBuffer((byte *)&native_event, sizeof(native_event_t));
|
||||
}
|
||||
|
||||
static void UpdateVolume(int time)
|
||||
{
|
||||
int volume = master_volume * volume_factor + 0.5f;
|
||||
master_volume_msg[5] = volume & 0x7F;
|
||||
master_volume_msg[6] = (volume >> 7) & 0x7F;
|
||||
SendLongMsg(time, master_volume_msg, sizeof(master_volume_msg));
|
||||
}
|
||||
|
||||
static void ResetDevice(void)
|
||||
{
|
||||
int i;
|
||||
@ -245,43 +265,43 @@ static void ResetDevice(void)
|
||||
for (i = 0; i < MIDI_CHANNELS_PER_TRACK; ++i)
|
||||
{
|
||||
// midiOutReset() sends "all notes off" and "reset all controllers."
|
||||
SendShortMsg(MIDI_EVENT_CONTROLLER | i, MIDI_CONTROLLER_ALL_SOUND_OFF, 0);
|
||||
SendShortMsg(0, MIDI_EVENT_CONTROLLER, i, MIDI_CONTROLLER_ALL_SOUND_OFF, 0);
|
||||
|
||||
// Reset pitch bend sensitivity to +/- 2 semitones and 0 cents.
|
||||
SendShortMsg(MIDI_EVENT_CONTROLLER | i, MIDI_CONTROLLER_RPN_MSB, 0);
|
||||
SendShortMsg(MIDI_EVENT_CONTROLLER | i, MIDI_CONTROLLER_RPN_LSB, 0);
|
||||
SendShortMsg(MIDI_EVENT_CONTROLLER | i, MIDI_CONTROLLER_DATA_ENTRY_MSB, 2);
|
||||
SendShortMsg(MIDI_EVENT_CONTROLLER | i, MIDI_CONTROLLER_DATA_ENTRY_LSB, 0);
|
||||
SendShortMsg(MIDI_EVENT_CONTROLLER | i, MIDI_CONTROLLER_RPN_MSB, 127);
|
||||
SendShortMsg(MIDI_EVENT_CONTROLLER | i, MIDI_CONTROLLER_RPN_LSB, 127);
|
||||
SendShortMsg(0, MIDI_EVENT_CONTROLLER, i, MIDI_CONTROLLER_RPN_MSB, 0);
|
||||
SendShortMsg(0, MIDI_EVENT_CONTROLLER, i, MIDI_CONTROLLER_RPN_LSB, 0);
|
||||
SendShortMsg(0, MIDI_EVENT_CONTROLLER, i, MIDI_CONTROLLER_DATA_ENTRY_MSB, 2);
|
||||
SendShortMsg(0, MIDI_EVENT_CONTROLLER, i, MIDI_CONTROLLER_DATA_ENTRY_LSB, 0);
|
||||
SendShortMsg(0, MIDI_EVENT_CONTROLLER, i, MIDI_CONTROLLER_RPN_MSB, 127);
|
||||
SendShortMsg(0, MIDI_EVENT_CONTROLLER, i, MIDI_CONTROLLER_RPN_LSB, 127);
|
||||
|
||||
// Reset channel volume and pan.
|
||||
SendShortMsg(MIDI_EVENT_CONTROLLER | i, MIDI_CONTROLLER_MAIN_VOLUME, 100);
|
||||
SendShortMsg(MIDI_EVENT_CONTROLLER | i, MIDI_CONTROLLER_PAN, 64);
|
||||
SendShortMsg(0, MIDI_EVENT_CONTROLLER, i, MIDI_CONTROLLER_MAIN_VOLUME, 100);
|
||||
SendShortMsg(0, MIDI_EVENT_CONTROLLER, i, MIDI_CONTROLLER_PAN, 64);
|
||||
|
||||
// Reset instrument.
|
||||
SendShortMsg(MIDI_EVENT_CONTROLLER | i, MIDI_CONTROLLER_BANK_SELECT_MSB, 0);
|
||||
SendShortMsg(MIDI_EVENT_CONTROLLER | i, MIDI_CONTROLLER_BANK_SELECT_LSB, 0);
|
||||
SendShortMsg(MIDI_EVENT_PROGRAM_CHANGE | i, 0, 0);
|
||||
SendShortMsg(0, MIDI_EVENT_CONTROLLER, i, MIDI_CONTROLLER_BANK_SELECT_MSB, 0);
|
||||
SendShortMsg(0, MIDI_EVENT_CONTROLLER, i, MIDI_CONTROLLER_BANK_SELECT_LSB, 0);
|
||||
SendShortMsg(0, MIDI_EVENT_PROGRAM_CHANGE, i, 0, 0);
|
||||
}
|
||||
|
||||
// Send SysEx reset message.
|
||||
switch (winmm_reset_type)
|
||||
{
|
||||
case 1: // GS Reset
|
||||
SendLongMsg(gs_reset, sizeof(gs_reset));
|
||||
SendLongMsg(0, gs_reset, sizeof(gs_reset));
|
||||
break;
|
||||
|
||||
case 2: // GM System On
|
||||
SendLongMsg(gm_system_on, sizeof(gm_system_on));
|
||||
SendLongMsg(0, gm_system_on, sizeof(gm_system_on));
|
||||
break;
|
||||
|
||||
case 3: // GM2 System On
|
||||
SendLongMsg(gm2_system_on, sizeof(gm2_system_on));
|
||||
SendLongMsg(0, gm2_system_on, sizeof(gm2_system_on));
|
||||
break;
|
||||
|
||||
case 4: // XG System On
|
||||
SendLongMsg(xg_system_on, sizeof(xg_system_on));
|
||||
SendLongMsg(0, xg_system_on, sizeof(xg_system_on));
|
||||
break;
|
||||
|
||||
default: // None
|
||||
@ -291,17 +311,196 @@ static void ResetDevice(void)
|
||||
// Send delay after reset.
|
||||
if (winmm_reset_delay > 0)
|
||||
{
|
||||
// Convert ms to ticks (see "Standard MIDI Files 1.0" page 14).
|
||||
int ticks = (float)winmm_reset_delay * 1000 * timediv / tempo + 0.5f;
|
||||
|
||||
SendDelayMsg(ticks);
|
||||
SendDelayMsg();
|
||||
}
|
||||
|
||||
for (i = 0; i < MIDI_CHANNELS_PER_TRACK; ++i)
|
||||
{
|
||||
// Reset reverb and chorus.
|
||||
SendShortMsg(MIDI_EVENT_CONTROLLER | i, MIDI_CONTROLLER_REVERB, winmm_reverb_level);
|
||||
SendShortMsg(MIDI_EVENT_CONTROLLER | i, MIDI_CONTROLLER_CHORUS, winmm_chorus_level);
|
||||
SendShortMsg(0, MIDI_EVENT_CONTROLLER, i, MIDI_CONTROLLER_REVERB, winmm_reverb_level);
|
||||
SendShortMsg(0, MIDI_EVENT_CONTROLLER, i, MIDI_CONTROLLER_CHORUS, winmm_chorus_level);
|
||||
}
|
||||
}
|
||||
|
||||
static boolean IsSysExReset(const byte *msg, int length)
|
||||
{
|
||||
if (length < 5)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (msg[0])
|
||||
{
|
||||
case 0x41: // Roland
|
||||
switch (msg[2])
|
||||
{
|
||||
case 0x42: // GS
|
||||
switch (msg[3])
|
||||
{
|
||||
case 0x12: // DT1
|
||||
if (length == 10 &&
|
||||
msg[4] == 0x00 && // Address MSB
|
||||
msg[5] == 0x00 && // Address
|
||||
msg[6] == 0x7F && // Address LSB
|
||||
((msg[7] == 0x00 && // Data (MODE-1)
|
||||
msg[8] == 0x01) || // Checksum (MODE-1)
|
||||
(msg[7] == 0x01 && // Data (MODE-2)
|
||||
msg[8] == 0x00))) // Checksum (MODE-2)
|
||||
{
|
||||
// SC-88 System Mode Set
|
||||
// 41 <dev> 42 12 00 00 7F 00 01 F7 (MODE-1)
|
||||
// 41 <dev> 42 12 00 00 7F 01 00 F7 (MODE-2)
|
||||
return true;
|
||||
}
|
||||
else if (length == 10 &&
|
||||
msg[4] == 0x40 && // Address MSB
|
||||
msg[5] == 0x00 && // Address
|
||||
msg[6] == 0x7F && // Address LSB
|
||||
msg[7] == 0x00 && // Data (GS Reset)
|
||||
msg[8] == 0x41) // Checksum
|
||||
{
|
||||
// GS Reset
|
||||
// 41 <dev> 42 12 40 00 7F 00 41 F7
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x43: // Yamaha
|
||||
switch (msg[2])
|
||||
{
|
||||
case 0x2B: // TG300
|
||||
if (length == 9 &&
|
||||
msg[3] == 0x00 && // Start Address b20 - b14
|
||||
msg[4] == 0x00 && // Start Address b13 - b7
|
||||
msg[5] == 0x7F && // Start Address b6 - b0
|
||||
msg[6] == 0x00 && // Data
|
||||
msg[7] == 0x01) // Checksum
|
||||
{
|
||||
// TG300 All Parameter Reset
|
||||
// 43 <dev> 2B 00 00 7F 00 01 F7
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x4C: // XG
|
||||
if (length == 8 &&
|
||||
msg[3] == 0x00 && // Address High
|
||||
msg[4] == 0x00 && // Address Mid
|
||||
msg[5] == 0x7E && // Address Low
|
||||
msg[6] == 0x00) // Data
|
||||
{
|
||||
// XG System On
|
||||
// 43 <dev> 4C 00 00 7E 00 F7
|
||||
return true;
|
||||
}
|
||||
else if (length == 8 &&
|
||||
msg[3] == 0x00 && // Address High
|
||||
msg[4] == 0x00 && // Address Mid
|
||||
msg[5] == 0x7F && // Address Low
|
||||
msg[6] == 0x00) // Data
|
||||
{
|
||||
// XG All Parameter Reset
|
||||
// 43 <dev> 4C 00 00 7F 00 F7
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x7E: // Universal Non-Real Time
|
||||
switch (msg[2])
|
||||
{
|
||||
case 0x09: // General Midi
|
||||
if (length == 5 &&
|
||||
(msg[3] == 0x01 || // GM System On
|
||||
msg[3] == 0x02 || // GM System Off
|
||||
msg[3] == 0x03)) // GM2 System On
|
||||
{
|
||||
// GM System On/Off, GM2 System On
|
||||
// 7E <dev> 09 01 F7
|
||||
// 7E <dev> 09 02 F7
|
||||
// 7E <dev> 09 03 F7
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static boolean IsMasterVolume(const byte *msg, int length, unsigned int *volume)
|
||||
{
|
||||
// General Midi (7F <dev> 04 01 <lsb> <msb> F7)
|
||||
if (length == 7 &&
|
||||
msg[0] == 0x7F && // Universal Real Time
|
||||
msg[2] == 0x04 && // Device Control
|
||||
msg[3] == 0x01) // Master Volume
|
||||
{
|
||||
*volume = (msg[4] & 0x7F) | ((msg[5] & 0x7F) << 7);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Roland (41 <dev> 42 12 40 00 04 <vol> <sum> F7)
|
||||
if (length == 10 &&
|
||||
msg[0] == 0x41 && // Roland
|
||||
msg[2] == 0x42 && // GS
|
||||
msg[3] == 0x12 && // DT1
|
||||
msg[4] == 0x40 && // Address MSB
|
||||
msg[5] == 0x00 && // Address
|
||||
msg[6] == 0x04) // Address LSB
|
||||
{
|
||||
*volume = DEFAULT_MASTER_VOLUME * (msg[7] & 0x7F) / 127;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Yamaha (43 <dev> 4C 00 00 04 <vol> F7)
|
||||
if (length == 8 &&
|
||||
msg[0] == 0x43 && // Yamaha
|
||||
msg[2] == 0x4C && // XG
|
||||
msg[3] == 0x00 && // Address High
|
||||
msg[4] == 0x00 && // Address Mid
|
||||
msg[5] == 0x04) // Address Low
|
||||
{
|
||||
*volume = DEFAULT_MASTER_VOLUME * (msg[6] & 0x7F) / 127;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void SendSysExMsg(int time, const byte *data, int length)
|
||||
{
|
||||
native_event_t native_event;
|
||||
const byte event_type = MIDI_EVENT_SYSEX;
|
||||
|
||||
if (IsMasterVolume(data, length, &master_volume))
|
||||
{
|
||||
// Found a master volume message in the MIDI file. Take this new
|
||||
// value and scale it by the user's volume slider.
|
||||
UpdateVolume(time);
|
||||
return;
|
||||
}
|
||||
|
||||
// Send the SysEx message.
|
||||
native_event.dwDeltaTime = time;
|
||||
native_event.dwStreamID = 0;
|
||||
native_event.dwEvent = MAKE_EVT(length + sizeof(byte), 0, 0, MEVT_LONGMSG);
|
||||
WriteBuffer((byte *)&native_event, sizeof(native_event_t));
|
||||
WriteBuffer(&event_type, sizeof(byte));
|
||||
WriteBuffer(data, length);
|
||||
WriteBufferPad();
|
||||
|
||||
if (IsSysExReset(data, length))
|
||||
{
|
||||
// SysEx reset also resets master volume. Take the default master
|
||||
// volume and scale it by the user's volume slider.
|
||||
master_volume = DEFAULT_MASTER_VOLUME;
|
||||
UpdateVolume(0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -316,29 +515,27 @@ static void FillBuffer(void)
|
||||
{
|
||||
initial_playback = false;
|
||||
|
||||
master_volume = DEFAULT_MASTER_VOLUME;
|
||||
ResetDevice();
|
||||
StreamOut();
|
||||
return;
|
||||
}
|
||||
|
||||
// If the volume has changed, stick those events at the start of this buffer.
|
||||
if (update_volume)
|
||||
{
|
||||
update_volume = false;
|
||||
|
||||
for (i = 0; i < MIDI_CHANNELS_PER_TRACK; ++i)
|
||||
{
|
||||
int volume = (int)((float)channel_volume[i] * volume_factor + 0.5f);
|
||||
|
||||
SendShortMsg(MIDI_EVENT_CONTROLLER | i, MIDI_CONTROLLER_MAIN_VOLUME,
|
||||
volume);
|
||||
}
|
||||
UpdateVolume(0);
|
||||
StreamOut();
|
||||
return;
|
||||
}
|
||||
|
||||
for (num_events = 0; num_events < STREAM_MAX_EVENTS; )
|
||||
{
|
||||
midi_event_t *event;
|
||||
DWORD data = 0;
|
||||
int min_time = INT_MAX;
|
||||
int idx = -1;
|
||||
int delta_time;
|
||||
|
||||
// Look for an event with a minimal delta time.
|
||||
for (i = 0; i < MIDI_NumTracks(song.file); ++i)
|
||||
@ -385,6 +582,8 @@ static void FillBuffer(void)
|
||||
continue;
|
||||
}
|
||||
|
||||
delta_time = min_time - song.current_time;
|
||||
|
||||
switch ((int)event->event_type)
|
||||
{
|
||||
case MIDI_EVENT_META:
|
||||
@ -392,77 +591,38 @@ static void FillBuffer(void)
|
||||
{
|
||||
tempo = MAKE_EVT(event->data.meta.data[2],
|
||||
event->data.meta.data[1], event->data.meta.data[0], 0);
|
||||
data = MAKE_EVT(tempo, 0, 0, MEVT_TEMPO);
|
||||
}
|
||||
break;
|
||||
|
||||
case MIDI_EVENT_CONTROLLER:
|
||||
// Adjust volume as needed.
|
||||
if (event->data.channel.param1 == MIDI_CONTROLLER_MAIN_VOLUME)
|
||||
{
|
||||
int volume = event->data.channel.param2;
|
||||
|
||||
channel_volume[event->data.channel.channel] = volume;
|
||||
|
||||
volume = (int)((float)volume * volume_factor + 0.5f);
|
||||
|
||||
data = MAKE_EVT(event->event_type | event->data.channel.channel,
|
||||
event->data.channel.param1, (volume & 0x7F),
|
||||
MEVT_SHORTMSG);
|
||||
|
||||
UpdateTempo(delta_time);
|
||||
break;
|
||||
}
|
||||
// Fall through.
|
||||
continue;
|
||||
|
||||
case MIDI_EVENT_CONTROLLER:
|
||||
case MIDI_EVENT_NOTE_OFF:
|
||||
case MIDI_EVENT_NOTE_ON:
|
||||
case MIDI_EVENT_AFTERTOUCH:
|
||||
case MIDI_EVENT_PITCH_BEND:
|
||||
data = MAKE_EVT(event->event_type | event->data.channel.channel,
|
||||
event->data.channel.param1, event->data.channel.param2,
|
||||
MEVT_SHORTMSG);
|
||||
SendShortMsg(delta_time, event->event_type, event->data.channel.channel,
|
||||
event->data.channel.param1, event->data.channel.param2);
|
||||
break;
|
||||
|
||||
case MIDI_EVENT_PROGRAM_CHANGE:
|
||||
case MIDI_EVENT_CHAN_AFTERTOUCH:
|
||||
data = MAKE_EVT(event->event_type | event->data.channel.channel,
|
||||
event->data.channel.param1, 0, MEVT_SHORTMSG);
|
||||
SendShortMsg(delta_time, event->event_type, event->data.channel.channel,
|
||||
event->data.channel.param1, 0);
|
||||
break;
|
||||
|
||||
case MIDI_EVENT_SYSEX:
|
||||
case MIDI_EVENT_SYSEX_SPLIT:
|
||||
if (winmm_allow_sysex)
|
||||
{
|
||||
uint32_t length = event->data.sysex.length + sizeof(byte);
|
||||
data = MAKE_EVT(length, 0, 0, MEVT_LONGMSG);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Preserve timing with a NOP.
|
||||
data = MAKE_EVT(0, 0, 0, MEVT_NOP);
|
||||
}
|
||||
break;
|
||||
SendSysExMsg(delta_time, event->data.sysex.data, event->data.sysex.length);
|
||||
song.current_time = min_time;
|
||||
StreamOut();
|
||||
return;
|
||||
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
if (data)
|
||||
{
|
||||
native_event_t native_event;
|
||||
|
||||
native_event.dwDeltaTime = min_time - song.current_time;
|
||||
native_event.dwStreamID = 0;
|
||||
native_event.dwEvent = data;
|
||||
WriteBuffer((byte *)&native_event, sizeof(native_event_t));
|
||||
|
||||
if (winmm_allow_sysex && (event->event_type == MIDI_EVENT_SYSEX ||
|
||||
event->event_type == MIDI_EVENT_SYSEX_SPLIT))
|
||||
{
|
||||
WriteBuffer((byte *)&event->event_type, sizeof(byte));
|
||||
WriteBuffer(event->data.sysex.data, event->data.sysex.length);
|
||||
WriteBufferPad();
|
||||
}
|
||||
|
||||
num_events++;
|
||||
song.current_time = min_time;
|
||||
}
|
||||
num_events++;
|
||||
song.current_time = min_time;
|
||||
}
|
||||
|
||||
if (num_events)
|
||||
@ -518,6 +678,14 @@ static boolean I_WIN_InitMusic(void)
|
||||
|
||||
static void I_WIN_SetMusicVolume(int volume)
|
||||
{
|
||||
if (last_volume == volume)
|
||||
{
|
||||
// Ignore holding key down in volume menu.
|
||||
return;
|
||||
}
|
||||
|
||||
last_volume = volume;
|
||||
|
||||
volume_factor = sqrtf((float)volume / 15);
|
||||
|
||||
update_volume = true;
|
||||
@ -637,12 +805,6 @@ static void *I_WIN_RegisterSong(void *data, int len)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Initialize channels volume.
|
||||
for (i = 0; i < MIDI_CHANNELS_PER_TRACK; ++i)
|
||||
{
|
||||
channel_volume[i] = 100;
|
||||
}
|
||||
|
||||
prop_timediv.cbStruct = sizeof(MIDIPROPTIMEDIV);
|
||||
prop_timediv.dwTimeDiv = MIDI_GetFileTimeDivision(song.file);
|
||||
mmr = midiStreamProperty(hMidiStream, (LPBYTE)&prop_timediv,
|
||||
|
@ -99,7 +99,6 @@ extern int winmm_reset_type;
|
||||
extern int winmm_reset_delay;
|
||||
extern int winmm_reverb_level;
|
||||
extern int winmm_chorus_level;
|
||||
extern int winmm_allow_sysex;
|
||||
#endif
|
||||
extern boolean demobar;
|
||||
extern boolean smoothlight;
|
||||
@ -2349,13 +2348,6 @@ default_t defaults[] = {
|
||||
{40}, {0, 127}, number, ss_none, wad_no,
|
||||
"fine tune default reverb level for native MIDI"
|
||||
},
|
||||
|
||||
{
|
||||
"winmm_allow_sysex",
|
||||
(config_t *) &winmm_allow_sysex, NULL,
|
||||
{0}, {0, 1}, number, ss_none, wad_no,
|
||||
"Allow SysEx messages from MIDI files for native MIDI"
|
||||
},
|
||||
#endif
|
||||
|
||||
// [FG] uncapped rendering frame rate
|
||||
|
Loading…
x
Reference in New Issue
Block a user