15 #include "midi/base.h"
18 extern inline struct ALsoundfont
*LookupSfont(ALCdevice
*device
, ALuint id
);
19 extern inline struct ALsoundfont
*RemoveSfont(ALCdevice
*device
, ALuint id
);
21 static void ALsoundfont_Construct(ALsoundfont
*self
);
22 static void ALsoundfont_Destruct(ALsoundfont
*self
);
23 void ALsoundfont_deleteSoundfont(ALsoundfont
*self
, ALCdevice
*device
);
24 ALsoundfont
*ALsoundfont_getDefSoundfont(ALCcontext
*context
);
25 static size_t ALsoundfont_read(ALvoid
*buf
, size_t bytes
, ALvoid
*ptr
);
28 AL_API
void AL_APIENTRY
alGenSoundfontsSOFT(ALsizei n
, ALuint
*ids
)
35 context
= GetContextRef();
39 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
41 device
= context
->Device
;
42 for(cur
= 0;cur
< n
;cur
++)
44 ALsoundfont
*sfont
= calloc(1, sizeof(ALsoundfont
));
47 alDeleteSoundfontsSOFT(cur
, ids
);
48 SET_ERROR_AND_GOTO(context
, AL_OUT_OF_MEMORY
, done
);
50 ALsoundfont_Construct(sfont
);
52 err
= NewThunkEntry(&sfont
->id
);
53 if(err
== AL_NO_ERROR
)
54 err
= InsertUIntMapEntry(&device
->SfontMap
, sfont
->id
, sfont
);
55 if(err
!= AL_NO_ERROR
)
57 ALsoundfont_Destruct(sfont
);
58 memset(sfont
, 0, sizeof(ALsoundfont
));
61 alDeleteSoundfontsSOFT(cur
, ids
);
62 SET_ERROR_AND_GOTO(context
, err
, done
);
69 ALCcontext_DecRef(context
);
72 AL_API ALvoid AL_APIENTRY
alDeleteSoundfontsSOFT(ALsizei n
, const ALuint
*ids
)
79 context
= GetContextRef();
83 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
85 device
= context
->Device
;
88 /* Check for valid soundfont ID */
91 if(!(sfont
=device
->DefaultSfont
))
94 else if((sfont
=LookupSfont(device
, ids
[i
])) == NULL
)
95 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
96 if(ReadRef(&sfont
->ref
) != 0)
97 SET_ERROR_AND_GOTO(context
, AL_INVALID_OPERATION
, done
);
104 MidiSynth
*synth
= device
->Synth
;
105 WriteLock(&synth
->Lock
);
106 if(device
->DefaultSfont
!= NULL
)
107 ALsoundfont_deleteSoundfont(device
->DefaultSfont
, device
);
108 device
->DefaultSfont
= NULL
;
109 WriteUnlock(&synth
->Lock
);
112 else if((sfont
=RemoveSfont(device
, ids
[i
])) == NULL
)
115 ALsoundfont_Destruct(sfont
);
117 memset(sfont
, 0, sizeof(*sfont
));
122 ALCcontext_DecRef(context
);
125 AL_API ALboolean AL_APIENTRY
alIsSoundfontSOFT(ALuint id
)
130 context
= GetContextRef();
131 if(!context
) return AL_FALSE
;
133 ret
= ((!id
|| LookupSfont(context
->Device
, id
)) ?
136 ALCcontext_DecRef(context
);
141 AL_API
void AL_APIENTRY
alGetSoundfontivSOFT(ALuint id
, ALenum param
, ALint
*values
)
148 context
= GetContextRef();
151 device
= context
->Device
;
153 sfont
= ALsoundfont_getDefSoundfont(context
);
154 else if(!(sfont
=LookupSfont(device
, id
)))
155 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
158 case AL_PRESETS_SIZE_SOFT
:
159 values
[0] = sfont
->NumPresets
;
162 case AL_PRESETS_SOFT
:
163 for(i
= 0;i
< sfont
->NumPresets
;i
++)
164 values
[i
] = sfont
->Presets
[i
]->id
;
168 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
172 ALCcontext_DecRef(context
);
175 AL_API
void AL_APIENTRY
alSoundfontPresetsSOFT(ALuint id
, ALsizei count
, const ALuint
*pids
)
180 ALsfpreset
**presets
;
183 context
= GetContextRef();
186 device
= context
->Device
;
188 SET_ERROR_AND_GOTO(context
, AL_INVALID_OPERATION
, done
);
189 if(!(sfont
=LookupSfont(device
, id
)))
190 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
192 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
194 WriteLock(&sfont
->Lock
);
195 if(ReadRef(&sfont
->ref
) != 0)
197 WriteUnlock(&sfont
->Lock
);
198 SET_ERROR_AND_GOTO(context
, AL_INVALID_OPERATION
, done
);
205 presets
= calloc(count
, sizeof(presets
[0]));
208 WriteUnlock(&sfont
->Lock
);
209 SET_ERROR_AND_GOTO(context
, AL_OUT_OF_MEMORY
, done
);
212 for(i
= 0;i
< count
;i
++)
214 if(!(presets
[i
]=LookupPreset(device
, pids
[i
])))
217 WriteUnlock(&sfont
->Lock
);
218 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
223 for(i
= 0;i
< count
;i
++)
224 IncrementRef(&presets
[i
]->ref
);
226 presets
= ExchangePtr((XchgPtr
*)&sfont
->Presets
, presets
);
227 count
= ExchangeInt(&sfont
->NumPresets
, count
);
228 WriteUnlock(&sfont
->Lock
);
230 for(i
= 0;i
< count
;i
++)
231 DecrementRef(&presets
[i
]->ref
);
235 ALCcontext_DecRef(context
);
239 AL_API
void AL_APIENTRY
alLoadSoundfontSOFT(ALuint id
, size_t(*cb
)(ALvoid
*,size_t,ALvoid
*), ALvoid
*user
)
246 context
= GetContextRef();
249 device
= context
->Device
;
251 SET_ERROR_AND_GOTO(context
, AL_INVALID_OPERATION
, done
);
252 if(!(sfont
=LookupSfont(device
, id
)))
253 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
255 WriteLock(&sfont
->Lock
);
256 if(ReadRef(&sfont
->ref
) != 0)
258 WriteUnlock(&sfont
->Lock
);
259 SET_ERROR_AND_GOTO(context
, AL_INVALID_OPERATION
, done
);
261 if(sfont
->NumPresets
> 0)
263 WriteUnlock(&sfont
->Lock
);
264 SET_ERROR_AND_GOTO(context
, AL_INVALID_OPERATION
, done
);
270 loadSf2(&reader
, sfont
, context
);
271 WriteUnlock(&sfont
->Lock
);
274 ALCcontext_DecRef(context
);
278 static void ALsoundfont_Construct(ALsoundfont
*self
)
280 InitRef(&self
->ref
, 0);
282 self
->Presets
= NULL
;
283 self
->NumPresets
= 0;
285 RWLockInit(&self
->Lock
);
290 static void ALsoundfont_Destruct(ALsoundfont
*self
)
294 FreeThunkEntry(self
->id
);
297 for(i
= 0;i
< self
->NumPresets
;i
++)
299 DecrementRef(&self
->Presets
[i
]->ref
);
300 self
->Presets
[i
] = NULL
;
303 self
->Presets
= NULL
;
304 self
->NumPresets
= 0;
307 ALsoundfont
*ALsoundfont_getDefSoundfont(ALCcontext
*context
)
309 ALCdevice
*device
= context
->Device
;
310 al_string fname
= AL_STRING_INIT_STATIC();
311 const char *namelist
;
313 if(device
->DefaultSfont
)
314 return device
->DefaultSfont
;
316 device
->DefaultSfont
= calloc(1, sizeof(device
->DefaultSfont
[0]));
317 ALsoundfont_Construct(device
->DefaultSfont
);
319 namelist
= getenv("ALSOFT_SOUNDFONT");
320 if(!namelist
|| !namelist
[0])
321 ConfigValueStr("midi", "soundfont", &namelist
);
322 while(namelist
&& namelist
[0])
324 const char *next
, *end
;
327 while(*namelist
&& (isspace(*namelist
) || *namelist
== ','))
331 next
= strchr(namelist
, ',');
332 end
= next
? next
++ : (namelist
+strlen(namelist
));
333 while(--end
!= namelist
&& isspace(*end
)) {
337 al_string_append_range(&fname
, namelist
, end
+1);
340 f
= OpenDataFile(al_string_get_cstr(fname
), "openal/soundfonts");
342 ERR("Failed to open %s\n", al_string_get_cstr(fname
));
346 reader
.cb
= ALsoundfont_read
;
349 TRACE("Loading %s\n", al_string_get_cstr(fname
));
350 loadSf2(&reader
, device
->DefaultSfont
, context
);
354 al_string_clear(&fname
);
356 AL_STRING_DEINIT(fname
);
358 return device
->DefaultSfont
;
361 void ALsoundfont_deleteSoundfont(ALsoundfont
*self
, ALCdevice
*device
)
363 ALsfpreset
**presets
;
365 VECTOR(ALbuffer
*) buffers
;
368 VECTOR_INIT(buffers
);
369 presets
= ExchangePtr((XchgPtr
*)&self
->Presets
, NULL
);
370 num_presets
= ExchangeInt(&self
->NumPresets
, 0);
372 for(i
= 0;i
< num_presets
;i
++)
374 ALsfpreset
*preset
= presets
[i
];
375 ALfontsound
**sounds
;
380 sounds
= ExchangePtr((XchgPtr
*)&preset
->Sounds
, NULL
);
381 num_sounds
= ExchangeInt(&preset
->NumSounds
, 0);
383 DeletePreset(device
, preset
);
386 for(j
= 0;j
< num_sounds
;j
++)
387 DecrementRef(&sounds
[j
]->ref
);
388 /* Some fontsounds may not be immediately deletable because they're
389 * linked to another fontsound. When those fontsounds are deleted
390 * they should become deletable, so use a loop until all fontsounds
394 for(j
= 0;j
< num_sounds
;j
++)
396 if(sounds
[j
] && ReadRef(&sounds
[j
]->ref
) == 0)
401 if((buffer
=ATOMIC_LOAD(&sounds
[j
]->Buffer
)) != NULL
)
405 #define MATCH_BUFFER(_i) (buffer == *(_i))
406 VECTOR_FIND_IF(iter
, ALbuffer
*, buffers
, MATCH_BUFFER
);
407 if(iter
== VECTOR_ITER_END(buffers
))
408 VECTOR_PUSH_BACK(buffers
, buffer
);
411 DeleteFontsound(device
, sounds
[j
]);
419 ALsoundfont_Destruct(self
);
422 #define DELETE_BUFFER(iter) do { \
423 assert(ReadRef(&(*(iter))->ref) == 0); \
424 DeleteBuffer(device, *(iter)); \
426 VECTOR_FOR_EACH(ALbuffer
*, buffers
, DELETE_BUFFER
);
428 VECTOR_DEINIT(buffers
);
432 static size_t ALsoundfont_read(ALvoid
*buf
, size_t bytes
, ALvoid
*ptr
)
434 return fread(buf
, 1, bytes
, (FILE*)ptr
);
438 /* ReleaseALSoundfonts
440 * Called to destroy any soundfonts that still exist on the device
442 void ReleaseALSoundfonts(ALCdevice
*device
)
445 for(i
= 0;i
< device
->SfontMap
.size
;i
++)
447 ALsoundfont
*temp
= device
->SfontMap
.array
[i
].value
;
448 device
->SfontMap
.array
[i
].value
= NULL
;
450 ALsoundfont_Destruct(temp
);
452 memset(temp
, 0, sizeof(*temp
));