Identity gain step is 1, not 0
[openal-soft.git] / OpenAL32 / alSoundfont.c
bloba89ce4d137a0148525114bf951006c10c8a8e538
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"
13 #include "midi/base.h"
16 extern inline struct ALsoundfont *LookupSfont(ALCdevice *device, ALuint id);
17 extern inline struct ALsoundfont *RemoveSfont(ALCdevice *device, ALuint id);
19 void ALsoundfont_Construct(ALsoundfont *self);
20 void ALsoundfont_Destruct(ALsoundfont *self);
21 void ALsoundfont_deleteSoundfont(ALsoundfont *self, ALCdevice *device);
22 ALsoundfont *ALsoundfont_getDefSoundfont(ALCcontext *context);
23 static size_t ALsoundfont_read(ALvoid *buf, size_t bytes, ALvoid *ptr);
26 AL_API void AL_APIENTRY alGenSoundfontsSOFT(ALsizei n, ALuint *ids)
28 ALCdevice *device;
29 ALCcontext *context;
30 ALsizei cur = 0;
31 ALenum err;
33 context = GetContextRef();
34 if(!context) return;
36 if(!(n >= 0))
37 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
39 device = context->Device;
40 for(cur = 0;cur < n;cur++)
42 ALsoundfont *sfont = calloc(1, sizeof(ALsoundfont));
43 if(!sfont)
45 alDeleteSoundfontsSOFT(cur, ids);
46 SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
48 ALsoundfont_Construct(sfont);
50 err = NewThunkEntry(&sfont->id);
51 if(err == AL_NO_ERROR)
52 err = InsertUIntMapEntry(&device->SfontMap, sfont->id, sfont);
53 if(err != AL_NO_ERROR)
55 ALsoundfont_Destruct(sfont);
56 memset(sfont, 0, sizeof(ALsoundfont));
57 free(sfont);
59 alDeleteSoundfontsSOFT(cur, ids);
60 SET_ERROR_AND_GOTO(context, err, done);
63 ids[cur] = sfont->id;
66 done:
67 ALCcontext_DecRef(context);
70 AL_API ALvoid AL_APIENTRY alDeleteSoundfontsSOFT(ALsizei n, const ALuint *ids)
72 ALCdevice *device;
73 ALCcontext *context;
74 ALsoundfont *sfont;
75 ALsizei i;
77 context = GetContextRef();
78 if(!context) return;
80 if(!(n >= 0))
81 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
83 device = context->Device;
84 for(i = 0;i < n;i++)
86 /* Check for valid soundfont ID */
87 if(ids[i] == 0)
89 if(!(sfont=device->DefaultSfont))
90 continue;
92 else if((sfont=LookupSfont(device, ids[i])) == NULL)
93 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
94 if(sfont->Mapped != AL_FALSE || sfont->ref != 0)
95 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
98 for(i = 0;i < n;i++)
100 if(ids[i] == 0)
102 MidiSynth *synth = device->Synth;
103 WriteLock(&synth->Lock);
104 if(device->DefaultSfont != NULL)
105 ALsoundfont_deleteSoundfont(device->DefaultSfont, device);
106 device->DefaultSfont = NULL;
107 WriteUnlock(&synth->Lock);
108 continue;
110 else if((sfont=RemoveSfont(device, ids[i])) == NULL)
111 continue;
113 ALsoundfont_Destruct(sfont);
115 memset(sfont, 0, sizeof(*sfont));
116 free(sfont);
119 done:
120 ALCcontext_DecRef(context);
123 AL_API ALboolean AL_APIENTRY alIsSoundfontSOFT(ALuint id)
125 ALCcontext *context;
126 ALboolean ret;
128 context = GetContextRef();
129 if(!context) return AL_FALSE;
131 ret = ((!id || LookupSfont(context->Device, id)) ?
132 AL_TRUE : AL_FALSE);
134 ALCcontext_DecRef(context);
136 return ret;
139 AL_API ALvoid AL_APIENTRY alSoundfontSamplesSOFT(ALuint id, ALenum type, ALsizei count, const ALvoid *samples)
141 ALCdevice *device;
142 ALCcontext *context;
143 ALsoundfont *sfont;
144 void *ptr;
146 context = GetContextRef();
147 if(!context) return;
149 device = context->Device;
150 if(id == 0)
151 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
152 if(!(sfont=LookupSfont(device, id)))
153 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
154 if(type != AL_SHORT_SOFT)
155 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
156 if(count <= 0)
157 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
159 WriteLock(&sfont->Lock);
160 if(sfont->ref != 0)
161 alSetError(context, AL_INVALID_OPERATION);
162 else if(sfont->Mapped)
163 alSetError(context, AL_INVALID_OPERATION);
164 else if(!(ptr=realloc(sfont->Samples, count * sizeof(ALshort))))
165 alSetError(context, AL_OUT_OF_MEMORY);
166 else
168 sfont->Samples = ptr;
169 sfont->NumSamples = count;
170 if(samples != NULL)
171 memcpy(sfont->Samples, samples, count * sizeof(ALshort));
173 WriteUnlock(&sfont->Lock);
175 done:
176 ALCcontext_DecRef(context);
179 AL_API void AL_APIENTRY alGetSoundfontSamplesSOFT(ALuint id, ALsizei offset, ALsizei count, ALenum type, ALvoid *samples)
181 ALCdevice *device;
182 ALCcontext *context;
183 ALsoundfont *sfont;
185 context = GetContextRef();
186 if(!context) return;
188 device = context->Device;
189 if(id == 0)
190 sfont = ALsoundfont_getDefSoundfont(context);
191 else if(!(sfont=LookupSfont(device, id)))
192 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
193 if(type != AL_SHORT_SOFT)
194 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
195 if(offset < 0 || count <= 0)
196 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
198 ReadLock(&sfont->Lock);
199 if(offset >= sfont->NumSamples || count > (sfont->NumSamples-offset))
200 alSetError(context, AL_INVALID_VALUE);
201 else if(sfont->Mapped)
202 alSetError(context, AL_INVALID_OPERATION);
203 else
205 /* TODO: Allow conversion. */
206 memcpy(samples, sfont->Samples + offset*sizeof(ALshort), count * sizeof(ALshort));
208 ReadUnlock(&sfont->Lock);
210 done:
211 ALCcontext_DecRef(context);
214 AL_API ALvoid* AL_APIENTRY alSoundfontMapSamplesSOFT(ALuint id, ALsizei offset, ALsizei length)
216 ALCdevice *device;
217 ALCcontext *context;
218 ALsoundfont *sfont;
219 ALvoid *ptr = NULL;
221 context = GetContextRef();
222 if(!context) return NULL;
224 device = context->Device;
225 if(id == 0)
226 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
227 if(!(sfont=LookupSfont(device, id)))
228 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
229 if(offset < 0 || (ALuint)offset > sfont->NumSamples*sizeof(ALshort))
230 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
231 if(length <= 0 || (ALuint)length > (sfont->NumSamples*sizeof(ALshort) - offset))
232 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
234 ReadLock(&sfont->Lock);
235 if(sfont->ref != 0)
236 alSetError(context, AL_INVALID_OPERATION);
237 else if(ExchangeInt(&sfont->Mapped, AL_TRUE) == AL_TRUE)
238 alSetError(context, AL_INVALID_OPERATION);
239 else
240 ptr = (ALbyte*)sfont->Samples + offset;
241 ReadUnlock(&sfont->Lock);
243 done:
244 ALCcontext_DecRef(context);
246 return ptr;
249 AL_API ALvoid AL_APIENTRY alSoundfontUnmapSamplesSOFT(ALuint id)
251 ALCdevice *device;
252 ALCcontext *context;
253 ALsoundfont *sfont;
255 context = GetContextRef();
256 if(!context) return;
258 device = context->Device;
259 if(id == 0)
260 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
261 if(!(sfont=LookupSfont(device, id)))
262 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
263 if(ExchangeInt(&sfont->Mapped, AL_FALSE) == AL_FALSE)
264 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
266 done:
267 ALCcontext_DecRef(context);
270 AL_API void AL_APIENTRY alGetSoundfontivSOFT(ALuint id, ALenum param, ALint *values)
272 ALCdevice *device;
273 ALCcontext *context;
274 ALsoundfont *sfont;
275 ALsizei i;
277 context = GetContextRef();
278 if(!context) return;
280 device = context->Device;
281 if(id == 0)
282 sfont = ALsoundfont_getDefSoundfont(context);
283 else if(!(sfont=LookupSfont(device, id)))
284 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
285 switch(param)
287 case AL_PRESETS_SIZE_SOFT:
288 values[0] = sfont->NumPresets;
289 break;
291 case AL_PRESETS_SOFT:
292 for(i = 0;i < sfont->NumPresets;i++)
293 values[i] = sfont->Presets[i]->id;
294 break;
296 case AL_SAMPLE_LENGTH_SOFT:
297 values[0] = sfont->NumSamples;
298 break;
300 case AL_FORMAT_TYPE_SOFT:
301 values[0] = AL_SHORT_SOFT;
302 break;
304 default:
305 SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
308 done:
309 ALCcontext_DecRef(context);
312 AL_API void AL_APIENTRY alSoundfontPresetsSOFT(ALuint id, ALsizei count, const ALuint *pids)
314 ALCdevice *device;
315 ALCcontext *context;
316 ALsoundfont *sfont;
317 ALsfpreset **presets;
318 ALsizei i;
320 context = GetContextRef();
321 if(!context) return;
323 device = context->Device;
324 if(id == 0)
325 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
326 if(!(sfont=LookupSfont(device, id)))
327 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
328 if(count < 0)
329 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
331 WriteLock(&sfont->Lock);
332 if(sfont->ref != 0)
334 WriteUnlock(&sfont->Lock);
335 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
338 if(count == 0)
339 presets = NULL;
340 else
342 presets = calloc(count, sizeof(presets[0]));
343 if(!presets)
345 WriteUnlock(&sfont->Lock);
346 SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
349 for(i = 0;i < count;i++)
351 if(!(presets[i]=LookupPreset(device, pids[i])))
353 WriteUnlock(&sfont->Lock);
354 SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
359 for(i = 0;i < count;i++)
360 IncrementRef(&presets[i]->ref);
362 presets = ExchangePtr((XchgPtr*)&sfont->Presets, presets);
363 count = ExchangeInt(&sfont->NumPresets, count);
364 WriteUnlock(&sfont->Lock);
366 for(i = 0;i < count;i++)
367 DecrementRef(&presets[i]->ref);
368 free(presets);
370 done:
371 ALCcontext_DecRef(context);
375 AL_API void AL_APIENTRY alLoadSoundfontSOFT(ALuint id, size_t(*cb)(ALvoid*,size_t,ALvoid*), ALvoid *user)
377 ALCdevice *device;
378 ALCcontext *context;
379 ALsoundfont *sfont;
380 Reader reader;
382 context = GetContextRef();
383 if(!context) return;
385 device = context->Device;
386 if(id == 0)
387 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
388 if(!(sfont=LookupSfont(device, id)))
389 SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
391 WriteLock(&sfont->Lock);
392 if(sfont->ref != 0)
394 WriteUnlock(&sfont->Lock);
395 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
397 if(sfont->Mapped)
399 WriteUnlock(&sfont->Lock);
400 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
402 if(sfont->NumPresets > 0)
404 WriteUnlock(&sfont->Lock);
405 SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
408 reader.cb = cb;
409 reader.ptr = user;
410 reader.error = 0;
411 loadSf2(&reader, sfont, context);
412 WriteUnlock(&sfont->Lock);
414 done:
415 ALCcontext_DecRef(context);
419 void ALsoundfont_Construct(ALsoundfont *self)
421 self->ref = 0;
423 self->Presets = NULL;
424 self->NumPresets = 0;
426 self->Samples = NULL;
427 self->NumSamples = 0;
429 RWLockInit(&self->Lock);
430 self->Mapped = AL_FALSE;
432 self->id = 0;
435 void ALsoundfont_Destruct(ALsoundfont *self)
437 ALsizei i;
439 FreeThunkEntry(self->id);
440 self->id = 0;
442 for(i = 0;i < self->NumPresets;i++)
444 DecrementRef(&self->Presets[i]->ref);
445 self->Presets[i] = NULL;
447 free(self->Presets);
448 self->Presets = NULL;
449 self->NumPresets = 0;
451 free(self->Samples);
452 self->Samples = NULL;
453 self->NumSamples = 0;
456 ALsoundfont *ALsoundfont_getDefSoundfont(ALCcontext *context)
458 ALCdevice *device = context->Device;
459 const char *fname;
461 if(device->DefaultSfont)
462 return device->DefaultSfont;
464 device->DefaultSfont = calloc(1, sizeof(device->DefaultSfont[0]));
465 ALsoundfont_Construct(device->DefaultSfont);
467 fname = getenv("ALSOFT_SOUNDFONT");
468 if((fname && fname[0]) || ConfigValueStr("midi", "soundfont", &fname))
470 FILE *f;
472 f = OpenDataFile(fname, "openal/soundfonts");
473 if(f == NULL)
474 ERR("Failed to open %s\n", fname);
475 else
477 Reader reader;
478 reader.cb = ALsoundfont_read;
479 reader.ptr = f;
480 reader.error = 0;
481 TRACE("Loading %s\n", fname);
482 loadSf2(&reader, device->DefaultSfont, context);
483 fclose(f);
487 return device->DefaultSfont;
490 void ALsoundfont_deleteSoundfont(ALsoundfont *self, ALCdevice *device)
492 ALsfpreset **presets;
493 ALsizei num_presets;
494 ALsizei i;
496 presets = ExchangePtr((XchgPtr*)&self->Presets, NULL);
497 num_presets = ExchangeInt(&self->NumPresets, 0);
499 for(i = 0;i < num_presets;i++)
501 ALsfpreset *preset = presets[i];
502 ALfontsound **sounds;
503 ALsizei num_sounds;
504 ALboolean deleting;
505 ALsizei j;
507 sounds = ExchangePtr((XchgPtr*)&preset->Sounds, NULL);
508 num_sounds = ExchangeInt(&preset->NumSounds, 0);
509 DeletePreset(preset, device);
510 preset = NULL;
512 for(j = 0;j < num_sounds;j++)
513 DecrementRef(&sounds[j]->ref);
514 /* Some fontsounds may not be immediately deletable because they're
515 * linked to another fontsound. When those fontsounds are deleted
516 * they should become deletable, so use a loop until all fontsounds
517 * are deleted. */
518 do {
519 deleting = AL_FALSE;
520 for(j = 0;j < num_sounds;j++)
522 if(sounds[j] && sounds[j]->ref == 0)
524 deleting = AL_TRUE;
525 RemoveFontsound(device, sounds[j]->id);
526 ALfontsound_Destruct(sounds[j]);
527 free(sounds[j]);
528 sounds[j] = NULL;
531 } while(deleting);
532 free(sounds);
535 ALsoundfont_Destruct(self);
536 free(self);
540 static size_t ALsoundfont_read(ALvoid *buf, size_t bytes, ALvoid *ptr)
542 return fread(buf, 1, bytes, (FILE*)ptr);
546 /* ReleaseALSoundfonts
548 * Called to destroy any soundfonts that still exist on the device
550 void ReleaseALSoundfonts(ALCdevice *device)
552 ALsizei i;
553 for(i = 0;i < device->SfontMap.size;i++)
555 ALsoundfont *temp = device->SfontMap.array[i].value;
556 device->SfontMap.array[i].value = NULL;
558 ALsoundfont_Destruct(temp);
560 memset(temp, 0, sizeof(*temp));
561 free(temp);