Document the different filter types, and combine some split lines
[openal-soft.git] / Alc / midi / base.c
blob1850a6c67afe08d96c2f42c94c5e757ea93e3e6b
2 #include "config.h"
4 #include <stdlib.h>
5 #include <string.h>
6 #include <limits.h>
8 #include "midi/base.h"
10 #include "alMidi.h"
11 #include "alMain.h"
12 #include "alError.h"
13 #include "alThunk.h"
14 #include "evtqueue.h"
15 #include "rwlock.h"
16 #include "alu.h"
19 /* MIDI events */
20 #define SYSEX_EVENT (0xF0)
23 void InitEvtQueue(EvtQueue *queue)
25 queue->events = NULL;
26 queue->maxsize = 0;
27 queue->size = 0;
28 queue->pos = 0;
31 void ResetEvtQueue(EvtQueue *queue)
33 ALsizei i;
34 for(i = 0;i < queue->size;i++)
36 if(queue->events[i].event == SYSEX_EVENT)
38 free(queue->events[i].param.sysex.data);
39 queue->events[i].param.sysex.data = NULL;
43 free(queue->events);
44 queue->events = NULL;
45 queue->maxsize = 0;
46 queue->size = 0;
47 queue->pos = 0;
50 ALenum InsertEvtQueue(EvtQueue *queue, const MidiEvent *evt)
52 ALsizei pos;
54 if(queue->maxsize == queue->size)
56 if(queue->pos > 0)
58 /* Queue has some stale entries, remove them to make space for more
59 * events. */
60 for(pos = 0;pos < queue->pos;pos++)
62 if(queue->events[pos].event == SYSEX_EVENT)
64 free(queue->events[pos].param.sysex.data);
65 queue->events[pos].param.sysex.data = NULL;
68 memmove(&queue->events[0], &queue->events[queue->pos],
69 (queue->size-queue->pos)*sizeof(queue->events[0]));
70 queue->size -= queue->pos;
71 queue->pos = 0;
73 else
75 /* Queue is full, double the allocated space. */
76 void *temp = NULL;
77 ALsizei newsize;
79 newsize = (queue->maxsize ? (queue->maxsize<<1) : 16);
80 if(newsize > queue->maxsize)
81 temp = realloc(queue->events, newsize * sizeof(queue->events[0]));
82 if(!temp)
83 return AL_OUT_OF_MEMORY;
85 queue->events = temp;
86 queue->maxsize = newsize;
90 pos = queue->pos;
91 if(queue->size > 0)
93 ALsizei high = queue->size - 1;
94 while(pos < high)
96 ALsizei mid = pos + (high-pos)/2;
97 if(queue->events[mid].time < evt->time)
98 pos = mid + 1;
99 else
100 high = mid;
102 while(pos < queue->size && queue->events[pos].time <= evt->time)
103 pos++;
105 if(pos < queue->size)
106 memmove(&queue->events[pos+1], &queue->events[pos],
107 (queue->size-pos)*sizeof(queue->events[0]));
110 queue->events[pos] = *evt;
111 queue->size++;
113 return AL_NO_ERROR;
117 void MidiSynth_Construct(MidiSynth *self, ALCdevice *device)
119 InitEvtQueue(&self->EventQueue);
121 RWLockInit(&self->Lock);
123 self->Soundfonts = NULL;
124 self->NumSoundfonts = 0;
126 self->Gain = 1.0f;
127 self->State = AL_INITIAL;
129 self->ClockBase = 0;
130 self->SamplesDone = 0;
131 self->SampleRate = device->Frequency;
134 void MidiSynth_Destruct(MidiSynth *self)
136 ALsizei i;
138 for(i = 0;i < self->NumSoundfonts;i++)
139 DecrementRef(&self->Soundfonts[i]->ref);
140 free(self->Soundfonts);
141 self->Soundfonts = NULL;
142 self->NumSoundfonts = 0;
144 ResetEvtQueue(&self->EventQueue);
148 ALenum MidiSynth_selectSoundfonts(MidiSynth *self, ALCcontext *context, ALsizei count, const ALuint *ids)
150 ALCdevice *device = context->Device;
151 ALsoundfont **sfonts;
152 ALsizei i;
154 if(self->State != AL_INITIAL && self->State != AL_STOPPED)
155 return AL_INVALID_OPERATION;
157 sfonts = calloc(1, count * sizeof(sfonts[0]));
158 if(!sfonts) return AL_OUT_OF_MEMORY;
160 for(i = 0;i < count;i++)
162 if(ids[i] == 0)
163 sfonts[i] = ALsoundfont_getDefSoundfont(context);
164 else if(!(sfonts[i]=LookupSfont(device, ids[i])))
166 free(sfonts);
167 return AL_INVALID_VALUE;
171 for(i = 0;i < count;i++)
172 IncrementRef(&sfonts[i]->ref);
173 sfonts = ExchangePtr((XchgPtr*)&self->Soundfonts, sfonts);
174 count = ExchangeInt(&self->NumSoundfonts, count);
176 for(i = 0;i < count;i++)
177 DecrementRef(&sfonts[i]->ref);
178 free(sfonts);
180 return AL_NO_ERROR;
183 extern inline void MidiSynth_setGain(MidiSynth *self, ALfloat gain);
184 extern inline ALfloat MidiSynth_getGain(const MidiSynth *self);
185 extern inline void MidiSynth_setState(MidiSynth *self, ALenum state);
186 extern inline ALenum MidiSynth_getState(const MidiSynth *self);
188 void MidiSynth_stop(MidiSynth *self)
190 ResetEvtQueue(&self->EventQueue);
192 self->ClockBase = 0;
193 self->SamplesDone = 0;
196 extern inline void MidiSynth_reset(MidiSynth *self);
197 extern inline ALuint64 MidiSynth_getTime(const MidiSynth *self);
198 extern inline ALuint64 MidiSynth_getNextEvtTime(const MidiSynth *self);
200 void MidiSynth_setSampleRate(MidiSynth *self, ALuint srate)
202 if(self->SampleRate != srate)
204 self->ClockBase += self->SamplesDone * MIDI_CLOCK_RES / self->SampleRate;
205 self->SamplesDone = 0;
206 self->SampleRate = srate;
210 extern inline void MidiSynth_update(MidiSynth *self, ALCdevice *device);
212 ALenum MidiSynth_insertEvent(MidiSynth *self, ALuint64 time, ALuint event, ALsizei param1, ALsizei param2)
214 MidiEvent entry;
215 entry.time = time;
216 entry.event = event;
217 entry.param.val[0] = param1;
218 entry.param.val[1] = param2;
219 return InsertEvtQueue(&self->EventQueue, &entry);
222 ALenum MidiSynth_insertSysExEvent(MidiSynth *self, ALuint64 time, const ALbyte *data, ALsizei size)
224 MidiEvent entry;
225 ALenum err;
227 entry.time = time;
228 entry.event = SYSEX_EVENT;
229 entry.param.sysex.size = size;
230 entry.param.sysex.data = malloc(size);
231 if(!entry.param.sysex.data)
232 return AL_OUT_OF_MEMORY;
233 memcpy(entry.param.sysex.data, data, size);
235 err = InsertEvtQueue(&self->EventQueue, &entry);
236 if(err != AL_NO_ERROR)
237 free(entry.param.sysex.data);
238 return err;