From 795f0b283fcb1c8777723dc1cc850826d39c6806 Mon Sep 17 00:00:00 2001 From: Matthias Braun Date: Thu, 23 Jun 2005 01:45:32 +0000 Subject: [PATCH] Added a new SoundManager based on OpenAL. I also simplified the API along the 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 --- configure.ac | 27 +- data/levels/world2/level2.stl | 21 +- src/Jamfile | 3 +- src/audio/semantic.cache | 41 +- src/audio/sound_file.cpp | 309 +++++++++ src/audio/sound_file.h | 26 + src/audio/sound_manager.cpp | 391 +++++------ src/audio/sound_manager.h | 156 ++--- src/audio/sound_source.cpp | 70 ++ src/audio/sound_source.h | 31 + src/audio/stream_sound_source.cpp | 76 +++ src/audio/stream_sound_source.h | 34 + src/badguy/badguy.cpp | 5 +- src/badguy/badguy.h | 2 + src/badguy/bomb.cpp | 3 +- src/badguy/flame.cpp | 32 +- src/badguy/flame.h | 6 + src/badguy/jumpy.cpp | 2 +- src/badguy/mriceblock.cpp | 7 +- src/badguy/mrtree.cpp | 2 +- src/badguy/nolok_01.cpp | 2 +- src/badguy/rocketexplosion.cpp | 4 +- src/badguy/yeti.cpp | 6 +- src/control/joystickkeyboardcontroller.h | 2 +- src/game_session.cpp | 12 +- src/gameconfig.cpp | 14 - src/gameconfig.h | 5 - src/leveleditor.cpp | 1053 ------------------------------ src/leveleditor.h | 155 ----- src/main.cpp | 20 +- src/misc.cpp | 1 + src/object/ambient_sound.cpp | 39 +- src/object/ambient_sound.h | 5 +- src/object/block.cpp | 10 +- src/object/fireworks.cpp | 2 +- src/object/flower.cpp | 3 +- src/object/growup.cpp | 3 +- src/object/invisible_block.cpp | 3 +- src/object/player.cpp | 11 +- src/object/player.h | 2 +- src/object/powerup.cpp | 5 +- src/physfs/physfs_stream.cpp | 52 +- src/physfs/physfs_stream.h | 3 + src/player_status.cpp | 5 +- src/resources.cpp | 10 +- src/resources.h | 4 - src/scripting/sound.cpp | 13 +- src/scripting/sound.h | 2 +- src/scripting/wrapper.cpp | 6 +- src/sector.cpp | 16 +- src/sector.h | 5 +- src/textscroller.cpp | 2 + src/title.cpp | 8 +- src/worldmap.cpp | 8 +- src/worldmap.h | 3 - 55 files changed, 1034 insertions(+), 1704 deletions(-) create mode 100644 src/audio/sound_file.cpp create mode 100644 src/audio/sound_file.h create mode 100644 src/audio/sound_source.cpp create mode 100644 src/audio/sound_source.h create mode 100644 src/audio/stream_sound_source.cpp create mode 100644 src/audio/stream_sound_source.h delete mode 100644 src/leveleditor.cpp delete mode 100644 src/leveleditor.h diff --git a/configure.ac b/configure.ac index a504fd255..043aaaaa8 100644 --- a/configure.ac +++ b/configure.ac @@ -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 -#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 ], [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 ], + [alutInit(0, 0);]), + [], [-lopenal], + [], + [AC_MSG_ERROR([Please intall OpenAL])], + [], []) + dnl Checks for library functions. AC_CHECK_FUNCS(mkdir strdup strstr) diff --git a/data/levels/world2/level2.stl b/data/levels/world2/level2.stl index a5e7665e6..e1487ee3b 100644 --- a/data/levels/world2/level2.stl +++ b/data/levels/world2/level2.stl @@ -197,10 +197,6 @@ (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) diff --git a/src/Jamfile b/src/Jamfile index ba6b3759c..f5efe6ab5 100644 --- a/src/Jamfile +++ b/src/Jamfile @@ -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 ; diff --git a/src/audio/semantic.cache b/src/audio/semantic.cache index 56637514e..d7bfa812a 100644 --- a/src/audio/semantic.cache +++ b/src/audio/semantic.cache @@ -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 index 000000000..1420a1750 --- /dev/null +++ b/src/audio/sound_file.cpp @@ -0,0 +1,309 @@ +/** Used SDL_mixer and glest source as reference */ +#include + +#include "sound_file.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +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 (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 (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 (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 (_buffer); + int section = 0; + size_t totalBytesRead= 0; + + while(buffer_size>0){ + long bytesRead + = ov_read(&vorbis_file, buffer, static_cast (buffer_size), 0, 2, 1, + §ion); + 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 (source); + + PHYSFS_sint64 res + = PHYSFS_read(file, ptr, static_cast (size), + static_cast (nmemb)); + if(res <= 0) + return 0; + + return static_cast (res); +} + +int +OggSoundFile::cb_seek(void* source, ogg_int64_t offset, int whence) +{ + PHYSFS_file* file = reinterpret_cast (source); + + switch(whence) { + case SEEK_SET: + if(PHYSFS_seek(file, static_cast (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 (source); + PHYSFS_close(file); + return 0; +} + +long +OggSoundFile::cb_tell(void* source) +{ + PHYSFS_file* file = reinterpret_cast (source); + return static_cast (PHYSFS_tell(file)); +} + +//--------------------------------------------------------------------------- + +#include +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 index 000000000..81184b13a --- /dev/null +++ b/src/audio/sound_file.h @@ -0,0 +1,26 @@ +#ifndef __SOUND_FILE_H__ +#define __SOUND_FILE_H__ + +#include +#include + +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 + diff --git a/src/audio/sound_manager.cpp b/src/audio/sound_manager.cpp index bb26ed2e7..7d9572434 100644 --- a/src/audio/sound_manager.cpp +++ b/src/audio/sound_manager.cpp @@ -1,252 +1,265 @@ -// $Id: sound_manager.cpp 2334 2005-04-04 16:26:14Z grumbel $ -// -// SuperTux - A Jump'n Run -// Copyright (C) 2004 Matthias Braun - -#include -#include -#include +#include "sound_manager.h" + #include +#include #include -#include +#include -#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 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 (file->size), + static_cast (file->rate)); + check_al_error("Couldn't fill audio buffer: "); + } catch(...) { + delete[] samples; + throw; } + delete[] samples; - std::map::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::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::iterator, bool> result = - musics.insert( - std::make_pair (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()); + } } diff --git a/src/audio/sound_manager.h b/src/audio/sound_manager.h index cacd26fba..7542527be 100644 --- a/src/audio/sound_manager.h +++ b/src/audio/sound_manager.h @@ -1,136 +1,74 @@ -// $Id: sound_manager.h 2353 2005-04-06 23:00:16Z matzebraun $ -// -// SuperTux - A Jump'n Run -// Copyright (C) 2004 Matthias Braun #include #include -#include "SDL_mixer.h" -#include "math/vector.h" +#include +#include + +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 SoundBuffers; + SoundBuffers buffers; + typedef std::vector 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 Sounds; - Sounds sounds; - - typedef std::map 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 index 000000000..b0ebdc8e2 --- /dev/null +++ b/src/audio/sound_source.cpp @@ -0,0 +1,70 @@ +#include + +#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 index 000000000..65797ca4d --- /dev/null +++ b/src/audio/sound_source.h @@ -0,0 +1,31 @@ +#ifndef __SOUND_SOURCE_H__ +#define __SOUND_SOURCE_H__ + +#include +#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 index 000000000..d282c4dbf --- /dev/null +++ b/src/audio/stream_sound_source.cpp @@ -0,0 +1,76 @@ +#include + +#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 index 000000000..b5002f234 --- /dev/null +++ b/src/audio/stream_sound_source.h @@ -0,0 +1,34 @@ +#ifndef __STREAM_SOUND_SOURCE_H__ +#define __STREAM_SOUND_SOURCE_H__ + +#include +#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 + diff --git a/src/badguy/badguy.cpp b/src/badguy/badguy.cpp index aa0af892a..f20a798a8 100644 --- a/src/badguy/badguy.cpp +++ b/src/badguy/badguy.cpp @@ -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); diff --git a/src/badguy/badguy.h b/src/badguy/badguy.h index b6a1d0661..ac891a613 100644 --- a/src/badguy/badguy.h +++ b/src/badguy/badguy.h @@ -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 diff --git a/src/badguy/bomb.cpp b/src/badguy/bomb.cpp index 848e62da1..45eca337a 100644 --- a/src/badguy/bomb.cpp +++ b/src/badguy/bomb.cpp @@ -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); } diff --git a/src/badguy/flame.cpp b/src/badguy/flame.cpp index cd60f20ea..0bd892bf7 100644 --- a/src/badguy/flame.cpp +++ b/src/badguy/flame.cpp @@ -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 diff --git a/src/badguy/flame.h b/src/badguy/flame.h index 225cef09b..877fa9bd3 100644 --- a/src/badguy/flame.h +++ b/src/badguy/flame.h @@ -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 diff --git a/src/badguy/jumpy.cpp b/src/badguy/jumpy.cpp index a90f0a02b..07f126fc3 100644 --- a/src/badguy/jumpy.cpp +++ b/src/badguy/jumpy.cpp @@ -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); } diff --git a/src/badguy/mriceblock.cpp b/src/badguy/mriceblock.cpp index d37a2b5c7..c3926460a 100644 --- a/src/badguy/mriceblock.cpp +++ b/src/badguy/mriceblock.cpp @@ -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; diff --git a/src/badguy/mrtree.cpp b/src/badguy/mrtree.cpp index 601eebcfb..509eda997 100644 --- a/src/badguy/mrtree.cpp +++ b/src/badguy/mrtree.cpp @@ -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"); diff --git a/src/badguy/nolok_01.cpp b/src/badguy/nolok_01.cpp index 255cee575..7882cd46e 100644 --- a/src/badguy/nolok_01.cpp +++ b/src/badguy/nolok_01.cpp @@ -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); diff --git a/src/badguy/rocketexplosion.cpp b/src/badguy/rocketexplosion.cpp index 6929ea6d2..882769346 100644 --- a/src/badguy/rocketexplosion.cpp +++ b/src/badguy/rocketexplosion.cpp @@ -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(); } diff --git a/src/badguy/yeti.cpp b/src/badguy/yeti.cpp index 87faba0b8..c6f083412 100644 --- a/src/badguy/yeti.cpp +++ b/src/badguy/yeti.cpp @@ -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"); diff --git a/src/control/joystickkeyboardcontroller.h b/src/control/joystickkeyboardcontroller.h index 6520a2b7e..2a5f52757 100644 --- a/src/control/joystickkeyboardcontroller.h +++ b/src/control/joystickkeyboardcontroller.h @@ -99,7 +99,7 @@ private: friend class KeyboardMenu; friend class JoystickMenu; - char last_keys[20]; + char last_keys[20]; }; #endif diff --git a/src/game_session.cpp b/src/game_session.cpp index 4f5495c50..59827039f 100644 --- a/src/game_session.cpp +++ b/src/game_session.cpp @@ -35,13 +35,9 @@ #include -#ifndef WIN32 -#include -#include -#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") { diff --git a/src/gameconfig.cpp b/src/gameconfig.cpp index 94fa2acae..b763feff2 100644 --- a/src/gameconfig.cpp +++ b/src/gameconfig.cpp @@ -26,7 +26,6 @@ #include #include -#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) { diff --git a/src/gameconfig.h b/src/gameconfig.h index cd9c1fe9d..d16ebe65b 100644 --- a/src/gameconfig.h +++ b/src/gameconfig.h @@ -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 index 7cc0756da..000000000 --- a/src/leveleditor.cpp +++ /dev/null @@ -1,1053 +0,0 @@ -// $Id$ -// -// SuperTux -// Copyright (C) 2005 Matthias Braun -// -// 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 - -#include -#include - -#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::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::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 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 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 (*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 (*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 (*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 (*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 (*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 (*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 (*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 index 33b067769..000000000 --- a/src/leveleditor.h +++ /dev/null @@ -1,155 +0,0 @@ -// $Id$ -// -// SuperTux -// Copyright (C) 2005 Matthias Braun -// -// 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 -#include - -#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 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 > 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 diff --git a/src/main.cpp b/src/main.cpp index 2b05e6c20..16a9cd051 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -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); } } diff --git a/src/misc.cpp b/src/misc.cpp index fcdd6f1ab..b66fbc8c5 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -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" diff --git a/src/object/ambient_sound.cpp b/src/object/ambient_sound.cpp index ad5b896f8..cdb355676 100644 --- a/src/object/ambient_sound.cpp +++ b/src/object/ambient_sound.cpp @@ -19,15 +19,17 @@ #include #include +#include #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(); diff --git a/src/object/ambient_sound.h b/src/object/ambient_sound.h index ce39f7a6b..8c2807f45 100644 --- a/src/object/ambient_sound.h +++ b/src/object/ambient_sound.h @@ -42,12 +42,13 @@ #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 diff --git a/src/object/block.cpp b/src/object/block.cpp index d61e420d5..ed0ea7008 100644 --- a/src/object/block.cpp +++ b/src/object/block.cpp @@ -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) { diff --git a/src/object/fireworks.cpp b/src/object/fireworks.cpp index f8ae8cf1f..c3226712c 100644 --- a/src/object/fireworks.cpp +++ b/src/object/fireworks.cpp @@ -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); } } diff --git a/src/object/flower.cpp b/src/object/flower.cpp index 974c27749..8c68307a9 100644 --- a/src/object/flower.cpp +++ b/src/object/flower.cpp @@ -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; } diff --git a/src/object/growup.cpp b/src/object/growup.cpp index da9aae1c8..db90163e1 100644 --- a/src/object/growup.cpp +++ b/src/object/growup.cpp @@ -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(&other); if(player != 0) { player->set_bonus(GROWUP_BONUS, true); - sound_manager->play_sound("grow"); + sound_manager->play("grow"); remove_me(); return ABORT_MOVE; diff --git a/src/object/invisible_block.cpp b/src/object/invisible_block.cpp index 3231b01de..f68b241ca 100644 --- a/src/object/invisible_block.cpp +++ b/src/object/invisible_block.cpp @@ -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; diff --git a/src/object/player.cpp b/src/object/player.cpp index dd71bb924..49bb5a063 100644 --- a/src/object/player.cpp +++ b/src/object/player.cpp @@ -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); diff --git a/src/object/player.h b/src/object/player.h index e310cadbe..985648b95 100644 --- a/src/object/player.h +++ b/src/object/player.h @@ -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 */ diff --git a/src/object/powerup.cpp b/src/object/powerup.cpp index 3ba31dfa7..1f338a658 100644 --- a/src/object/powerup.cpp +++ b/src/object/powerup.cpp @@ -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") { diff --git a/src/physfs/physfs_stream.cpp b/src/physfs/physfs_stream.cpp index 0a41a545c..c054ccf94 100644 --- a/src/physfs/physfs_stream.cpp +++ b/src/physfs/physfs_stream.cpp @@ -19,6 +19,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "physfs_stream.h" +#include #include #include #include @@ -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 (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 (ptell) - static_cast (egptr() - gptr()); + pos += static_cast (ptell) - static_cast (egptr() - gptr()); + break; + case std::ios_base::end: + pos += static_cast (PHYSFS_fileLength(file)); + break; + default: +#ifdef DEBUG + assert(false); +#else + return pos_type(off_type(-1)); +#endif + } + + return seekpos(static_cast (pos), mode); +} + //--------------------------------------------------------------------------- OFileStreambuf::OFileStreambuf(const std::string& filename) diff --git a/src/physfs/physfs_stream.h b/src/physfs/physfs_stream.h index 5267483af..6b6b6271e 100644 --- a/src/physfs/physfs_stream.h +++ b/src/physfs/physfs_stream.h @@ -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; diff --git a/src/player_status.cpp b/src/player_status.cpp index 304a076b7..c953d920d 100644 --- a/src/player_status.cpp +++ b/src/player_status.cpp @@ -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 diff --git a/src/resources.cpp b/src/resources.cpp index 7ab1cbfe0..1f338a1cb 100644 --- a/src/resources.cpp +++ b/src/resources.cpp @@ -27,10 +27,6 @@ #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: */ diff --git a/src/resources.h b/src/resources.h index 200a9a283..cf90875e3 100644 --- a/src/resources.h +++ b/src/resources.h @@ -20,7 +20,6 @@ #define SUPERTUX_RESOURCES_H #include -#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; diff --git a/src/scripting/sound.cpp b/src/scripting/sound.cpp index f3c77f7a7..3e14fd35b 100644 --- a/src/scripting/sound.cpp +++ b/src/scripting/sound.cpp @@ -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); } } diff --git a/src/scripting/sound.h b/src/scripting/sound.h index 10d56da8b..51aa7b951 100644 --- a/src/scripting/sound.h +++ b/src/scripting/sound.h @@ -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(); diff --git a/src/scripting/wrapper.cpp b/src/scripting/wrapper.cpp index 7dfa7ac92..e750b96d3 100644 --- a/src/scripting/wrapper.cpp +++ b/src/scripting/wrapper.cpp @@ -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[] = { diff --git a/src/sector.cpp b/src/sector.cpp index 4fab8ba57..6f2f3f246 100644 --- a/src/sector.cpp +++ b/src/sector.cpp @@ -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; } } diff --git a/src/sector.h b/src/sector.h index 51a135b99..195d88a8d 100644 --- a/src/sector.h +++ b/src/sector.h @@ -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; diff --git a/src/textscroller.cpp b/src/textscroller.cpp index 20d900ce5..c06a26006 100644 --- a/src/textscroller.cpp +++ b/src/textscroller.cpp @@ -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; diff --git a/src/title.cpp b/src/title.cpp index 91a632f52..2f99169ea 100644 --- a/src/title.cpp +++ b/src/title.cpp @@ -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(); diff --git a/src/worldmap.cpp b/src/worldmap.cpp index c4e3d29e0..2b4e84754 100644 --- a/src/worldmap.cpp +++ b/src/worldmap.cpp @@ -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); diff --git a/src/worldmap.h b/src/worldmap.h index fa71bbce3..0ac6e3e90 100644 --- a/src/worldmap.h +++ b/src/worldmap.h @@ -23,7 +23,6 @@ #include #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 SpawnPoints; SpawnPoints spawn_points; - MusicRef song; - Vector offset; std::string savegame_file; -- 2.11.0