mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-27 22:42:57 +00:00
- Fixed: OPLMIDIDevice sent the wrong pitch wheel value to the player code.
Missimp.mid sounds a lot better now, though still a little off. - Fixed: MIDI files that had ticks with nothing but meta-events did not play properly. (fixes sonic3_finalboss.mid) SVN r868 (trunk)
This commit is contained in:
parent
f72635ac69
commit
f23e9df084
6 changed files with 75 additions and 46 deletions
|
@ -1,4 +1,8 @@
|
||||||
March 29, 2008
|
March 29, 2008
|
||||||
|
- Fixed: OPLMIDIDevice sent the wrong pitch wheel value to the player code.
|
||||||
|
Missimp.mid sounds a lot better now, though still a little off.
|
||||||
|
- Fixed: MIDI files that had ticks with nothing but meta-events did not play
|
||||||
|
properly. (fixes sonic3_finalboss.mid)
|
||||||
- Applied Const's Makefile.linux changes.
|
- Applied Const's Makefile.linux changes.
|
||||||
- Made the OPL MIDI synth available from Linux.
|
- Made the OPL MIDI synth available from Linux.
|
||||||
|
|
||||||
|
|
|
@ -92,7 +92,8 @@ int musicBlock::playTick()
|
||||||
OPLplayNote(channel, note, -1);
|
OPLplayNote(channel, note, -1);
|
||||||
} break;
|
} break;
|
||||||
case 2: // pitch wheel
|
case 2: // pitch wheel
|
||||||
OPLpitchWheel(channel, *score++);
|
// MUS pitch wheel is 8 bits, but MIDI is 14
|
||||||
|
OPLpitchWheel(channel, *score++ << (14 - 8));
|
||||||
break;
|
break;
|
||||||
case 3: // system event (valueless controller)
|
case 3: // system event (valueless controller)
|
||||||
OPLchangeControl(channel, *score++, 0);
|
OPLchangeControl(channel, *score++, 0);
|
||||||
|
|
|
@ -95,20 +95,19 @@ int musicBlock::occupyChannel(uint slot, uint channel,
|
||||||
int note, int volume, struct OP2instrEntry *instrument, uchar secondary)
|
int note, int volume, struct OP2instrEntry *instrument, uchar secondary)
|
||||||
{
|
{
|
||||||
struct OPL2instrument *instr;
|
struct OPL2instrument *instr;
|
||||||
struct OPLdata *data = &driverdata;
|
|
||||||
struct channelEntry *ch = &channels[slot];
|
struct channelEntry *ch = &channels[slot];
|
||||||
|
|
||||||
ch->channel = channel;
|
ch->channel = channel;
|
||||||
ch->note = note;
|
ch->note = note;
|
||||||
ch->flags = secondary ? CH_SECONDARY : 0;
|
ch->flags = secondary ? CH_SECONDARY : 0;
|
||||||
if (data->channelModulation[channel] >= MOD_MIN)
|
if (driverdata.channelModulation[channel] >= MOD_MIN)
|
||||||
ch->flags |= CH_VIBRATO;
|
ch->flags |= CH_VIBRATO;
|
||||||
ch->time = MLtime;
|
ch->time = MLtime;
|
||||||
if (volume == -1)
|
if (volume == -1)
|
||||||
volume = data->channelLastVolume[channel];
|
volume = driverdata.channelLastVolume[channel];
|
||||||
else
|
else
|
||||||
data->channelLastVolume[channel] = volume;
|
driverdata.channelLastVolume[channel] = volume;
|
||||||
ch->realvolume = calcVolume(data->channelVolume[channel], 256, ch->volume = volume);
|
ch->realvolume = calcVolume(driverdata.channelVolume[channel], 256, ch->volume = volume);
|
||||||
if (instrument->flags & FL_FIXED_PITCH)
|
if (instrument->flags & FL_FIXED_PITCH)
|
||||||
note = instrument->note;
|
note = instrument->note;
|
||||||
else if (channel == PERCUSSION)
|
else if (channel == PERCUSSION)
|
||||||
|
@ -117,7 +116,7 @@ int musicBlock::occupyChannel(uint slot, uint channel,
|
||||||
ch->finetune = (instrument->finetune - 0x80) >> 1;
|
ch->finetune = (instrument->finetune - 0x80) >> 1;
|
||||||
else
|
else
|
||||||
ch->finetune = 0;
|
ch->finetune = 0;
|
||||||
ch->pitch = ch->finetune + data->channelPitch[channel];
|
ch->pitch = ch->finetune + driverdata.channelPitch[channel];
|
||||||
if (secondary)
|
if (secondary)
|
||||||
instr = &instrument->instr[1];
|
instr = &instrument->instr[1];
|
||||||
else
|
else
|
||||||
|
@ -135,7 +134,7 @@ int musicBlock::occupyChannel(uint slot, uint channel,
|
||||||
io->OPLwriteInstrument(slot, instr);
|
io->OPLwriteInstrument(slot, instr);
|
||||||
if (ch->flags & CH_VIBRATO)
|
if (ch->flags & CH_VIBRATO)
|
||||||
writeModulation(slot, instr, 1);
|
writeModulation(slot, instr, 1);
|
||||||
io->OPLwritePan(slot, instr, data->channelPan[channel]);
|
io->OPLwritePan(slot, instr, driverdata.channelPan[channel]);
|
||||||
io->OPLwriteVolume(slot, instr, ch->realvolume);
|
io->OPLwriteVolume(slot, instr, ch->realvolume);
|
||||||
writeFrequency(slot, note, ch->pitch, 1);
|
writeFrequency(slot, note, ch->pitch, 1);
|
||||||
return slot;
|
return slot;
|
||||||
|
@ -254,8 +253,7 @@ void musicBlock::OPLreleaseNote(uint channel, uchar note)
|
||||||
{
|
{
|
||||||
uint i;
|
uint i;
|
||||||
uint id = channel;
|
uint id = channel;
|
||||||
struct OPLdata *data = &driverdata;
|
uint sustain = driverdata.channelSustain[channel];
|
||||||
uint sustain = data->channelSustain[channel];
|
|
||||||
|
|
||||||
for(i = 0; i < io->OPLchannels; i++)
|
for(i = 0; i < io->OPLchannels; i++)
|
||||||
{
|
{
|
||||||
|
@ -274,11 +272,9 @@ void musicBlock::OPLpitchWheel(uint channel, int pitch)
|
||||||
{
|
{
|
||||||
uint i;
|
uint i;
|
||||||
uint id = channel;
|
uint id = channel;
|
||||||
struct OPLdata *data = &driverdata;
|
|
||||||
|
|
||||||
//pitch -= 0x80;
|
pitch >>= 7;
|
||||||
pitch >>= 1;
|
driverdata.channelPitch[channel] = pitch;
|
||||||
data->channelPitch[channel] = pitch;
|
|
||||||
for(i = 0; i < io->OPLchannels; i++)
|
for(i = 0; i < io->OPLchannels; i++)
|
||||||
{
|
{
|
||||||
struct channelEntry *ch = &channels[i];
|
struct channelEntry *ch = &channels[i];
|
||||||
|
@ -365,14 +361,13 @@ void musicBlock::OPLprogramChange(uint channel, int value)
|
||||||
void musicBlock::OPLplayMusic(int vol)
|
void musicBlock::OPLplayMusic(int vol)
|
||||||
{
|
{
|
||||||
uint i;
|
uint i;
|
||||||
struct OPLdata *data = &driverdata;
|
|
||||||
|
|
||||||
for (i = 0; i < CHANNELS; i++)
|
for (i = 0; i < CHANNELS; i++)
|
||||||
{
|
{
|
||||||
data->channelVolume[i] = vol; /* default volume 127 for MUS (full volume) */
|
driverdata.channelVolume[i] = vol; /* default volume 127 for MUS (full volume) */
|
||||||
data->channelSustain[i] = 0;
|
driverdata.channelSustain[i] = 0;
|
||||||
data->channelLastVolume[i] = 64;
|
driverdata.channelLastVolume[i] = 64;
|
||||||
data->channelPitch[i] = 64;
|
driverdata.channelPitch[i] = 64;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,10 +44,10 @@
|
||||||
// MACROS ------------------------------------------------------------------
|
// MACROS ------------------------------------------------------------------
|
||||||
|
|
||||||
#if defined(_DEBUG) && defined(_WIN32)
|
#if defined(_DEBUG) && defined(_WIN32)
|
||||||
#define UNIMPL(m,c,s,t) \
|
#define DEBUGOUT(m,c,s,t) \
|
||||||
{ char foo[128]; sprintf(foo, m, c, s, t); OutputDebugString(foo); }
|
{ char foo[128]; sprintf(foo, m, c, s, t); OutputDebugString(foo); }
|
||||||
#else
|
#else
|
||||||
#define UNIMPL(m,c,s,t)
|
#define DEBUGOUT(m,c,s,t)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
|
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
|
||||||
|
@ -125,6 +125,7 @@ int OPLMIDIDevice::Open(void (*callback)(unsigned int, void *, DWORD, DWORD), vo
|
||||||
|
|
||||||
OPLstopMusic();
|
OPLstopMusic();
|
||||||
OPLplayMusic(100);
|
OPLplayMusic(100);
|
||||||
|
DEBUGOUT("========= New song started ==========\n", 0, 0, 0);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -178,6 +179,7 @@ int OPLMIDIDevice::SetTempo(int tempo)
|
||||||
{
|
{
|
||||||
Tempo = tempo;
|
Tempo = tempo;
|
||||||
CalcTickRate();
|
CalcTickRate();
|
||||||
|
DEBUGOUT("Tempo changed to %.0f, %.2f samples/tick\n", Tempo, SamplesPerTick, 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,6 +193,7 @@ int OPLMIDIDevice::SetTimeDiv(int timediv)
|
||||||
{
|
{
|
||||||
Division = timediv;
|
Division = timediv;
|
||||||
CalcTickRate();
|
CalcTickRate();
|
||||||
|
DEBUGOUT("Division changed to %.0f, %.2f samples/tick\n", Division, SamplesPerTick, 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -375,8 +378,7 @@ int OPLMIDIDevice::PlayTick()
|
||||||
DWORD *event = (DWORD *)(Events->lpData + Position);
|
DWORD *event = (DWORD *)(Events->lpData + Position);
|
||||||
if (MEVT_EVENTTYPE(event[2]) == MEVT_TEMPO)
|
if (MEVT_EVENTTYPE(event[2]) == MEVT_TEMPO)
|
||||||
{
|
{
|
||||||
Tempo = MEVT_EVENTPARM(event[2]);
|
SetTempo(MEVT_EVENTPARM(event[2]));
|
||||||
CalcTickRate();
|
|
||||||
}
|
}
|
||||||
else if (MEVT_EVENTTYPE(event[2]) == MEVT_LONGMSG)
|
else if (MEVT_EVENTTYPE(event[2]) == MEVT_LONGMSG)
|
||||||
{ // Should I handle master volume changes?
|
{ // Should I handle master volume changes?
|
||||||
|
@ -459,7 +461,7 @@ void OPLMIDIDevice::HandleEvent(int status, int parm1, int parm2)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MIDI_POLYPRESS:
|
case MIDI_POLYPRESS:
|
||||||
UNIMPL("Unhandled note aftertouch: Channel %d, note %d, value %d\n", channel, parm1, parm2);
|
DEBUGOUT("Unhandled note aftertouch: Channel %d, note %d, value %d\n", channel, parm1, parm2);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MIDI_CTRLCHANGE:
|
case MIDI_CTRLCHANGE:
|
||||||
|
@ -480,7 +482,7 @@ void OPLMIDIDevice::HandleEvent(int status, int parm1, int parm2)
|
||||||
case 126: OPLchangeControl(channel, ctrlMono, parm2); break;
|
case 126: OPLchangeControl(channel, ctrlMono, parm2); break;
|
||||||
case 127: OPLchangeControl(channel, ctrlPoly, parm2); break;
|
case 127: OPLchangeControl(channel, ctrlPoly, parm2); break;
|
||||||
default:
|
default:
|
||||||
UNIMPL("Unhandled controller: Channel %d, controller %d, value %d\n", channel, parm1, parm2);
|
DEBUGOUT("Unhandled controller: Channel %d, controller %d, value %d\n", channel, parm1, parm2);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -490,12 +492,11 @@ void OPLMIDIDevice::HandleEvent(int status, int parm1, int parm2)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MIDI_CHANPRESS:
|
case MIDI_CHANPRESS:
|
||||||
UNIMPL("Unhandled channel aftertouch: Channel %d, value %d\n", channel, parm1, 0);
|
DEBUGOUT("Unhandled channel aftertouch: Channel %d, value %d\n", channel, parm1, 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MIDI_PITCHBEND:
|
case MIDI_PITCHBEND:
|
||||||
// MUS pitch is 8 bit, but MIDI pitch is 14-bit
|
OPLpitchWheel(channel, parm1 | (parm2 << 7));
|
||||||
OPLpitchWheel(channel, (parm1 | (parm2 >> 1)) >> (14 - 8));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -297,6 +297,7 @@ protected:
|
||||||
void DoRestart();
|
void DoRestart();
|
||||||
bool CheckDone();
|
bool CheckDone();
|
||||||
DWORD *MakeEvents(DWORD *events, DWORD *max_events_p, DWORD max_time);
|
DWORD *MakeEvents(DWORD *events, DWORD *max_events_p, DWORD max_time);
|
||||||
|
void AdvanceTracks(DWORD time);
|
||||||
|
|
||||||
struct TrackInfo;
|
struct TrackInfo;
|
||||||
|
|
||||||
|
|
|
@ -307,36 +307,63 @@ bool MIDISong2::CheckDone()
|
||||||
|
|
||||||
DWORD *MIDISong2::MakeEvents(DWORD *events, DWORD *max_event_p, DWORD max_time)
|
DWORD *MIDISong2::MakeEvents(DWORD *events, DWORD *max_event_p, DWORD max_time)
|
||||||
{
|
{
|
||||||
|
DWORD *start_events;
|
||||||
DWORD tot_time = 0;
|
DWORD tot_time = 0;
|
||||||
DWORD time = 0;
|
DWORD time = 0;
|
||||||
|
DWORD delay;
|
||||||
|
|
||||||
|
start_events = events;
|
||||||
while (TrackDue && events < max_event_p && tot_time <= max_time)
|
while (TrackDue && events < max_event_p && tot_time <= max_time)
|
||||||
{
|
{
|
||||||
time = TrackDue->Delay;
|
// It's possible that this tick may be nothing meta-events and
|
||||||
// Advance time for all tracks by the amount needed for the one up next.
|
// not generate any real events. Repeat this until we actually
|
||||||
if (time != 0)
|
// get some output so we don't send an empty buffer to the MIDI
|
||||||
{
|
// device.
|
||||||
tot_time += time * Tempo / Division;
|
|
||||||
for (int i = 0; i < NumTracks; ++i)
|
|
||||||
{
|
|
||||||
if (!Tracks[i].Finished)
|
|
||||||
{
|
|
||||||
Tracks[i].Delay -= time;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Play all events for this tic.
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
events = SendCommand(events, TrackDue, time);
|
delay = TrackDue->Delay;
|
||||||
TrackDue = FindNextDue();
|
time += delay;
|
||||||
time = 0;
|
// Advance time for all tracks by the amount needed for the one up next.
|
||||||
|
tot_time += delay * Tempo / Division;
|
||||||
|
AdvanceTracks(delay);
|
||||||
|
// Play all events for this tick.
|
||||||
|
do
|
||||||
|
{
|
||||||
|
DWORD *new_events = SendCommand(events, TrackDue, time);
|
||||||
|
TrackDue = FindNextDue();
|
||||||
|
if (new_events != events)
|
||||||
|
{
|
||||||
|
time = 0;
|
||||||
|
}
|
||||||
|
events = new_events;
|
||||||
|
}
|
||||||
|
while (TrackDue && TrackDue->Delay == 0 && events < max_event_p);
|
||||||
}
|
}
|
||||||
while (TrackDue && TrackDue->Delay == 0 && events < max_event_p);
|
while (start_events == events && TrackDue);
|
||||||
|
time = 0;
|
||||||
}
|
}
|
||||||
return events;
|
return events;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// MIDISong2 :: AdvanceTracks
|
||||||
|
//
|
||||||
|
// Advaces time for all tracks by the specified amount.
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
void MIDISong2::AdvanceTracks(DWORD time)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < NumTracks; ++i)
|
||||||
|
{
|
||||||
|
if (!Tracks[i].Finished)
|
||||||
|
{
|
||||||
|
Tracks[i].Delay -= time;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// MIDISong2 :: SendCommand
|
// MIDISong2 :: SendCommand
|
||||||
|
|
Loading…
Reference in a new issue