Allow "deleting" the default soundfont

The ID remains valid and the soundfont will be reloaded as needed, but this
provides a way for the application to clear up the soundfont memory.
This commit is contained in:
Chris Robinson 2014-01-04 05:30:57 -08:00
parent bb54743425
commit 540a99e71f
4 changed files with 68 additions and 53 deletions

View File

@ -1950,54 +1950,7 @@ static ALCvoid FreeDevice(ALCdevice *device)
} }
if(device->DefaultSfont) if(device->DefaultSfont)
{ MidiSynth_deleteSoundfont(device, device->DefaultSfont);
ALsoundfont *sfont = device->DefaultSfont;
ALsfpreset **presets;
ALsizei num_presets;
ALsizei i;
presets = ExchangePtr((XchgPtr*)&sfont->Presets, NULL);
num_presets = ExchangeInt(&sfont->NumPresets, 0);
for(i = 0;i < num_presets;i++)
{
ALsfpreset *preset = presets[i];
ALfontsound **sounds;
ALsizei num_sounds;
ALboolean deleting;
ALsizei j;
sounds = ExchangePtr((XchgPtr*)&preset->Sounds, NULL);
num_sounds = ExchangeInt(&preset->NumSounds, 0);
DeletePreset(preset, device);
preset = NULL;
for(j = 0;j < num_sounds;j++)
DecrementRef(&sounds[j]->ref);
/* Some fontsounds may not be immediately deletable because they're
* linked to another fontsound. When those fontsounds are deleted
* they should become deletable, so use a loop until all fontsounds
* are deleted. */
do {
deleting = AL_FALSE;
for(j = 0;j < num_sounds;j++)
{
if(sounds[j] && sounds[j]->ref == 0)
{
deleting = AL_TRUE;
RemoveFontsound(device, sounds[j]->id);
ALfontsound_Destruct(sounds[j]);
free(sounds[j]);
sounds[j] = NULL;
}
}
} while(deleting);
free(sounds);
}
ALsoundfont_Destruct(sfont);
free(sfont);
}
device->DefaultSfont = NULL; device->DefaultSfont = NULL;
if(device->BufferMap.size > 0) if(device->BufferMap.size > 0)

View File

@ -188,6 +188,55 @@ ALsoundfont *MidiSynth_getDefSoundfont(ALCcontext *context)
return device->DefaultSfont; return device->DefaultSfont;
} }
void MidiSynth_deleteSoundfont(ALCdevice *device, ALsoundfont *sfont)
{
ALsfpreset **presets;
ALsizei num_presets;
ALsizei i;
presets = ExchangePtr((XchgPtr*)&sfont->Presets, NULL);
num_presets = ExchangeInt(&sfont->NumPresets, 0);
for(i = 0;i < num_presets;i++)
{
ALsfpreset *preset = presets[i];
ALfontsound **sounds;
ALsizei num_sounds;
ALboolean deleting;
ALsizei j;
sounds = ExchangePtr((XchgPtr*)&preset->Sounds, NULL);
num_sounds = ExchangeInt(&preset->NumSounds, 0);
DeletePreset(preset, device);
preset = NULL;
for(j = 0;j < num_sounds;j++)
DecrementRef(&sounds[j]->ref);
/* Some fontsounds may not be immediately deletable because they're
* linked to another fontsound. When those fontsounds are deleted
* they should become deletable, so use a loop until all fontsounds
* are deleted. */
do {
deleting = AL_FALSE;
for(j = 0;j < num_sounds;j++)
{
if(sounds[j] && sounds[j]->ref == 0)
{
deleting = AL_TRUE;
RemoveFontsound(device, sounds[j]->id);
ALfontsound_Destruct(sounds[j]);
free(sounds[j]);
sounds[j] = NULL;
}
}
} while(deleting);
free(sounds);
}
ALsoundfont_Destruct(sfont);
free(sfont);
}
ALenum MidiSynth_selectSoundfonts(MidiSynth *self, ALCcontext *context, ALsizei count, const ALuint *ids) ALenum MidiSynth_selectSoundfonts(MidiSynth *self, ALCcontext *context, ALsizei count, const ALuint *ids)
{ {
ALCdevice *device = context->Device; ALCdevice *device = context->Device;

View File

@ -53,6 +53,7 @@ typedef struct MidiSynth {
void MidiSynth_Construct(MidiSynth *self, ALCdevice *device); void MidiSynth_Construct(MidiSynth *self, ALCdevice *device);
void MidiSynth_Destruct(MidiSynth *self); void MidiSynth_Destruct(MidiSynth *self);
struct ALsoundfont *MidiSynth_getDefSoundfont(ALCcontext *context); struct ALsoundfont *MidiSynth_getDefSoundfont(ALCcontext *context);
void MidiSynth_deleteSoundfont(ALCdevice *device, struct ALsoundfont *sfont);
ALenum MidiSynth_selectSoundfonts(MidiSynth *self, ALCcontext *context, ALsizei count, const ALuint *ids); ALenum MidiSynth_selectSoundfonts(MidiSynth *self, ALCcontext *context, ALsizei count, const ALuint *ids);
inline void MidiSynth_setGain(MidiSynth *self, ALfloat gain) { self->Gain = gain; } inline void MidiSynth_setGain(MidiSynth *self, ALfloat gain) { self->Gain = gain; }
inline ALfloat MidiSynth_getGain(const MidiSynth *self) { return self->Gain; } inline ALfloat MidiSynth_getGain(const MidiSynth *self) { return self->Gain; }

View File

@ -76,11 +76,13 @@ AL_API ALvoid AL_APIENTRY alDeleteSoundfontsSOFT(ALsizei n, const ALuint *ids)
device = context->Device; device = context->Device;
for(i = 0;i < n;i++) for(i = 0;i < n;i++)
{ {
if(!ids[i])
continue;
/* Check for valid soundfont ID */ /* Check for valid soundfont ID */
if((sfont=LookupSfont(device, ids[i])) == NULL) if(ids[i] == 0)
{
if(!(sfont=device->DefaultSfont))
continue;
}
else if((sfont=LookupSfont(device, ids[i])) == NULL)
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
if(sfont->Mapped != AL_FALSE || sfont->ref != 0) if(sfont->Mapped != AL_FALSE || sfont->ref != 0)
SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done); SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
@ -88,7 +90,17 @@ AL_API ALvoid AL_APIENTRY alDeleteSoundfontsSOFT(ALsizei n, const ALuint *ids)
for(i = 0;i < n;i++) for(i = 0;i < n;i++)
{ {
if((sfont=RemoveSfont(device, ids[i])) == NULL) if(ids[i] == 0)
{
MidiSynth *synth = device->Synth;
WriteLock(&synth->Lock);
if(device->DefaultSfont != NULL)
MidiSynth_deleteSoundfont(device, device->DefaultSfont);
device->DefaultSfont = NULL;
WriteUnlock(&synth->Lock);
continue;
}
else if((sfont=RemoveSfont(device, ids[i])) == NULL)
continue; continue;
ALsoundfont_Destruct(sfont); ALsoundfont_Destruct(sfont);