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
|
||||
- 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.
|
||||
- Made the OPL MIDI synth available from Linux.
|
||||
|
||||
|
|
|
@ -92,7 +92,8 @@ int musicBlock::playTick()
|
|||
OPLplayNote(channel, note, -1);
|
||||
} break;
|
||||
case 2: // pitch wheel
|
||||
OPLpitchWheel(channel, *score++);
|
||||
// MUS pitch wheel is 8 bits, but MIDI is 14
|
||||
OPLpitchWheel(channel, *score++ << (14 - 8));
|
||||
break;
|
||||
case 3: // system event (valueless controller)
|
||||
OPLchangeControl(channel, *score++, 0);
|
||||
|
|
|
@ -95,20 +95,19 @@ int musicBlock::occupyChannel(uint slot, uint channel,
|
|||
int note, int volume, struct OP2instrEntry *instrument, uchar secondary)
|
||||
{
|
||||
struct OPL2instrument *instr;
|
||||
struct OPLdata *data = &driverdata;
|
||||
struct channelEntry *ch = &channels[slot];
|
||||
|
||||
ch->channel = channel;
|
||||
ch->note = note;
|
||||
ch->flags = secondary ? CH_SECONDARY : 0;
|
||||
if (data->channelModulation[channel] >= MOD_MIN)
|
||||
if (driverdata.channelModulation[channel] >= MOD_MIN)
|
||||
ch->flags |= CH_VIBRATO;
|
||||
ch->time = MLtime;
|
||||
if (volume == -1)
|
||||
volume = data->channelLastVolume[channel];
|
||||
volume = driverdata.channelLastVolume[channel];
|
||||
else
|
||||
data->channelLastVolume[channel] = volume;
|
||||
ch->realvolume = calcVolume(data->channelVolume[channel], 256, ch->volume = volume);
|
||||
driverdata.channelLastVolume[channel] = volume;
|
||||
ch->realvolume = calcVolume(driverdata.channelVolume[channel], 256, ch->volume = volume);
|
||||
if (instrument->flags & FL_FIXED_PITCH)
|
||||
note = instrument->note;
|
||||
else if (channel == PERCUSSION)
|
||||
|
@ -117,7 +116,7 @@ int musicBlock::occupyChannel(uint slot, uint channel,
|
|||
ch->finetune = (instrument->finetune - 0x80) >> 1;
|
||||
else
|
||||
ch->finetune = 0;
|
||||
ch->pitch = ch->finetune + data->channelPitch[channel];
|
||||
ch->pitch = ch->finetune + driverdata.channelPitch[channel];
|
||||
if (secondary)
|
||||
instr = &instrument->instr[1];
|
||||
else
|
||||
|
@ -135,7 +134,7 @@ int musicBlock::occupyChannel(uint slot, uint channel,
|
|||
io->OPLwriteInstrument(slot, instr);
|
||||
if (ch->flags & CH_VIBRATO)
|
||||
writeModulation(slot, instr, 1);
|
||||
io->OPLwritePan(slot, instr, data->channelPan[channel]);
|
||||
io->OPLwritePan(slot, instr, driverdata.channelPan[channel]);
|
||||
io->OPLwriteVolume(slot, instr, ch->realvolume);
|
||||
writeFrequency(slot, note, ch->pitch, 1);
|
||||
return slot;
|
||||
|
@ -254,8 +253,7 @@ void musicBlock::OPLreleaseNote(uint channel, uchar note)
|
|||
{
|
||||
uint i;
|
||||
uint id = channel;
|
||||
struct OPLdata *data = &driverdata;
|
||||
uint sustain = data->channelSustain[channel];
|
||||
uint sustain = driverdata.channelSustain[channel];
|
||||
|
||||
for(i = 0; i < io->OPLchannels; i++)
|
||||
{
|
||||
|
@ -274,11 +272,9 @@ void musicBlock::OPLpitchWheel(uint channel, int pitch)
|
|||
{
|
||||
uint i;
|
||||
uint id = channel;
|
||||
struct OPLdata *data = &driverdata;
|
||||
|
||||
//pitch -= 0x80;
|
||||
pitch >>= 1;
|
||||
data->channelPitch[channel] = pitch;
|
||||
pitch >>= 7;
|
||||
driverdata.channelPitch[channel] = pitch;
|
||||
for(i = 0; i < io->OPLchannels; i++)
|
||||
{
|
||||
struct channelEntry *ch = &channels[i];
|
||||
|
@ -365,14 +361,13 @@ void musicBlock::OPLprogramChange(uint channel, int value)
|
|||
void musicBlock::OPLplayMusic(int vol)
|
||||
{
|
||||
uint i;
|
||||
struct OPLdata *data = &driverdata;
|
||||
|
||||
for (i = 0; i < CHANNELS; i++)
|
||||
{
|
||||
data->channelVolume[i] = vol; /* default volume 127 for MUS (full volume) */
|
||||
data->channelSustain[i] = 0;
|
||||
data->channelLastVolume[i] = 64;
|
||||
data->channelPitch[i] = 64;
|
||||
driverdata.channelVolume[i] = vol; /* default volume 127 for MUS (full volume) */
|
||||
driverdata.channelSustain[i] = 0;
|
||||
driverdata.channelLastVolume[i] = 64;
|
||||
driverdata.channelPitch[i] = 64;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -44,10 +44,10 @@
|
|||
// MACROS ------------------------------------------------------------------
|
||||
|
||||
#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); }
|
||||
#else
|
||||
#define UNIMPL(m,c,s,t)
|
||||
#define DEBUGOUT(m,c,s,t)
|
||||
#endif
|
||||
|
||||
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
|
||||
|
@ -125,6 +125,7 @@ int OPLMIDIDevice::Open(void (*callback)(unsigned int, void *, DWORD, DWORD), vo
|
|||
|
||||
OPLstopMusic();
|
||||
OPLplayMusic(100);
|
||||
DEBUGOUT("========= New song started ==========\n", 0, 0, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -178,6 +179,7 @@ int OPLMIDIDevice::SetTempo(int tempo)
|
|||
{
|
||||
Tempo = tempo;
|
||||
CalcTickRate();
|
||||
DEBUGOUT("Tempo changed to %.0f, %.2f samples/tick\n", Tempo, SamplesPerTick, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -191,6 +193,7 @@ int OPLMIDIDevice::SetTimeDiv(int timediv)
|
|||
{
|
||||
Division = timediv;
|
||||
CalcTickRate();
|
||||
DEBUGOUT("Division changed to %.0f, %.2f samples/tick\n", Division, SamplesPerTick, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -375,8 +378,7 @@ int OPLMIDIDevice::PlayTick()
|
|||
DWORD *event = (DWORD *)(Events->lpData + Position);
|
||||
if (MEVT_EVENTTYPE(event[2]) == MEVT_TEMPO)
|
||||
{
|
||||
Tempo = MEVT_EVENTPARM(event[2]);
|
||||
CalcTickRate();
|
||||
SetTempo(MEVT_EVENTPARM(event[2]));
|
||||
}
|
||||
else if (MEVT_EVENTTYPE(event[2]) == MEVT_LONGMSG)
|
||||
{ // Should I handle master volume changes?
|
||||
|
@ -459,7 +461,7 @@ void OPLMIDIDevice::HandleEvent(int status, int parm1, int parm2)
|
|||
break;
|
||||
|
||||
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;
|
||||
|
||||
case MIDI_CTRLCHANGE:
|
||||
|
@ -480,7 +482,7 @@ void OPLMIDIDevice::HandleEvent(int status, int parm1, int parm2)
|
|||
case 126: OPLchangeControl(channel, ctrlMono, parm2); break;
|
||||
case 127: OPLchangeControl(channel, ctrlPoly, parm2); break;
|
||||
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;
|
||||
|
@ -490,12 +492,11 @@ void OPLMIDIDevice::HandleEvent(int status, int parm1, int parm2)
|
|||
break;
|
||||
|
||||
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;
|
||||
|
||||
case MIDI_PITCHBEND:
|
||||
// MUS pitch is 8 bit, but MIDI pitch is 14-bit
|
||||
OPLpitchWheel(channel, (parm1 | (parm2 >> 1)) >> (14 - 8));
|
||||
OPLpitchWheel(channel, parm1 | (parm2 << 7));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -297,6 +297,7 @@ protected:
|
|||
void DoRestart();
|
||||
bool CheckDone();
|
||||
DWORD *MakeEvents(DWORD *events, DWORD *max_events_p, DWORD max_time);
|
||||
void AdvanceTracks(DWORD time);
|
||||
|
||||
struct TrackInfo;
|
||||
|
||||
|
|
|
@ -307,36 +307,63 @@ bool MIDISong2::CheckDone()
|
|||
|
||||
DWORD *MIDISong2::MakeEvents(DWORD *events, DWORD *max_event_p, DWORD max_time)
|
||||
{
|
||||
DWORD *start_events;
|
||||
DWORD tot_time = 0;
|
||||
DWORD time = 0;
|
||||
DWORD delay;
|
||||
|
||||
start_events = events;
|
||||
while (TrackDue && events < max_event_p && tot_time <= max_time)
|
||||
{
|
||||
time = TrackDue->Delay;
|
||||
// Advance time for all tracks by the amount needed for the one up next.
|
||||
if (time != 0)
|
||||
{
|
||||
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.
|
||||
// It's possible that this tick may be nothing meta-events and
|
||||
// not generate any real events. Repeat this until we actually
|
||||
// get some output so we don't send an empty buffer to the MIDI
|
||||
// device.
|
||||
do
|
||||
{
|
||||
events = SendCommand(events, TrackDue, time);
|
||||
TrackDue = FindNextDue();
|
||||
time = 0;
|
||||
delay = TrackDue->Delay;
|
||||
time += delay;
|
||||
// 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;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// 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
|
||||
|
|
Loading…
Reference in a new issue