aboutsummaryrefslogtreecommitdiffstats
path: root/Alc/midi/fluidsynth.c
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2014-02-02 02:39:56 -0800
committerChris Robinson <[email protected]>2014-02-02 02:39:56 -0800
commit7c4339c195e29b17c8f76e6fbe9c8ee1b4f7b9b8 (patch)
tree728e3298bff7d7612ee6d7fcd88a2049d343d763 /Alc/midi/fluidsynth.c
parent755f161fc58aec0b541c7783ed716bd5c861a615 (diff)
Rework MIDI clock timing
It's best to avoid using doubles in the mixer since the FPU's set to single- precision mode. The new clock timing is similar to the device clock timing, and should hopefully be less prone to drift caused by fp rounding errors.
Diffstat (limited to 'Alc/midi/fluidsynth.c')
-rw-r--r--Alc/midi/fluidsynth.c72
1 files changed, 31 insertions, 41 deletions
diff --git a/Alc/midi/fluidsynth.c b/Alc/midi/fluidsynth.c
index 9d58f87b..d2db71e3 100644
--- a/Alc/midi/fluidsynth.c
+++ b/Alc/midi/fluidsynth.c
@@ -640,24 +640,12 @@ static void FSynth_setState(FSynth *self, ALenum state)
static void FSynth_stop(FSynth *self)
{
MidiSynth *synth = STATIC_CAST(MidiSynth, self);
+ ALuint64 curtime;
ALsizei chan;
/* Make sure all pending events are processed. */
- while(!(synth->SamplesToNext >= 1.0))
- {
- ALuint64 time = synth->NextEvtTime;
- if(time == UINT64_MAX)
- break;
-
- synth->SamplesSinceLast -= (time - synth->LastEvtTime) * synth->SamplesPerTick;
- synth->SamplesSinceLast = maxd(synth->SamplesSinceLast, 0.0);
- synth->LastEvtTime = time;
- FSynth_processQueue(self, time);
-
- synth->NextEvtTime = MidiSynth_getNextEvtTime(synth);
- if(synth->NextEvtTime != UINT64_MAX)
- synth->SamplesToNext += (synth->NextEvtTime - synth->LastEvtTime) * synth->SamplesPerTick;
- }
+ curtime = MidiSynth_getTime(synth);
+ FSynth_processQueue(self, curtime);
/* All notes off */
for(chan = 0;chan < 16;chan++)
@@ -759,6 +747,7 @@ static void FSynth_process(FSynth *self, ALuint SamplesToDo, ALfloat (*restrict
{
MidiSynth *synth = STATIC_CAST(MidiSynth, self);
ALenum state = synth->State;
+ ALuint64 curtime;
ALuint total = 0;
if(state == AL_INITIAL)
@@ -770,41 +759,42 @@ static void FSynth_process(FSynth *self, ALuint SamplesToDo, ALfloat (*restrict
return;
}
+ curtime = MidiSynth_getTime(synth);
while(total < SamplesToDo)
{
- if(synth->SamplesToNext >= 1.0)
- {
- ALuint todo = minu(SamplesToDo - total, fastf2u(synth->SamplesToNext));
+ ALuint64 time, diff;
+ ALint tonext;
- fluid_synth_write_float(self->Synth, todo,
- &DryBuffer[FrontLeft][total], 0, 1,
- &DryBuffer[FrontRight][total], 0, 1);
- total += todo;
- synth->SamplesSinceLast += todo;
- synth->SamplesToNext -= todo;
+ time = MidiSynth_getNextEvtTime(synth);
+ diff = maxu64(time, curtime) - curtime;
+ if(diff >= MIDI_CLOCK_RES || time == UINT64_MAX)
+ {
+ /* If there's no pending event, or if it's more than 1 second
+ * away, do as many samples as we can. */
+ tonext = INT_MAX;
}
else
{
- ALuint64 time = synth->NextEvtTime;
- if(time == UINT64_MAX)
- {
- synth->SamplesSinceLast += SamplesToDo-total;
- fluid_synth_write_float(self->Synth, SamplesToDo-total,
- &DryBuffer[FrontLeft][total], 0, 1,
- &DryBuffer[FrontRight][total], 0, 1);
- break;
- }
-
- synth->SamplesSinceLast -= (time - synth->LastEvtTime) * synth->SamplesPerTick;
- synth->SamplesSinceLast = maxd(synth->SamplesSinceLast, 0.0);
- synth->LastEvtTime = time;
- FSynth_processQueue(self, time);
+ /* Figure out how many samples until the next event. */
+ tonext = (ALint)(((diff * synth->SampleRate)+(MIDI_CLOCK_RES-1)) / MIDI_CLOCK_RES);
+ tonext -= total;
+ }
- synth->NextEvtTime = MidiSynth_getNextEvtTime(synth);
- if(synth->NextEvtTime != UINT64_MAX)
- synth->SamplesToNext += (synth->NextEvtTime - synth->LastEvtTime) * synth->SamplesPerTick;
+ if(tonext > 0)
+ {
+ ALuint todo = mini(tonext, SamplesToDo-total);
+ fluid_synth_write_float(self->Synth, todo, DryBuffer[FrontLeft], total, 1,
+ DryBuffer[FrontRight], total, 1);
+ total += todo;
+ tonext -= todo;
}
+ if(total < SamplesToDo && tonext == 0)
+ FSynth_processQueue(self, time);
}
+
+ synth->SamplesDone += SamplesToDo;
+ synth->ClockBase += (synth->SamplesDone/synth->SampleRate) * MIDI_CLOCK_RES;
+ synth->SamplesDone %= synth->SampleRate;
}