Added a new SoundManager based on OpenAL. I also simplified the API along the
authorMatthias Braun <matze@braunis.de>
Thu, 23 Jun 2005 01:45:32 +0000 (01:45 +0000)
committerMatthias Braun <matze@braunis.de>
Thu, 23 Jun 2005 01:45:32 +0000 (01:45 +0000)
way.
OpenAL gives you some neat effects like positional sounds moving along while
they are played. Try a level with a flame to see this in action.

Some notes:
- don't forget to run autogen.sh and configure again
- The AmbientSound object probably needs an overhaul now
- You can't play .mod files anymore, they have to be converted to .ogg
- There's a bug that keeps supertux open for several seconds instead of closing
  it, didn't investigate yet why.

SVN-Revision: 2636

55 files changed:
configure.ac
data/levels/world2/level2.stl
src/Jamfile
src/audio/semantic.cache
src/audio/sound_file.cpp [new file with mode: 0644]
src/audio/sound_file.h [new file with mode: 0644]
src/audio/sound_manager.cpp
src/audio/sound_manager.h
src/audio/sound_source.cpp [new file with mode: 0644]
src/audio/sound_source.h [new file with mode: 0644]
src/audio/stream_sound_source.cpp [new file with mode: 0644]
src/audio/stream_sound_source.h [new file with mode: 0644]
src/badguy/badguy.cpp
src/badguy/badguy.h
src/badguy/bomb.cpp
src/badguy/flame.cpp
src/badguy/flame.h
src/badguy/jumpy.cpp
src/badguy/mriceblock.cpp
src/badguy/mrtree.cpp
src/badguy/nolok_01.cpp
src/badguy/rocketexplosion.cpp
src/badguy/yeti.cpp
src/control/joystickkeyboardcontroller.h
src/game_session.cpp
src/gameconfig.cpp
src/gameconfig.h
src/leveleditor.cpp [deleted file]
src/leveleditor.h [deleted file]
src/main.cpp
src/misc.cpp
src/object/ambient_sound.cpp
src/object/ambient_sound.h
src/object/block.cpp
src/object/fireworks.cpp
src/object/flower.cpp
src/object/growup.cpp
src/object/invisible_block.cpp
src/object/player.cpp
src/object/player.h
src/object/powerup.cpp
src/physfs/physfs_stream.cpp
src/physfs/physfs_stream.h
src/player_status.cpp
src/resources.cpp
src/resources.h
src/scripting/sound.cpp
src/scripting/sound.h
src/scripting/wrapper.cpp
src/sector.cpp
src/sector.h
src/textscroller.cpp
src/title.cpp
src/worldmap.cpp
src/worldmap.h

index a504fd2..043aaaa 100644 (file)
@@ -83,6 +83,8 @@ else
 fi
 AC_SUBST([VARIANT])
 
