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
)
33 context
= GetContextRef();
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
));
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
));
59 alDeleteSoundfontsSOFT(cur
, ids
);
60 SET_ERROR_AND_GOTO(context
, err
, done
);
67 ALCcontext_DecRef(context
);
70 AL_API ALvoid AL_APIENTRY
alDeleteSoundfontsSOFT(ALsizei n
, const ALuint
*ids
)
77 context
= GetContextRef();
81 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
83 device
= context
->Device
;
86 /* Check for valid soundfont ID */
89 if(!(sfont
=device
->DefaultSfont
))
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
);
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
);
110 else if((sfont
=RemoveSfont(device
, ids
[i
])) == NULL
)
113 ALsoundfont_Destruct(sfont
);
115 memset(sfont
, 0, sizeof(*sfont
));
120 ALCcontext_DecRef(context
);
123 AL_API ALboolean AL_APIENTRY
alIsSoundfontSOFT(ALuint id
)
128 context
= GetContextRef();
129 if(!context
) return AL_FALSE
;
131 ret
= ((!id
|| LookupSfont(context
->Device
, id
)) ?
134 ALCcontext_DecRef(context
);
139 AL_API ALvoid AL_APIENTRY
alSoundfontSamplesSOFT(ALuint id
, ALenum type
, ALsizei count
, const ALvoid
*samples
)
146 context
= GetContextRef();
149 device
= context
->Device
;
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
);
157 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
159 WriteLock(&sfont
->Lock
);
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
);
168 sfont
->Samples
= ptr
;
169 sfont
->NumSamples
= count
;
171 memcpy(sfont
->Samples
, samples
, count
* sizeof(ALshort
));
173 WriteUnlock(&sfont
->Lock
);
176 ALCcontext_DecRef(context
);
179 AL_API
void AL_APIENTRY
alGetSoundfontSamplesSOFT(ALuint id
, ALsizei offset
, ALsizei count
, ALenum type
, ALvoid
*samples
)
185 context
= GetContextRef();
188 device
= context
->Device
;
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
);
205 /* TODO: Allow conversion. */
206 memcpy(samples
, sfont
->Samples
+ offset
*sizeof(ALshort
), count
* sizeof(ALshort
));
208 ReadUnlock(&sfont
->Lock
);
211 ALCcontext_DecRef(context
);
214 AL_API ALvoid
* AL_APIENTRY
alSoundfontMapSamplesSOFT(ALuint id
, ALsizei offset
, ALsizei length
)
221 context
= GetContextRef();
222 if(!context
) return NULL
;
224 device
= context
->Device
;
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
);
236 alSetError(context
, AL_INVALID_OPERATION
);
237 else if(ExchangeInt(&sfont
->Mapped
, AL_TRUE
) == AL_TRUE
)
238 alSetError(context
, AL_INVALID_OPERATION
);
240 ptr
= (ALbyte
*)sfont
->Samples
+ offset
;
241 ReadUnlock(&sfont
->Lock
);
244 ALCcontext_DecRef(context
);
249 AL_API ALvoid AL_APIENTRY
alSoundfontUnmapSamplesSOFT(ALuint id
)
255 context
= GetContextRef();
258 device
= context
->Device
;
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
);
267 ALCcontext_DecRef(context
);
270 AL_API
void AL_APIENTRY
alGetSoundfontivSOFT(ALuint id
, ALenum param
, ALint
*values
)
277 context
= GetContextRef();
280 device
= context
->Device
;
282 sfont
= ALsoundfont_getDefSoundfont(context
);
283 else if(!(sfont
=LookupSfont(device
, id
)))
284 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
287 case AL_PRESETS_SIZE_SOFT
:
288 values
[0] = sfont
->NumPresets
;
291 case AL_PRESETS_SOFT
:
292 for(i
= 0;i
< sfont
->NumPresets
;i
++)
293 values
[i
] = sfont
->Presets
[i
]->id
;
296 case AL_SAMPLE_LENGTH_SOFT
:
297 values
[0] = sfont
->NumSamples
;
300 case AL_FORMAT_TYPE_SOFT
:
301 values
[0] = AL_SHORT_SOFT
;
305 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
309 ALCcontext_DecRef(context
);
312 AL_API
void AL_APIENTRY
alSoundfontPresetsSOFT(ALuint id
, ALsizei count
, const ALuint
*pids
)
317 ALsfpreset
**presets
;
320 context
= GetContextRef();
323 device
= context
->Device
;
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
);
329 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
331 WriteLock(&sfont
->Lock
);
334 WriteUnlock(&sfont
->Lock
);
335 SET_ERROR_AND_GOTO(context
, AL_INVALID_OPERATION
, done
);
342 presets
= calloc(count
, sizeof(presets
[0]));
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
])))
354 WriteUnlock(&sfont
->Lock
);
355 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
360 for(i
= 0;i
< count
;i
++)
361 IncrementRef(&presets
[i
]->ref
);
363 presets
= ExchangePtr((XchgPtr
*)&sfont
->Presets
, presets
);
364 count
= ExchangeInt(&sfont
->NumPresets
, count
);
365 WriteUnlock(&sfont
->Lock
);
367 for(i
= 0;i
< count
;i
++)
368 DecrementRef(&presets
[i
]->ref
);
372 ALCcontext_DecRef(context
);
376 AL_API
void AL_APIENTRY
alLoadSoundfontSOFT(ALuint id
, size_t(*cb
)(ALvoid
*,size_t,ALvoid
*), ALvoid
*user
)
383 context
= GetContextRef();
386 device
= context
->Device
;
388 SET_ERROR_AND_GOTO(context
, AL_INVALID_OPERATION
, done
);
389 if(!(sfont
=LookupSfont(device
, id
)))
390 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
392 WriteLock(&sfont
->Lock
);
395 WriteUnlock(&sfont
->Lock
);
396 SET_ERROR_AND_GOTO(context
, AL_INVALID_OPERATION
, done
);
400 WriteUnlock(&sfont
->Lock
);
401 SET_ERROR_AND_GOTO(context
, AL_INVALID_OPERATION
, done
);
403 if(sfont
->NumPresets
> 0)
405 WriteUnlock(&sfont
->Lock
);
406 SET_ERROR_AND_GOTO(context
, AL_INVALID_OPERATION
, done
);
412 loadSf2(&reader
, sfont
, context
);
413 WriteUnlock(&sfont
->Lock
);
416 ALCcontext_DecRef(context
);
420 void ALsoundfont_Construct(ALsoundfont
*self
)
424 self
->Presets
= NULL
;
425 self
->NumPresets
= 0;
427 self
->Samples
= NULL
;
428 self
->NumSamples
= 0;
430 RWLockInit(&self
->Lock
);
431 self
->Mapped
= AL_FALSE
;
436 void ALsoundfont_Destruct(ALsoundfont
*self
)
440 FreeThunkEntry(self
->id
);
443 for(i
= 0;i
< self
->NumPresets
;i
++)
445 DecrementRef(&self
->Presets
[i
]->ref
);
446 self
->Presets
[i
] = NULL
;
449 self
->Presets
= NULL
;
450 self
->NumPresets
= 0;
453 self
->Samples
= NULL
;
454 self
->NumSamples
= 0;
457 ALsoundfont
*ALsoundfont_getDefSoundfont(ALCcontext
*context
)
459 ALCdevice
*device
= context
->Device
;
462 if(device
->DefaultSfont
)
463 return device
->DefaultSfont
;
465 device
->DefaultSfont
= calloc(1, sizeof(device
->DefaultSfont
[0]));
466 ALsoundfont_Construct(device
->DefaultSfont
);
468 fname
= getenv("ALSOFT_SOUNDFONT");
469 if((fname
&& fname
[0]) || ConfigValueStr("midi", "soundfont", &fname
))
473 f
= OpenDataFile(fname
, "openal/soundfonts");
475 ERR("Failed to open %s\n", fname
);
479 reader
.cb
= ALsoundfont_read
;
482 TRACE("Loading %s\n", fname
);
483 loadSf2(&reader
, device
->DefaultSfont
, context
);
488 return device
->DefaultSfont
;
491 void ALsoundfont_deleteSoundfont(ALsoundfont
*self
, ALCdevice
*device
)
493 ALsfpreset
**presets
;
497 presets
= ExchangePtr((XchgPtr
*)&self
->Presets
, NULL
);
498 num_presets
= ExchangeInt(&self
->NumPresets
, 0);
500 for(i
= 0;i
< num_presets
;i
++)
502 ALsfpreset
*preset
= presets
[i
];
503 ALfontsound
**sounds
;
508 sounds
= ExchangePtr((XchgPtr
*)&preset
->Sounds
, NULL
);
509 num_sounds
= ExchangeInt(&preset
->NumSounds
, 0);
510 DeletePreset(preset
, device
);
513 for(j
= 0;j
< num_sounds
;j
++)
514 DecrementRef(&sounds
[j
]->ref
);
515 /* Some fontsounds may not be immediately deletable because they're
516 * linked to another fontsound. When those fontsounds are deleted
517 * they should become deletable, so use a loop until all fontsounds
521 for(j
= 0;j
< num_sounds
;j
++)
523 if(sounds
[j
] && sounds
[j
]->ref
== 0)
526 RemoveFontsound(device
, sounds
[j
]->id
);
527 ALfontsound_Destruct(sounds
[j
]);
536 ALsoundfont_Destruct(self
);
541 static size_t ALsoundfont_read(ALvoid
*buf
, size_t bytes
, ALvoid
*ptr
)
543 return fread(buf
, 1, bytes
, (FILE*)ptr
);
547 /* ReleaseALSoundfonts
549 * Called to destroy any soundfonts that still exist on the device
551 void ReleaseALSoundfonts(ALCdevice
*device
)
554 for(i
= 0;i
< device
->SfontMap
.size
;i
++)
556 ALsoundfont
*temp
= device
->SfontMap
.array
[i
].value
;
557 device
->SfontMap
.array
[i
].value
= NULL
;
559 ALsoundfont_Destruct(temp
);
561 memset(temp
, 0, sizeof(*temp
));