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
])))
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
);
371 ALCcontext_DecRef(context
);
375 AL_API
void AL_APIENTRY
alLoadSoundfontSOFT(ALuint id
, size_t(*cb
)(ALvoid
*,size_t,ALvoid
*), ALvoid
*user
)
382 context
= GetContextRef();
385 device
= context
->Device
;
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
);
394 WriteUnlock(&sfont
->Lock
);
395 SET_ERROR_AND_GOTO(context
, AL_INVALID_OPERATION
, done
);
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
);
411 loadSf2(&reader
, sfont
, context
);
412 WriteUnlock(&sfont
->Lock
);
415 ALCcontext_DecRef(context
);
419 void ALsoundfont_Construct(ALsoundfont
*self
)
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
;
435 void ALsoundfont_Destruct(ALsoundfont
*self
)
439 FreeThunkEntry(self
->id
);
442 for(i
= 0;i
< self
->NumPresets
;i
++)
444 DecrementRef(&self
->Presets
[i
]->ref
);
445 self
->Presets
[i
] = NULL
;
448 self
->Presets
= NULL
;
449 self
->NumPresets
= 0;
452 self
->Samples
= NULL
;
453 self
->NumSamples
= 0;
456 ALsoundfont
*ALsoundfont_getDefSoundfont(ALCcontext
*context
)
458 ALCdevice
*device
= context
->Device
;
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
))
472 f
= OpenDataFile(fname
, "openal/soundfonts");
474 ERR("Failed to open %s\n", fname
);
478 reader
.cb
= ALsoundfont_read
;
481 TRACE("Loading %s\n", fname
);
482 loadSf2(&reader
, device
->DefaultSfont
, context
);
487 return device
->DefaultSfont
;
490 void ALsoundfont_deleteSoundfont(ALsoundfont
*self
, ALCdevice
*device
)
492 ALsfpreset
**presets
;
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
;
507 sounds
= ExchangePtr((XchgPtr
*)&preset
->Sounds
, NULL
);
508 num_sounds
= ExchangeInt(&preset
->NumSounds
, 0);
509 DeletePreset(preset
, device
);
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
520 for(j
= 0;j
< num_sounds
;j
++)
522 if(sounds
[j
] && sounds
[j
]->ref
== 0)
525 RemoveFontsound(device
, sounds
[j
]->id
);
526 ALfontsound_Destruct(sounds
[j
]);
535 ALsoundfont_Destruct(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
)
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
));