Standardize some New/Delete methods
[openal-soft.git] / OpenAL32 / alSoundfont.c
blob6ba4772c474cf9cdee867154800b13b7a8f393d2
2 #include "config.h"
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
8 #include "alMain.h"
9 #include "alMidi.h"
10 #include "alThunk.h"
11 #include "alError.h"
12 #include <alBuffer.h>
14 #include "midi/base.h"
17 extern inline struct ALsoundfont *LookupSfont(ALCdevice *device, ALuint id);
18 extern inline struct ALsoundfont *RemoveSfont(ALCdevice *device, ALuint id);
20 void ALsoundfont_Construct(ALsoundfont *self);
21 void ALsoundfont_Destruct(ALsoundfont *self);
22 void ALsoundfont_deleteSoundfont(ALsoundfont *self, ALCdevice *device);
23 ALsoundfont *ALsoundfont_getDefSoundfont(ALCcontext *context);
24 static size_t ALsoundfont_read(ALvoid *buf, size_t bytes, ALvoid *ptr);
27 AL_API void AL_APIENTRY alGenSoundfontsSOFT(ALsizei n, ALuint *ids)
29 ALCdevice *device;
30 ALCcontext *context;
31 ALsizei cur = 0;
32 ALenum err;
34 context = GetContextRef();
35 if(!context) return;
37 if(!(n >= 0))
38 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
40 device = context->Device;
41 for(cur = 0;cur < n;cur++)
43 ALsoundfont *sfont = calloc(1, sizeof(ALsoundfont));
44 if(!sfont)
46 alDeleteSoundfontsSOFT(cur, ids);
47 SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
49 ALsoundfont_Construct(sfont);
51 err = NewThunkEntry(&sfont->id);
52 if(err == AL_NO_ERROR)
53 err = InsertUIntMapEntry(&device->SfontMap, sfont->id, sfont);
54 if(err != AL_NO_ERROR)
56 ALsoundfont_Destruct(sfont);
57 memset(sfont, 0, sizeof(ALsoundfont));
58 free(sfont);
60 alDeleteSoundfontsSOFT(cur, ids);
61 SET_ERROR_AND_GOTO(context, err, done);
64 ids[cur] = sfont->id;
67 done:
68 ALCcontext_DecRef(context);
71 AL_API ALvoid AL_APIENTRY alDeleteSoundfontsSOFT(ALsizei n, const ALuint *ids)
73 ALCdevice *device;
74 ALCcontext *context;
75 ALsoundfont *sfont;
76 ALsizei i;
78 context = GetContextRef();
79 if(!context) return;
81 if(!(n >= 0))
82 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
84 device = context->Device;
85 for(i = 0;i < n;i++)
87 /* Check for valid soundfont ID */
88 if(ids[i] == 0)
90 if(!(sfont=device->DefaultSfont))
91 continue;
93 else if((sfont=LookupSfont(device, ids[i])) == NULL)
94 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
95 if(ReadRef(&sfont->ref) != 0)
96 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
99 for(i = 0;i < n;i++)
101 if(ids[i] == 0)
103 MidiSynth *synth = device->Synth;
104 WriteLock(&synth->Lock);
105 if(device->DefaultSfont != NULL)
106 ALsoundfont_deleteSoundfont(device->DefaultSfont, device);
107 device->DefaultSfont = NULL;
108 WriteUnlock(&synth->Lock);
109 continue;
111 else if((sfont=RemoveSfont(device, ids[i])) == NULL)
112 continue;
114 ALsoundfont_Destruct(sfont);
116 memset(sfont, 0, sizeof(*sfont));
117 free(sfont);
120 done:
121 ALCcontext_DecRef(context);
124 AL_API ALboolean AL_APIENTRY alIsSoundfontSOFT(ALuint id)
126 ALCcontext *context;
127 ALboolean ret;
129 context = GetContextRef();
130 if(!context) return AL_FALSE;
132 ret = ((!id || LookupSfont(context->Device, id)) ?
133 AL_TRUE : AL_FALSE);
135 ALCcontext_DecRef(context);
137 return ret;
140 AL_API void AL_APIENTRY alGetSoundfontivSOFT(ALuint id, ALenum param, ALint *values)
142 ALCdevice *device;
143 ALCcontext *context;
144 ALsoundfont *sfont;
145 ALsizei i;
147 context = GetContextRef();
148 if(!context) return;
150 device = context->Device;
151 if(id == 0)
152 sfont = ALsoundfont_getDefSoundfont(context);
153 else if(!(sfont=LookupSfont(device, id)))
154 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
155 switch(param)
157 case AL_PRESETS_SIZE_SOFT:
158 values[0] = sfont->NumPresets;
159 break;
161 case AL_PRESETS_SOFT:
162 for(i = 0;i < sfont->NumPresets;i++)
163 values[i] = sfont->Presets[i]->id;
164 break;
166 default:
167 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
170 done:
171 ALCcontext_DecRef(context);
174 AL_API void AL_APIENTRY alSoundfontPresetsSOFT(ALuint id, ALsizei count, const ALuint *pids)
176 ALCdevice *device;
177 ALCcontext *context;
178 ALsoundfont *sfont;
179 ALsfpreset **presets;
180 ALsizei i;
182 context = GetContextRef();
183 if(!context) return;
185 device = context->Device;
186 if(id == 0)
187 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
188 if(!(sfont=LookupSfont(device, id)))
189 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
190 if(count < 0)
191 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
193 WriteLock(&sfont->Lock);
194 if(ReadRef(&sfont->ref) != 0)
196 WriteUnlock(&sfont->Lock);
197 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
200 if(count == 0)
201 presets = NULL;
202 else
204 presets = calloc(count, sizeof(presets[0]));
205 if(!presets)
207 WriteUnlock(&sfont->Lock);
208 SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
211 for(i = 0;i < count;i++)
213 if(!(presets[i]=LookupPreset(device, pids[i])))
215 free(presets);
216 WriteUnlock(&sfont->Lock);
217 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
222 for(i = 0;i < count;i++)
223 IncrementRef(&presets[i]->ref);
225 presets = ExchangePtr((XchgPtr*)&sfont->Presets, presets);
226 count = ExchangeInt(&sfont->NumPresets, count);
227 WriteUnlock(&sfont->Lock);
229 for(i = 0;i < count;i++)
230 DecrementRef(&presets[i]->ref);
231 free(presets);
233 done:
234 ALCcontext_DecRef(context);
238 AL_API void AL_APIENTRY alLoadSoundfontSOFT(ALuint id, size_t(*cb)(ALvoid*,size_t,ALvoid*), ALvoid *user)
240 ALCdevice *device;
241 ALCcontext *context;
242 ALsoundfont *sfont;
243 Reader reader;
245 context = GetContextRef();
246 if(!context) return;
248 device = context->Device;
249 if(id == 0)
250 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
251 if(!(sfont=LookupSfont(device, id)))
252 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
254 WriteLock(&sfont->Lock);
255 if(ReadRef(&sfont->ref) != 0)
257 WriteUnlock(&sfont->Lock);
258 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
260 if(sfont->NumPresets > 0)
262 WriteUnlock(&sfont->Lock);
263 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
266 reader.cb = cb;
267 reader.ptr = user;
268 reader.error = 0;
269 loadSf2(&reader, sfont, context);
270 WriteUnlock(&sfont->Lock);
272 done:
273 ALCcontext_DecRef(context);
277 void ALsoundfont_Construct(ALsoundfont *self)
279 InitRef(&self->ref, 0);
281 self->Presets = NULL;
282 self->NumPresets = 0;
284 RWLockInit(&self->Lock);
286 self->id = 0;
289 void ALsoundfont_Destruct(ALsoundfont *self)
291 ALsizei i;
293 FreeThunkEntry(self->id);
294 self->id = 0;
296 for(i = 0;i < self->NumPresets;i++)
298 DecrementRef(&self->Presets[i]->ref);
299 self->Presets[i] = NULL;
301 free(self->Presets);
302 self->Presets = NULL;
303 self->NumPresets = 0;
306 ALsoundfont *ALsoundfont_getDefSoundfont(ALCcontext *context)
308 ALCdevice *device = context->Device;
309 const char *fname;
311 if(device->DefaultSfont)
312 return device->DefaultSfont;
314 device->DefaultSfont = calloc(1, sizeof(device->DefaultSfont[0]));
315 ALsoundfont_Construct(device->DefaultSfont);
317 fname = getenv("ALSOFT_SOUNDFONT");
318 if((fname && fname[0]) || ConfigValueStr("midi", "soundfont", &fname))
320 FILE *f;
322 f = OpenDataFile(fname, "openal/soundfonts");
323 if(f == NULL)
324 ERR("Failed to open %s\n", fname);
325 else
327 Reader reader;
328 reader.cb = ALsoundfont_read;
329 reader.ptr = f;
330 reader.error = 0;
331 TRACE("Loading %s\n", fname);
332 loadSf2(&reader, device->DefaultSfont, context);
333 fclose(f);
337 return device->DefaultSfont;
340 void ALsoundfont_deleteSoundfont(ALsoundfont *self, ALCdevice *device)
342 ALsfpreset **presets;
343 ALsizei num_presets;
344 ALbuffer *buffer = NULL;
345 ALsizei i;
347 presets = ExchangePtr((XchgPtr*)&self->Presets, NULL);
348 num_presets = ExchangeInt(&self->NumPresets, 0);
350 for(i = 0;i < num_presets;i++)
352 ALsfpreset *preset = presets[i];
353 ALfontsound **sounds;
354 ALsizei num_sounds;
355 ALboolean deleting;
356 ALsizei j;
358 sounds = ExchangePtr((XchgPtr*)&preset->Sounds, NULL);
359 num_sounds = ExchangeInt(&preset->NumSounds, 0);
361 DeletePreset(device, preset);
362 preset = NULL;
364 for(j = 0;j < num_sounds;j++)
365 DecrementRef(&sounds[j]->ref);
366 /* Some fontsounds may not be immediately deletable because they're
367 * linked to another fontsound. When those fontsounds are deleted
368 * they should become deletable, so use a loop until all fontsounds
369 * are deleted. */
370 do {
371 deleting = AL_FALSE;
372 for(j = 0;j < num_sounds;j++)
374 if(sounds[j] && ReadRef(&sounds[j]->ref) == 0)
376 deleting = AL_TRUE;
377 if(!buffer)
378 buffer = sounds[j]->Buffer;
379 else if(sounds[j]->Buffer)
380 assert(sounds[j]->Buffer == buffer);
381 DeleteFontsound(device, sounds[j]);
382 sounds[j] = NULL;
385 } while(deleting);
386 free(sounds);
389 ALsoundfont_Destruct(self);
390 free(self);
392 if(buffer)
394 assert(ReadRef(&buffer->ref) == 0);
395 DeleteBuffer(device, buffer);
400 static size_t ALsoundfont_read(ALvoid *buf, size_t bytes, ALvoid *ptr)
402 return fread(buf, 1, bytes, (FILE*)ptr);
406 /* ReleaseALSoundfonts
408 * Called to destroy any soundfonts that still exist on the device
410 void ReleaseALSoundfonts(ALCdevice *device)
412 ALsizei i;
413 for(i = 0;i < device->SfontMap.size;i++)
415 ALsoundfont *temp = device->SfontMap.array[i].value;
416 device->SfontMap.array[i].value = NULL;
418 ALsoundfont_Destruct(temp);
420 memset(temp, 0, sizeof(*temp));
421 free(temp);