diff options
author | Chris Robinson <[email protected]> | 2014-02-02 02:39:56 -0800 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2014-02-02 02:39:56 -0800 |
commit | 7c4339c195e29b17c8f76e6fbe9c8ee1b4f7b9b8 (patch) | |
tree | 728e3298bff7d7612ee6d7fcd88a2049d343d763 /Alc/midi/fluidsynth.c | |
parent | 755f161fc58aec0b541c7783ed716bd5c861a615 (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.c | 72 |
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; } |