1 /* 2 * Copyright (C) 2000-2013 The Exult Team 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 */ 18 19 #ifndef AUDIO_H 20 #define AUDIO_H 21 22 #include <map> 23 #include <memory> 24 #include <vector> 25 #include <SDL.h> 26 #include <SDL_audio.h> 27 #include "AudioMixer.h" 28 #include "exceptions.h" 29 #include "exult_constants.h" 30 #include "Flex.h" 31 #include "Midi.h" 32 33 namespace Pentagram { 34 class AudioSample; 35 } 36 struct File_spec; 37 class Game_object; 38 class MyMidiPlayer; 39 class SFX_cached; 40 class Tile_coord; 41 42 #define MAX_SOUND_FALLOFF 24 43 /* 44 * Music: 45 */ 46 enum Combat_song 47 { 48 CSBattle_Over, 49 CSAttacked1, 50 CSAttacked2, 51 CSVictory, 52 CSRun_Away, 53 CSDanger, 54 CSHidden_Danger 55 }; 56 57 /* 58 * This is a resource-management class for SFX. Maybe make it a 59 * template class and use for other resources also? 60 * Based on code by Sam Lantinga et al on: 61 * http://www.ibm.com/developerworks/library/l-pirates2/ 62 */ 63 class SFX_cache_manager { 64 using SFX_cached = std::pair<int,Pentagram::AudioSample*>; 65 66 std::map<int, SFX_cached> cache; 67 68 // Tries to locate a sfx in the cache based on sfx num. 69 SFX_cached *find_sfx(int id); 70 71 public: 72 SFX_cache_manager() = default; 73 ~SFX_cache_manager(); 74 SFX_cache_manager(const SFX_cache_manager&) = default; 75 SFX_cache_manager(SFX_cache_manager&&) = default; 76 SFX_cache_manager& operator=(const SFX_cache_manager&) = default; 77 SFX_cache_manager& operator=(SFX_cache_manager&&) = default; 78 // For SFX played through 'play_wave_sfx'. Searched cache for 79 // the sfx first, then loads from the sfx file if needed. 80 Pentagram::AudioSample *request(Flex *sfx_file, int id); 81 // Empties the cache. 82 void flush(Pentagram::AudioMixer *mixer = nullptr); 83 // Remove unused sounds from the cache. 84 void garbage_collect(); 85 }; 86 87 88 //---- Audio ----------------------------------------------------------- 89 90 class Audio : nonreplicatable 91 { 92 private: 93 static Audio *self; 94 static const int *bg2si_songs; // Converts BG songs to SI songs. 95 static const int *bg2si_sfxs; // Converts BG sfx's to SI sfx's. 96 bool truthful_ = false; 97 bool speech_enabled = true, music_enabled = true, effects_enabled = true, speech_with_subs = false; 98 bool allow_music_looping; 99 std::unique_ptr<SFX_cache_manager> sfxs; // SFX and voice cache manager 100 bool initialized = false; 101 SDL_AudioSpec wanted; 102 std::unique_ptr<Pentagram::AudioMixer> mixer; 103 bool audio_enabled; 104 std::unique_ptr<Flex> sfx_file; // Holds .wav sound effects. 105 // You never allocate an Audio object directly, you rather access it using get_ptr() 106 Audio(); 107 ~Audio(); 108 void Init(int _samplerate,int _channels); 109 110 public: 111 friend class Tired_of_compiler_warnings; 112 static void Init(); 113 static void Destroy(); 114 static Audio* get_ptr(); 115 116 // Given BG sfx, get SI if playing SI. game_sfx(int sfx)117 static int game_sfx(int sfx) 118 { return bg2si_sfxs ? bg2si_sfxs[sfx] : sfx; } 119 120 // Given BG song, get SI if playing SI. game_music(int mus)121 static int game_music(int mus) 122 { return bg2si_songs ? bg2si_songs[mus] : mus; } 123 124 void Init_sfx(); 125 honest_sample_rates()126 void honest_sample_rates() { truthful_=true; } 127 void cancel_streams(); // Dump any audio streams 128 129 void pause_audio(); 130 void resume_audio(); 131 132 void copy_and_play(const uint8 *sound_data,uint32 len,bool); 133 void play(std::unique_ptr<uint8[]> sound_data,uint32 len,bool); 134 void playfile(const char *,const char *,bool); 135 bool playing(); 136 void start_music(int num,bool continuous=false,const std::string& flex=MAINMUS); 137 void start_music(const std::string& fname,int num,bool continuous=false); 138 void start_music_combat(Combat_song song,bool continuous); 139 void stop_music(); 140 int play_sound_effect(int num, int volume = AUDIO_MAX_VOLUME, 141 int balance = 0, int repeat = 0, int distance=0); 142 int play_wave_sfx(int num, int volume = AUDIO_MAX_VOLUME, 143 int balance = 0, int repeat = 0, int distance=0); 144 int play_sound_effect(int num, const Game_object *obj, int volume = AUDIO_MAX_VOLUME, int repeat = 0); 145 int play_sound_effect(int num, const Tile_coord &tile, int volume = AUDIO_MAX_VOLUME, int repeat = 0); 146 // These two do not cache the SFX, and play it directly from the file. 147 int play_sound_effect(const File_spec& sfxfile, int num, int volume = AUDIO_MAX_VOLUME, 148 int balance = 0, int repeat = 0, int distance=0); 149 int play_wave_sfx(const File_spec& sfxfile, int num, int volume = AUDIO_MAX_VOLUME, 150 int balance = 0, int repeat = 0, int distance=0); 151 152 static void get_2d_position_for_tile(const Tile_coord &tile, int &distance, int &balance); 153 154 int update_sound_effect(int chan, const Game_object *obj); 155 int update_sound_effect(int chan, const Tile_coord &tile); 156 157 void stop_sound_effect(int chan); 158 159 void stop_sound_effects(); 160 bool start_speech(int num,bool wait=false); 161 void stop_speech(); is_speech_enabled()162 bool is_speech_enabled() const { return speech_enabled; } set_speech_enabled(bool ena)163 void set_speech_enabled(bool ena) { speech_enabled = ena; } is_speech_with_subs()164 bool is_speech_with_subs() const { return speech_with_subs; } is_music_enabled()165 bool is_music_enabled() const { return music_enabled; } set_music_enabled(bool ena)166 void set_music_enabled(bool ena) { music_enabled = ena; } are_effects_enabled()167 bool are_effects_enabled() const { return effects_enabled; } set_effects_enabled(bool ena)168 void set_effects_enabled(bool ena) { effects_enabled = ena; } is_audio_enabled()169 bool is_audio_enabled() const { return audio_enabled; } 170 void set_audio_enabled(bool ena); is_music_looping_allowed()171 bool is_music_looping_allowed() const { return allow_music_looping; } set_allow_music_looping(bool ena)172 void set_allow_music_looping(bool ena) { allow_music_looping = ena; } 173 static bool can_sfx(const std::string &file, std::string *out = nullptr); 174 static bool have_roland_sfx(Exult_Game game, std::string *out = nullptr); 175 static bool have_sblaster_sfx(Exult_Game game, std::string *out = nullptr); 176 static bool have_midi_sfx(std::string *out = nullptr); 177 static bool have_config_sfx(const std::string &game, std::string *out = nullptr); 178 static void channel_complete_callback(int chan); 179 180 bool is_track_playing(int num) const; 181 bool is_voice_playing() const; 182 get_sfx_file()183 Flex *get_sfx_file() 184 { return sfx_file.get(); } get_sfx_cache()185 SFX_cache_manager *get_sfx_cache() const 186 { return sfxs.get(); } 187 188 MyMidiPlayer *get_midi() const; 189 }; 190 191 #endif 192