- 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:
Randy Heit 2008-03-30 02:51:34 +00:00
parent f72635ac69
commit f23e9df084
6 changed files with 75 additions and 46 deletions

View file

@ -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.

View file

@ -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);

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;

View file

@ -307,16 +307,54 @@ 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)
// 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
{
tot_time += time * Tempo / Division;
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 (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)
@ -324,17 +362,6 @@ DWORD *MIDISong2::MakeEvents(DWORD *events, DWORD *max_event_p, DWORD max_time)
Tracks[i].Delay -= time;
}
}
}
// Play all events for this tic.
do
{
events = SendCommand(events, TrackDue, time);
TrackDue = FindNextDue();
time = 0;
}
while (TrackDue && TrackDue->Delay == 0 && events < max_event_p);
}
return events;
}
//==========================================================================