# HG changeset patch # User koda # Date 1277129304 -7200 # Node ID 0e968ba12a849cf6f5281455589e957287b4d455 # Parent a8c673657b79f15ecb50c35dc5a9a8fe26528296# Parent 0ad90165fde0d965cf4b23f2ac82c7f4d6cde03a memory management for openalbridge added openalbridge as dependency of hwengine usound formatted clearly diff -r 0ad90165fde0 -r 0e968ba12a84 CMakeLists.txt --- 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) diff -r 0ad90165fde0 -r 0e968ba12a84 hedgewars/CMakeLists.txt --- 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) diff -r 0ad90165fde0 -r 0e968ba12a84 hedgewars/uSound.pas --- 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; diff -r 0ad90165fde0 -r 0e968ba12a84 misc/libopenalbridge/CMakeLists.txt --- 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}) + diff -r 0ad90165fde0 -r 0e968ba12a84 misc/libopenalbridge/commands.c --- 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++; } } diff -r 0ad90165fde0 -r 0e968ba12a84 misc/libopenalbridge/openalbridge.c --- 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 diff -r 0ad90165fde0 -r 0e968ba12a84 misc/libopenalbridge/openalbridge.h --- 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); diff -r 0ad90165fde0 -r 0e968ba12a84 misc/libopenalbridge/openalbridge_t.h --- 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() diff -r 0ad90165fde0 -r 0e968ba12a84 misc/libopenalbridge/tester.c --- /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 +#include "openalbridge.h" + +int main (int argc, int **argv) { + + openal_init(); + + openal_close(); + + return 0; +} \ No newline at end of file diff -r 0ad90165fde0 -r 0e968ba12a84 misc/libopenalbridge/wrappers.c --- 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; +} diff -r 0ad90165fde0 -r 0e968ba12a84 misc/libopenalbridge/wrappers.h --- 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*/