memory management for openalbridge
added openalbridge as dependency of hwengine
usound formatted clearly
--- a/CMakeLists.txt Sun Jun 20 22:46:23 2010 -0400
+++ b/CMakeLists.txt Mon Jun 21 16:08:24 2010 +0200
@@ -183,6 +183,7 @@
endif(WITH_SERVER)
add_subdirectory(hedgewars)
+add_subdirectory(misc/libopenalbridge)
if(NOT BUILD_ENGINE_LIBRARY)
add_subdirectory(bin)
add_subdirectory(QTfrontend)
--- a/hedgewars/CMakeLists.txt Sun Jun 20 22:46:23 2010 -0400
+++ b/hedgewars/CMakeLists.txt Mon Jun 21 16:08:24 2010 +0200
@@ -76,6 +76,7 @@
SinTable.inc
options.inc
${CMAKE_CURRENT_BINARY_DIR}/config.inc
+ openalbridge
)
if(BUILD_ENGINE_LIBRARY)
--- a/hedgewars/uSound.pas Sun Jun 20 22:46:23 2010 -0400
+++ b/hedgewars/uSound.pas Mon Jun 21 16:08:24 2010 +0200
@@ -40,8 +40,8 @@
procedure PlaySound(snd: TSound; keepPlaying: boolean);
procedure PlaySound(snd: TSound; voicepack: PVoicepack);
procedure PlaySound(snd: TSound; voicepack: PVoicepack; keepPlaying: boolean);
-function LoopSound(snd: TSound): LongInt;
-function LoopSound(snd: TSound; voicepack: PVoicepack): LongInt;
+function LoopSound(snd: TSound): LongInt;
+function LoopSound(snd: TSound; voicepack: PVoicepack): LongInt;
procedure PlayMusic;
procedure PauseMusic;
procedure ResumeMusic;
@@ -65,14 +65,14 @@
var i: Longword;
begin
i:= 0;
-while (voicepacks[i].name <> name) and (voicepacks[i].name <> '') do
+ while (voicepacks[i].name <> name) and (voicepacks[i].name <> '') do
begin
- inc(i);
- TryDo(i <= cMaxTeams, 'Engine bug: AskForVoicepack i > cMaxTeams', true)
+ inc(i);
+ TryDo(i <= cMaxTeams, 'Engine bug: AskForVoicepack i > cMaxTeams', true)
end;
-voicepacks[i].name:= name;
-AskForVoicepack:= @voicepacks[i]
+ voicepacks[i].name:= name;
+ AskForVoicepack:= @voicepacks[i]
end;
procedure InitSound;
@@ -110,22 +110,22 @@
var i: TSound;
t: Longword;
begin
-for t:= 0 to cMaxTeams do
- if voicepacks[t].name <> '' then
- for i:= Low(TSound) to High(TSound) do
- if voicepacks[t].chunks[i] <> nil then
- Mix_FreeChunk(voicepacks[t].chunks[i]);
+ for t:= 0 to cMaxTeams do
+ if voicepacks[t].name <> '' then
+ for i:= Low(TSound) to High(TSound) do
+ if voicepacks[t].chunks[i] <> nil then
+ Mix_FreeChunk(voicepacks[t].chunks[i]);
-if Mus <> nil then
- Mix_FreeMusic(Mus);
+ if Mus <> nil then
+ Mix_FreeMusic(Mus);
{$IFDEF SDL_MIXER_NEWER}
-// make sure all instances of sdl_mixer are unloaded before continuing
-while Mix_Init(0) <> 0 do
- Mix_Quit();
+ // make sure all instances of sdl_mixer are unloaded before continuing
+ while Mix_Init(0) <> 0 do
+ Mix_Quit();
{$ENDIF}
-Mix_CloseAudio();
+ Mix_CloseAudio();
end;
procedure SoundLoad;
@@ -137,28 +137,28 @@
defVoicepack:= AskForVoicepack('Default');
-for i:= Low(TSound) to High(TSound) do
- if (Soundz[i].Path <> ptVoices) and (Soundz[i].FileName <> '') then
+ for i:= Low(TSound) to High(TSound) do
+ if (Soundz[i].Path <> ptVoices) and (Soundz[i].FileName <> '') then
begin
- s:= Pathz[Soundz[i].Path] + '/' + Soundz[i].FileName;
- WriteToConsole(msgLoading + s + ' ');
- defVoicepack^.chunks[i]:= Mix_LoadWAV_RW(SDL_RWFromFile(Str2PChar(s), 'rb'), 1);
- TryDo(defVoicepack^.chunks[i] <> nil, msgFailed, true);
- WriteLnToConsole(msgOK);
+ s:= Pathz[Soundz[i].Path] + '/' + Soundz[i].FileName;
+ WriteToConsole(msgLoading + s + ' ');
+ defVoicepack^.chunks[i]:= Mix_LoadWAV_RW(SDL_RWFromFile(Str2PChar(s), 'rb'), 1);
+ TryDo(defVoicepack^.chunks[i] <> nil, msgFailed, true);
+ WriteLnToConsole(msgOK);
end;
-for t:= 0 to cMaxTeams do
- if voicepacks[t].name <> '' then
- for i:= Low(TSound) to High(TSound) do
- if (Soundz[i].Path = ptVoices) and (Soundz[i].FileName <> '') then
+ for t:= 0 to cMaxTeams do
+ if voicepacks[t].name <> '' then
+ for i:= Low(TSound) to High(TSound) do
+ if (Soundz[i].Path = ptVoices) and (Soundz[i].FileName <> '') then
begin
- s:= Pathz[Soundz[i].Path] + '/' + voicepacks[t].name + '/' + Soundz[i].FileName;
- WriteToConsole(msgLoading + s + ' ');
- voicepacks[t].chunks[i]:= Mix_LoadWAV_RW(SDL_RWFromFile(Str2PChar(s), 'rb'), 1);
- if voicepacks[t].chunks[i] = nil then
- WriteLnToConsole(msgFailed)
- else
- WriteLnToConsole(msgOK)
+ s:= Pathz[Soundz[i].Path] + '/' + voicepacks[t].name + '/' + Soundz[i].FileName;
+ WriteToConsole(msgLoading + s + ' ');
+ voicepacks[t].chunks[i]:= Mix_LoadWAV_RW(SDL_RWFromFile(Str2PChar(s), 'rb'), 1);
+ if voicepacks[t].chunks[i] = nil then
+ WriteLnToConsole(msgFailed)
+ else
+ WriteLnToConsole(msgOK)
end;
end;
@@ -179,15 +179,16 @@
procedure PlaySound(snd: TSound; voicepack: PVoicepack; keepPlaying: boolean);
begin
-if (not isSoundEnabled) or fastUntilLag then exit;
-
-if keepPlaying and (lastChan[snd] <> -1) and (Mix_Playing(lastChan[snd]) <> 0) then
- exit;
+ if (not isSoundEnabled) or fastUntilLag then
+ exit;
-if (voicepack <> nil) and (voicepack^.chunks[snd] <> nil) then
- lastChan[snd]:= Mix_PlayChannelTimed(-1, voicepack^.chunks[snd], 0, -1)
-else
- lastChan[snd]:= Mix_PlayChannelTimed(-1, defVoicepack^.chunks[snd], 0, -1)
+ if keepPlaying and (lastChan[snd] <> -1) and (Mix_Playing(lastChan[snd]) <> 0) then
+ exit;
+
+ if (voicepack <> nil) and (voicepack^.chunks[snd] <> nil) then
+ lastChan[snd]:= Mix_PlayChannelTimed(-1, voicepack^.chunks[snd], 0, -1)
+ else
+ lastChan[snd]:= Mix_PlayChannelTimed(-1, defVoicepack^.chunks[snd], 0, -1)
end;
function LoopSound(snd: TSound): LongInt;
@@ -197,76 +198,79 @@
function LoopSound(snd: TSound; voicepack: PVoicepack): LongInt;
begin
-if (not isSoundEnabled) or fastUntilLag then
+ if (not isSoundEnabled) or fastUntilLag then
begin
- LoopSound:= -1;
- exit
+ LoopSound:= -1;
+ exit
end;
-if (voicepack <> nil) and (voicepack^.chunks[snd] <> nil) then
- LoopSound:= Mix_PlayChannelTimed(-1, voicepack^.chunks[snd], -1, -1)
-else
- LoopSound:= Mix_PlayChannelTimed(-1, defVoicepack^.chunks[snd], -1, -1)
+ if (voicepack <> nil) and (voicepack^.chunks[snd] <> nil) then
+ LoopSound:= Mix_PlayChannelTimed(-1, voicepack^.chunks[snd], -1, -1)
+ else
+ LoopSound:= Mix_PlayChannelTimed(-1, defVoicepack^.chunks[snd], -1, -1)
end;
procedure StopSound(snd: TSound);
begin
-if not isSoundEnabled then exit;
-if (lastChan[snd] <> -1) and (Mix_Playing(lastChan[snd]) <> 0) then
+ if not isSoundEnabled then exit;
+ if (lastChan[snd] <> -1) and (Mix_Playing(lastChan[snd]) <> 0) then
begin
- Mix_HaltChannel(lastChan[snd]);
- lastChan[snd]:= -1;
+ Mix_HaltChannel(lastChan[snd]);
+ lastChan[snd]:= -1;
end;
end;
procedure StopSound(chn: LongInt);
begin
-if not isSoundEnabled then exit;
-if (chn <> -1) and (Mix_Playing(chn) <> 0) then Mix_HaltChannel(chn);
+ if not isSoundEnabled then exit;
+
+ if (chn <> -1) and (Mix_Playing(chn) <> 0) then
+ Mix_HaltChannel(chn);
end;
procedure PlayMusic;
var s: shortstring;
begin
-if (not isSoundEnabled)
- or (MusicFN = '')
- or (not isMusicEnabled) then exit;
+ if (not isSoundEnabled) or (MusicFN = '') or (not isMusicEnabled) then
+ exit;
+
+ s:= PathPrefix + '/Music/' + MusicFN;
+ WriteToConsole(msgLoading + s + ' ');
-s:= PathPrefix + '/Music/' + MusicFN;
-WriteToConsole(msgLoading + s + ' ');
+ Mus:= Mix_LoadMUS(Str2PChar(s));
+ TryDo(Mus <> nil, msgFailed, false);
+ WriteLnToConsole(msgOK);
-Mus:= Mix_LoadMUS(Str2PChar(s));
-TryDo(Mus <> nil, msgFailed, false);
-WriteLnToConsole(msgOK);
-
-SDLTry(Mix_FadeInMusic(Mus, -1, 3000) <> -1, false)
+ SDLTry(Mix_FadeInMusic(Mus, -1, 3000) <> -1, false)
end;
function ChangeVolume(voldelta: LongInt): LongInt;
begin
-if not isSoundEnabled then
- exit(0);
+ if not isSoundEnabled then
+ exit(0);
-inc(Volume, voldelta);
-if Volume < 0 then Volume:= 0;
-Mix_Volume(-1, Volume);
-Volume:= Mix_Volume(-1, -1);
-if isMusicEnabled then Mix_VolumeMusic(Volume * 4 div 8);
-ChangeVolume:= Volume * 100 div MIX_MAX_VOLUME
+ inc(Volume, voldelta);
+ if Volume < 0 then Volume:= 0;
+ Mix_Volume(-1, Volume);
+ Volume:= Mix_Volume(-1, -1);
+ if isMusicEnabled then Mix_VolumeMusic(Volume * 4 div 8);
+ ChangeVolume:= Volume * 100 div MIX_MAX_VOLUME
end;
procedure PauseMusic;
begin
-if (MusicFN = '') or (not isMusicEnabled) then exit;
+ if (MusicFN = '') or (not isMusicEnabled) then
+ exit;
-Mix_PauseMusic(Mus);
+ Mix_PauseMusic(Mus);
end;
procedure ResumeMusic;
begin
-if (MusicFN = '') or (not isMusicEnabled) then exit;
+ if (MusicFN = '') or (not isMusicEnabled) then
+ exit;
-Mix_ResumeMusic(Mus);
+ Mix_ResumeMusic(Mus);
end;
procedure initModule;
--- a/misc/libopenalbridge/CMakeLists.txt Sun Jun 20 22:46:23 2010 -0400
+++ b/misc/libopenalbridge/CMakeLists.txt Mon Jun 21 16:08:24 2010 +0200
@@ -7,9 +7,7 @@
set(LIBRARY_OUTPUT_PATH ${EXECUTABLE_OUTPUT_PATH})
#list of source files for libraries
-set(openal_src
- openalbridge.c loaders.c wrappers.c errlib.c
-)
+set(openal_src openalbridge.c loaders.c wrappers.c commands.c)
#build a static library for human systems
set (build_type STATIC)
@@ -17,9 +15,7 @@
#visualstudio and windows in general don't like static linking, so we're building the library in shared mode
if(WIN32)
#workaround for visualstudio (wants headers in the source list)
- set(openal_src
- openalbridge.h openalbridge_t.h loaders.h wrappers.h globals.h oggvorbis.h errlib.h ${openal_src}
- )
+ set(openal_src *.h ${openal_src})
#deps for the shared library
link_libraries(${VORBISFILE_LIBRARY})
link_libraries(${VORBIS_LIBRARY})
@@ -39,3 +35,8 @@
#install it in the executable directory
install(TARGETS openalbridge DESTINATION bin)
endif(WIN32)
+
+#type make openalbridge_test to get a small executable test
+add_executable(openalbridge_test "${hedgewars_SOURCE_DIR}/misc/libopenalbridge/tester.c")
+target_link_libraries(openalbridge_test openalbridge ${OPENAL_LIBRARY} ${OGGVORBIS_LIBRARIES})
+
--- a/misc/libopenalbridge/commands.c Sun Jun 20 22:46:23 2010 -0400
+++ b/misc/libopenalbridge/commands.c Mon Jun 21 16:08:24 2010 +0200
@@ -92,8 +92,6 @@
fprintf(stderr,"(Bridge Warning) - failed to play sound %d\n", index);
return;
}
-
- the_sounds[index].stats++;
}
}
--- a/misc/libopenalbridge/openalbridge.c Sun Jun 20 22:46:23 2010 -0400
+++ b/misc/libopenalbridge/openalbridge.c Mon Jun 21 16:08:24 2010 +0200
@@ -34,22 +34,14 @@
// Initialize an OpenAL contex and allocate memory space for data and buffers
// It can be called twice to increase the cache size
-int openal_init (int memorysize) {
+int openal_init (void) {
ALCcontext *context;
ALCdevice *device;
int i;
// reuse old context and resize the existing
if (openal_ready() == AL_TRUE) {
- cache_size += memorysize;
- fprintf(stderr,"(Bridge Info) - already initialized, resizing cache to %d\n", cache_size);
- the_sounds = (al_sound_t *)Realloc (the_sounds, sizeof(al_sound_t) * cache_size);
- for (i = cache_size - memorysize; i < cache_size; i++) {
- the_sounds[i].filename = NULL;
- the_sounds[i].buffer = -1;
- the_sounds[i].source_index = -1;
- the_sounds[i].stats = 0;
- }
+ fprintf(stderr,"(Bridge Info) - already initialized\n");
instances_number++;
return AL_TRUE;
}
@@ -57,12 +49,9 @@
cache_pointer = 0;
instances_number++;
- // set the memory dimentsion and the increment width when reallocating
- if (memorysize <= 0)
- cache_size = 50;
- else
- cache_size = memorysize;
-
+ // initial memory size
+ cache_size = 50;
+
// open hardware device if present
device = alcOpenDevice(NULL);
sources_number = 16;
@@ -110,12 +99,8 @@
}
the_sounds = (al_sound_t *)Malloc (sizeof(al_sound_t) * cache_size);
- for (i = 0; i < cache_size; i++) {
- the_sounds[i].filename = NULL;
- the_sounds[i].buffer = -1;
- the_sounds[i].source_index = -1;
- the_sounds[i].stats = 0;
- }
+ for (i = 0; i < cache_size; i++)
+ the_sounds[i] = new_sound_el();
alGetError();
return AL_TRUE;
@@ -135,15 +120,16 @@
instances_number--;
if (instances_number > 0) {
+ // release memory only when last session ends
return;
}
- //TODO: free other stuff also
- for (i = 0; i < cache_size; i++)
- alDeleteBuffers (1, &the_sounds[i].buffer);
+ for (i = 0; i < cache_size; i++) {
+ openal_unloadfile(i);
+ }
free(the_sounds);
- alSourceStopv (sources_number, Sources);
+ alSourceStopv (sources_number, Sources);
alDeleteSources (sources_number, Sources);
free(Sources);
@@ -174,8 +160,8 @@
ALenum format, error;
ALsizei bitsize, freq;
uint32_t fileformat;
- al_sound_t soundData;
- int len, i;
+ al_sound_t sound_data;
+ int len, i, index = -1;
char *data;
FILE *fp;
@@ -193,16 +179,24 @@
#endif
return i;
}
+ // if we don't have memory available search for a free element
+ if (cache_pointer >= cache_size)
+ if (the_sounds[i].is_used == AL_FALSE)
+ index = i;
}
- if (cache_pointer >= cache_size) {
- fprintf(stderr,"(Bridge ERROR) - Cache size limit reached; consider allocating more space\n", filename);
- return -2;
- }
+ if (index == -1 && cache_pointer >= cache_size) {
+ fprintf(stderr,"(Bridge Info) - No free spots found; doubling cache size\n", filename);
+ cache_size *= 2;
+ the_sounds = (al_sound_t *)Realloc (the_sounds, sizeof(al_sound_t) * cache_size);
+ for (i = cache_size - 50; i < cache_size; i++)
+ the_sounds[i] = new_sound_el();
+ } else
+ index = ++cache_pointer;
+
// detect the file format, as written in the first 4 bytes of the header
fp = Fopen (filename, "rb");
-
if (fp == NULL) {
fprintf(stderr,"(Bridge ERROR) - File %s not loaded\n", filename);
return -3;
@@ -210,7 +204,6 @@
error = fread (&fileformat, sizeof(uint32_t), 1, fp);
fclose (fp);
-
if (error < 0) {
fprintf(stderr,"(Bridge ERROR) - File %s is too short\n", filename);
return -4;
@@ -231,26 +224,26 @@
if (error != 0) {
fprintf(stderr,"(Bridge ERROR) - error loading file %s\n", filename);
- free(data);
+ if(data)
+ free(data);
return -6;
}
- alGenBuffers(1, &soundData.buffer);
- soundData.filename = filename;
- soundData.source_index = -1;
- soundData.stats = 0;
+ // alGenBuffers happens here
+ sound_data = init_sound_el(filename);
if (AL_NO_ERROR != alGetError()) {
- fprintf(stderr,"(Bridge ERROR) - Failed to allocate memory for buffers\n");
+ fprintf(stderr,"(Bridge ERROR) - Failed to allocate memory for buffer %d\n", index);
+ free(data);
return -5;
}
// copy pcm data in one buffer and free it
- alBufferData(soundData.buffer, format, data, bitsize, freq);
+ alBufferData(sound_data.buffer, format, data, bitsize, freq);
free(data);
if (AL_NO_ERROR != alGetError()) {
- fprintf(stderr,"(Bridge ERROR) - Failed to write data to buffers\n");
+ fprintf(stderr,"(Bridge ERROR) - Failed to write data to buffer %d\n", index);
return -8;
}
@@ -260,6 +253,21 @@
fprintf(stderr,"(Bridge Info) - successfully loaded %s\n", filename);
// returns the index of the source you just loaded, increments it and exits
- the_sounds[cache_pointer] = soundData;
- return cache_pointer++;
+ the_sounds[index] = sound_data;
+ return index;
}
+
+
+void openal_unloadfile (uint32_t index) {
+ ALint state;
+
+ if (openal_ready() == AL_TRUE && index < cache_size && the_sounds[index].is_used == AL_TRUE) {
+ alGetSourcei (Sources[the_sounds[index].source_index], AL_SOURCE_STATE, &state);
+ if (state == AL_PLAYING || state == AL_PAUSED)
+ openal_stopsound(index);
+
+ // free memory and
+ alDeleteBuffers (1, &the_sounds[index].buffer);
+ the_sounds[index] = new_sound_el();
+ }
+}
\ No newline at end of file
--- a/misc/libopenalbridge/openalbridge.h Sun Jun 20 22:46:23 2010 -0400
+++ b/misc/libopenalbridge/openalbridge.h Mon Jun 21 16:08:24 2010 +0200
@@ -27,7 +27,7 @@
#endif
// init audio context and allocate memory
- int openal_init (int memorysize);
+ int openal_init (void);
// close audio subsytem and free memory
void openal_close (void);
--- a/misc/libopenalbridge/openalbridge_t.h Sun Jun 20 22:46:23 2010 -0400
+++ b/misc/libopenalbridge/openalbridge_t.h Mon Jun 21 16:08:24 2010 +0200
@@ -32,7 +32,7 @@
const char *filename; // name of the sound file
ALuint buffer; // actual sound content
uint32_t source_index; // index of the associated source
- uint32_t stats; // number of times the sound has been played
+ ALboolean is_used; // tells if the element can be overwritten
} al_sound_t;
#pragma pack()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/libopenalbridge/tester.c Mon Jun 21 16:08:24 2010 +0200
@@ -0,0 +1,11 @@
+#include <stdio.h>
+#include "openalbridge.h"
+
+int main (int argc, int **argv) {
+
+ openal_init();
+
+ openal_close();
+
+ return 0;
+}
\ No newline at end of file
--- a/misc/libopenalbridge/wrappers.c Sun Jun 20 22:46:23 2010 -0400
+++ b/misc/libopenalbridge/wrappers.c Mon Jun 21 16:08:24 2010 +0200
@@ -44,7 +44,7 @@
}
-FILE *Fopen (const char *fname, char *mode) {
+FILE *Fopen (const char *fname, char *mode) {
FILE *fp;
fp = fopen(fname,mode);
@@ -55,3 +55,24 @@
}
+al_sound_t new_sound_el (void) {
+ al_sound_t sound;
+
+ sound.filename = NULL;
+ sound.buffer = -1;
+ sound.source_index = -1;
+ sound.is_used = AL_FALSE;
+
+ return sound;
+}
+
+al_sound_t init_sound_el (const char *str) {
+ al_sound_t sound;
+
+ sound.filename = str;
+ sound.source_index = -1;
+ sound.is_used = AL_TRUE;
+ alGenBuffers(1, &sound.buffer);
+
+ return sound;
+}
--- a/misc/libopenalbridge/wrappers.h Sun Jun 20 22:46:23 2010 -0400
+++ b/misc/libopenalbridge/wrappers.h Mon Jun 21 16:08:24 2010 +0200
@@ -26,5 +26,7 @@
void *Realloc (void *aptr, size_t nbytes);
FILE *Fopen (const char *fname, char *mode);
void helper_fade (void *tmp);
+al_sound_t new_sound_el (void);
+al_sound_t init_sound_el (const char *str);
#endif /*_OALB_WRAPPERS_H*/