14 #include "midi/base.h"
17 typedef struct SSynth
{
18 DERIVE_FROM_TYPE(MidiSynth
);
21 static void SSynth_mixSamples(SSynth
*self
, ALuint SamplesToDo
, ALfloat (*restrict DryBuffer
)[BUFFERSIZE
]);
23 static void SSynth_Construct(SSynth
*self
, ALCdevice
*device
);
24 static void SSynth_Destruct(SSynth
*self
);
25 static DECLARE_FORWARD3(SSynth
, MidiSynth
, ALenum
, selectSoundfonts
, ALCcontext
*, ALsizei
, const ALuint
*)
26 static DECLARE_FORWARD1(SSynth
, MidiSynth
, void, setGain
, ALfloat
)
27 static DECLARE_FORWARD(SSynth
, MidiSynth
, void, stop
)
28 static DECLARE_FORWARD(SSynth
, MidiSynth
, void, reset
)
29 static void SSynth_update(SSynth
*self
, ALCdevice
*device
);
30 static void SSynth_process(SSynth
*self
, ALuint SamplesToDo
, ALfloat (*restrict DryBuffer
)[BUFFERSIZE
]);
31 DECLARE_DEFAULT_ALLOCATORS(SSynth
)
32 DEFINE_MIDISYNTH_VTABLE(SSynth
);
35 static void SSynth_Construct(SSynth
*self
, ALCdevice
*device
)
37 MidiSynth_Construct(STATIC_CAST(MidiSynth
, self
), device
);
38 SET_VTABLE2(SSynth
, MidiSynth
, self
);
41 static void SSynth_Destruct(SSynth
* UNUSED(self
))
46 static void SSynth_update(SSynth
* UNUSED(self
), ALCdevice
* UNUSED(device
))
51 static void SSynth_mixSamples(SSynth
* UNUSED(self
), ALuint
UNUSED(SamplesToDo
), ALfloat (*restrict DryBuffer
)[BUFFERSIZE
])
57 static void SSynth_processQueue(SSynth
*self
, ALuint64 time
)
59 EvtQueue
*queue
= &STATIC_CAST(MidiSynth
, self
)->EventQueue
;
61 while(queue
->pos
< queue
->size
&& queue
->events
[queue
->pos
].time
<= time
)
65 static void SSynth_process(SSynth
*self
, ALuint SamplesToDo
, ALfloat (*restrict DryBuffer
)[BUFFERSIZE
])
67 MidiSynth
*synth
= STATIC_CAST(MidiSynth
, self
);
68 ALenum state
= synth
->State
;
72 if(state
== AL_INITIAL
)
74 if(state
!= AL_PLAYING
)
76 SSynth_mixSamples(self
, SamplesToDo
, DryBuffer
);
80 curtime
= MidiSynth_getTime(synth
);
81 while(total
< SamplesToDo
)
86 time
= MidiSynth_getNextEvtTime(synth
);
87 diff
= maxu64(time
, curtime
) - curtime
;
88 if(diff
>= MIDI_CLOCK_RES
|| time
== UINT64_MAX
)
90 /* If there's no pending event, or if it's more than 1 second
91 * away, do as many samples as we can. */
96 /* Figure out how many samples until the next event. */
97 tonext
= (ALint
)((diff
*synth
->SampleRate
+ (MIDI_CLOCK_RES
-1)) / MIDI_CLOCK_RES
);
99 /* For efficiency reasons, try to mix a multiple of 64 samples
100 * (~1ms @ 44.1khz) before processing the next event. */
101 tonext
= (tonext
+63) & ~63;
106 ALuint todo
= mini(tonext
, SamplesToDo
-total
);
107 SSynth_mixSamples(self
, todo
, DryBuffer
);
111 if(total
< SamplesToDo
&& tonext
<= 0)
112 SSynth_processQueue(self
, time
);
115 synth
->SamplesDone
+= SamplesToDo
;
116 synth
->ClockBase
+= (synth
->SamplesDone
/synth
->SampleRate
) * MIDI_CLOCK_RES
;
117 synth
->SamplesDone
%= synth
->SampleRate
;
121 MidiSynth
*SSynth_create(ALCdevice
*device
)
125 /* This option is temporary. Once this synth is in a more usable state, a
126 * more generic selector should be used. */
127 if(!GetConfigValueBool("midi", "internal-synth", 0))
129 TRACE("Not using internal MIDI synth\n");
133 synth
= SSynth_New(sizeof(*synth
));
136 ERR("Failed to allocate SSynth\n");
139 SSynth_Construct(synth
, device
);
140 return STATIC_CAST(MidiSynth
, synth
);