Allow loading multiple soundfonts with FluidSynth
[openal-soft.git] / OpenAL32 / alSoundfont.c
blob4bc4da48f81c2e48babd436fb2db386ea85390e5
2 #include "config.h"
4 #include <stdlib.h>
5 #include <string.h>
7 #include "alMain.h"
8 #include "alMidi.h"
9 #include "alThunk.h"
10 #include "alError.h"
12 #include "midi/base.h"
15 extern inline struct ALsoundfont *LookupSfont(ALCdevice *device, ALuint id);
16 extern inline struct ALsoundfont *RemoveSfont(ALCdevice *device, ALuint id);
19 AL_API void AL_APIENTRY alGenSoundfontsSOFT(ALsizei n, ALuint *ids)
21 ALCdevice *device;
22 ALCcontext *context;
23 ALsizei cur = 0;
24 ALenum err;
26 context = GetContextRef();
27 if(!context) return;
29 if(!(n >= 0))
30 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
32 device = context->Device;
33 for(cur = 0;cur < n;cur++)
35 ALsoundfont *sfont = calloc(1, sizeof(ALsoundfont));
36 if(!sfont)
38 alDeleteSoundfontsSOFT(cur, ids);
39 SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
41 ALsoundfont_Construct(sfont);
43 err = NewThunkEntry(&sfont->id);
44 if(err == AL_NO_ERROR)
45 err = InsertUIntMapEntry(&device->SfontMap, sfont->id, sfont);
46 if(err != AL_NO_ERROR)
48 ALsoundfont_Destruct(sfont);
49 memset(sfont, 0, sizeof(ALsoundfont));
50 free(sfont);
52 alDeleteSoundfontsSOFT(cur, ids);
53 SET_ERROR_AND_GOTO(context, err, done);
56 ids[cur] = sfont->id;
59 done:
60 ALCcontext_DecRef(context);
63 AL_API ALvoid AL_APIENTRY alDeleteSoundfontsSOFT(ALsizei n, const ALuint *ids)
65 ALCdevice *device;
66 ALCcontext *context;
67 ALsoundfont *sfont;
68 ALsizei i;
70 context = GetContextRef();
71 if(!context) return;
73 if(!(n >= 0))
74 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
76 device = context->Device;
77 for(i = 0;i < n;i++)
79 if(!ids[i])
80 continue;
82 /* Check for valid soundfont ID */
83 if((sfont=LookupSfont(device, ids[i])) == NULL)
84 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
85 if(sfont->Mapped != AL_FALSE || sfont->ref != 0)
86 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
89 for(i = 0;i < n;i++)
91 if((sfont=RemoveSfont(device, ids[i])) == NULL)
92 continue;
94 ALsoundfont_Destruct(sfont);
96 memset(sfont, 0, sizeof(*sfont));
97 free(sfont);
100 done:
101 ALCcontext_DecRef(context);
104 AL_API ALboolean AL_APIENTRY alIsSoundfontSOFT(ALuint id)
106 ALCcontext *context;
107 ALboolean ret;
109 context = GetContextRef();
110 if(!context) return AL_FALSE;
112 ret = ((!id || LookupSfont(context->Device, id)) ?
113 AL_TRUE : AL_FALSE);
115 ALCcontext_DecRef(context);
117 return ret;
120 AL_API ALvoid AL_APIENTRY alSoundfontSamplesSOFT(ALuint sfid, ALenum type, ALsizei count, const ALvoid *samples)
122 ALCdevice *device;
123 ALCcontext *context;
124 ALsoundfont *sfont;
125 void *ptr;
127 context = GetContextRef();
128 if(!context) return;
130 device = context->Device;
131 if(!(sfont=LookupSfont(device, sfid)))
132 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
133 if(type != AL_SHORT_SOFT)
134 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
135 if(count <= 0)
136 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
138 WriteLock(&sfont->Lock);
139 if(sfont->ref != 0)
140 alSetError(context, AL_INVALID_OPERATION);
141 else if(sfont->Mapped)
142 alSetError(context, AL_INVALID_OPERATION);
143 else if(!(ptr=realloc(sfont->Samples, count * sizeof(ALshort))))
144 alSetError(context, AL_OUT_OF_MEMORY);
145 else
147 sfont->Samples = ptr;
148 sfont->NumSamples = count;
149 if(samples != NULL)
150 memcpy(sfont->Samples, samples, count * sizeof(ALshort));
152 WriteUnlock(&sfont->Lock);
154 done:
155 ALCcontext_DecRef(context);
158 AL_API ALvoid* AL_APIENTRY alSoundfontMapSamplesSOFT(ALuint sfid, ALsizei offset, ALsizei length)
160 ALCdevice *device;
161 ALCcontext *context;
162 ALsoundfont *sfont;
163 ALvoid *ptr = NULL;
165 context = GetContextRef();
166 if(!context) return NULL;
168 device = context->Device;
169 if(!(sfont=LookupSfont(device, sfid)))
170 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
171 if(offset < 0 || (ALuint)offset > sfont->NumSamples*sizeof(ALshort))
172 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
173 if(length <= 0 || (ALuint)length > (sfont->NumSamples*sizeof(ALshort) - offset))
174 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
176 ReadLock(&sfont->Lock);
177 if(sfont->ref != 0)
178 alSetError(context, AL_INVALID_OPERATION);
179 else if(ExchangeInt(&sfont->Mapped, AL_TRUE) == AL_TRUE)
180 alSetError(context, AL_INVALID_OPERATION);
181 else
182 ptr = (ALbyte*)sfont->Samples + offset;
183 ReadUnlock(&sfont->Lock);
185 done:
186 ALCcontext_DecRef(context);
188 return ptr;
191 AL_API ALvoid AL_APIENTRY alSoundfontUnmapSamplesSOFT(ALuint sfid)
193 ALCdevice *device;
194 ALCcontext *context;
195 ALsoundfont *sfont;
197 context = GetContextRef();
198 if(!context) return;
200 device = context->Device;
201 if(!(sfont=LookupSfont(device, sfid)))
202 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
203 if(ExchangeInt(&sfont->Mapped, AL_FALSE) == AL_FALSE)
204 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
206 done:
207 ALCcontext_DecRef(context);
210 AL_API void AL_APIENTRY alGetSoundfontivSOFT(ALuint id, ALenum param, ALint *values)
212 ALCdevice *device;
213 ALCcontext *context;
214 ALsoundfont *sfont;
215 ALsizei i;
217 context = GetContextRef();
218 if(!context) return;
220 device = context->Device;
221 if(!(sfont=LookupSfont(device, id)))
222 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
223 switch(param)
225 case AL_PRESETS_SIZE_SOFT:
226 values[0] = sfont->NumPresets;
227 break;
229 case AL_PRESETS_SOFT:
230 for(i = 0;i < sfont->NumPresets;i++)
231 values[i] = sfont->Presets[i]->id;
232 break;
234 case AL_SAMPLE_LENGTH_SOFT:
235 values[0] = sfont->NumSamples;
236 break;
238 case AL_FORMAT_TYPE_SOFT:
239 values[0] = AL_SHORT_SOFT;
240 break;
242 default:
243 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
246 done:
247 ALCcontext_DecRef(context);
250 AL_API void AL_APIENTRY alSoundfontPresetsSOFT(ALuint id, ALsizei count, const ALuint *pids)
252 ALCdevice *device;
253 ALCcontext *context;
254 ALsoundfont *sfont;
255 ALsfpreset **presets;
256 ALsizei i;
258 context = GetContextRef();
259 if(!context) return;
261 device = context->Device;
262 if(!(sfont=LookupSfont(device, id)))
263 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
264 if(count < 0)
265 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
267 WriteLock(&sfont->Lock);
268 if(sfont->ref != 0)
270 WriteUnlock(&sfont->Lock);
271 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
274 if(count == 0)
275 presets = NULL;
276 else
278 presets = calloc(count, sizeof(presets[0]));
279 if(!presets)
281 WriteUnlock(&sfont->Lock);
282 SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
285 for(i = 0;i < count;i++)
287 if(!(presets[i]=LookupPreset(device, pids[i])))
289 WriteUnlock(&sfont->Lock);
290 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
295 for(i = 0;i < count;i++)
296 IncrementRef(&presets[i]->ref);
298 presets = ExchangePtr((XchgPtr*)&sfont->Presets, presets);
299 count = ExchangeInt(&sfont->NumPresets, count);
300 WriteUnlock(&sfont->Lock);
302 for(i = 0;i < count;i++)
303 DecrementRef(&presets[i]->ref);
304 free(presets);
306 done:
307 ALCcontext_DecRef(context);
311 /* ReleaseALSoundfonts
313 * Called to destroy any soundfonts that still exist on the device
315 void ReleaseALSoundfonts(ALCdevice *device)
317 ALsizei i;
318 for(i = 0;i < device->SfontMap.size;i++)
320 ALsoundfont *temp = device->SfontMap.array[i].value;
321 device->SfontMap.array[i].value = NULL;
323 ALsoundfont_Destruct(temp);
325 memset(temp, 0, sizeof(*temp));
326 free(temp);