+AC_C_BIGENDIAN()
+
 AC_MSG_CHECKING(whether OpenGL should be used)
 AC_ARG_ENABLE(opengl,
               AC_HELP_STRING([--disable-opengl], [disable OpenGL support]),
@@ -115,21 +117,8 @@ AM_PATH_SDL($SDL_VERSION,
             :,
            AC_MSG_ERROR([*** SDL version $SDL_VERSION not found!]))
 
-NP_FINDLIB([SDLMIXER], [SDL_mixer], [SDL_mixer >= 1.2],
-        NP_LANG_PROGRAM([#include <SDL_mixer.h>
-#if MIX_MAJOR_VERSION < 1
-# error SDLMix too old
-#else
-# if MIX_MAJOR_VERSION == 1
-#  if MIX_MINOR_VERSION < 2
-#   error SDLMix too old
-#  endif
-# endif
-#endif], [Mix_OpenAudio(0, 0, 0, 0);]),
-        [], [-lSDL_mixer],
-        [],
-        [AC_MSG_ERROR([Please install SDLMixer >=1.2.2])],
-        [$SDL_CFLAGS], [$SDL_LIBS])
+XIPH_PATH_VORBIS(, [AC_MSG_ERROR([Please install libvorbis])])
+XIPH_PATH_OGG(, [AC_MSG_ERROR([Please install libogg])])
 
 NP_FINDLIB([SDLIMAGE], [SDL_image], [SDL_image >= 1.2],
         NP_LANG_PROGRAM([#include <SDL_image.h>], [IMG_Load("");]),
@@ -147,6 +136,14 @@ NP_FINDLIB([PHYSFS], [physfs], [physfs >= 1.0.0],
         [],
         [AC_MSG_ERROR([Please install physfs >= 1.0])])
 
+NP_FINDLIB([OPENAL], [OpenAL], [OpenAL],
+         NP_LANG_PROGRAM([#include <AL/alut.h>],
+           [alutInit(0, 0);]),
+         [], [-lopenal],
+         [],
+         [AC_MSG_ERROR([Please intall OpenAL])],
+         [], [])
+
 dnl Checks for library functions.
 AC_CHECK_FUNCS(mkdir strdup strstr)
 
index a5e7665..e1487ee 100644 (file)
                     (powerup (x 3168) (y 416)
         (sprite (_ "eat-me"))
         (script "
-function wait(time) {
-  set_wakeup_time(time);
-  suspend();
-}
 DisplayEffect.fade_out(1);
 wait(1);
 Level.flip_vertically();
@@ -212,10 +208,6 @@ DisplayEffect.fade_in(1);
         (powerup
           (sprite "red-potion")
           (script "
-function wait(time) {
-  set_wakeup_time(time);
-  suspend();
-}
 DisplayEffect.fade_out(1);
 wait(1);
 Level.flip_vertically();
@@ -226,10 +218,6 @@ DisplayEffect.fade_in(1);
       (powerup (x 8608) (y 1024)
         (sprite "red-potion")
         (script "
-function wait(time) {
-  set_wakeup_time(time);
-  suspend();
-}
 DisplayEffect.fade_out(1);
 wait(1);
 Level.flip_vertically();
@@ -239,10 +227,6 @@ DisplayEffect.fade_in(1);
       (powerup (x 9952) (y 416)
         (sprite "red-potion")
         (script "
-function wait(time) {
-  set_wakeup_time(time);
-  suspend();
-}
 DisplayEffect.fade_out(1);
 wait(1);
 Level.flip_vertically();
@@ -251,10 +235,7 @@ DisplayEffect.fade_in(1);
       )
       (powerup (x 8000) (y 352)
         (sprite "gold-key")
-        (script "function wait(time) {
-                 set_wakeup_time(time);
-                 suspend();}
-                 wait(7);
+        (script "wait(7);
                  Level.finish();")
       )
       (infoblock (x 2560) (y 320)
index ba6b375..f5efe6a 100644 (file)
@@ -6,6 +6,7 @@ SubInclude TOP src scripting ;
 sources = 
     [ Wildcard *.cpp *.h ]
     [ Wildcard audio : *.cpp *.h ]
+    [ Wildcard audio/newapi : *.cpp *.h ]
     [ Wildcard badguy : *.cpp *.h ]
     [ Wildcard control : *.cpp *.h ]
     [ Wildcard gui : *.cpp *.h ]
@@ -23,7 +24,7 @@ TRANSLATABLE_SOURCES += [ SearchSource $(sources) ] ;
 Application supertux : $(sources) $(wrapper_objects) ;
 C++Flags supertux : -DAPPDATADIR='\"$(appdatadir)\"' ;
 LinkWith supertux : squirrel ;
-ExternalLibs supertux : SDL SDLMIXER SDLIMAGE GL ICONV PHYSFS BINRELOC ;
+ExternalLibs supertux : SDL SDLIMAGE GL OPENAL VORBIS VORBISFILE OGG ICONV PHYSFS BINRELOC ;
 Help supertux : "Build the supertux executable" ;
 IncludeDir supertux : squirrel/include ;
 
index 5663751..d7bfa81 100644 (file)
@@ -3,24 +3,43 @@
 (semanticdb-project-database "semantic.cache"
   :file "semantic.cache"
   :tables (list 
+   (semanticdb-table "sound_manager.cpp"
+    :file "sound_manager.cpp"
+    :pointmax 5898
+    :major-mode 'c++-mode
+    :tokens '(("sound_manager.h" include nil nil nil [1 27]) ("stdexcept" include t nil nil [29 49]) ("iostream" include t nil nil [50 69]) ("sstream" include t nil nil [70 88]) ("memory" include t nil nil [89 106]) ("sound_file.h" include nil nil nil [108 131]) ("sound_source.h" include nil nil nil [132 157]) ("stream_sound_source.h" include nil nil nil [158 190]) ("SoundManager" function ("SoundManager" type "class") nil ((parent . "SoundManager") (constructor . t)) nil nil [192 925]) ("SoundManager" function "void" nil ((parent . "SoundManager") (destructor . t)) nil nil [927 1366]) ("load_file_into_buffer" function ("ALuint" type "class") (("filename" variable ("std::string" type "class") nil ((const . t)) nil nil [1411 1439])) ((parent . "SoundManager")) nil nil [1368 2032]) ("create_sound_source" function ("SoundSource" type "class") (("filename" variable ("std::string" type "class") nil ((const . t)) nil nil [2081 2109])) ((parent . "SoundManager") (pointer . 1)) nil nil [2034 2556]) ("play" function ("void") (("soundname" variable ("std::string" type "class") nil ((const . t)) nil nil [2582 2611]) ("pos" variable ("Vector" type "class") nil ((const . t)) nil nil [2612 2630])) ((parent . "SoundManager")) nil nil [2558 3122]) ("enable_sound" function ("void") (("enable" variable ("bool" type "class") nil nil nil nil [3156 3168])) ((parent . "SoundManager")) nil nil [3124 3228]) ("enable_music" function ("void") (("enable" variable ("bool" type "class") nil nil nil nil [3262 3274])) ((parent . "SoundManager")) nil nil [3230 3363]) ("play_music" function ("void") (("filename" variable ("std::string" type "class") nil ((const . t)) nil nil [3395 3423])) ((parent . "SoundManager")) nil nil [3365 3746]) ("set_listener_position" function ("void") (("pos" variable ("Vector" type "class") nil nil nil nil [3789 3800])) ((parent . "SoundManager")) nil nil [3748 3850]) ("set_listener_velocity" function ("void") (("vel" variable ("Vector" type "class") nil nil nil nil [3893 3904])) ((parent . "SoundManager")) nil nil [3852 3954]) ("update" function ("void") nil ((parent . "SoundManager")) nil nil [3956 4410]) ("get_sample_format" function ("ALenum" type "class") (("file" variable ("SoundFile" type "class") nil ((pointer . 1)) nil nil [4451 4467])) ((parent . "SoundManager")) nil nil [4412 5081]) ("print_openal_version" function ("void") nil ((parent . "SoundManager")) nil nil [5083 5410]) ("check_alc_error" function ("void") (("message" variable "char" nil ((const . t) (pointer . 1)) nil nil [5447 5467])) ((parent . "SoundManager")) nil nil [5412 5669]) ("check_al_error" function ("void") (("message" variable "char" nil ((const . t) (pointer . 1)) nil nil [5705 5725])) ((parent . "SoundManager")) nil nil [5671 5896]))
+    :unmatched-syntax 'nil
+    )
+   (semanticdb-table "stream_sound_source.h"
+    :file "stream_sound_source.h"
+    :pointmax 682
+    :major-mode 'c++-mode
+    :tokens '(("__STREAM_SOUND_SOURCE_H__" variable nil nil ((const . t)) nil nil [35 71]) ("sound_source.h" include nil nil nil [89 114]) ("SoundFile" type "class" nil nil nil nil nil [116 132]) ("StreamSoundSource" type "class" (("public" label ((reparse-symbol . classsubparts)) [181 188]) ("StreamSoundSource" function ("StreamSoundSource" type "class") (("file" variable ("SoundFile" type "class") nil ((pointer . 1)) nil nil [209 225])) ((constructor . t) (prototype . t)) nil ((reparse-symbol . classsubparts)) [191 226]) ("StreamSoundSource" function "void" nil ((typemodifiers "virtual") (destructor . t) (prototype . t)) nil ((reparse-symbol . classsubparts)) [229 258]) ("update" function ("void") nil ((prototype . t)) nil ((reparse-symbol . classsubparts)) [262 276]) ("private" label ((reparse-symbol . classsubparts)) [280 288]) ("STREAMFRAGMENTS" variable ("size_t" type "class") "5" ((const . t) (typemodifiers "static")) nil nil [344 384]) ("STREAMFRAGMENTS" variable "int" nil nil nil nil [452 468]) ("fillBufferAndQueue" function ("void") (("buffer" variable ("ALuint" type "class") nil nil nil nil [496 510])) ((prototype . t)) nil ((reparse-symbol . classsubparts)) [472 511]) ("file" variable ("SoundFile" type "class") nil ((pointer . 1)) nil nil [514 530]) ("buffers" variable ("ALuint" type "class") nil ((dereference . 1)) nil nil [533 565]) ("format" variable ("ALenum" type "class") nil nil nil nil [568 582]) ("FadeState" type "enum" (("NoFading" variable "int" nil ((const . t)) nil ((reparse-symbol . enumsubparts)) [603 612]) ("FadingOn" variable "int" nil ((const . t)) nil ((reparse-symbol . enumsubparts)) [613 622]) ("FadingOff" variable "int" nil ((const . t)) nil ((reparse-symbol . enumsubparts)) [623 634])) nil nil nil ((reparse-symbol . classsubparts)) [586 635]) ("fade_state" variable ("FadeState" type "class") nil nil nil nil [638 659])) (("SoundSource")) nil nil nil [134 672]))
+    )
    (semanticdb-table "sound_manager.h"
     :file "sound_manager.h"
-    :pointmax 3413
+    :pointmax 1796
     :major-mode 'c++-mode
-    :tokens '(("SUPERTUX_SOUND_MANAGER_H" variable nil nil ((const . t)) nil nil [915 950]) ("string" include t nil nil [949 966]) ("vector" include t nil nil [967 984]) ("map" include t nil nil [985 999]) ("SDL_mixer.h" include nil nil nil [1001 1023]) ("math/vector.h" include nil nil nil [1024 1048]) ("MusicRef" type "class" nil nil nil nil nil [1077 1092]) ("MovingObject" type "class" nil nil nil nil nil [1093 1112]) ("SoundManager" type "class" (("public" label ((reparse-symbol . classsubparts)) [1206 1213]) ("SoundManager" function ("SoundManager" type "class") nil ((constructor . t) (prototype . t)) nil ((reparse-symbol . classsubparts)) [1216 1231]) ("SoundManager" function "void" nil ((destructor . t) (prototype . t)) nil ((reparse-symbol . classsubparts)) [1234 1250]) ("play_sound" function ("void") (("sound" variable ("std::string" type "class") nil ((const . t)) nil nil [1288 1313])) ((prototype . t)) nil ((reparse-symbol . classsubparts)) [1272 1314]) ("play_sound" function ("void") (("sound" variable ("std::string" type "class") nil ((const . t)) nil nil [1375 1400]) ("pos" variable ("Vector" type "class") nil ((const . t)) nil nil [1401 1419]) ("pos2" variable ("Vector" type "class") nil ((const . t)) nil nil [1426 1445])) ((prototype . t)) nil ((reparse-symbol . classsubparts)) [1359 1446]) ("play_sound" function ("void") (("sound" variable ("std::string" type "class") nil ((const . t)) nil nil [1523 1548]) ("object" variable ("MovingObject" type "class") nil ((const . t) (pointer . 1)) nil nil [1549 1576]) ("pos" variable ("Vector" type "class") nil ((const . t)) nil nil [1583 1601])) ((prototype . t)) nil ((reparse-symbol . classsubparts)) [1507 1602]) ("load_music" function ("MusicRef" type "class") (("file" variable ("std::string" type "class") nil ((const . t)) nil nil [1699 1723])) ((prototype . t)) nil ((reparse-symbol . classsubparts)) [1679 1724]) ("preload_sound" function ("Mix_Chunk" type "class") (("name" variable ("std::string" type "class") nil ((const . t)) nil nil [1934 1958])) ((pointer . 1) (prototype . t)) nil ((reparse-symbol . classsubparts)) [1909 1959]) ("exists_music" function ("bool" type "class") (("filename" variable ("std::string" type "class") nil ((const . t)) nil nil [2024 2052])) ((prototype . t)) nil ((reparse-symbol . classsubparts)) [2006 2053]) ("play_music" function ("void") (("music" variable ("MusicRef" type "class") nil ((const . t)) nil nil [2159 2181]) ("loops" variable "int" "-1" nil nil nil [2182 2196])) ((prototype . t)) nil ((reparse-symbol . classsubparts)) [2143 2198]) ("halt_music" function ("void") nil ((prototype . t)) nil ((reparse-symbol . classsubparts)) [2220 2238]) ("enable_music" function ("void") (("enable" variable ("bool" type "class") nil nil nil nil [2288 2300])) ((prototype . t)) nil ((reparse-symbol . classsubparts)) [2270 2301]) ("music_enabled" function ("bool" type "class") nil nil nil ((reparse-symbol . classsubparts)) [2329 2385]) ("enable_sound" function ("void") (("enable" variable ("bool" type "class") nil nil nil nil [2435 2447])) ((prototype . t)) nil ((reparse-symbol . classsubparts)) [2417 2448]) ("sound_enabled" function ("bool" type "class") nil nil nil ((reparse-symbol . classsubparts)) [2476 2532]) ("audio_device_available" function ("bool" type "class") nil nil nil ((reparse-symbol . classsubparts)) [2562 2624]) ("set_audio_device_available" function ("void") (("available" variable ("bool" type "class") nil nil nil nil [2660 2675])) nil nil ((reparse-symbol . classsubparts)) [2628 2713]) ("private" label ((reparse-symbol . classsubparts)) [2715 2723]) ("MusicRef" type "class" nil nil nil nil ((reparse-symbol . classsubparts)) [2733 2748]) ("Setup" type "class" nil nil nil nil ((reparse-symbol . classsubparts)) [2758 2770]) ("MusicResource" type "class" (("public" label ((reparse-symbol . classsubparts)) [2927 2934]) ("MusicResource" function "void" nil ((destructor . t) (prototype . t)) nil ((reparse-symbol . classsubparts)) [2941 2958]) ("manager" variable ("SoundManager" type "class") nil ((pointer . 1)) nil nil [2966 2988]) ("music" variable ("Mix_Music" type "class") nil ((pointer . 1)) nil nil [2995 3012]) ("refcount" variable "int" nil nil nil nil [3019 3032])) nil nil nil ((reparse-symbol . classsubparts)) [2897 3039]) ("free_music" function ("void") (("music" variable ("MusicResource" type "class") nil ((pointer . 1)) nil nil [3059 3080])) ((prototype . t)) nil ((reparse-symbol . classsubparts)) [3043 3081]) ("Sounds" type "typedef" nil ("std::map") ((typedef "std::map" type "class")) nil nil [3085 3134]) ("sounds" variable ("Sounds" type "class") nil nil nil nil [3137 3151]) ("Musics" type "typedef" nil ("std::map") ((typedef "std::map" type "class")) nil nil [3155 3207]) ("musics" variable ("Musics" type "class") nil nil nil nil [3210 3224]) ("current_music" variable ("MusicResource" type "class") nil ((pointer . 1)) nil nil [3228 3257]) ("m_music_enabled" variable ("bool" type "class") nil nil nil nil [3260 3281]) ("m_sound_enabled" variable ("bool" type "class") nil nil nil nil [3284 3305]) ("audio_device" variable ("bool" type "class") nil nil nil nil [3308 3326])) nil nil nil nil [1185 3374]))
-    :unmatched-syntax 'nil
+    :tokens '(("__SOUND_MANAGER_H__" variable nil nil ((const . t)) nil nil [29 59]) ("math/vector.h" include nil nil nil [58 82]) ("string" include t nil nil [83 100]) ("vector" include t nil nil [101 118]) ("map" include t nil nil [119 133]) ("AL/alc.h" include t nil nil [135 154]) ("AL/al.h" include t nil nil [155 173]) ("SoundHandle" type "typedef" nil ("void") ((pointer . 1) (typedef "void")) nil nil [175 201]) ("SoundFile" type "class" nil nil nil nil nil [203 219]) ("SoundSource" type "class" nil nil nil nil nil [220 238]) ("StreamSoundSource" type "class" nil nil nil nil nil [239 263]) ("SoundManager" type "class" (("public" label ((reparse-symbol . classsubparts)) [286 293]) ("SoundManager" function ("SoundManager" type "class") nil ((constructor . t) (prototype . t)) nil ((reparse-symbol . classsubparts)) [296 311]) ("SoundManager" function "void" nil ((typemodifiers "virtual") (destructor . t) (prototype . t)) nil ((reparse-symbol . classsubparts)) [314 338]) ("enable_sound" function ("void") (("sound_enabled" variable ("bool" type "class") nil nil nil nil [360 379])) ((prototype . t)) nil ((reparse-symbol . classsubparts)) [342 380]) ("create_sound_source" function ("SoundSource" type "class") (("filename" variable ("std::string" type "class") nil ((const . t)) nil nil [692 720])) ((pointer . 1) (prototype . t)) nil ((reparse-symbol . classsubparts)) [659 721]) ("play" function ("void") (("name" variable ("std::string" type "class") nil ((const . t)) nil nil [890 914]) ("pos" variable ("Vector" type "class") "Vector(-1, -1)" ((const . t)) nil nil [915 949])) ((prototype . t)) nil ((reparse-symbol . classsubparts)) [880 951]) ("set_listener_position" function ("void") (("position" variable ("Vector" type "class") nil nil nil nil [982 998])) ((prototype . t)) nil ((reparse-symbol . classsubparts)) [955 999]) ("set_listener_velocity" function ("void") (("velocity" variable ("Vector" type "class") nil nil nil nil [1029 1045])) ((prototype . t)) nil ((reparse-symbol . classsubparts)) [1002 1046]) ("enable_music" function ("void") (("music_enabled" variable ("bool" type "class") nil nil nil nil [1068 1087])) ((prototype . t)) nil ((reparse-symbol . classsubparts)) [1050 1088]) ("play_music" function ("void") (("filename" variable ("std::string" type "class") nil ((const . t)) nil nil [1107 1135])) ((prototype . t)) nil ((reparse-symbol . classsubparts)) [1091 1136]) ("update" function ("void") nil ((prototype . t)) nil ((reparse-symbol . classsubparts)) [1140 1154]) ("private" label ((reparse-symbol . classsubparts)) [1156 1164]) ("SoundSource" type "class" nil nil nil nil ((reparse-symbol . classsubparts)) [1174 1192]) ("StreamSoundSource" type "class" nil nil nil nil ((reparse-symbol . classsubparts)) [1202 1226]) ("load_file_into_buffer" function ("ALuint" type "class") (("filename" variable ("std::string" type "class") nil ((const . t)) nil nil [1266 1294])) ((typemodifiers "static") (prototype . t)) nil ((reparse-symbol . classsubparts)) [1230 1295]) ("get_sample_format" function ("ALenum" type "class") (("file" variable ("SoundFile" type "class") nil ((pointer . 1)) nil nil [1330 1346])) ((typemodifiers "static") (prototype . t)) nil ((reparse-symbol . classsubparts)) [1298 1347]) ("print_openal_version" function ("void") nil ((prototype . t)) nil ((reparse-symbol . classsubparts)) [1351 1379]) ("check_alc_error" function ("void") (("message" variable "char" nil ((const . t) (pointer . 1)) nil nil [1403 1423])) ((prototype . t)) nil ((reparse-symbol . classsubparts)) [1382 1424]) ("check_al_error" function ("void") (("message" variable "char" nil ((const . t) (pointer . 1)) nil nil [1454 1474])) ((typemodifiers "static") (prototype . t)) nil ((reparse-symbol . classsubparts)) [1427 1475]) ("device" variable ("ALCdevice" type "class") nil ((pointer . 1)) nil nil [1479 1497]) ("context" variable ("ALCcontext" type "class") nil ((pointer . 1)) nil nil [1500 1520]) ("sound_enabled" variable ("bool" type "class") nil nil nil nil [1523 1542]) ("SoundBuffers" type "typedef" nil ("std::map") ((typedef "std::map" type "class")) nil nil [1546 1597]) ("buffers" variable ("SoundBuffers" type "class") nil nil nil nil [1600 1621]) ("SoundSources" type "typedef" nil ("std::vector") ((typedef "std::vector" type "class")) nil nil [1624 1671]) ("sources" variable ("SoundSources" type "class") nil nil nil nil [1674 1695]) ("music_source" variable ("StreamSoundSource" type "class") nil ((pointer . 1)) nil nil [1699 1731]) ("music_enabled" variable ("bool" type "class") nil nil nil nil [1735 1754]) ("current_music" variable ("std::string" type "class") nil nil nil nil [1757 1783])) nil nil nil nil [265 1786]))
+    :unmatched-syntax '((FRIEND 1195 . 1201) (FRIEND 1167 . 1173))
     )
-   (semanticdb-table "musicref.h"
-    :file "musicref.h"
-    :pointmax 1371
+   (semanticdb-table "stream_sound_source.cpp"
+    :file "stream_sound_source.cpp"
+    :pointmax 1971
     :major-mode 'c++-mode
-    :tokens '(("SUPERTUX_MUSICREF_H" variable nil nil ((const . t)) nil nil [907 937]) ("sound_manager.h" include nil nil nil [936 962]) ("SuperTux" type "namespace" (("MusicRef" type "class" (("public" label ((reparse-symbol . classsubparts)) [1085 1092]) ("MusicRef" function ("MusicRef" type "class") nil ((constructor . t) (prototype . t)) nil ((reparse-symbol . classsubparts)) [1093 1106]) ("MusicRef" function ("MusicRef" type "class") (("other" variable ("MusicRef" type "class") nil ((const . t)) nil nil [1118 1140])) ((constructor . t) (prototype . t)) nil ((reparse-symbol . classsubparts)) [1107 1141]) ("MusicRef" function "void" nil ((destructor . t) (prototype . t)) nil ((reparse-symbol . classsubparts)) [1142 1156]) ("=" function ("MusicRef" type "class") (("other" variable ("MusicRef" type "class") nil ((const . t)) nil nil [1183 1205])) ((prototype . t)) nil ((reparse-symbol . classsubparts)) [1160 1206]) ("private" label ((reparse-symbol . classsubparts)) [1208 1216]) ("SoundManager" type "class" nil nil nil nil ((reparse-symbol . classsubparts)) [1226 1245]) ("MusicRef" function ("MusicRef" type "class") (("music" variable ("SoundManager::MusicResource" type "class") nil ((pointer . 1)) nil nil [1257 1292])) ((constructor . t) (prototype . t)) nil ((reparse-symbol . classsubparts)) [1246 1293]) ("music" variable ("SoundManager::MusicResource" type "class") nil ((pointer . 1)) nil nil [1297 1334])) nil nil nil ((reparse-symbol . namespacesubparts)) [1068 1337])) nil nil nil nil [964 1338]))
+    :tokens '(("config.h" include t nil nil [1 20]) ("stream_sound_source.h" include nil nil nil [22 54]) ("sound_manager.h" include nil nil nil [55 81]) ("sound_file.h" include nil nil nil [82 105]) ("StreamSoundSource" function ("StreamSoundSource" type "class") (("file" variable ("SoundFile" type "class") nil ((pointer . 1)) nil nil [144 160])) ((parent . "StreamSoundSource") (constructor . t)) nil nil [107 516]) ("StreamSoundSource" function "void" nil ((parent . "StreamSoundSource") (destructor . t)) nil nil [518 673]) ("update" function ("void") nil ((parent . "StreamSoundSource")) nil nil [675 1326]) ("fillBufferAndQueue" function ("void") (("buffer" variable ("ALuint" type "class") nil nil nil nil [1371 1385])) ((parent . "StreamSoundSource")) nil nil [1328 1970]))
     )
-   (semanticdb-table "sound_manager.cpp"
-    :file "sound_manager.cpp"
-    :pointmax 5703
+   (semanticdb-table "sound_source.h"
+    :file "sound_source.h"
+    :pointmax 474
+    :major-mode 'c++-mode
+    :tokens '(("__SOUND_SOURCE_H__" variable nil nil ((const . t)) nil nil [28 57]) ("AL/al.h" include t nil nil [56 74]) ("math/vector.h" include nil nil nil [75 99]) ("SoundSource" type "class" (("public" label ((reparse-symbol . classsubparts)) [121 128]) ("SoundSource" function ("SoundSource" type "class") nil ((constructor . t) (prototype . t)) nil ((reparse-symbol . classsubparts)) [131 145]) ("SoundSource" function "void" nil ((typemodifiers "virtual") (destructor . t) (prototype . t)) nil ((reparse-symbol . classsubparts)) [148 171]) ("play" function ("void") nil ((prototype . t)) nil ((reparse-symbol . classsubparts)) [175 187]) ("stop" function ("void") nil ((prototype . t)) nil ((reparse-symbol . classsubparts)) [190 202]) ("playing" function ("bool" type "class") nil ((prototype . t)) nil ((reparse-symbol . classsubparts)) [205 220]) ("set_looping" function ("void") (("looping" variable ("bool" type "class") nil nil nil nil [241 254])) ((prototype . t)) nil ((reparse-symbol . classsubparts)) [224 255]) ("set_volume" function ("void") (("volume" variable "float" nil nil nil nil [310 323])) ((prototype . t)) nil ((reparse-symbol . classsubparts)) [294 324]) ("set_position" function ("void") (("position" variable ("Vector" type "class") nil nil nil nil [345 361])) ((prototype . t)) nil ((reparse-symbol . classsubparts)) [327 362]) ("set_velocity" function ("void") (("position" variable ("Vector" type "class") nil nil nil nil [383 399])) ((prototype . t)) nil ((reparse-symbol . classsubparts)) [365 400]) ("protected" label ((reparse-symbol . classsubparts)) [402 412]) ("SoundManager" type "class" nil nil nil nil ((reparse-symbol . classsubparts)) [422 441]) ("source" variable ("ALuint" type "class") nil nil nil nil [447 461])) nil nil nil nil [101 464]))
+    )
+   (semanticdb-table "sound_file.cpp"
+    :file "sound_file.cpp"
+    :pointmax 7443
     :major-mode 'c++-mode
-    :tokens '(("config.h" include t nil nil [882 901]) ("cmath" include t nil nil [903 919]) ("cassert" include t nil nil [920 938]) ("sstream" include t nil nil [960 978]) ("audio/sound_manager.h" include nil nil nil [980 1012]) ("audio/musicref.h" include nil nil nil [1013 1040]) ("app/globals.h" include nil nil nil [1041 1065]) ("app/setup.h" include nil nil nil [1066 1088]) ("moving_object.h" include nil nil nil [1089 1115]) ("resources.h" include nil nil nil [1116 1138]) ("SoundManager" function ("SoundManager" type "class") nil ((parent . "SoundManager") (constructor . t)) nil nil [1167 1292]) ("SoundManager" function "void" nil ((parent . "SoundManager") (destructor . t)) nil nil [1294 1448]) ("play_sound" function ("void") (("name" variable ("std::string" type "class") nil ((const . t)) nil nil [1480 1504])) ((parent . "SoundManager")) nil nil [1450 1731]) ("play_sound" function ("void") (("sound" variable ("std::string" type "class") nil ((const . t)) nil nil [1763 1788]) ("object" variable ("MovingObject" type "class") nil ((const . t) (pointer . 1)) nil nil [1789 1816]) ("pos" variable ("Vector" type "class") nil ((const . t)) nil nil [1821 1839])) ((parent . "SoundManager")) nil nil [1733 1976]) ("play_sound" function ("void") (("sound" variable ("std::string" type "class") nil ((const . t)) nil nil [2008 2033]) ("pos" variable ("Vector" type "class") nil ((const . t)) nil nil [2034 2052]) ("pos2" variable ("Vector" type "class") nil ((const . t)) nil nil [2057 2076])) ((parent . "SoundManager")) nil nil [1978 2777]) ("load_music" function ("MusicRef" type "class") (("file" variable ("std::string" type "class") nil ((const . t)) nil nil [2813 2837])) ((parent . "SoundManager")) nil nil [2779 3197]) ("exists_music" function ("bool" type "class") (("file" variable ("std::string" type "class") nil ((const . t)) nil nil [3231 3255])) ((parent . "SoundManager")) nil nil [3199 3885]) ("free_music" function ("void") (("" variable ("MusicResource" type "class") nil ((pointer . 1)) nil nil [3917 3933])) ((parent . "SoundManager")) nil nil [3887 4069]) ("play_music" function ("void") (("musicref" variable ("MusicRef" type "class") nil ((const . t)) nil nil [4101 4126]) ("loops" variable "int" nil nil nil nil [4127 4137])) ((parent . "SoundManager")) nil nil [4071 4438]) ("halt_music" function ("void") nil ((parent . "SoundManager")) nil nil [4440 4682]) ("enable_music" function ("void") (("enable" variable ("bool" type "class") nil nil nil nil [4716 4728])) ((parent . "SoundManager")) nil nil [4684 4978]) ("enable_sound" function ("void") (("enable" variable ("bool" type "class") nil nil nil nil [5012 5024])) ((parent . "SoundManager")) nil nil [4980 5091]) ("MusicResource" function "void" nil ((parent . "SoundManager::MusicResource") (destructor . t)) nil nil [5093 5233]) ("preload_sound" function ("Mix_Chunk" type "class") (("name" variable ("std::string" type "class") nil ((const . t)) nil nil [5274 5298])) ((parent . "SoundManager") (pointer . 1)) nil nil [5235 5701]))
+    :tokens '(("config.h" include t nil nil [53 72]) ("sound_file.h" include nil nil nil [74 97]) ("stdio.h" include t nil nil [99 117]) ("stdint.h" include t nil nil [118 137]) ("algorithm" include t nil nil [138 158]) ("stdexcept" include t nil nil [159 179]) ("sstream" include t nil nil [180 198]) ("physfs.h" include t nil nil [199 218]) ("vorbis/codec.h" include t nil nil [219 244]) ("vorbis/vorbisfile.h" include t nil nil [245 275]) ("WavSoundFile" type "class" (("public" label ((reparse-symbol . classsubparts)) [317 324]) ("WavSoundFile" function ("WavSoundFile" type "class") (("file" variable ("PHYSFS_file" type "class") nil ((pointer . 1)) nil nil [340 358])) ((constructor . t) (prototype . t)) nil ((reparse-symbol . classsubparts)) [327 359]) ("WavSoundFile" function "void" nil ((destructor . t) (prototype . t)) nil ((reparse-symbol . classsubparts)) [362 378]) ("read" function ("size_t" type "class") (("buffer" variable "void" nil ((pointer . 1)) nil nil [394 407]) ("buffer_size" variable ("size_t" type "class") nil nil nil nil [408 427])) ((prototype . t)) nil ((reparse-symbol . classsubparts)) [382 428]) ("reset" function ("void") nil ((prototype . t)) nil ((reparse-symbol . classsubparts)) [431 444]) ("private" label ((reparse-symbol . classsubparts)) [446 454]) ("file" variable ("PHYSFS_file" type "class") nil ((pointer . 1)) nil nil [457 475]) ("datastart" variable ("PHYSFS_sint64" type "class") nil nil nil nil [481 505])) (("SoundFile")) nil nil nil [277 508]) ("read32LE" function ("uint32_t" type "class") (("file" variable ("PHYSFS_file" type "class") nil ((pointer . 1)) nil nil [542 560])) ((typemodifiers "static" "inline")) nil nil [510 692]) ("read16LE" function ("uint16_t" type "class") (("file" variable ("PHYSFS_file" type "class") nil ((pointer . 1)) nil nil [726 744])) ((typemodifiers "static" "inline")) nil nil [694 876]) ("WavSoundFile" function ("WavSoundFile" type "class") (("file" variable ("PHYSFS_file" type "class") nil ((pointer . 1)) nil nil [905 923])) ((parent . "WavSoundFile") (constructor . t)) nil nil [878 3302]) ("WavSoundFile" function "void" nil ((parent . "WavSoundFile") (destructor . t)) nil nil [3304 3359]) ("reset" function ("void") nil ((parent . "WavSoundFile")) nil nil [3361 3492]) ("read" function ("size_t" type "class") (("buffer" variable "void" nil ((pointer . 1)) nil nil [3520 3533]) ("buffer_size" variable ("size_t" type "class") nil nil nil nil [3534 3553])) ((parent . "WavSoundFile")) nil nil [3494 3884]) ("OggSoundFile" type "class" (("public" label ((reparse-symbol . classsubparts)) [4005 4012]) ("OggSoundFile" function ("OggSoundFile" type "class") (("file" variable ("PHYSFS_file" type "class") nil ((pointer . 1)) nil nil [4028 4046])) ((constructor . t) (prototype . t)) nil ((reparse-symbol . classsubparts)) [4015 4047]) ("OggSoundFile" function "void" nil ((destructor . t) (prototype . t)) nil ((reparse-symbol . classsubparts)) [4050 4066]) ("read" function ("size_t" type "class") (("buffer" variable "void" nil ((pointer . 1)) nil nil [4082 4095]) ("buffer_size" variable ("size_t" type "class") nil nil nil nil [4096 4115])) ((prototype . t)) nil ((reparse-symbol . classsubparts)) [4070 4116]) ("private" label ((reparse-symbol . classsubparts)) [4118 4126]) ("cb_read" function ("size_t" type "class") (("ptr" variable "void" nil ((pointer . 1)) nil nil [4151 4161]) ("size" variable ("size_t" type "class") nil nil nil nil [4162 4174]) ("nmemb" variable ("size_t" type "class") nil nil nil nil [4175 4188]) ("source" variable "void" nil ((pointer . 1)) nil nil [4189 4202])) ((typemodifiers "static") (prototype . t)) nil ((reparse-symbol . classsubparts)) [4129 4203]) ("cb_seek" function ("int") (("source" variable "void" nil ((pointer . 1)) nil nil [4225 4238]) ("offset" variable ("ogg_int64_t" type "class") nil nil nil nil [4239 4258]) ("whence" variable "int" nil nil nil nil [4259 4270])) ((typemodifiers "static") (prototype . t)) nil ((reparse-symbol . classsubparts)) [4206 4271]) ("cb_close" function ("int") (("source" variable "void" nil ((pointer . 1)) nil nil [4294 4307])) ((typemodifiers "static") (prototype . t)) nil ((reparse-symbol . classsubparts)) [4274 4308]) ("cb_tell" function ("long") (("source" variable "void" nil ((pointer . 1)) nil nil [4331 4344])) ((typemodifiers "static") (prototype . t)) nil ((reparse-symbol . classsubparts)) [4311 4345]) ("file" variable ("PHYSFS_file" type "class") nil ((pointer . 1)) nil nil [4351 4369]) ("vorbis_file" variable ("OggVorbis_File" type "class") nil nil nil nil [4372 4399])) (("SoundFile")) nil nil nil [3965 4402]) ("OggSoundFile" function ("OggSoundFile" type "class") (("file" variable ("PHYSFS_file" type "class") nil ((pointer . 1)) nil nil [4431 4449])) ((parent . "OggSoundFile") (constructor . t)) nil nil [4404 4786]) ("OggSoundFile" function "void" nil ((parent . "OggSoundFile") (destructor . t)) nil nil [4788 4847]) ("read" function ("size_t" type "class") (("_buffer" variable "void" nil ((pointer . 1)) nil nil [4875 4889]) ("buffer_size" variable ("size_t" type "class") nil nil nil nil [4890 4909])) ((parent . "OggSoundFile")) nil nil [4849 5318]) ("cb_read" function ("size_t" type "class") (("ptr" variable "void" nil ((pointer . 1)) nil nil [5349 5359]) ("size" variable ("size_t" type "class") nil nil nil nil [5360 5372]) ("nmemb" variable ("size_t" type "class") nil nil nil nil [5373 5386]) ("source" variable "void" nil ((pointer . 1)) nil nil [5387 5400])) ((parent . "OggSoundFile")) nil nil [5320 5666]) ("cb_seek" function ("int") (("source" variable "void" nil ((pointer . 1)) nil nil [5694 5707]) ("offset" variable ("ogg_int64_t" type "class") nil nil nil nil [5708 5727]) ("whence" variable "int" nil nil nil nil [5728 5739])) ((parent . "OggSoundFile")) nil nil [5668 6270]) ("cb_close" function ("int") (("source" variable "void" nil ((pointer . 1)) nil nil [6301 6314])) ((parent . "OggSoundFile")) nil nil [6274 6415]) ("cb_tell" function ("long") (("source" variable "void" nil ((pointer . 1)) nil nil [6444 6457])) ((parent . "OggSoundFile")) nil nil [6417 6572]) ("fstream" include t nil nil [6653 6671]) ("load_sound_file" function ("SoundFile" type "class") (("filename" variable ("std::string" type "class") nil ((const . t)) nil nil [6699 6727])) ((pointer . 1)) nil nil [6672 7441]))
     :unmatched-syntax 'nil
     )
    )
diff --git a/src/audio/sound_file.cpp b/src/audio/sound_file.cpp
new file mode 100644 (file)
index 0000000..1420a17
--- /dev/null
@@ -0,0 +1,309 @@
+/** Used SDL_mixer and glest source as reference */
+#include <config.h>
+
+#include "sound_file.h"
+
+#include <stdio.h>
+#include <stdint.h>
+#include <algorithm>
+#include <stdexcept>
+#include <sstream>
+#include <physfs.h>
+#include <vorbis/codec.h>
+#include <vorbis/vorbisfile.h>
+
+class WavSoundFile : public SoundFile
+{
+public:
+  WavSoundFile(PHYSFS_file* file);
+  ~WavSoundFile();
+
+  size_t read(void* buffer, size_t buffer_size);
+  void reset();
+
+private:
+  PHYSFS_file* file;
+  
+  PHYSFS_sint64 datastart;
+};
+
+static inline uint32_t read32LE(PHYSFS_file* file)
+{
+  uint32_t result;
+  if(PHYSFS_readULE32(file, &result) == 0)
+    throw std::runtime_error("file too short");
+
+  return result;
+}
+
+static inline uint16_t read16LE(PHYSFS_file* file)
+{
+  uint16_t result;
+  if(PHYSFS_readULE16(file, &result) == 0)
+    throw std::runtime_error("file too short");
+
+  return result;
+}
+
+WavSoundFile::WavSoundFile(PHYSFS_file* file)
+{
+  this->file = file;
+
+  char magic[4];
+  if(PHYSFS_read(file, magic, sizeof(magic), 1) != 1)
+    throw std::runtime_error("Couldn't read file magic (not a wave file)");
+  if(strncmp(magic, "RIFF", 4) != 0) {
+    printf("MAGIC: %4s.\n", magic);
+    throw std::runtime_error("file is not a RIFF wav file");
+  }
+
+  uint32_t wavelen = read32LE(file);
+  (void) wavelen;
+  
+  if(PHYSFS_read(file, magic, sizeof(magic), 1) != 1)
+    throw std::runtime_error("Couldn't read chunk header (not a wav file?)");
+  if(strncmp(magic, "WAVE", 4) != 0)
+    throw std::runtime_error("file is not a valid RIFF/WAVE file");
+
+  char chunkmagic[4];
+  uint32_t chunklen;
+
+  // search audio data format chunk
+  do {
+    if(PHYSFS_read(file, chunkmagic, sizeof(chunkmagic), 1) != 1)
+      throw std::runtime_error("EOF while searching format chunk");    
+    chunklen = read32LE(file);
+    
+    if(strncmp(chunkmagic, "fmt ", 4) == 0)
+      break;
+
+    if(strncmp(chunkmagic, "fact", 4) == 0
+        || strncmp(chunkmagic, "LIST", 4) == 0) {
+      // skip chunk
+      if(PHYSFS_seek(file, PHYSFS_tell(file) + chunklen) == 0)
+        throw std::runtime_error("EOF while searching fmt chunk");
+    } else {
+      throw std::runtime_error("complex WAVE files not supported");
+    }
+  } while(true); 
+
+  if(chunklen < 16)
+    throw std::runtime_error("Format chunk too short");
+  // parse format
+  uint16_t encoding = read16LE(file);
+  if(encoding != 1)
+    throw std::runtime_error("only PCM encoding supported");
+  channels = read16LE(file);
+  rate = read32LE(file);
+  uint32_t byterate = read32LE(file);
+  (void) byterate;
+  uint16_t blockalign = read16LE(file);
+  (void) blockalign;
+  bits_per_sample = read16LE(file);
+
+  if(chunklen > 16) {
+    if(PHYSFS_seek(file, PHYSFS_tell(file) + (chunklen-16)) == 0)
+      throw std::runtime_error("EOF while reading reast of format chunk");
+  }
+
+  // set file offset to DATA chunk data
+  do {
+    if(PHYSFS_read(file, chunkmagic, sizeof(chunkmagic), 1) != 1)
+      throw std::runtime_error("EOF while searching data chunk");    
+    chunklen = read32LE(file);
+
+    if(strncmp(chunkmagic, "data", 4) == 0)
+      break;
+
+    // skip chunk
+    if(PHYSFS_seek(file, PHYSFS_tell(file) + chunklen) == 0)
+      throw std::runtime_error("EOF while searching fmt chunk");
+  } while(true);
+
+  datastart = PHYSFS_tell(file);
+  size = static_cast<size_t> (chunklen);
+}
+
+WavSoundFile::~WavSoundFile()
+{
+  PHYSFS_close(file);
+}
+
+void
+WavSoundFile::reset()
+{
+  if(PHYSFS_seek(file, datastart) == 0)
+    throw std::runtime_error("Couldn't seek to data start");
+}
+
+size_t
+WavSoundFile::read(void* buffer, size_t buffer_size)
+{
+  PHYSFS_sint64 end = datastart + size;
+  PHYSFS_sint64 cur = PHYSFS_tell(file);
+  if(cur >= end)
+    return 0;
+  
+  size_t readsize = std::min(static_cast<size_t> (end - cur), buffer_size);
+  if(PHYSFS_read(file, buffer, readsize, 1) != 1)
+    throw std::runtime_error("read error while reading samples");
+
+  return readsize;
+}
+
+//---------------------------------------------------------------------------
+
+class OggSoundFile : public SoundFile
+{
+public:
+  OggSoundFile(PHYSFS_file* file);
+  ~OggSoundFile();
+
+  size_t read(void* buffer, size_t buffer_size);
+  void reset();
+
+private:
+  static size_t cb_read(void* ptr, size_t size, size_t nmemb, void* source);
+  static int cb_seek(void* source, ogg_int64_t offset, int whence);
+  static int cb_close(void* source);
+  static long cb_tell(void* source);
+  
+  PHYSFS_file* file;
+  OggVorbis_File vorbis_file;
+};
+
+OggSoundFile::OggSoundFile(PHYSFS_file* file)
+{
+  this->file = file;
+
+  ov_callbacks callbacks = { cb_read, cb_seek, cb_close, cb_tell };
+  ov_open_callbacks(file, &vorbis_file, 0, 0, callbacks);
+
+  vorbis_info* vi = ov_info(&vorbis_file, -1);
+  channels = vi->channels;
+  rate = vi->rate;
+  bits_per_sample = 16;
+  size = static_cast<size_t> (ov_pcm_total(&vorbis_file, -1) * 2);
+}
+
+OggSoundFile::~OggSoundFile()
+{
+  ov_clear(&vorbis_file);
+}
+
+size_t
+OggSoundFile::read(void* _buffer, size_t buffer_size)
+{
+  char* buffer = reinterpret_cast<char*> (_buffer);
+  int section = 0;
+  size_t totalBytesRead= 0;
+
+  while(buffer_size>0){
+    long bytesRead 
+      = ov_read(&vorbis_file, buffer, static_cast<int> (buffer_size), 0, 2, 1,
+          &section);
+    if(bytesRead==0){
+      break;
+    }
+    buffer_size -= bytesRead;
+    buffer += bytesRead;
+    totalBytesRead += bytesRead;
+  }
+  
+  return totalBytesRead;
+}
+
+void
+OggSoundFile::reset()
+{
+  ov_raw_seek(&vorbis_file, 0);
+}
+
+size_t
+OggSoundFile::cb_read(void* ptr, size_t size, size_t nmemb, void* source)
+{
+  PHYSFS_file* file = reinterpret_cast<PHYSFS_file*> (source);
+  
+  PHYSFS_sint64 res 
+    = PHYSFS_read(file, ptr, static_cast<PHYSFS_uint32> (size),
+        static_cast<PHYSFS_uint32> (nmemb));
+  if(res <= 0)
+    return 0;
+
+  return static_cast<size_t> (res);
+}
+
+int
+OggSoundFile::cb_seek(void* source, ogg_int64_t offset, int whence)
+{
+  PHYSFS_file* file = reinterpret_cast<PHYSFS_file*> (source);
+
+  switch(whence) {
+    case SEEK_SET:
+      if(PHYSFS_seek(file, static_cast<PHYSFS_uint64> (offset)) == 0)
+        return -1;
+      break;
+    case SEEK_CUR:
+      if(PHYSFS_seek(file, PHYSFS_tell(file) + offset) == 0)
+        return -1;
+      break;
+    case SEEK_END:
+      if(PHYSFS_seek(file, PHYSFS_fileLength(file) + offset) == 0)
+        return -1;
+      break;
+    default:
+#ifdef DEBUG
+      assert(false);
+#else
+      return -1;
+#endif
+  }
+  return 0;
+}
+  
+int
+OggSoundFile::cb_close(void* source)
+{
+  PHYSFS_file* file = reinterpret_cast<PHYSFS_file*> (source);
+  PHYSFS_close(file);
+  return 0;
+}
+
+long
+OggSoundFile::cb_tell(void* source)
+{
+  PHYSFS_file* file = reinterpret_cast<PHYSFS_file*> (source);
+  return static_cast<long> (PHYSFS_tell(file));
+}
+
+//---------------------------------------------------------------------------
+
+#include <fstream>
+SoundFile* load_sound_file(const std::string& filename)
+{
+  PHYSFS_file* file = PHYSFS_openRead(filename.c_str());
+  if(!file) {
+    std::stringstream msg;
+    msg << "Couldn't open '" << filename << "': " << PHYSFS_getLastError();
+    throw std::runtime_error(msg.str());
+  }
+    
+  try {
+    char magic[4];
+    if(PHYSFS_read(file, magic, sizeof(magic), 1) != 1)
+      throw std::runtime_error("Couldn't read magic, file too short");
+    PHYSFS_seek(file, 0);
+    if(strncmp(magic, "RIFF", 4) == 0)
+      return new WavSoundFile(file);
+    else if(strncmp(magic, "OggS", 4) == 0)
+      return new OggSoundFile(file);
+    else
+      throw std::runtime_error("Unknown file format");
+  } catch(std::exception& e) {
+    std::stringstream msg;
+    msg << "Couldn't read '" << filename << "': " << e.what();
+    throw std::runtime_error(msg.str());
+  }
+}
+
diff --git a/src/audio/sound_file.h b/src/audio/sound_file.h
new file mode 100644 (file)
index 0000000..81184b1
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef __SOUND_FILE_H__
+#define __SOUND_FILE_H__
+
+#include <stdio.h>
+#include <iostream>
+
+class SoundFile
+{
+public:
+  virtual ~SoundFile()
+  { }
+
+  virtual size_t read(void* buffer, size_t buffer_size) = 0;
+  virtual void reset() = 0;
+
+  int channels;
+  int rate;
+  int bits_per_sample;
+  /// size in bytes
+  size_t size;
+};
+
+SoundFile* load_sound_file(const std::string& filename);
+
+#endif
+
index bb26ed2..7d95724 100644 (file)
-//  $Id: sound_manager.cpp 2334 2005-04-04 16:26:14Z grumbel $
-//
-//  SuperTux -  A Jump'n Run
-//  Copyright (C) 2004 Matthias Braun <matze@braunis.de
-//
-//  This program is free software; you can redistribute it and/or
-//  modify it under the terms of the GNU General Public License
-//  as published by the Free Software Foundation; either version 2
-//  of the License, or (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-//
-//  You should have received a copy of the GNU General Public License
-//  along with this program; if not, write to the Free Software
-//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-#include <config.h>
-
-#include <cmath>
-#include <cassert>
-#include <iostream>
+#include "sound_manager.h"
+
 #include <stdexcept>
+#include <iostream>
 #include <sstream>
-#include <physfs.h>
+#include <memory>
 
-#include "audio/sound_manager.h"
-
-#include "audio/musicref.h"
-#include "physfs/physfs_sdl.h"
-#include "moving_object.h"
-#include "resources.h"
+#include "sound_file.h"
+#include "sound_source.h"
+#include "stream_sound_source.h"
 
 SoundManager::SoundManager()
-  : current_music(0), m_music_enabled(true) , m_sound_enabled(true),
-    audio_device(false)
+  : device(0), context(0), sound_enabled(false), music_source(0)
 {
+  try {
+    device = alcOpenDevice(0);
+    if(device == 0) {
+      print_openal_version();
+      throw std::runtime_error("Couldn't open audio device.");
+    }
+
+    int attributes[] = { 0 };
+    context = alcCreateContext(device, attributes);
+    check_alc_error("Couldn't create audio context: ");
+    alcMakeContextCurrent(context);
+    check_alc_error("Couldn't select audio context: ");
+
+    check_al_error("Audio error after init: ");
+    sound_enabled = true;
+  } catch(std::exception& e) {
+    device = 0;
+    context = 0;
+    std::cerr << "Couldn't initialize audio device:" << e.what() << "\n";
+    print_openal_version();
+  }
 }
 
 SoundManager::~SoundManager()
 {
-  for(Sounds::iterator i = sounds.begin(); i != sounds.end(); ++i) {
-    Mix_FreeChunk(i->second);
-  }
-  sounds.clear();
-}
+  delete music_source;
 
-int
-SoundManager::play_sound(const std::string& name,int loops)
-{
-  if(!audio_device || !m_sound_enabled)
-    return -1;
-  
-  Mix_Chunk* chunk = preload_sound(name);
-  if(chunk == 0) {
-    std::cerr << "Sound '" << name << "' not found.\n";
-    return -1;
+  for(SoundSources::iterator i = sources.begin(); i != sources.end(); ++i) {
+    delete *i;
   }
-  int chan=Mix_PlayChannel(-1, chunk, loops);  
-  Mix_Volume(chan,MIX_MAX_VOLUME);
-  return chan;
-}
 
-
-int
-SoundManager::play_sound(const std::string& sound, const MovingObject* object,
-    const Vector& pos)
-{
-  // TODO keep track of the object later and move the sound along with the
-  // object.
-  return play_sound(sound, object->get_pos(), pos);
-}
-
-int
-SoundManager::play_sound(const std::string& sound, const Vector& pos,
-    const Vector& pos2)
-{
-  if(!audio_device || !m_sound_enabled)
-    return -1;
-
-  Mix_Chunk* chunk = preload_sound(sound);
-  if(chunk == 0) {
-    std::cerr << "Sound '" << sound << "' not found.\n";
-    return -1;                                               
+  for(SoundBuffers::iterator i = buffers.begin(); i != buffers.end(); ++i) {
+    ALuint buffer = i->second;
+    alDeleteBuffers(1, &buffer);
   }
 
-  // TODO make sure this formula is good
-  float distance 
-    = pos2.x- pos.x;
-  int loud = int(255.0/float(1600) * fabsf(distance));
-  if(loud > 255)
-    return -1;
-
-  int chan = Mix_PlayChannel(-1, chunk, 0);
-  if(chan < 0)
-    return -1;         
-  Mix_Volume(chan,MIX_MAX_VOLUME);                         
-  Mix_SetDistance(chan, loud);
-
-  // very bad way to do this...
-  if(distance > 100)
-    Mix_SetPanning(chan, 230, 24);
-  else if(distance < -100)
-    Mix_SetPanning(chan, 24, 230);
-  return chan;
+  if(context != 0) {
+    alcMakeContextCurrent(0);
+    alcDestroyContext(context);
+  }
+  if(device != 0) {
+    alcCloseDevice(device);
+  }
 }
 
-MusicRef
-SoundManager::load_music(const std::string& file)
+ALuint
+SoundManager::load_file_into_buffer(const std::string& filename)
 {
-  if(!audio_device)
-    return MusicRef(0);
-
-  if(!exists_music(file)) {
-    std::stringstream msg;
-    msg << "Couldn't load musicfile '" << file << "': " << SDL_GetError();
-    throw std::runtime_error(msg.str());
+  // open sound file
+  std::auto_ptr<SoundFile> file (load_sound_file(filename));
+  
+  ALenum format = get_sample_format(file.get());
+  ALuint buffer;
+  alGenBuffers(1, &buffer);
+  check_al_error("Couldn't create audio buffer: ");
+  char* samples = new char[file->size];
+  try {
+    file->read(samples, file->size);
+    alBufferData(buffer, format, samples,
+        static_cast<ALsizei> (file->size),
+        static_cast<ALsizei> (file->rate));
+    check_al_error("Couldn't fill audio buffer: ");
+  } catch(...) {
+    delete[] samples;
+    throw;
   }
+  delete[] samples;
 
-  std::map<std::string, MusicResource>::iterator i = musics.find(file);
-  assert(i != musics.end());
-  return MusicRef(& (i->second));
+  return buffer;
 }
 
-bool
-SoundManager::exists_music(const std::string& filename)
+SoundSource*
+SoundManager::create_sound_source(const std::string& filename)
 {
-  if(!audio_device)
-    return true;
+  if(!sound_enabled)
+    return 0;
+
+  ALuint buffer;
   
-  // song already loaded?
-  std::map<std::string, MusicResource>::iterator i = musics.find(filename);
-  if(i != musics.end()) {
-    return true;                                      
+  // reuse an existing static sound buffer            
+  SoundBuffers::iterator i = buffers.find(filename);
+  if(i != buffers.end()) {
+    buffer = i->second;
+  } else {
+    buffer = load_file_into_buffer(filename);
+    buffers.insert(std::make_pair(filename, buffer));
   }
-  const char* dir = PHYSFS_getRealDir(filename.c_str());
-  if(dir == 0)
-    return false;
-  Mix_Music* song = Mix_LoadMUS( (std::string(dir) + "/" + filename).c_str() );
-  if(song == 0)
-    return false;
-
-  // insert into music list
-  std::pair<std::map<std::string, MusicResource>::iterator, bool> result = 
-    musics.insert(
-        std::make_pair<std::string, MusicResource> (filename, MusicResource()));
-  MusicResource& resource = result.first->second;
-  resource.manager = this;
-  resource.music = song;
-
-  return true;
+  
+  SoundSource* source = new SoundSource();
+  alSourcei(source->source, AL_BUFFER, buffer);
+  return source;  
 }
 
 void
-SoundManager::free_music(MusicResource* )
+SoundManager::play(const std::string& soundname, const Vector& pos)
 {
-  // TODO free music, currently we can't do this since SDL_mixer seems to have
-  // some bugs if you load/free alot of mod files.  
+  std::string filename = "sounds/";
+  filename += soundname;
+  filename += ".wav";
+  try {
+    SoundSource* source = create_sound_source(filename);
+    if(source == 0)
+      return;
+    if(pos == Vector(-1, -1)) {
+      alSourcef(source->source, AL_ROLLOFF_FACTOR, 0);
+    } else {
+      source->set_position(pos);
+    }
+    source->play();
+    sources.push_back(source);
+  } catch(std::exception& e) {
+    std::cout << "Couldn't play sound " << filename << ": " << e.what() << "\n";
+  }
 }
 
 void
-SoundManager::play_music(const MusicRef& musicref, int loops)
+SoundManager::enable_sound(bool enable)
 {
-  if(!audio_device)
+  if(device == 0)
     return;
-
-  if(musicref.music == 0 || current_music == musicref.music)
-    return;
-
-  if(current_music)
-    current_music->refcount--;
-  
-  current_music = musicref.music;
-  current_music->refcount++;
-  
-  if(m_music_enabled)
-    Mix_PlayMusic(current_music->music, loops);
+  sound_enabled = enable;
 }
 
 void
-SoundManager::halt_music()
+SoundManager::enable_music(bool enable)
 {
-  if(!audio_device)
+  if(device == 0)
     return;
-  
-  Mix_HaltMusic();
-  
-  if(current_music) {
-    current_music->refcount--;
-    if(current_music->refcount == 0)
-      free_music(current_music);
-    current_music = 0;
+  music_enabled = enable;
+  if(music_enabled) {
+    play_music(current_music);
+  } else {
+    if(music_source) {
+      delete music_source;
+      music_source = 0;
+    }
   }
 }
 
 void
-SoundManager::enable_music(bool enable)
+SoundManager::play_music(const std::string& filename)
 {
-  if(!audio_device)
+  if(filename == current_music)
     return;
-
-  if(enable == m_music_enabled)
+  current_music = filename;
+  if(!music_enabled)
     return;
-  
-  m_music_enabled = enable;
-  if(m_music_enabled == false) {
-    Mix_HaltMusic();
-  } else {
-    if(current_music)
-      Mix_PlayMusic(current_music->music, -1);
+
+  try {
+    StreamSoundSource* newmusic 
+      = new StreamSoundSource(load_sound_file(filename));
+
+    alSourcef(newmusic->source, AL_ROLLOFF_FACTOR, 0);
+    newmusic->play();
+    delete music_source;
+    music_source = newmusic;
+  } catch(std::exception& e) {
+    std::cerr << "Couldn't play music file '" << filename << "': "
+      << e.what() << "\n";
   }
 }
 
 void
-SoundManager::enable_sound(bool enable)
+SoundManager::set_listener_position(Vector pos)
 {
-  if(!audio_device)
-    return;
-  
-  m_sound_enabled = enable;
+  alListener3f(AL_POSITION, pos.x, pos.y, 0);
 }
 
-SoundManager::MusicResource::~MusicResource()
+void
+SoundManager::set_listener_velocity(Vector vel)
 {
-  // don't free music buggy SDL_Mixer crashs for some mod files
-  // Mix_FreeMusic(music);
+  alListener3f(AL_VELOCITY, vel.x, vel.y, 0);
 }
 
-Mix_Chunk* SoundManager::preload_sound(const std::string& name)
+void
+SoundManager::update()
 {
-  if(!audio_device)
-    return 0;
-
-  Sounds::iterator i = sounds.find(name);
-  if(i != sounds.end()) {
-    return i->second;
+  // check for finished sound sources
+  for(SoundSources::iterator i = sources.begin(); i != sources.end(); ) {
+    SoundSource* source = *i;
+    if(!source->playing()) {
+      delete source;
+      i = sources.erase(i);
+    } else {
+      ++i;
+    }
   }
-
-  std::string filename = "sounds/";
-  filename += name;
-  filename += ".wav";
+  // check streaming sounds
+  if(music_source)
+    music_source->update();
   
-  Mix_Chunk* chunk = Mix_LoadWAV_RW(get_physfs_SDLRWops(filename), true);
-  if(chunk != 0) {
-    sounds.insert(std::make_pair(name, chunk));
+  alcProcessContext(context);
+  check_alc_error("Error while processing audio context: ");
+}
+
+ALenum
+SoundManager::get_sample_format(SoundFile* file)
+{
+  if(file->channels == 2) {
+    if(file->bits_per_sample == 16) {
+      return AL_FORMAT_STEREO16;
+    } else if(file->bits_per_sample == 8) {
+      return AL_FORMAT_STEREO8;
+    } else {
+      throw std::runtime_error("Only 16 and 8 bit samples supported");
+    }
+  } else if(file->channels == 1) {
+    if(file->bits_per_sample == 16) {
+      return AL_FORMAT_MONO16;
+    } else if(file->bits_per_sample == 8) {
+      return AL_FORMAT_MONO8;
+    } else {
+      throw std::runtime_error("Only 16 and 8 bit samples supported");
+    }
   }
+  
+  throw std::runtime_error("Only 1 and 2 channel samples supported");
+}
 
-  return chunk;
+void
+SoundManager::print_openal_version()
+{
+  std::cout << "OpenAL Vendor: " << alGetString(AL_VENDOR) << "\n"
+            << "OpenAL Version: " << alGetString(AL_VERSION) << "\n" 
+            << "OpenAL Renderer: " << alGetString(AL_RENDERER) << "\n"
+            << "OpenAl Extensions: " << alGetString(AL_RENDERER) << "\n";
+}
+
+void
+SoundManager::check_alc_error(const char* message)
+{
+  int err = alcGetError(device);
+  if(err != ALC_NO_ERROR) {
+    std::stringstream msg;
+    msg << message << alcGetString(device, err);
+    throw std::runtime_error(msg.str());
+  }                
+}
+
+void
+SoundManager::check_al_error(const char* message)
+{
+  int err = alGetError();
+  if(err != AL_NO_ERROR) {
+    std::stringstream msg;
+    msg << message << alGetString(err);
+    throw std::runtime_error(msg.str());
+  }  
 }
 
index cacd26f..7542527 100644 (file)
-//  $Id: sound_manager.h 2353 2005-04-06 23:00:16Z matzebraun $
-//
-//  SuperTux -  A Jump'n Run
-//  Copyright (C) 2004 Matthias Braun <matze@braunis.de
-//
-//  This program is free software; you can redistribute it and/or
-//  modify it under the terms of the GNU General Public License
-//  as published by the Free Software Foundation; either version 2
-//  of the License, or (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-//
-//  You should have received a copy of the GNU General Public License
-//  along with this program; if not, write to the Free Software
-//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-#ifndef SUPERTUX_SOUND_MANAGER_H
-#define SUPERTUX_SOUND_MANAGER_H
+#ifndef __SOUND_MANAGER_H__
+#define __SOUND_MANAGER_H__
 
+#include "math/vector.h"
 #include <string>
 #include <vector>
 #include <map>
 
-#include "SDL_mixer.h"
-#include "math/vector.h"
+#include <AL/alc.h>
+#include <AL/al.h>
+
+typedef void* SoundHandle;
 
-class MusicRef;
-class MovingObject;
+class SoundFile;
+class SoundSource;
+class StreamSoundSource;
 
-/** Sound manager
- * This class handles all sounds that are played
- */
 class SoundManager
 {
 public:
   SoundManager();
-  ~SoundManager();
-
-  /// Play sound (maybe looping), return channel number (or -1 on error)
-  int play_sound(const std::string& sound,int loops=0);
-
-  /// Play sound relative to two Vectors.
-  int play_sound(const std::string& sound, const Vector& pos,
-      const Vector& pos2);
-  /// Play sound relative to a MovingObject and a Vector.
-  int play_sound(const std::string& sound, const MovingObject* object,
-      const Vector& pos);
-  
-  /** Load music.
-   * Is used to load the music for a MusicRef.
-   */
-  MusicRef load_music(const std::string& file);
+  virtual ~SoundManager();
 
+  void enable_sound(bool sound_enabled);
   /**
-   * If the sound isn't loaded yet try to load it.
-   * Returns an existing instance of the sound, loads a new one and returns that
-   * or returns 0 if loading failed.
+   * Creates a new sound source object which plays the specified soundfile.
+   * You are responsible for deleting the sound source later (this will stop the
+   * sound).
+   * This function might throw exceptions. It returns 0 if no audio device is
+   * available.
    */
-  Mix_Chunk* preload_sound(const std::string& name);
+  SoundSource* create_sound_source(const std::string& filename);
+  /**
+   * Convenience function to simply play a sound at a given position.
+   * This functions constructs prepends sounds/ to the name and adds .wav
+   */
+  void play(const std::string& name, const Vector& pos = Vector(-1, -1));
 
-  /// Test if a certain music file exists.
-  bool exists_music(const std::string& filename);
+  void set_listener_position(Vector position);
+  void set_listener_velocity(Vector velocity);
 
-  /** Play music.
-   * @param loops: Defaults to -1, which means endless loops.
-   */
-  void play_music(const MusicRef& music, int loops = -1);
+  void enable_music(bool music_enabled);
+  void play_music(const std::string& filename);
 
-  /// Halt music.
-  void halt_music();
+  void update();
 
-  /// Enable/Disable music.
-  void enable_music(bool enable);
+private:
+  friend class SoundSource;
+  friend class StreamSoundSource;
 
-  /// Is music enabled?
-  bool music_enabled()
-  {
-    return m_music_enabled;
-  }
+  static ALuint load_file_into_buffer(const std::string& filename);
+  static ALenum get_sample_format(SoundFile* file);
 
-  /// Enable/Disable sound.
-  void enable_sound(bool enable);
+  void print_openal_version();
+  void check_alc_error(const char* message);
+  static void check_al_error(const char* message);
 
-  /// Is sound enabled?
-  bool sound_enabled()
-  {
-    return m_sound_enabled;
-  }
+  ALCdevice* device;
+  ALCcontext* context;
+  bool sound_enabled;
 
-  /// Is audio available?
-  bool audio_device_available()
-  {
-    return audio_device;
-  }
+  typedef std::map<std::string, ALuint> SoundBuffers;
+  SoundBuffers buffers;
+  typedef std::vector<SoundSource*> SoundSources;
+  SoundSources sources;
 
-  void set_audio_device_available(bool available)
-  {
-    audio_device = available;
-  }
+  StreamSoundSource* music_source;
 
-private:
-  friend class MusicRef;
-  friend class Setup;
-  
-  /// Resource for music.
-  /** Contains the raw music data and
-      information for music reference
-      counting. */
-  class MusicResource
-    {
-    public:
-      ~MusicResource();
-
-      SoundManager* manager;
-      Mix_Music* music;
-      int refcount;
-    };
-
-  void free_music(MusicResource* music);
-
-  typedef std::map<std::string, Mix_Chunk*> Sounds;
-  Sounds sounds;
-
-  typedef std::map<std::string, MusicResource> Musics;
-  Musics musics;
-
-  MusicResource* current_music;
-  bool m_music_enabled;
-  bool m_sound_enabled;
-  bool audio_device;        /* true: available and initialized */
+  bool music_enabled;
+  std::string current_music;
 };
 
-#endif /*SUPERTUX_SOUND_MANAGER_H*/
+#endif
 
diff --git a/src/audio/sound_source.cpp b/src/audio/sound_source.cpp
new file mode 100644 (file)
index 0000000..b0ebdc8
--- /dev/null
@@ -0,0 +1,70 @@
+#include <config.h>
+
+#include "sound_source.h"
+#include "sound_manager.h"
+
+SoundSource::SoundSource()
+{
+  alGenSources(1, &source);
+  SoundManager::check_al_error("Couldn't create audio source: ");
+  set_reference_distance(128);
+}
+
+SoundSource::~SoundSource()
+{
+  stop();
+  alDeleteSources(1, &source);
+}
+
+void
+SoundSource::stop()
+{
+  alSourceStop(source);
+  alSourcei(source, AL_BUFFER, AL_NONE);
+  SoundManager::check_al_error("Problem stopping audio source: ");
+}
+
+void
+SoundSource::play()
+{
+  alSourcePlay(source);
+  SoundManager::check_al_error("Couldn't start audio source: ");
+}
+
+bool
+SoundSource::playing()
+{
+  ALint state = AL_PLAYING;
+  alGetSourcei(source, AL_SOURCE_STATE, &state);
+  return state != AL_STOPPED;
+}
+
+void
+SoundSource::set_looping(bool looping)
+{
+  alSourcei(source, AL_LOOPING, looping ? AL_TRUE : AL_FALSE);
+}
+
+void
+SoundSource::set_position(Vector position)
+{
+  alSource3f(source, AL_POSITION, position.x, position.y, 0);
+}
+
+void
+SoundSource::set_velocity(Vector velocity)
+{
+  alSource3f(source, AL_VELOCITY, velocity.x, velocity.y, 0);
+}
+
+void
+SoundSource::set_gain(float gain)
+{
+  alSourcef(source, AL_GAIN, gain);
+}
+
+void
+SoundSource::set_reference_distance(float distance)
+{
+  alSourcef(source, AL_REFERENCE_DISTANCE, distance);
+}
diff --git a/src/audio/sound_source.h b/src/audio/sound_source.h
new file mode 100644 (file)
index 0000000..65797ca
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef __SOUND_SOURCE_H__
+#define __SOUND_SOURCE_H__
+
+#include <AL/al.h>
+#include "math/vector.h"
+
+class SoundSource
+{
+public:
+  SoundSource();
+  virtual ~SoundSource();
+
+  void play();
+  void stop();
+  bool playing();
+
+  void set_looping(bool looping);
+  /// Set volume (0.0 is silent, 1.0 is normal)
+  void set_gain(float gain);
+  void set_position(Vector position);
+  void set_velocity(Vector position);
+  void set_reference_distance(float distance);
+
+protected:
+  friend class SoundManager;
+  
+  ALuint source;
+};
+
+#endif
+
diff --git a/src/audio/stream_sound_source.cpp b/src/audio/stream_sound_source.cpp
new file mode 100644 (file)
index 0000000..d282c4d
--- /dev/null
@@ -0,0 +1,76 @@
+#include <config.h>
+
+#include "stream_sound_source.h"
+#include "sound_manager.h"
+#include "sound_file.h"
+
+StreamSoundSource::StreamSoundSource(SoundFile* file)
+{
+  this->file = file;
+  alGenBuffers(STREAMFRAGMENTS, buffers);
+  SoundManager::check_al_error("Couldn't allocate audio buffers: ");
+  format = SoundManager::get_sample_format(file);
+  try {
+    for(size_t i = 0; i < STREAMFRAGMENTS; ++i) {
+      fillBufferAndQueue(buffers[i]);
+    }
+  } catch(...) {
+    alDeleteBuffers(STREAMFRAGMENTS, buffers);
+  }
+}
+
+StreamSoundSource::~StreamSoundSource()
+{
+  alDeleteBuffers(STREAMFRAGMENTS, buffers);
+  SoundManager::check_al_error("Couldn't delete audio buffers: ");
+}
+
+void
+StreamSoundSource::update()
+{
+  if(!playing())
+    return;
+
+  ALint processed = 0;
+  alGetSourcei(source, AL_BUFFERS_PROCESSED, &processed);
+  while(processed > 0) {
+    processed--;
+
+    ALuint buffer;
+    alSourceUnqueueBuffers(source, 1, &buffer);
+    SoundManager::check_al_error("Couldn't unqueu audio buffer: ");
+
+    fillBufferAndQueue(buffer);
+  }
+  
+  // we might have to restart the source if we had a buffer underrun
+  if(!playing()) {
+    std::cerr << "Restarting audio source because of buffer underrun.\n";
+    alSourcePlay(source);
+    SoundManager::check_al_error("Couldn't restart audio source: ");
+  }
+
+  // TODO handle fading
+}
+
+void
+StreamSoundSource::fillBufferAndQueue(ALuint buffer)
+{
+  // fill buffer
+  char* bufferdata = new char[STREAMFRAGMENTSIZE];
+  size_t bytesread = 0;
+  do {
+    bytesread += file->read(bufferdata + bytesread,
+        STREAMFRAGMENTSIZE - bytesread);
+    if(bytesread < STREAMFRAGMENTSIZE) {
+      file->reset();
+    }
+  } while(bytesread < STREAMFRAGMENTSIZE);
+  
+  alBufferData(buffer, format, bufferdata, STREAMFRAGMENTSIZE, file->rate);
+  delete[] bufferdata;
+  SoundManager::check_al_error("Couldn't refill audio buffer: ");
+
+  alSourceQueueBuffers(source, 1, &buffer);
+  SoundManager::check_al_error("Couldn't queue audio buffer: ");
+}
diff --git a/src/audio/stream_sound_source.h b/src/audio/stream_sound_source.h
new file mode 100644 (file)
index 0000000..b5002f2
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef __STREAM_SOUND_SOURCE_H__
+#define __STREAM_SOUND_SOURCE_H__
+
+#include <stdio.h>
+#include "sound_source.h"
+
+class SoundFile;
+
+class StreamSoundSource : public SoundSource
+{
+public:
+  StreamSoundSource(SoundFile* file);
+  virtual ~StreamSoundSource();
+
+  void update();
+  
+private:
+  static const size_t STREAMBUFFERSIZE = 1024 * 500;
+  static const size_t STREAMFRAGMENTS = 5;
+  static const size_t STREAMFRAGMENTSIZE 
+    = STREAMBUFFERSIZE / STREAMFRAGMENTS;
+
+  void fillBufferAndQueue(ALuint buffer);
+  SoundFile* file;
+  ALuint buffers[STREAMFRAGMENTS];
+  ALenum format;
+
+  enum FadeState { NoFading, FadingOn, FadingOff };
+  FadeState fade_state;
+  // TODO
+};
+
+#endif
+
index aa0af89..f20a798 100644 (file)
@@ -181,7 +181,7 @@ BadGuy::collision_squished(Player& )
 void
 BadGuy::kill_squished(Player& player)
 {
-  sound_manager->play_sound("squish", get_pos(), player.get_pos());
+  sound_manager->play("squish", get_pos());
   physic.enable_gravity(true);
   physic.set_velocity_x(0);
   physic.set_velocity_y(0);
@@ -193,8 +193,7 @@ BadGuy::kill_squished(Player& player)
 void
 BadGuy::kill_fall()
 {
-  sound_manager->play_sound("fall", this,
-      Sector::current()->player->get_pos());
+  sound_manager->play("fall", get_pos());
   global_stats.add_points(BADGUYS_KILLED_STAT, 1);
   physic.set_velocity_y(0);
   physic.enable_gravity(true);
index b6a1d06..ac891a6 100644 (file)
@@ -36,6 +36,8 @@
 #include "lisp/lisp.h"
 #include "lisp/writer.h"
 #include "video/drawing_context.h"
+#include "audio/sound_manager.h"
+#include "audio/sound_source.h"
 #include "sprite/sprite_manager.h"
 
 class BadGuy : public MovingObject, public Serializable
index 848e62d..45eca33 100644 (file)
@@ -92,8 +92,7 @@ Bomb::explode()
 {
   state = 1;
   sprite->set_action("explosion");
-  sound_manager->play_sound("explosion", get_pos(),
-                            Sector::current()->player->get_pos());
+  sound_manager->play("explosion", get_pos());
   timer.start(EXPLOSIONTIME);
 }
 
index cd60f20..0bd892b 100644 (file)
@@ -23,7 +23,7 @@
 #include "flame.h"
 
 Flame::Flame(const lisp::Lisp& reader)
-  : angle(0), radius(100), speed(2)
+  : angle(0), radius(100), speed(2), source(0)
 {
   reader.get("x", start_position.x);
   reader.get("y", start_position.y);
@@ -36,6 +36,11 @@ Flame::Flame(const lisp::Lisp& reader)
   countMe = false;
 }
 
+Flame::~Flame()
+{
+  delete source;
+}
+
 void
 Flame::write(lisp::Writer& writer)
 {
@@ -56,6 +61,31 @@ Flame::active_update(float elapsed_time)
   Vector newpos(start_position.x + cos(angle) * radius,
                 start_position.y + sin(angle) * radius);
   movement = newpos - get_pos();
+
+  source->set_position(get_pos());
+}
+
+void
+Flame::activate()
+{
+  delete source;
+  source = sound_manager->create_sound_source("sounds/flame.wav");
+  if(!source) {
+    std::cerr << "Couldn't start flame sound.\n";
+    return;
+  }
+  source->set_position(get_pos());
+  source->set_looping(true);
+  source->set_gain(2.0);
+  source->set_reference_distance(32);
+  source->play();
+}
+
+void
+Flame::deactivate()
+{
+  delete source;
+  source = 0;
 }
 
 void
index 225cef0..877fa9b 100644 (file)
@@ -27,6 +27,10 @@ class Flame : public BadGuy
 {
 public:
   Flame(const lisp::Lisp& reader);
+  ~Flame();
+
+  void activate();
+  void deactivate();
 
   void write(lisp::Writer& write);
   void active_update(float elapsed_time);
@@ -36,6 +40,8 @@ private:
   float angle;
   float radius;
   float speed;
+
+  SoundSource* source;
 };
 
 #endif
index a90f0a0..07f126f 100644 (file)
@@ -70,7 +70,7 @@ Jumpy::hit(const CollisionHit& chit)
     
     physic.set_velocity_y(JUMPSPEED);
     // TODO create a nice sound for this...
-    //sound_manager->play_sound("skid");
+    //sound_manager->play("skid");
   } else if(chit.normal.y < .5) { // bumped on roof
     physic.set_velocity_y(0);
   }
index d37a2b5..c392646 100644 (file)
@@ -105,8 +105,7 @@ MrIceBlock::collision_solid(GameObject& object, const CollisionHit& hit)
       dir = dir == LEFT ? RIGHT : LEFT;
       sprite->set_action(dir == LEFT ? "flat-left" : "flat-right");
       physic.set_velocity_x(-physic.get_velocity_x());
-      sound_manager->play_sound("ricochet", get_pos(),
-                                Sector::current()->player->get_pos());
+      sound_manager->play("ricochet", get_pos());
       break;
     }
     case ICESTATE_FLAT:
@@ -153,7 +152,7 @@ MrIceBlock::collision_squished(Player& player)
       }
 
       // flatten
-      sound_manager->play_sound("stomp", get_pos(), player.get_pos());
+      sound_manager->play("stomp", get_pos());
       physic.set_velocity_x(0);
       physic.set_velocity_y(0); 
       
@@ -163,7 +162,7 @@ MrIceBlock::collision_squished(Player& player)
       break;
     case ICESTATE_FLAT:
       // kick
-      sound_manager->play_sound("kick", this, player.get_pos());
+      sound_manager->play("kick", get_pos());
 
       if(player.get_pos().x < get_pos().x) {
         dir = RIGHT;
index 601eebc..509eda9 100644 (file)
@@ -64,7 +64,7 @@ MrTree::collision_squished(Player& player)
     mystate = STATE_NORMAL;
     activate();
 
-    sound_manager->play_sound("squish", get_pos(), player.get_pos());      
+    sound_manager->play("squish", get_pos());
     player.bounce(*this);
   } else {
     sprite->set_action(dir == LEFT ? "squished-left" : "squished-right");
index 255cee5..7882cd4 100644 (file)
@@ -147,7 +147,7 @@ Nolok_01::kill_fall()
   bullet_hitpoints--;
   if (bullet_hitpoints <= 0) {
    hitpoints = 0;
-   sound_manager->play_sound("fall", this,
+   sound_manager->play("fall", this,
                              Sector::current()->player->get_pos());
    physic.set_velocity_y(0);
    physic.enable_gravity(true);
index 6929ea6..8827693 100644 (file)
@@ -76,14 +76,12 @@ void
 RocketExplosion::explode()
 {
   sprite->set_action(dir == LEFT ? "explosion-left" : "explosion-right");
-  sound_manager->play_sound("explosion", get_pos(),
-                            Sector::current()->player->get_pos());
+  sound_manager->play("explosion", get_pos());
   timer.start(EXPLOSIONTIME, true);
 }
 
 void
 RocketExplosion::kill_fall()
 {
-  explode();
 }
 
index 87faba0..c6f0834 100644 (file)
@@ -47,8 +47,10 @@ Yeti::Yeti(const lisp::Lisp& reader)
   sprite->set_action("right");
   state = INIT;
   side = LEFT;
+#if 0
   sound_manager->preload_sound("yeti_gna");
   sound_manager->preload_sound("yeti_roar");
+#endif
   hit_points = INITIAL_HITPOINTS;
   reader.get("dead-script", dead_script);
   countMe = false;
@@ -87,7 +89,7 @@ Yeti::active_update(float elapsed_time)
     case ANGRY_JUMPING:
       if(timer.check()) {
         // jump
-        sound_manager->play_sound("yeti_gna");
+        sound_manager->play("yeti_gna");
         physic.set_velocity_y(JUMP_VEL1);
       }
       break;
@@ -139,7 +141,7 @@ Yeti::collision_squished(Player& player)
     return true;
 
   player.bounce(*this);
-  sound_manager->play_sound("yeti_roar");
+  sound_manager->play("yeti_roar");
   hit_points--;
   if(hit_points <= 0) {
     sprite->set_action("dead");
index 6520a2b..2a5f527 100644 (file)
@@ -99,7 +99,7 @@ private:
   friend class KeyboardMenu;
   friend class JoystickMenu;
 
-       char last_keys[20];
+  char last_keys[20];
 };
 
 #endif
index 4f5495c..5982703 100644 (file)
 
 #include <SDL.h>
 
-#ifndef WIN32
-#include <sys/types.h>
-#include <ctype.h>
-#endif
-
 #include "game_session.h"
 #include "video/screen.h"
+#include "audio/sound_manager.h"
 #include "gui/menu.h"
 #include "sector.h"
 #include "level.h"
@@ -429,6 +425,10 @@ GameSession::update(float elapsed_time)
     newsector = "";
     newspawnpoint = "";
   }
+
+  // update sounds
+  sound_manager->set_listener_position(currentsector->player->get_pos());
+  sound_manager->update();
 }
 
 void 
@@ -698,7 +698,7 @@ GameSession::start_sequence(const std::string& sequencename)
     end_sequence = ENDSEQUENCE_RUNNING;
     endsequence_timer.start(7.0); // 7 seconds until we finish the map
     last_x_pos = -1;
-    sound_manager->play_music(level_end_song, 0);
+    sound_manager->play_music("music/leveldone.mod");
     currentsector->player->invincible_timer.start(7.0);
 
     if(sequencename == "fireworks") {
index 94fa2ac..b763fef 100644 (file)
@@ -26,7 +26,6 @@
 #include <sstream>
 #include <fstream>
 
-#include "audio/sound_manager.h"
 #include "lisp/parser.h"
 #include "lisp/lisp.h"
 #include "lisp/writer.h"
@@ -47,11 +46,6 @@ Config::Config()
   screenwidth = 800;
   screenheight = 600;
   use_gl = true;
-
-  audio_frequency = MIX_DEFAULT_FREQUENCY;
-  audio_channels = MIX_DEFAULT_CHANNELS;
-  audio_chunksize = 2048;
-  audio_voices = MIX_CHANNELS;
 }
 
 Config::~Config()
@@ -81,10 +75,6 @@ Config::load()
   if(config_audio_lisp) {
     config_audio_lisp->get("sound_enabled", sound_enabled);
     config_audio_lisp->get("music_enabled", music_enabled);
-    config_audio_lisp->get("frequency", audio_frequency);
-    config_audio_lisp->get("channels", audio_channels);
-    config_audio_lisp->get("voices", audio_voices);
-    config_audio_lisp->get("chunksize", audio_chunksize);
   }
 
   const lisp::Lisp* config_control_lisp = config_lisp->get_lisp("control");
@@ -112,10 +102,6 @@ Config::save()
   writer.start_list("audio");
   writer.write_bool("sound_enabled", sound_enabled);
   writer.write_bool("music_enabled", music_enabled);
-  writer.write_int("frequency", audio_frequency);
-  writer.write_int("channels", audio_channels);
-  writer.write_int("voices", audio_voices);
-  writer.write_int("chunksize", audio_chunksize);
   writer.end_list("audio");
 
   if(main_controller) {
index cd9c1fe..d16ebe6 100644 (file)
@@ -36,11 +36,6 @@ public:
   int screenheight;
   bool use_gl;
 
-  int audio_frequency;
-  int audio_channels;
-  int audio_voices;
-  int audio_chunksize;
-  
   bool use_fullscreen;
   bool show_fps;
   bool sound_enabled;
diff --git a/src/leveleditor.cpp b/src/leveleditor.cpp
deleted file mode 100644 (file)
index 7cc0756..0000000
+++ /dev/null
@@ -1,1053 +0,0 @@
-//  $Id$
-// 
-//  SuperTux
-//  Copyright (C) 2005 Matthias Braun <matze@braunis.de>
-//
-//  This program is free software; you can redistribute it and/or
-//  modify it under the terms of the GNU General Public License
-//  as published by the Free Software Foundation; either version 2
-//  of the License, or (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-// 
-//  You should have received a copy of the GNU General Public License
-//  along with this program; if not, write to the Free Software
-//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-//  02111-1307, USA.
-
-/***************************************************************************
-                  leveleditor.cpp  -  built'in leveleditor
-                     -------------------
-    begin                : June, 23 2004
-    copyright            : (C) 2004 by Ricardo Cruz
-    email                : rick2@aeiou.pt
- ***************************************************************************/
-
-/***************************************************************************
- *                                                                         *
- *   This program is free software; you can redistribute it and/or modify  *
- *   it under the terms of the GNU General Public License as published by  *
- *   the Free Software Foundation; either version 2 of the License, or     *
- *   (at your option) any later version.                                   *
- *                                                                         *
- ***************************************************************************/
-#if 0
-#include <config.h>
-
-#include <stdlib.h>
-#include <algorithm>
-
-#include "gui/mousecursor.h"
-#include "gui/menu.h"
-#include "gui/button.h"
-#include "audio/sound_manager.h"
-#include "app/gettext.h"
-#include "sprite/sprite.h"
-#include "leveleditor.h"
-#include "resources.h"
-#include "tile.h"
-#include "tile_manager.h"
-#include "sector.h"
-#include "game_session.h"
-#include "object_factory.h"
-#include "object/gameobjs.h"
-#include "object/camera.h"
-#include "object/tilemap.h"
-#include "object/background.h"
-
-LevelEditor::LevelEditor()
-{
-  show_grid = true;
-
-  selection.clear();
-  selection_end = selection_ini = Vector(0,0);
-  left_button = middle_button = mouse_moved =  false;
-  level = 0;
-  level_subset = 0;
-
-  cur_layer = LAYER_TILES;
-  level_changed = false;
-
-  sector = 0;
-  zoom = 1.0;
-
-  /* Creating menus */
-  level_subsets = FileSystem::dsubdirs("/levels", "info");
-  subset_menu = new Menu();
-  subset_menu->add_label(_("Load Subset"));
-  subset_menu->additem(MN_HL,"",0,0);
-  int i = 0;
-  for(std::set<std::string>::iterator it = level_subsets.begin(); it != level_subsets.end(); ++it, ++i)
-    subset_menu->additem(MN_ACTION, (*it),0,0,i);
-  subset_menu->additem(MN_HL,"",0,0);
-  subset_menu->additem(MN_BACK,_("Back"),0,0);
-
-  create_subset_menu = new Menu();
-  create_subset_menu->additem(MN_LABEL,_("New Level Subset"),0,0);
-  create_subset_menu->additem(MN_HL,"",0,0);
-  create_subset_menu->additem(MN_TEXTFIELD,_("Filename   "),0,0,MN_ID_FILENAME_SUBSET);
-  create_subset_menu->additem(MN_TEXTFIELD,_("Title      "),0,0,MN_ID_TITLE_SUBSET);
-  create_subset_menu->additem(MN_TEXTFIELD,_("Description"),0,0,MN_ID_DESCRIPTION_SUBSET);
-  create_subset_menu->additem(MN_ACTION,_("Create"),0,0, MN_ID_CREATE_SUBSET);
-  create_subset_menu->additem(MN_HL,"",0,0);
-  create_subset_menu->additem(MN_BACK,_("Back"),0,0);
-
-  main_menu = new Menu();
-  main_menu->additem(MN_LABEL,_("Level Editor Menu"),0,0);
-  main_menu->additem(MN_HL,"",0,0);
-  main_menu->additem(MN_ACTION,_("Return to Level Editor"),0,0,MN_ID_RETURN);
-  main_menu->additem(MN_GOTO,_("Create Level Subset"),0,create_subset_menu);
-  main_menu->additem(MN_GOTO,_("Load Level Subset"),0,subset_menu);
-  main_menu->additem(MN_HL,"",0,0);
-  main_menu->additem(MN_ACTION,_("Quit Level Editor"),0,0,MN_ID_QUIT);
-
-  settings_menu = new Menu();
-  settings_menu->additem(MN_LABEL,_("Level Settings"),0,0);
-  settings_menu->additem(MN_HL,"",0,0);
-  settings_menu->additem(MN_TEXTFIELD,_("Name    "),0,0,MN_ID_NAME);
-  settings_menu->additem(MN_TEXTFIELD,_("Author  "),0,0,MN_ID_AUTHOR);
-  settings_menu->additem(MN_NUMFIELD, _("Width   "),0,0,MN_ID_WIDTH);
-  settings_menu->additem(MN_NUMFIELD, _("Height  "),0,0,MN_ID_HEIGHT);
-  settings_menu->additem(MN_HL,"",0,0);
-  settings_menu->additem(MN_ACTION,_("Apply"),0,0,MN_ID_APPLY_SETTINGS);
-
-  /* Creating button groups */
-  load_buttons_gfx();
-
-  tiles_board = new ButtonGroup(Vector(SCREEN_WIDTH - 140, 100),
-            Vector(32,32), Vector(4,8));
-
-  tiles_board->add_button(Button(img_rubber_bt, _("Eraser"), SDLKey(SDLK_DELETE)), 0);
-  unsigned int id;
-  for(id = 1; id < tile_manager->get_max_tileid(); id++)
-    {
-    const Tile* tile = tile_manager->get(id);
-    if(!tile)
-      continue;
-
-    Surface* surface = tile->get_editor_image();
-    if(!surface)
-      continue;
-
-    Button button = Button(surface, "", SDLKey(0));
-    tiles_board->add_button(button, id);
-    }
-  gameobjs_first_id = id;
-
-  for(Factories::iterator i = object_factories->begin();
-      i != object_factories->end(); ++i) {
-    
-//    Surface *img = badguy.get_image();
-// FIXME: get image from object. Using the rubber in the meanwhile.
-    tiles_board->add_button(Button(img_rubber_bt, i->first,
-                            SDLKey(SDLK_1+id)), id++);
-  }
-
-  tiles_layer = new ButtonGroup(Vector(12, SCREEN_HEIGHT-64), Vector(80,20), Vector(1,3));
-  tiles_layer->add_button(Button(img_foreground_bt, _("Edtit foreground tiles"),
-                         SDLK_F10), LAYER_FOREGROUNDTILES);
-  tiles_layer->add_button(Button(img_interactive_bt, _("Edit interactive tiles"),
-                         SDLK_F11), LAYER_TILES, true);
-  tiles_layer->add_button(Button(img_background_bt, _("Edit background tiles"),
-                         SDLK_F12), LAYER_BACKGROUNDTILES);
-
-  level_options = new ButtonGroup(Vector(SCREEN_WIDTH-164, SCREEN_HEIGHT-36), Vector(32,32), Vector(5,1));
-  level_options->add_pair_of_buttons(Button(img_next_sector_bt, _("Next sector"), SDLKey(0)), BT_NEXT_SECTOR,
-                 Button(img_previous_sector_bt, _("Prevous sector"), SDLKey(0)), BT_PREVIOUS_SECTOR);
-  level_options->add_pair_of_buttons(Button(img_next_level_bt, _("Next level"), SDLKey(0)), BT_NEXT_LEVEL,
-                 Button(img_previous_level_bt, _("Prevous level"), SDLKey(0)), BT_PREVIOUS_LEVEL);
-  level_options->add_button(Button(img_save_level_bt, _("Save level"), SDLK_F5), BT_LEVEL_SAVE);
-  level_options->add_button(Button(img_test_level_bt, _("Test level"), SDLK_F6), BT_LEVEL_TEST);
-  level_options->add_button(Button(img_setup_level_bt, _("Setup level"), SDLK_F7), BT_LEVEL_SETUP);
-}
-
-LevelEditor::~LevelEditor()
-{
-free_buttons_gfx();
-
-delete tiles_board;
-delete tiles_layer;
-delete level_options;
-
-delete subset_menu;
-delete create_subset_menu;
-delete main_menu;
-delete settings_menu;
-
-delete level;
-delete level_subset;
-}
-
-void LevelEditor::load_buttons_gfx()
-{
-img_foreground_bt = new Surface(datadir + "/images/leveleditor/foreground.png", true);
-img_interactive_bt = new Surface(datadir + "/images/leveleditor/interactive.png", true);
-img_background_bt = new Surface(datadir + "/images/leveleditor/background.png", true);
-
-img_save_level_bt = new Surface(datadir + "/images/leveleditor/save-level.png", true);
-img_test_level_bt = new Surface(datadir + "/images/leveleditor/test-level.png", true);
-img_setup_level_bt = new Surface(datadir + "/images/leveleditor/setup-level.png", true);
-
-img_rubber_bt = new Surface(datadir + "/images/leveleditor/rubber.png", true);
-
-img_previous_level_bt = new Surface(datadir + "/images/leveleditor/previous-level.png", true);
-img_next_level_bt = new Surface(datadir + "/images/leveleditor/next-level.png", true);
-img_previous_sector_bt = new Surface(datadir + "/images/leveleditor/previous-sector.png", true);
-img_next_sector_bt = new Surface(datadir + "/images/leveleditor/next-sector.png", true);
-}
-
-void LevelEditor::free_buttons_gfx()
-{
-delete img_foreground_bt;
-delete img_interactive_bt;
-delete img_background_bt;
-
-delete img_save_level_bt;
-delete img_test_level_bt;
-delete img_setup_level_bt;
-
-delete img_rubber_bt;
-
-delete img_previous_level_bt;
-delete img_next_level_bt;
-delete img_previous_sector_bt;
-delete img_next_sector_bt;
-}
-
-void LevelEditor::run(const std::string filename)
-{
-  sound_manager->halt_music();
-  Menu::set_current(0);
-
-  DrawingContext context;
-
-  if(!filename.empty())
-    {
-    level_nb = -1;
-    load_level(filename);
-    }
-  else
-    Menu::set_current(main_menu);
-
-  mouse_cursor->set_state(MC_NORMAL);
-
-  done = false;
-  while(!done)
-    {
-    events();
-    action();
-    draw(context);
-    }
-
-  if(level_changed)
-    if(confirm_dialog(NULL, _("Level not saved. Wanna to?")))
-      save_level();
-}
-
-void LevelEditor::events()
-{
-  mouse_moved = false;
-
-  SDL_Event event;
-  while(SDL_PollEvent(&event))
-    {
-    Menu* menu = Menu::current();
-    if(menu)
-      {
-      menu->event(event);
-      menu->action();
-      if(menu == main_menu)
-        {
-        switch (main_menu->check())
-          {
-          case MN_ID_RETURN:
-            Menu::set_current(0);
-            break;
-          case MN_ID_QUIT:
-            done = true;
-            break;
-          }
-        }
-      else if(menu == create_subset_menu)
-        {
-        // activate or deactivate Create button if any filename as been specified
-        if(create_subset_menu->get_item_by_id(MN_ID_FILENAME_SUBSET).input[0] == '\0')
-          create_subset_menu->get_item_by_id(MN_ID_CREATE_SUBSET).kind = MN_DEACTIVE;
-        else
-          create_subset_menu->get_item_by_id(MN_ID_CREATE_SUBSET).kind = MN_ACTION;
-
-        if(create_subset_menu->check() == MN_ID_CREATE_SUBSET)
-          {   // applying settings:
-          std::string subset_name = create_subset_menu->get_item_by_id(MN_ID_FILENAME_SUBSET).input;
-          LevelSubset::create(subset_name);
-
-          delete level_subset;
-          level_subset = new LevelSubset();
-          level_subset->load(create_subset_menu->get_item_by_id(MN_ID_FILENAME_SUBSET).input);
-
-          level_subset->title = create_subset_menu->get_item_by_id(MN_ID_TITLE_SUBSET).input;
-          level_subset->description = create_subset_menu->get_item_by_id(MN_ID_DESCRIPTION_SUBSET).input;
-          //FIXME: generate better level filenames
-          level_subset->add_level(subset_name+'/'+"new_level.stl");
-          Level* newlevel = new Level();
-          newlevel->add_sector(create_sector("main", 25, 19));
-          newlevel->save(level_subset->get_level_filename(0));
-          level_subset->save();
-          
-          load_level(0);
-
-          create_subset_menu->get_item_by_id(MN_ID_FILENAME_SUBSET).change_input("");
-          create_subset_menu->get_item_by_id(MN_ID_TITLE_SUBSET).change_input("");
-          create_subset_menu->get_item_by_id(MN_ID_DESCRIPTION_SUBSET).change_input("");
-          }
-        }
-      else if(menu == subset_menu)
-        {
-        int i = subset_menu->check();
-        if(i >= 0)
-          {
-          std::set<std::string>::iterator it = level_subsets.begin();
-          for(int t = 0; t < i; t++)
-            it++;
-          load_level_subset(*it);
-          Menu::set_current(0);
-          }
-        }
-      else if(menu == settings_menu)
-        {
-        if(settings_menu->check() == MN_ID_APPLY_SETTINGS)
-          {   // applying settings:
-          level_changed = true;
-
-          level->name = settings_menu->get_item_by_id(MN_ID_NAME).input;
-          level->author = settings_menu->get_item_by_id(MN_ID_AUTHOR).input;
-
-          solids->resize(atoi(settings_menu->get_item_by_id(MN_ID_WIDTH).input.c_str()),
-                atoi(settings_menu->get_item_by_id(MN_ID_HEIGHT).input.c_str()));
-          foregrounds->resize(atoi(settings_menu->get_item_by_id(MN_ID_WIDTH).input.c_str()),
-                atoi(settings_menu->get_item_by_id(MN_ID_HEIGHT).input.c_str()));
-          backgrounds->resize(atoi(settings_menu->get_item_by_id(MN_ID_WIDTH).input.c_str()),
-                atoi(settings_menu->get_item_by_id(MN_ID_HEIGHT).input.c_str()));
-
-          Menu::set_current(0);
-          }
-        }
-      }
-    // check for events in buttons
-    else if(tiles_board->event(event))
-      {
-      std::vector <int> vector;
-      vector.push_back(tiles_board->selected_id());
-
-      selection.clear();
-      selection.push_back(vector);
-      continue;
-      }
-    else if(tiles_layer->event(event))
-      {
-      cur_layer = tiles_layer->selected_id();
-      continue;
-      }
-    else if(level_options->event(event))
-      {
-      switch(level_options->selected_id())
-        {
-        case BT_LEVEL_SAVE:
-          save_level();
-          break;
-        case BT_LEVEL_TEST:
-          test_level();
-          break;
-        case BT_LEVEL_SETUP:
-          Menu::set_current(settings_menu);
-          break;
-        case BT_NEXT_LEVEL:
-          if(level_nb + 1 < level_subset->get_num_levels())
-            load_level(level_nb + 1);
-          else
-            {
-            char str[1024];
-            sprintf(str,_("Level %d doesn't exist. Create it?"), level_nb + 2);
-            if(confirm_dialog(NULL, str))
-              {
-              level_subset->add_level("new_level.stl");
-              Level* newlevel = new Level();
-              newlevel->add_sector(create_sector("main", 25, 19));
-              newlevel->save(level_subset->get_level_filename(level_nb + 1));
-              level_subset->save();
-              load_level(level_nb + 1);
-              }
-            }
-          break;
-        case BT_PREVIOUS_LEVEL:
-          if(level_nb - 1 >= 0)
-            load_level(level_nb - 1);
-          break;
-        case BT_NEXT_SECTOR:
-          std::cerr << "next sector.\n";
-          load_sector(sectornum+1);
-          break;
-        case BT_PREVIOUS_SECTOR:
-          std::cerr << "previous sector.\n";
-          if(sectornum > 0)
-            load_sector(sectornum-1);
-          break;
-        }
-      level_options->set_unselected();
-      continue;
-      }
-    else
-      {
-      switch(event.type)
-        {
-        case SDL_MOUSEMOTION:
-          mouse_moved = true;
-          mouse_x = event.motion.x;
-          mouse_y = event.motion.y;
-          if(SDL_GetMouseState(NULL, NULL)&SDL_BUTTON(SDL_BUTTON_RIGHT))
-            {  // movement like in strategy games
-            scroll.x += -1 * event.motion.xrel;
-            scroll.y += -1 * event.motion.yrel;
-            }
-          break;
-
-        case SDL_MOUSEBUTTONDOWN:
-          mouse_moved = true;
-          mouse_x = event.motion.x;
-          mouse_y = event.motion.y;          
-          if(event.button.button == SDL_BUTTON_LEFT)
-            left_button = true;
-          else if(event.button.button == SDL_BUTTON_MIDDLE)
-            {
-            middle_button = true;
-            selection_ini = Vector(event.button.x, event.button.y);
-            }
-          break;
-
-        case SDL_MOUSEBUTTONUP:
-          mouse_moved = true;
-          mouse_x = event.motion.x;
-          mouse_y = event.motion.y;                    
-          if(event.button.button == SDL_BUTTON_LEFT)
-            left_button = false;
-          else if(event.button.button == SDL_BUTTON_MIDDLE)
-            {
-            middle_button = false;
-            selection_end = Vector(event.button.x, event.button.y);
-
-            if(selection_end.x < selection_ini.x)
-              {
-              float t = selection_ini.x;
-              selection_ini.x = selection_end.x;
-              selection_end.x = t;
-              }
-            if(selection_end.y < selection_ini.y)
-              {
-              float t = selection_ini.y;
-              selection_ini.y = selection_end.y;
-              selection_end.y = t;
-              }
-
-            selection.clear();
-            std::vector <int> vector;
-
-            TileMap* tilemap = 0;
-            if(cur_layer == LAYER_FOREGROUNDTILES)
-              tilemap = foregrounds;
-            else if(cur_layer == LAYER_TILES)
-              tilemap = solids;
-            else if(cur_layer == LAYER_BACKGROUNDTILES)
-              tilemap = backgrounds;
-
-            for(int x = 0; x < (int)((selection_end.x - selection_ini.x)*zoom / 32) + 1; x++)
-              {
-              vector.clear();
-              for(int y = 0; y < (int)((selection_end.y - selection_ini.y)*zoom / 32) + 1; y++)
-                {
-                vector.push_back(tilemap->get_tile(x +
-                 (int)(((selection_ini.x+scroll.x)*zoom)/32),
-                 y + (int)(((selection_ini.y+scroll.y)*zoom)/32))->getID());
-                }
-              selection.push_back(vector);
-              }
-            }
-          break;
-
-        case SDL_KEYDOWN:   // key pressed
-          switch(event.key.keysym.sym)
-            {
-            case SDLK_ESCAPE:
-              Menu::set_current(main_menu);
-              break;
-            /* scrolling related events: */
-            case SDLK_HOME:
-              scroll.x = 0;
-              break;
-            case SDLK_END:
-              scroll.x = sector->solids->get_height()*32 - SCREEN_WIDTH;
-              break;
-            case SDLK_LEFT:
-              scroll.x -= 80;
-              break;
-            case SDLK_RIGHT:
-              scroll.x += 80;
-              break;
-            case SDLK_UP:
-              scroll.y -= 80;
-              break;
-            case SDLK_DOWN:
-              scroll.y += 80;
-              break;
-            case SDLK_PAGEUP:
-              scroll.x -= 450;
-              break;
-            case SDLK_PAGEDOWN:
-              scroll.x += 450;
-              break;
-            case SDLK_PLUS:
-            case SDLK_KP_PLUS:
-              zoom += 0.10;
-              break;
-            case SDLK_MINUS:
-            case SDLK_KP_MINUS:
-              zoom -= 0.10;
-              break;
-
-            case SDLK_F1:
-              show_help();
-              break;
-            case SDLK_F2:
-              show_grid = !show_grid;
-              break;
-            default:
-              break;
-            }
-          break;
-
-        case SDL_QUIT:   // window closed
-          done = true;
-          break;
-
-          default:
-            break;
-        }
-      }
-    }
-}
-
-void LevelEditor::action()
-{
-  mouse_cursor->set_state(MC_NORMAL);
-  if(tiles_board->is_hover() || tiles_layer->is_hover() || level_options->is_hover())
-    mouse_cursor->set_state(MC_LINK);
-
-  if(sector)
-    {
-    // don't scroll before the start or after the level's end
-    float width = sector->solids->get_width() * 32;
-    float height = sector->solids->get_height() * 32;
-
-    if(scroll.x < -SCREEN_WIDTH/2)
-      scroll.x = -SCREEN_WIDTH/2;
-    if(scroll.x > width - SCREEN_WIDTH/2)
-      scroll.x = width - SCREEN_WIDTH/2;
-    if(scroll.y < -SCREEN_HEIGHT/2)
-      scroll.y = -SCREEN_HEIGHT/2;
-    if(scroll.y > height - SCREEN_HEIGHT/2)
-      scroll.y = height - SCREEN_HEIGHT/2;
-
-    // set camera translation, since BadGuys like it
-    sector->camera->set_scrolling((int)scroll.x, (int)scroll.y);
-
-    if(left_button && mouse_moved)
-      for(unsigned int x = 0; x < selection.size(); x++)
-        for(unsigned int y = 0; y < selection[x].size(); y++)
-          change((int)(scroll.x + mouse_x) + (x*32),
-               (int)(scroll.y + mouse_y) + (y*32), selection[x][y], 
-               cur_layer);
-    }
-}
-
-#define FADING_TIME .6
-
-void LevelEditor::draw(DrawingContext& context)
-{
-  context.draw_text(white_text, _("Level Editor"), Vector(10, 5), LEFT_ALLIGN, LAYER_GUI);
-  mouse_cursor->draw(context);
-
-  // draw a filled background
-  context.draw_filled_rect(Vector(0,0), Vector(SCREEN_WIDTH,SCREEN_HEIGHT), Color(60,60,60), LAYER_BACKGROUND0-1);
-
-  if(level_name_timer.check())
-    {
-    context.push_transform();
-    if(level_name_timer.get_timeleft() < FADING_TIME)
-      context.set_alpha(int(level_name_timer.get_timeleft() * 255 / FADING_TIME));
-
-    context.draw_text(gold_text, level->name, Vector(SCREEN_WIDTH/2, 30), CENTER_ALLIGN, LAYER_GUI);
-    if(level_nb != -1)
-      {
-      char str[128];
-      sprintf(str, "%i/%i", level_nb+1, level_subset->get_num_levels());
-      context.draw_text(gold_text, str, Vector(SCREEN_WIDTH/2, 50), CENTER_ALLIGN, LAYER_GUI);
-      }
-
-    context.pop_transform();
-    }
-  if(sector)
-    context.draw_text(white_small_text, _("F1 for help"), Vector(5, 510), LEFT_ALLIGN, LAYER_GUI-10);
-  else
-    context.draw_text(white_small_text, _("Choose a level subset"), Vector(5, 510), LEFT_ALLIGN, LAYER_GUI-10);
-
-  Menu* menu = Menu::current();
-  if(menu)
-    menu->draw(context);
-  else
-    {
-    tiles_board->draw(context);
-    tiles_layer->draw(context);
-    level_options->draw(context);
-    }
-
-  // draw selection
-  if(sector)
-    {
-    if(!middle_button)
-      {
-      context.set_drawing_effect(SEMI_TRANSPARENT);
-
-      if(selection.size())
-        {
-        if(selection[0][0] == 0 && selection.size() == 1)
-            context.draw_surface(img_rubber_bt, Vector(mouse_x - 8,
-            mouse_y - 8), LAYER_GUI-2);
-        else if(selection[0][0] >= gameobjs_first_id || selection[0][0] < 0)
-          {
-  // FIXME: this should draw an object image near cursor
-  #if 0
-          int id = selection[0][0];
-
-          if(id == OBJ_TRAMPOLINE)
-            context.draw_surface(img_trampoline[0].get_frame(0), Vector(mouse_x - 8,
-            mouse_y - 8), LAYER_GUI-2);
-          else if(id == OBJ_FLYING_PLATFORM)
-            context.draw_surface(img_flying_platform->get_frame(0), Vector(mouse_x - 8,
-            mouse_y - 8), LAYER_GUI-2);
-          else
-          if(id == OBJ_DOOR)
-            /*context.draw_surface(door->get_frame(0), Vector(mouse_x - 8,
-            mouse_y - 8), LAYER_GUI-2);*/
-            ;
-          else
-            {
-            BadGuyKind kind = BadGuyKind((-id)-1);
-            BadGuy badguy(kind, 0,0);
-            badguy.activate(LEFT);
-            Surface *img = badguy.get_image();
-
-            context.draw_surface(img, Vector(mouse_x - 8,
-            mouse_y - 8), LAYER_GUI-2);
-            }
-  #endif
-          }
-        else
-          {
-          for(unsigned int x = 0; x < selection.size(); x++)
-            for(unsigned int y = 0; y < selection[x].size(); y++) {
-              const Tile* tile = tile_manager->get(selection[x][y]);
-              tile->draw(context,
-                  Vector(mouse_x + x*32 - 8, mouse_y + y*32 - 8),
-                  LAYER_GUI-2);
-            }
-          }
-        }
-      context.set_drawing_effect(NONE_EFFECT);
-      }
-    else
-      context.draw_filled_rect(Vector(std::min((int)selection_ini.x, mouse_x)*zoom,
-                     std::min((int)selection_ini.y, mouse_y))*zoom,
-                     Vector(abs(mouse_x - (int)selection_ini.x)*zoom,
-                     abs(mouse_y - (int)selection_ini.y)*zoom),
-                     Color(170,255,170,128), LAYER_GUI-2);
-
-    if(show_grid)
-      {
-      for(int x = 0; x < SCREEN_WIDTH / (32*zoom); x++)
-        {
-        int pos = (int)(x*32*zoom) - ((int)scroll.x % 32);
-        context.draw_filled_rect(Vector (pos, 0), Vector(1, SCREEN_HEIGHT),
-                  Color(225, 225, 225), LAYER_GUI-50);
-        }
-      for(int y = 0; y < SCREEN_HEIGHT / (32*zoom); y++)
-        {
-        int pos = (int)(y*32*zoom) - ((int)scroll.y % 32);
-        context.draw_filled_rect(Vector (0, pos), Vector(SCREEN_WIDTH, 1),
-                  Color(225, 225, 225), LAYER_GUI-50);
-        }
-      }
-
-    context.push_transform();
-    context.set_translation(scroll);
-    context.set_zooming(zoom);
-
-    for(Sector::GameObjects::iterator i = sector->gameobjects.begin(); i != sector->gameobjects.end(); ++i)
-      {
-      TileMap* tilemap = dynamic_cast<TileMap*> (*i);
-      if(tilemap)
-        {  // draw the non-selected tiles semi-transparently
-        context.push_transform();
-
-        if(tilemap->get_layer() != cur_layer)
-          context.set_drawing_effect(SEMI_TRANSPARENT);
-        (*i)->draw(context);
-
-        context.pop_transform();
-        continue;
-        }
-      Background* background = dynamic_cast<Background*> (*i);
-      if(background)
-        {  // don't resize background
-        context.push_transform();
-        context.set_zooming(1.0);
-        (*i)->draw(context);
-        context.pop_transform();
-        }
-      else
-        (*i)->draw(context);
-      }
-
-    context.pop_transform();
-    }
-  else
-    context.draw_filled_rect(Vector(0,0), Vector(SCREEN_WIDTH,SCREEN_HEIGHT),Color(0,0,0), LAYER_BACKGROUND0);
-
-  context.do_drawing();
-}
-
-void LevelEditor::load_level_subset(std::string filename)
-{
-  delete level_subset;
-  level_subset = new LevelSubset();
-  level_subset->load(filename.c_str());
-  load_level(0);
-}
-
-void LevelEditor::load_level(std::string filename)
-{
-  if(level_changed)
-    {
-    if(confirm_dialog(NULL, _("Level not saved. Wanna to?")))
-      save_level();
-    else
-      return;
-    }
-
-  level_filename = filename;
-
-  delete level;
-  level = new Level();
-  level->load(filename);
-  
-  sectornum = 0;
-  load_sector(0);
-  level_name_timer.start(3000);
-  scroll.x = scroll.y = 0;
-  level_changed = false;
-
-  settings_menu->get_item_by_id(MN_ID_NAME).change_input(level->name.c_str());
-  settings_menu->get_item_by_id(MN_ID_AUTHOR).change_input(level->author.c_str());
-}
-
-void LevelEditor::load_level(int nb)
-{
-  if(level_changed)
-    {
-    if(confirm_dialog(NULL, _("Level not saved. Wanna to?")))
-      save_level();
-    else
-      return;
-    }
-
-  level_nb = nb;
-  level_filename = level_subset->get_level_filename(level_nb);
-
-  load_level(level_filename);
-}
-
-void LevelEditor::load_sector(size_t num)
-{
-  assert(num <= level->get_sector_count());
-  
-  if(num >= level->get_sector_count())
-  {
-    if(!confirm_dialog(NULL, _("No more sectors exist. Create another?")))
-      return;
-    Sector* sector_ = create_sector("new_sector",25,19);
-    level->add_sector(sector_);
-    num = level->get_sector_count()-1;
-  }
-
-  sector = level->get_sector(num);
-
-  /* Load sector stuff */
-
-  sector->update_game_objects();
-
-  foregrounds = solids = backgrounds = 0;
-  /* Point foregrounds, backgrounds, solids to its layer */
-  for(Sector::GameObjects::iterator i = sector->gameobjects.begin(); i != sector->gameobjects.end(); i++)
-    {
-    TileMap* tilemap = dynamic_cast<TileMap*> (*i);
-    if(tilemap)
-      {
-      if(tilemap->get_layer() == LAYER_FOREGROUNDTILES)
-        foregrounds = tilemap;
-      else if(tilemap->get_layer() == LAYER_TILES)
-        solids = tilemap;
-      else if(tilemap->get_layer() == LAYER_BACKGROUNDTILES)
-        backgrounds = tilemap;
-      }
-    }
-
-  if(!foregrounds)
-    {
-    TileMap* tilemap = new TileMap(LAYER_FOREGROUNDTILES, false, solids->get_width(), solids->get_height());
-    sector->add_object(tilemap);
-    sector->update_game_objects();
-    }
-  if(!backgrounds)
-    {
-    TileMap* tilemap = new TileMap(LAYER_BACKGROUNDTILES, false, solids->get_width(), solids->get_height());
-    sector->add_object(tilemap);
-    sector->update_game_objects();
-    }
-
-  char str[64];
-  sprintf(str, "%i", solids->get_width());
-  settings_menu->get_item_by_id(MN_ID_WIDTH).change_input(str);
-  sprintf(str, "%i", solids->get_height());
-  settings_menu->get_item_by_id(MN_ID_HEIGHT).change_input(str);
-
-  sectornum = num;
-}
-
-void LevelEditor::save_level()
-{
-  level->save(level_filename);
-  level_changed = false;
-}
-
-void LevelEditor::test_level()
-{
-  if(level_changed) {
-    if(confirm_dialog(NULL, _("Level not saved. Wanna to?")))
-      save_level();
-    else
-      return;
-  }
-
-  GameSession session(level_filename, ST_GL_TEST);
-  session.run();
-  //  player_status.reset();
-  sound_manager->halt_music();
-}
-
-void LevelEditor::change(int x, int y, int newtile, int layer)
-{  
-  (void) layer;
-  // find the tilemap of the current layer, and then change the tile
-  if(x < 0 || (unsigned int)x >= sector->solids->get_width()*32 ||
-      y < 0 || (unsigned int)y >= sector->solids->get_height()*32)
-    return;
-
-  level_changed = true;
-  
-  if(zoom != 1)
-  { 
-    // no need to do this for normal view (no zoom)
-    x = (int)(x * (zoom*32) / 32);
-    y = (int)(y * (zoom*32) / 32);
-  }
-
-  if(newtile >= gameobjs_first_id)  // add object
-  {
-    // remove an active tile or object that might be there
-    change(x, y, 0, LAYER_TILES);
-
-    int id = 0;
-    GameObject* object = 0;
-    for(Factories::iterator i = object_factories->begin(); i !=
-        object_factories->end(); ++i) {
-      if(id == newtile - gameobjs_first_id) {
-        object = create_object(i->first, Vector(x, y));
-        break;
-      }
-      id++;
-    }
-    if(object) {
-      sector->add_object(object);
-      sector->update_game_objects();
-    }
-  } else if(cur_layer == LAYER_FOREGROUNDTILES) {
-    foregrounds->change(x/32, y/32, newtile);
-  } else if(cur_layer == LAYER_TILES) {
-    // remove a bad guy if it's there
-    // we /32 in order to round numbers
-    for(Sector::GameObjects::iterator i = sector->gameobjects.begin();
-        i < sector->gameobjects.end(); i++) {
-// FIXME: if there is a game objs in here, remove it!
-#if 0
-      BadGuy* badguy = dynamic_cast<BadGuy*> (*i);
-      if(badguy)
-        if((int)badguy->base.x/32 == x/32 && (int)badguy->base.y/32 == y/32)
-          sector->gameobjects.erase(i);
-      Trampoline* trampoline = dynamic_cast<Trampoline*> (*i);
-      if(trampoline)
-      {
-        if((int)trampoline->base.x/32 == x/32 && (int)trampoline->base.y/32 == y/32)
-          sector->gameobjects.erase(i);
-      }
-      FlyingPlatform* flying_platform = dynamic_cast<FlyingPlatform*> (*i);
-      if(flying_platform)
-        if((int)flying_platform->base.x/32 == x/32 && (int)flying_platform->base.y/32 == y/32)
-          sector->gameobjects.erase(i);
-      Door* door = dynamic_cast<Door*> (*i);
-      if(door)
-        if((int)door->get_area().x/32 == x/32 && (int)door->get_area().y/32 == y/32)
-          sector->gameobjects.erase(i);
-#endif
-    }
-    sector->update_game_objects();
-    solids->change(x/32, y/32, newtile);
-  } else if(cur_layer == LAYER_BACKGROUNDTILES)
-    backgrounds->change(x/32, y/32, newtile);
-}
-
-void LevelEditor::show_help()
-{
-  DrawingContext context;
-
-  bool show_grid_t = show_grid;
-  show_grid = false;
-  mouse_cursor->set_state(MC_HIDE);
-
-
-  char str[1024];
-  const char *text1[] = {
-           _("This is the built-in level editor. Its aim is to be intuitive\n"
-           "and simple to use, so it should be pretty straightforward.\n"
-           "\n"
-           "To open a level, first you'll have to select a level subset from\n"
-           "the menu (or create your own).\n"
-           "A level subset is basically a collection of levels.\n"
-           "They can then be played from the Contrib menu.\n"
-           "\n"
-           "To access the menu from the level editor, just press Esc.\n"
-           "\n"
-           "You are currently looking at the level. To scroll it, just\n"
-           "press the right mouse button and drag the mouse. It will move like\n"
-           "a strategy game.\n"
-           "You can also use the arrow keys and Page Up/Down.\n"
-           "\n"
-           "'+' and '-' keys can be used to zoom the level in/out.\n"
-           "\n"
-           "You probably already noticed those floating groups of buttons.\n"
-           "Each one serves a different purpose. To select a certain button\n"
-           "just press the Left mouse button on it. A few buttons have key\n"
-           "shortcuts. You can find them by pressing the Right mouse button on\n"
-           "a button. That will also show what that button does.\n"
-           "Groups of buttons can also be moved around by just dragging them,\n"
-           "while pressing the Left mouse button.\n"
-           "\n"
-           "Let's learn a bit of what each group of buttons does, shall we?\n"
-           "\n"
-           "To starting putting tiles and objects around use the bigger group\n"
-           "of buttons. Each button is a different tile. To put it on the level,\n"
-           "just press it and then left click in the level.\n"
-           "You can also copy tiles from the level by using the middle mouse button.\n"
-           "Use the mouse wheel to scroll that group of buttons. You will find\n"
-           "enemies and game objects in the bottom.\n")
-                  };
-
-  const char *text2[] = {
-           _("The Foreground/Interactive/Background buttons may be used to\n"
-           "see and edit the respective layer. Levels have three tiles layers:\n"
-           "Foreground - tiles are drawn on top of everything and have no contact\n"
-           "with the player.\n"
-           "Interactive - these are the tiles that have contact with the player.\n"
-           "Background - tiles are drawn underneath everything and have no contact\n"
-           "with the player.\n"
-           "The unselected layers will be drawn semi-transparently.\n"
-           "\n"
-           "Last, but not least, the group of buttons that's left serves\n"
-           "to do related actions with the level.\n"
-           "From left to right:\n"
-           "Mini arrows - can be used to choose other sectors.\n"
-           "Sectors are mini-levels, so to speak, that can be accessed using a door.\n"
-           "Big arrows - choose other level in the same level subset.\n"
-           "Diskette - save the level\n"
-           "Tux - test the level\n"
-           "Tools - set a few settings for the level, including resizing it.\n"
-           "\n"
-           "We have reached the end of this Howto.\n"
-           "\n"
-           "Don't forget to send us a few cool levels. :)\n"
-           "\n"
-           "Enjoy,\n"
-           "  SuperTux development team\n"
-           "\n"
-           "PS: If you are looking for something more powerful, you might like to\n"
-           "try FlexLay. FlexLay is a level editor that supports several games,\n"
-           "including SuperTux. It is an independent project.\n"
-           "Webpage: http://pingus.seul.org/~grumbel/flexlay/")
-                  };
-
-  const char **text[] = { text1, text2 };
-
-
-  bool done;
-  for(unsigned int i = 0; i < sizeof(text) / sizeof(text[0]); i++)
-    {
-    draw(context);
-
-    context.draw_text(blue_text, _("- Level Editor's Help -"), Vector(SCREEN_WIDTH/2, 60), CENTER_ALLIGN, LAYER_GUI);
-
-    context.draw_text(white_small_text, *text[i], Vector(20, 120), LEFT_ALLIGN, LAYER_GUI);
-
-    sprintf(str,_("Press any key to continue - Page %d/%d"), i+1, sizeof(text) / sizeof(text[0]));
-    context.draw_text(gold_text, str, Vector(SCREEN_WIDTH/2, SCREEN_HEIGHT-60), CENTER_ALLIGN, LAYER_GUI);
-
-    context.do_drawing();
-
-    done = false;
-
-    while(!done) {
-      SDL_Event event;
-      done = wait_for_event(event);
-      SDL_Delay(50);
-    }
-  }
-
-  show_grid = show_grid_t;
-  mouse_cursor->set_state(MC_NORMAL);
-}
-
-Sector*
-LevelEditor::create_sector(const std::string& name, size_t width, size_t height)
-{
-  Sector* sector = new Sector;
-  sector->set_name(name);
-  
-  sector->add_object(new TileMap(LAYER_BACKGROUNDTILES, false, width, height));
-  sector->add_object(new TileMap(LAYER_TILES, true, width, height));
-  sector->add_object(new TileMap(LAYER_FOREGROUNDTILES, false, width, height));
-  sector->add_object(new Camera(sector));
-  sector->update_game_objects();
-  
-  return sector;
-}
-
-#endif
diff --git a/src/leveleditor.h b/src/leveleditor.h
deleted file mode 100644 (file)
index 33b0677..0000000
+++ /dev/null
@@ -1,155 +0,0 @@
-//  $Id$
-// 
-//  SuperTux
-//  Copyright (C) 2005 Matthias Braun <matze@braunis.de>
-//
-//  This program is free software; you can redistribute it and/or
-//  modify it under the terms of the GNU General Public License
-//  as published by the Free Software Foundation; either version 2
-//  of the License, or (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-// 
-//  You should have received a copy of the GNU General Public License
-//  along with this program; if not, write to the Free Software
-//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-//  02111-1307, USA.
-#ifndef SUPERTUX_LEVELEDITOR_H
-#define SUPERTUX_LEVELEDITOR_H
-
-#if 0
-
-#include <set>
-#include <string>
-
-#include "video/drawing_context.h"
-#include "timer.h"
-#include "level.h"
-#include "level_subset.h"
-
-using namespace SuperTux;
-
-namespace SuperTux {
-class ButtonGroup;
-}
-
-class Menu;
-class Sector;
-class TileMap;
-class Surface;
-
-enum {
-  MN_ID_RETURN,
-  MN_ID_LOAD_SUBSET,
-  MN_ID_QUIT,
-
-  // settings menu ids:
-  MN_ID_NAME,
-  MN_ID_AUTHOR,
-  MN_ID_WIDTH,
-  MN_ID_HEIGHT,
-  MN_ID_APPLY_SETTINGS,
-  
-  // creating subset menu ids:
-  MN_ID_FILENAME_SUBSET,
-  MN_ID_TITLE_SUBSET,
-  MN_ID_DESCRIPTION_SUBSET,
-  MN_ID_CREATE_SUBSET
-  };
-
-enum {
-  BT_LEVEL_SAVE,
-  BT_LEVEL_TEST,
-  BT_LEVEL_SETUP,
-
-  BT_NEXT_LEVEL,
-  BT_PREVIOUS_LEVEL,
-  BT_NEXT_SECTOR,
-  BT_PREVIOUS_SECTOR
-  };
-
-enum {
-  OBJ_TRAMPOLINE = -100,
-  OBJ_FLYING_PLATFORM = -101,
-  OBJ_DOOR = -102
-  };
-
-class LevelEditor
-{
-public:
-  LevelEditor();
-  ~LevelEditor();
-
-  void run(const std::string filename = "");
-
-private:
-  void events();
-  void action();
-  void draw(DrawingContext& context);
-
-  void load_level_subset(std::string filename);
-  void load_level(std::string filename);
-  void load_level(int nb);
-  void load_sector(size_t num);
-
-  void save_level();
-  void test_level();
-  void setup_level();
-
-  void show_help();
-
-  void change(int x, int y, int newtile, int layer);
-
-  void load_buttons_gfx();
-  void free_buttons_gfx();
-
-  Level* level;
-  std::string level_filename;
-
-  size_t sectornum; // number of current sector
-  Sector* sector;  // current sector
-  TileMap *solids, *foregrounds, *backgrounds;
-  std::string sector_name;
-
-  std::set<std::string> level_subsets;
-  LevelSubset* level_subset;
-  int level_nb;
-
-  Menu* main_menu;
-  Menu* subset_menu;
-  Menu* create_subset_menu;
-  Menu* settings_menu;
-
-  bool left_button, middle_button, mouse_moved;
-  int mouse_x, mouse_y;
-  bool done;
-  bool show_grid;
-
-  Vector scroll;
-  float zoom;
-
-  Timer level_name_timer;
-
-  Surface *img_background_bt, *img_foreground_bt, *img_interactive_bt;
-  Surface *img_save_level_bt, *img_setup_level_bt, *img_test_level_bt;
-  Surface *img_rubber_bt;
-  Surface *img_previous_level_bt, *img_next_level_bt, *img_previous_sector_bt, *img_next_sector_bt;
-
-  ButtonGroup *tiles_board, *tiles_layer, *level_options;
-  int gameobjs_first_id, cur_layer;
-
-  std::vector <std::vector <int> > selection;
-  Vector selection_ini, selection_end;
-
-  bool level_changed;
-
-private:
-  Sector* create_sector(const std::string& name, size_t width, size_t height);
-};
-
-#endif
-
-#endif
index 2b05e6c..16a9cd0 100644 (file)
@@ -355,32 +355,13 @@ static void init_audio()
 {
   sound_manager = new SoundManager();
   
-  int format = MIX_DEFAULT_FORMAT;
-  if(Mix_OpenAudio(config->audio_frequency, format, config->audio_channels,
-                   config->audio_chunksize) < 0) {
-    std::cerr << "Couldn't initialize audio ("
-              << config->audio_frequency << "HZ, " << config->audio_channels
-              << " Channels, Format " << format << ", ChunkSize "
-              << config->audio_chunksize << "): " << SDL_GetError() << "\n";
-    return;
-  }
-  sound_manager->set_audio_device_available(true);
   sound_manager->enable_sound(config->sound_enabled);
   sound_manager->enable_music(config->music_enabled);
-  
-  if(Mix_AllocateChannels(config->audio_voices) < 0) {
-    std::cerr << "Couldn't allocate '" << config->audio_voices << "' audio voices: "
-              << SDL_GetError() << "\n";
-    return;
-  }
 }
 
 static void quit_audio()
 {
   if(sound_manager) {
-    if(sound_manager->audio_device_available())
-      Mix_CloseAudio();
-
     delete sound_manager;
     sound_manager = 0;
   }
@@ -416,6 +397,7 @@ void wait_for_event(float min_delay, float max_delay)
     }
     if(SDL_GetTicks() - ticks >= (max - min))
       running = false;
+    sound_manager->update();
     SDL_Delay(10);
   }
 }
index fcdd6f1..b66fbc8 100644 (file)
@@ -22,6 +22,7 @@
 #include "game_session.h"
 #include "gui/menu.h"
 #include "gui/button.h"
+#include "audio/sound_manager.h"
 #include "title.h"
 #include "resources.h"
 #include "worldmap.h"
index ad5b896..cdb3556 100644 (file)
 #include <config.h>
 
 #include <math.h>
+#include <stdexcept>
 
 #include "ambient_sound.h"
 #include "object_factory.h"
 #include "lisp/lisp.h"
 #include "sector.h"
+#include "audio/sound_manager.h"
+#include "audio/sound_source.h"
 
 AmbientSound::AmbientSound(const lisp::Lisp& lisp)
 {
-
   position.x=0;
   position.y=0;
 
@@ -72,13 +74,12 @@ AmbientSound::AmbientSound(const lisp::Lisp& lisp)
   
   lisp.get("silence_distance",silence_distance);
 
-  playing=-1; // not playing at the beginning
+  sound_source = 0; // not playing at the beginning
   latency=0;
 }
 
 AmbientSound::AmbientSound(Vector pos, float factor, float bias, float vol, std::string file)
 {
-
   position.x=pos.x;
   position.y=pos.y;
 
@@ -97,7 +98,7 @@ AmbientSound::AmbientSound(Vector pos, float factor, float bias, float vol, std:
   else
     silence_distance = 1/distance_factor;
 
-  playing=-1; // not playing at the beginning
+  sound_source = 0; // not playing at the beginning
   latency=0;
 }
 
@@ -112,18 +113,30 @@ AmbientSound::hit(Player& )
 
 void
 AmbientSound::stop_playing() {
-  if (playing>=0) {
-    Mix_HaltChannel(playing);
-    playing=-1;
-  }
+  delete sound_source;
+  sound_source = 0;
 }
 
 void
 AmbientSound::start_playing()
 {
-  playing=sound_manager->play_sound(sample,-1);
-  Mix_Volume(playing,0);
-  currentvolume=targetvolume=1e-20;
+  try {
+    std::string filename = "sounds/";
+    filename += sample;
+    filename += ".wav";
+    sound_source = sound_manager->create_sound_source(filename);
+    if(!sound_source)
+      throw std::runtime_error("file not found");
+   
+    sound_source->set_gain(0);
+    sound_source->set_looping(true);
+    currentvolume=targetvolume=1e-20;
+    sound_source->play();
+  } catch(std::exception& e) {
+    std::cerr << "Couldn't play '" << sample << "': " << e.what() << "\n";
+    delete sound_source;
+    sound_source = 0;
+  }
 }
 
 void
@@ -168,10 +181,10 @@ AmbientSound::update(float deltat)
     currentvolume*=pow(rise,deltat*10);
     currentvolume += 1e-6; // volume is at least 1e-6 (0 would never rise)
 
-    if (playing>=0) {
+    if (sound_source != 0) {
 
       // set the volume
-      Mix_Volume(playing,(int)(currentvolume*maximumvolume*MIX_MAX_VOLUME));
+      sound_source->set_gain(currentvolume*maximumvolume);
 
       if (sqrdistance>=silence_distance && currentvolume<1e-3)
        stop_playing();
index ce39f7a..8c2807f 100644 (file)
 #ifndef __AMBIENT_SOUND_H__
 #define __AMBIENT_SOUND_H__
 
-
 #include "game_object.h"
 #include "resources.h"
 #include "player.h"
 #include "SDL_mixer.h"
 
+class SoundSource;
+
 class AmbientSound : public GameObject
 {
 public:
@@ -65,7 +66,7 @@ private:
   Vector dimension;
 
   std::string sample;
-  int playing;
+  SoundSource* sound_source;
   int latency;
 
   float distance_factor;  /// distance scaling
index d61e420..ed0ea70 100644 (file)
@@ -203,7 +203,7 @@ void
 BonusBlock::try_open()
 {
   if(sprite->get_action_name() == "empty") {
-    sound_manager->play_sound("brick");
+    sound_manager->play("brick");
     return;
   }
   
@@ -224,7 +224,7 @@ BonusBlock::try_open()
             get_pos(), new Flower(Flower::FIREFLOWER));
         sector->add_object(riser);
       }
-      sound_manager->play_sound("upgrade");
+      sound_manager->play("upgrade");
       break;
 
     case CONTENT_ICEGROW:
@@ -236,7 +236,7 @@ BonusBlock::try_open()
             get_pos(), new Flower(Flower::ICEFLOWER));
         sector->add_object(riser);
       }      
-      sound_manager->play_sound("upgrade");
+      sound_manager->play("upgrade");
       break;
 
     case CONTENT_STAR:
@@ -251,7 +251,7 @@ BonusBlock::try_open()
       SpecialRiser* riser = new SpecialRiser(get_pos(), object);
       object = 0;
       sector->add_object(riser);
-      sound_manager->play_sound("upgrade");
+      sound_manager->play("upgrade");
       break;
 
     //default:
@@ -292,7 +292,7 @@ Brick::try_break(bool playerhit)
   if(sprite->get_action_name() == "empty")
     return;
   
-  sound_manager->play_sound("brick");
+  sound_manager->play("brick");
   Sector* sector = Sector::current();
   Player& player = *(sector->player);
   if(coin_counter > 0) {
index f8ae8cf..c322671 100644 (file)
@@ -51,7 +51,7 @@ Fireworks::update(float )
         sector->add_object(new Particles(pos, 0, 360, Vector(140, 140),
                 Vector(0, 0), 45, Color(red, green, 0), 3, 1.3,
                 LAYER_FOREGROUND1+1));
-        sound_manager->play_sound("fireworks");
+        sound_manager->play("fireworks");
         timer.start(((float) rand() / RAND_MAX) + .5);
     }
 }
index 974c277..8c68307 100644 (file)
@@ -25,6 +25,7 @@
 #include "camera.h"
 #include "sector.h"
 #include "player.h"
+#include "audio/sound_manager.h"
 #include "sprite/sprite_manager.h"
 
 Flower::Flower(Type _type)
@@ -66,7 +67,7 @@ Flower::collision(GameObject& other, const CollisionHit& )
   else
     player->set_bonus(ICE_BONUS, true);
   
-  sound_manager->play_sound("fire-flower");
+  sound_manager->play("fire-flower");
   remove_me();
   return ABORT_MOVE;
 }
index da9aae1..db90163 100644 (file)
@@ -25,6 +25,7 @@
 #include "camera.h"
 #include "sector.h"
 #include "player.h"
+#include "audio/sound_manager.h"
 #include "sprite/sprite_manager.h"
 
 GrowUp::GrowUp()
@@ -63,7 +64,7 @@ GrowUp::collision(GameObject& other, const CollisionHit& hit)
   Player* player = dynamic_cast<Player*>(&other);
   if(player != 0) {
     player->set_bonus(GROWUP_BONUS, true);
-    sound_manager->play_sound("grow");
+    sound_manager->play("grow");
     remove_me();
     
     return ABORT_MOVE;
index 3231b01..f68b241 100644 (file)
@@ -25,6 +25,7 @@
 #include "sprite/sprite.h"
 #include "sprite/sprite_manager.h"
 #include "video/drawing_context.h"
+#include "audio/sound_manager.h"
 #include "object_factory.h"
 
 InvisibleBlock::InvisibleBlock(const Vector& pos)
@@ -48,7 +49,7 @@ InvisibleBlock::hit(Player& )
     return;
 
   sprite->set_action("empty");
-  sound_manager->play_sound("brick");
+  sound_manager->play("brick");
   start_bounce();
   flags |= FLAG_SOLID;
   visible = true;
index dd71bb9..49bb5a0 100644 (file)
@@ -25,6 +25,7 @@
 
 #include "gettext.h"
 #include "sprite/sprite_manager.h"
+#include "audio/sound_manager.h"
 #include "player.h"
 #include "tile.h"
 #include "sprite/sprite.h"
@@ -269,7 +270,7 @@ Player::handle_horizontal_input()
     // let's skid!
     if(fabs(vx)>SKID_XM && !skidding_timer.started()) {
       skidding_timer.start(SKID_TIME);
-      sound_manager->play_sound("skid");
+      sound_manager->play("skid");
       // dust some partcles
       Sector::current()->add_object(
         new Particles(
@@ -365,9 +366,9 @@ Player::handle_vertical_input()
     can_flap = false;
     flaps_nb = 0; // Ricardo's flapping
     if (is_big())
-      sound_manager->play_sound("bigjump");
+      sound_manager->play("bigjump");
     else
-      sound_manager->play_sound("jump");
+      sound_manager->play("jump");
   } else if(!controller->hold(Controller::JUMP)) { // Let go of jump key
     if (!flapping && !duck && !falling_from_flap && !on_ground()) {
       can_flap = true;
@@ -789,7 +790,7 @@ Player::collision(GameObject& other, const CollisionHit& hit)
 void
 Player::make_invincible()
 {
-  sound_manager->play_sound("invincible");
+  sound_manager->play("invincible");
   invincible_timer.start(TUX_INVINCIBLE_TIME);
   Sector::current()->play_music(HERRING_MUSIC);               
 }
@@ -805,7 +806,7 @@ Player::kill(HurtMode mode)
           safe_timer.get_timeleft() > 0 || invincible_timer.get_timeleft() > 0)
     return;                          
   
-  sound_manager->play_sound("hurt");
+  sound_manager->play("hurt");
 
   physic.set_velocity_x(0);
 
index e310cad..985648b 100644 (file)
@@ -35,7 +35,7 @@ class BadGuy;
 class Portable;
 
 /* Times: */
-static const float TUX_SAFE_TIME = 1.250;
+static const float TUX_SAFE_TIME = 1.8;
 static const float TUX_INVINCIBLE_TIME = 10.0;
 static const float TUX_INVINCIBLE_TIME_WARNING = 2.0;
 static const float TUX_FLAPPING_TIME = 1; /* How long Tux can flap his wings to gain additional jump height */
index 3ba31df..1f338a6 100644 (file)
@@ -24,6 +24,7 @@
 #include "resources.h"
 #include "player.h"
 #include "sprite/sprite_manager.h"
+#include "audio/sound_manager.h"
 #include "object_factory.h"
 #include "sector.h"
 #include "scripting/script_interpreter.h"
@@ -73,10 +74,10 @@ PowerUp::collision(GameObject& other, const CollisionHit& hit)
   // some defaults if no script has been set
   if (sprite->get_name() == "egg") {
     player->set_bonus(GROWUP_BONUS, true);
-    sound_manager->play_sound("grow");
+    sound_manager->play("grow");
   } else if (sprite->get_name() == "fireflower") {
     player->set_bonus(FIRE_BONUS, true);
-    sound_manager->play_sound("fire-flower");
+    sound_manager->play("fire-flower");
   } else if (sprite->get_name() == "star") {
     player->make_invincible();
   } else if (sprite->get_name() == "1up") {
index 0a41a54..c054ccf 100644 (file)
@@ -19,6 +19,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
 #include "physfs_stream.h"
 
+#include <assert.h>
 #include <physfs.h>
 #include <stdexcept>
 #include <sstream>
@@ -42,17 +43,60 @@ IFileStreambuf::~IFileStreambuf()
 int
 IFileStreambuf::underflow()
 {
-    if(PHYSFS_eof(file))
+    if(PHYSFS_eof(file)) {
         return traits_type::eof();
-    
-    size_t bytesread = (size_t) PHYSFS_read(file, buf, 1, sizeof(buf));
-    if(bytesread == 0)
+    }
+   
+    PHYSFS_sint64 bytesread = (size_t) PHYSFS_read(file, buf, 1, sizeof(buf));
+    if(bytesread <= 0) {
         return traits_type::eof();
+    }
     setg(buf, buf, buf + bytesread);
 
     return buf[0];
 }
 
+IFileStreambuf::pos_type
+IFileStreambuf::seekpos(pos_type pos, std::ios_base::openmode)
+{
+  if(PHYSFS_seek(file, static_cast<PHYSFS_uint64> (pos)) == 0) {
+    return pos_type(off_type(-1));
+  }
+
+  // the seek invalidated the buffer
+  setg(buf, buf, buf);
+  return pos;
+}
+
+IFileStreambuf::pos_type
+IFileStreambuf::seekoff(off_type off, std::ios_base::seekdir dir,
+                        std::ios_base::openmode mode)
+{
+  off_type pos = off;
+  PHYSFS_sint64 ptell = PHYSFS_tell(file);
+  
+  switch(dir) {
+    case std::ios_base::beg:
+      break;
+    case std::ios_base::cur:
+      if(off == 0)
+        return static_cast<pos_type> (ptell) - static_cast<pos_type> (egptr() - gptr());
+      pos += static_cast<off_type> (ptell) - static_cast<off_type> (egptr() - gptr());
+      break;
+    case std::ios_base::end:
+      pos += static_cast<off_type> (PHYSFS_fileLength(file));
+      break;
+    default:
+#ifdef DEBUG
+      assert(false);
+#else
+      return pos_type(off_type(-1));
+#endif
+  }
+
+  return seekpos(static_cast<pos_type> (pos), mode);
+}
+
 //---------------------------------------------------------------------------
 
 OFileStreambuf::OFileStreambuf(const std::string& filename)
index 5267483..6b6b627 100644 (file)
@@ -34,6 +34,9 @@ public:
     
 protected:
     virtual int underflow();
+    virtual pos_type seekoff(off_type pos, std::ios_base::seekdir,
+        std::ios_base::openmode);
+    virtual pos_type seekpos(pos_type pos, std::ios_base::openmode);
 
 private:
     PHYSFS_file* file;
index 304a076..c953d92 100644 (file)
@@ -24,6 +24,7 @@
 #include "resources.h"
 #include "gettext.h"
 #include "video/drawing_context.h"
+#include "audio/sound_manager.h"
 #include "main.h"
 
 static const int START_LIVES = 4;
@@ -54,7 +55,7 @@ PlayerStatus::incLives()
 {
   if(lives < MAX_LIVES)
     ++lives;
-  sound_manager->play_sound("lifeup");
+  sound_manager->play("lifeup");
 }
 
 void
@@ -65,7 +66,7 @@ PlayerStatus::incCoins()
     incLives();
     coins = 0;
   }
-  sound_manager->play_sound("coin");
+  sound_manager->play("coin");
 }
 
 void
index 7ab1cbf..1f338a1 100644 (file)
 #include "object/gameobjs.h"
 #include "object/player.h"
 
-MusicRef herring_song;
-MusicRef level_end_song;
-MusicRef credits_song;
-
 SpriteManager* sprite_manager = 0;
 TileManager* tile_manager = 0;
 SoundManager* sound_manager = 0;
@@ -122,6 +118,7 @@ void load_shared()
   /* Tux life: */
   tux_life = new Surface("images/creatures/tux_small/tux-life.png", true);
 
+#if 0
   /* Sound effects: */
   sound_manager->preload_sound("jump");
   sound_manager->preload_sound("bigjump");
@@ -144,10 +141,7 @@ void load_shared()
   sound_manager->preload_sound("explosion");
   sound_manager->preload_sound("warp");
   sound_manager->preload_sound("fireworks");
-
-  /* Herring song */
-  herring_song = sound_manager->load_music("music/salcon.mod");
-  level_end_song = sound_manager->load_music("music/leveldone.mod");
+#endif
 }
 
 /* Free shared data: */
index 200a9a2..cf90875 100644 (file)
@@ -20,7 +20,6 @@
 #define SUPERTUX_RESOURCES_H
 
 #include <string>
-#include "audio/musicref.h"
 
 class SpriteManager;
 class Menu;
@@ -33,9 +32,6 @@ class MouseCursor;
 extern Surface* img_super_bkgd;
 extern Surface* tux_life;
 
-extern MusicRef herring_song;
-extern MusicRef level_end_song;
-
 extern SpriteManager* sprite_manager;
 extern TileManager* tile_manager;
 extern SoundManager* sound_manager;
index f3c77f7..3e14fd3 100644 (file)
@@ -6,8 +6,6 @@
 #include "resources.h"
 #include "audio/sound_manager.h"
 
-#define NOIMPL      printf("%s not implemented.\n", __PRETTY_FUNCTION__);
-
 namespace Scripting
 {
 
@@ -18,14 +16,17 @@ namespace Scripting
   {}
 
   void
-  Sound::play_music(const std::string& )
+  Sound::play_music(const std::string& name)
   {
-    NOIMPL;
+    std::string filename = "music/";
+    filename += name;
+    filename += ".ogg";
+    sound_manager->play_music(name);
   }
 
   void
-  Sound::play_sound(const std::string& name)
+  Sound::play(const std::string& name)
   {
-    sound_manager->play_sound(name);
+    sound_manager->play(name);
   }
 }
index 10d56da..51aa7b9 100644 (file)
@@ -14,7 +14,7 @@ public:
   /**
    * Play a sound effect. The name should be without path or .wav extension
    */
-  void play_sound(const std::string& soundfile);
+  void play(const std::string& soundfile);
 
 #ifndef SCRIPTING_API
   Sound();
index 7dfa7ac..e750b96 100644 (file)
@@ -292,14 +292,14 @@ static int Sound_play_music_wrapper(HSQUIRRELVM v)
   return 0;
 }
 
-static int Sound_play_sound_wrapper(HSQUIRRELVM v)
+static int Sound_play_wrapper(HSQUIRRELVM v)
 {
   Scripting::Sound* _this;
   sq_getinstanceup(v, 1, (SQUserPointer*) &_this, 0);
   const char* arg0;
   sq_getstring(v, 2, &arg0);
   
-  _this->play_sound(arg0);
+  _this->play(arg0);
   
   return 0;
 }
@@ -494,7 +494,7 @@ static WrappedFunction supertux_ScriptedObject_methods[] = {
 
 static WrappedFunction supertux_Sound_methods[] = {
   { "play_music", &Sound_play_music_wrapper },
-  { "play_sound", &Sound_play_sound_wrapper },
+  { "play", &Sound_play_wrapper },
 };
 
 static WrappedFunction supertux_Text_methods[] = {
index 4fab8ba..6f2f3f2 100644 (file)
@@ -157,7 +157,6 @@ Sector::parse(const lisp::Lisp& sector)
       iter.value()->get(gravity);
     } else if(token == "music") {
       iter.value()->get(song_title);
-      load_music();
     } else if(token == "spawnpoint") {
       SpawnPoint* sp = new SpawnPoint(iter.lisp());
       spawnpoints.push_back(sp);
@@ -244,7 +243,6 @@ Sector::parse_old_format(const lisp::Lisp& reader)
 
   song_title = "Mortimers_chipdisko.mod";
   reader.get("music", song_title);
-  load_music();
 
   int width, height = 15;
   reader.get("width", width);
@@ -771,7 +769,7 @@ Sector::add_bullet(const Vector& pos, float xm, Direction dir)
   }
   add_object(new_bullet);
 
-  sound_manager->play_sound("shoot");
+  sound_manager->play("shoot");
 
   return true;
 }
@@ -790,24 +788,18 @@ Sector::add_floating_text(const Vector& pos, const std::string& text)
 }
 
 void
-Sector::load_music()
-{
-  level_song = sound_manager->load_music("/music/" + song_title);
-}
-
-void
 Sector::play_music(MusicType type)
 {
   currentmusic = type;
   switch(currentmusic) {
     case LEVEL_MUSIC:
-      sound_manager->play_music(level_song);
+      sound_manager->play_music(std::string("music/") + song_title);
       break;
     case HERRING_MUSIC:
-      sound_manager->play_music(herring_song);
+      sound_manager->play_music("music/salcon.mod");
       break;
     default:
-      sound_manager->halt_music();
+      sound_manager->play_music("");
       break;
   }
 }
index 51a135b..195d88a 100644 (file)
@@ -24,7 +24,6 @@
 
 #include "direction.h"
 #include "math/vector.h"
-#include "audio/musicref.h"
 #include "video/drawing_context.h"
 
 namespace lisp {
@@ -42,6 +41,7 @@ class Bullet;
 class CollisionGrid;
 class ScriptInterpreter;
 class SpawnPoint;
+class MovingObject;
 
 enum MusicType {
   LEVEL_MUSIC,
@@ -108,15 +108,12 @@ public:
 private:
   void collision_object(MovingObject* object1, MovingObject* object2);
   
-  void load_music();
   GameObject* parse_object(const std::string& name, const lisp::Lisp& lisp);
   
   static Sector* _current;
   
   std::string name;
 
-  MusicRef level_song;
-
 public:
   std::string song_title;
   float gravity;
index 20d900c..c06a260 100644 (file)
@@ -27,6 +27,7 @@
 #include "video/drawing_context.h"
 #include "lisp/parser.h"
 #include "lisp/lisp.h"
+#include "audio/sound_manager.h"
 #include "main.h"
 #include "control/joystickkeyboardcontroller.h"
 
@@ -168,6 +169,7 @@ void display_text_file(const std::string& filename)
     }
     
     context.do_drawing();
+    sound_manager->update();
     
     if(SCREEN_HEIGHT+y-scroll < 0 && 20+SCREEN_HEIGHT+y-scroll < 0)
       done = 1;
index 91a632f..2f99169 100644 (file)
@@ -36,6 +36,7 @@
 #include "title.h"
 #include "video/screen.h"
 #include "video/surface.h"
+#include "audio/sound_manager.h"
 #include "gui/menu.h"
 #include "timer.h"
 #include "lisp/lisp.h"
@@ -44,7 +45,6 @@
 #include "level_subset.h"
 #include "game_session.h"
 #include "worldmap.h"
-#include "leveleditor.h"
 #include "player_status.h"
 #include "tile.h"
 #include "sector.h"
@@ -278,7 +278,6 @@ void title()
 {
   walking = true;
   //LevelEditor* leveleditor;
-  MusicRef credits_music;
   controller = new CodeController();
 
   titlesession = new GameSession("levels/misc/menu.stl", ST_GL_DEMO_GAME);
@@ -379,9 +378,7 @@ void title()
 #endif
                 case MNID_CREDITS:
                   fadeout(500);
-                  credits_music = sound_manager->load_music(
-                      "/music/credits.ogg");
-                  sound_manager->play_music(credits_music);
+                  sound_manager->play_music("music/credits.ogg");
                   display_text_file("credits.txt");
                   fadeout(500);
                   Menu::set_current(main_menu);
@@ -436,6 +433,7 @@ void title()
       }
 
       context.do_drawing();
+      sound_manager->update();
 
       //frame_rate.update();
 
index c4e3d29..2b4e847 100644 (file)
@@ -713,7 +713,7 @@ WorldMap::update(float delta)
         if (special_tile->teleport_dest != Vector(-1,-1))
           {
           // TODO: an animation, camera scrolling or a fading would be a nice touch
-          sound_manager->play_sound("warp");
+          sound_manager->play("warp");
           tux->back_direction = D_NONE;
           tux->set_tile_pos(special_tile->teleport_dest);
           SDL_Delay(1000);
@@ -828,7 +828,7 @@ WorldMap::update(float delta)
               break;
             }
 
-          sound_manager->play_music(song);
+          sound_manager->play_music(std::string("music/") + music);
           Menu::set_current(0);
           if (!savegame_file.empty())
             savegame(savegame_file);
@@ -985,8 +985,7 @@ WorldMap::display()
 
   quit = false;
 
-  song = sound_manager->load_music("music/" + music);
-  sound_manager->play_music(song);
+  sound_manager->play_music(std::string("music/") + music);
 
   if(!intro_displayed && intro_script != "") {
     try {
@@ -1035,6 +1034,7 @@ WorldMap::display()
     context.pop_transform();
     get_input();
     update(elapsed_time);
+    sound_manager->update();
       
     if(Menu::current()) {
       Menu::current()->draw(context);
index fa71bbc..0ac6e3e 100644 (file)
@@ -23,7 +23,6 @@
 #include <string>
 
 #include "math/vector.h"
-#include "audio/musicref.h"
 #include "video/screen.h"
 #include "lisp/lisp.h"
 #include "control/controller.h"
@@ -192,8 +191,6 @@ private:
   typedef std::vector<SpawnPoint*> SpawnPoints;
   SpawnPoints spawn_points;
 
-  MusicRef song;
-
   Vector offset;
   std::string savegame_file;