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
)
34 context
= GetContextRef();
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
));
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
));
60 alDeleteSoundfontsSOFT(cur
, ids
);
61 SET_ERROR_AND_GOTO(context
, err
, done
);
68 ALCcontext_DecRef(context
);
71 AL_API ALvoid AL_APIENTRY
alDeleteSoundfontsSOFT(ALsizei n
, const ALuint
*ids
)
78 context
= GetContextRef();
82 SET_ERROR_AND_GOTO(context
, AL_INVALID_VALUE
, done
);
84 device
= context
->Device
;
87 /* Check for valid soundfont ID */
90 if(!(sfont
=device
->DefaultSfont
))
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
);
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
);
111 else if((sfont
=RemoveSfont(device
, ids
[i
])) == NULL
)
114 ALsoundfont_Destruct(sfont
);
116 memset(sfont
, 0, sizeof(*sfont
));
121 ALCcontext_DecRef(context
);
124 AL_API ALboolean AL_APIENTRY
alIsSoundfontSOFT(ALuint id
)
129 context
= GetContextRef();
130 if(!context
) return AL_FALSE
;
132 ret
= ((!id
|| LookupSfont(context
->Device
, id
)) ?
135 ALCcontext_DecRef(context
);
140 AL_API
void AL_APIENTRY
alGetSoundfontivSOFT(ALuint id
, ALenum param
, ALint
*values
)
147 context
= GetContextRef();
150 device
= context
->Device
;
152 sfont
= ALsoundfont_getDefSoundfont(context
);
153 else if(!(sfont
=LookupSfont(device
, id
)))
154 SET_ERROR_AND_GOTO(context
, AL_INVALID_NAME
, done
);
157 case AL_PRESETS_SIZE_SOFT
:
158 values
[0] = sfont
->NumPresets
;
161 case AL_PRESETS_SOFT
:
162 for(i
= 0;i
< sfont
->NumPresets
;i
++)
163 values
[i
] = sfont
->Presets
[i
]->id
;
167 SET_ERROR_AND_GOTO(context
, AL_INVALID_ENUM
, done
);
171 ALCcontext_DecRef(context
);
174 AL_API
void AL_APIENTRY
alSoundfontPresetsSOFT(ALuint id
, ALsizei count
, const ALuint
*pids
)
179 ALsfpreset
**presets
;
182 context
= GetContextRef();
185 device
= context
->Device
;
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
);
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
);
204 presets
= calloc(count
, sizeof(presets
[0]));
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
])))
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
);
234 ALCcontext_DecRef(context
);
238 AL_API
void AL_APIENTRY
alLoadSoundfontSOFT(ALuint id
, size_t(*cb
)(ALvoid
*,size_t,ALvoid
*), ALvoid
*user
)
245 context
= GetContextRef();
248 device
= context
->Device
;
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
);
269 loadSf2(&reader
, sfont
, context
);
270 WriteUnlock(&sfont
->Lock
);
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
);
289 void ALsoundfont_Destruct(ALsoundfont
*self
)
293 FreeThunkEntry(self
->id
);
296 for(i
= 0;i
< self
->NumPresets
;i
++)
298 DecrementRef(&self
->Presets
[i
]->ref
);
299 self
->Presets
[i
] = NULL
;
302 self
->Presets
= NULL
;
303 self
->NumPresets
= 0;
306 ALsoundfont
*ALsoundfont_getDefSoundfont(ALCcontext
*context
)
308 ALCdevice
*device
= context
->Device
;
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
))
322 f
= OpenDataFile(fname
, "openal/soundfonts");
324 ERR("Failed to open %s\n", fname
);
328 reader
.cb
= ALsoundfont_read
;
331 TRACE("Loading %s\n", fname
);
332 loadSf2(&reader
, device
->DefaultSfont
, context
);
337 return device
->DefaultSfont
;
340 void ALsoundfont_deleteSoundfont(ALsoundfont
*self
, ALCdevice
*device
)
342 ALsfpreset
**presets
;
344 ALbuffer
*buffer
= NULL
;
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
;
358 sounds
= ExchangePtr((XchgPtr
*)&preset
->Sounds
, NULL
);
359 num_sounds
= ExchangeInt(&preset
->NumSounds
, 0);
361 DeletePreset(device
, preset
);
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
372 for(j
= 0;j
< num_sounds
;j
++)
374 if(sounds
[j
] && ReadRef(&sounds
[j
]->ref
) == 0)
378 buffer
= sounds
[j
]->Buffer
;
379 else if(sounds
[j
]->Buffer
)
380 assert(sounds
[j
]->Buffer
== buffer
);
381 DeleteFontsound(device
, sounds
[j
]);
389 ALsoundfont_Destruct(self
);
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
)
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
));