Release the sound device if it is no longer needed.

Added checkboxes to enable/disable sound/music.
Changed volume to be int instead of double.
This commit is contained in:
Jon Daniel 2005-07-31 18:56:58 +00:00
parent 84fb8a04c3
commit d06440d5bf
7 changed files with 255 additions and 173 deletions

View File

@ -85,7 +85,7 @@ bool less_campaigns_rank(const config* a, const config* b) {
class game_controller
{
public:
game_controller(int argc, char** argv, bool use_sound);
game_controller(int argc, char** argv);
display& disp();
@ -132,8 +132,8 @@ private:
CVideo video_;
const font::manager font_manager_;
const sound::manager sound_manager_;
const preferences::manager prefs_manager_;
const sound::manager sound_manager_;
const image::manager image_manager_;
const events::event_context main_event_context_;
const hotkey::manager hotkey_manager_;
@ -156,9 +156,9 @@ private:
preproc_map defines_map_, old_defines_map_;
};
game_controller::game_controller(int argc, char** argv, bool use_sound)
game_controller::game_controller(int argc, char** argv)
: argc_(argc), arg_(1), argv_(argv), thread_manager(),
sound_manager_(use_sound), test_mode_(false), multiplayer_mode_(false),
test_mode_(false), multiplayer_mode_(false),
no_gui_(false), use_caching_(true), force_bpp_(-1), disp_(NULL),
loaded_game_show_replay_(false)
{
@ -206,7 +206,8 @@ game_controller::game_controller(int argc, char** argv, bool use_sound)
game_config::debug = true;
} else if (val.substr(0, 6) == "--log-") {
} else if(val == "--nosound") {
//handled elsewhere
preferences::set_sound(false);
preferences::set_music(false);
} else if(val[0] == '-') {
std::cerr << "unknown option: " << val << std::endl;
throw config::error("unknown option");
@ -226,6 +227,13 @@ game_controller::game_controller(int argc, char** argv, bool use_sound)
}
}
if (preferences::sound() || preferences::music()) {
if(!sound::init_sound()) {
preferences::set_sound(false);
preferences::set_music(false);
}
}
}
display& game_controller::disp()
@ -1442,8 +1450,6 @@ int play_game(int argc, char** argv)
{
const int start_ticks = SDL_GetTicks();
bool use_sound = true;
//parse arguments that shouldn't require a display device
int arg;
for(arg = 1; arg != argc; ++arg) {
@ -1481,8 +1487,6 @@ int play_game(int argc, char** argv)
std::cout << game_config::path
<< "\n";
return 0;
} else if(val == "--nosound") {
use_sound = false;
} else if (val.substr(0, 6) == "--log-") {
size_t p = val.find('=');
if (p == std::string::npos) {
@ -1549,7 +1553,7 @@ int play_game(int argc, char** argv)
srand(time(NULL));
game_controller game(argc,argv,use_sound);
game_controller game(argc,argv);
if (!filesystem_init()) {
std::cerr << "cannot init filesystem code\n";

View File

@ -51,7 +51,7 @@ void timestamps(bool t) { timestamp = t; }
logger err("error", 0), warn("warning", 1), info("info", 2);
log_domain general("general"), ai("ai"), config("config"), display("display"), engine("engine"),
network("network"), filesystem("filesystem");
network("network"), filesystem("filesystem"), audio("audio");
log_domain::log_domain(char const *name) : domain_(log_domains.size())
{

View File

@ -42,7 +42,7 @@ public:
void timestamps(bool);
extern logger err, warn, info;
extern log_domain general, ai, config, display, engine, network, filesystem;
extern log_domain general, ai, config, display, engine, network, filesystem, audio;
class scope_logger
{

View File

@ -247,40 +247,24 @@ void set_language(const std::string& s)
int music_volume()
{
static const int default_value = 100;
const string_map::const_iterator volume = prefs.values.find("music_volume");
if(volume != prefs.values.end() && volume->second.empty() == false)
return atoi(volume->second.c_str());
else
return default_value;
return lexical_cast_default<int>(prefs["music_volume"], 100);
}
void set_music_volume(int vol)
{
std::stringstream stream;
stream << vol;
prefs["music_volume"] = stream.str();
sound::set_music_volume(vol / 100.0);
prefs["music_volume"] = lexical_cast_default<std::string>(vol, "100");
sound::set_music_volume(music_volume());
}
int sound_volume()
{
static const int default_value = 100;
const string_map::const_iterator volume = prefs.values.find("sound_volume");
if(volume != prefs.values.end() && volume->second.empty() == false)
return atoi(volume->second.c_str());
else
return default_value;
return lexical_cast_default<int>(prefs["sound_volume"], 100);
}
void set_sound_volume(int vol)
{
std::stringstream stream;
stream << vol;
prefs["sound_volume"] = stream.str();
sound::set_sound_volume(vol / 100.0);
prefs["sound_volume"] = lexical_cast_default<std::string>(vol, "100");
sound::set_sound_volume(sound_volume());
}
void mute(bool muted)
@ -464,6 +448,49 @@ void set_message_bell(bool ison)
prefs["message_bell"] = (ison ? "yes" : "no");
}
bool sound() {
return prefs["sound"] != "no";
}
void set_sound(bool ison) {
if(!sound() && ison) {
prefs["sound"] = "yes";
if(!music()) {
if(!sound::init_sound())
prefs["sound"] = "no";
}
} else if(sound() && !ison) {
prefs["sound"] = "no";
sound::stop_sound();
if(!music())
sound::close_sound();
}
return;
}
bool music() {
return prefs["music"] != "no";
}
void set_music(bool ison) {
if(!music() && ison) {
prefs["music"] = "yes";
if(!sound()) {
if(!sound::init_sound())
prefs["music"] = "no";
}
else
sound::play_music("");
} else if(music() && !ison) {
prefs["music"] = "no";
if(!sound())
sound::close_sound();
else
sound::stop_music();
}
return;
}
bool turn_dialog()
{
return prefs["turn_dialog"] == "yes";
@ -836,7 +863,7 @@ private:
show_grid_button_, show_floating_labels_button_, turn_dialog_button_,
turn_bell_button_, show_team_colours_button_, show_colour_cursors_button_,
show_haloing_button_, video_mode_button_, hotkeys_button_, gamma_button_,
flip_time_button_, advanced_button_;
flip_time_button_, advanced_button_, sound_button_, music_button_;
gui::label music_label_, sound_label_, scroll_label_, gamma_label_;
unsigned slider_label_width_;
@ -867,6 +894,8 @@ preferences_dialog::preferences_dialog(display& disp, const config& game_cfg)
hotkeys_button_(disp.video(), _("Hotkeys")),
gamma_button_(disp.video(), _("Adjust Gamma"), gui::button::TYPE_CHECK),
flip_time_button_(disp.video(), _("Reverse Time Graphics"), gui::button::TYPE_CHECK),
sound_button_(disp.video(), _("Enable/Disable sound"), gui::button::TYPE_CHECK),
music_button_(disp.video(), _("Enable/Disable music"), gui::button::TYPE_CHECK),
advanced_button_(disp.video(), "", gui::button::TYPE_CHECK),
music_label_(disp.video(), _("Music Volume:")), sound_label_(disp.video(), _("SFX Volume:")),
scroll_label_(disp.video(), _("Scroll Speed:")), gamma_label_(disp.video(), _("Gamma:")),
@ -885,16 +914,21 @@ preferences_dialog::preferences_dialog(display& disp, const config& game_cfg)
maximum<unsigned>(scroll_label_.width(),
gamma_label_.width())));
sound_button_.set_check(sound());
sound_button_.set_help_string(_("Sound on/off"));
sound_slider_.set_min(1);
sound_slider_.set_max(100);
sound_slider_.set_value(sound_volume());
sound_slider_.set_help_string(_("Change the sound effects volume"));
music_button_.set_check(music());
music_button_.set_help_string(_("Music on/off"));
music_slider_.set_min(1);
music_slider_.set_max(100);
music_slider_.set_value(music_volume());
music_slider_.set_help_string(_("Change the music volume"));
scroll_slider_.set_min(1);
scroll_slider_.set_max(100);
scroll_slider_.set_value(scroll_speed());
@ -990,16 +1024,23 @@ void preferences_dialog::update_location(SDL_Rect const &rect)
// Sound tab
ypos = rect.y;
music_label_.set_location(rect.x, ypos);
SDL_Rect music_rect = { rect.x + slider_label_width_, ypos,
rect.w - slider_label_width_ - border, 0 };
music_slider_.set_location(music_rect);
sound_button_.set_location(rect.x, ypos);
ypos += item_interline;
sound_label_.set_location(rect.x, ypos);
SDL_Rect sound_rect = { rect.x + slider_label_width_, ypos,
rect.w - slider_label_width_ - border, 0 };
const SDL_Rect sound_rect = { rect.x + slider_label_width_, ypos,
rect.w - slider_label_width_ - border, 0 };
sound_slider_.set_location(sound_rect);
ypos += item_interline;
music_button_.set_location(rect.x, ypos);
ypos += item_interline;
music_label_.set_location(rect.x, ypos);
const SDL_Rect music_rect = { rect.x + slider_label_width_, ypos,
rect.w - slider_label_width_ - border, 0 };
music_slider_.set_location(music_rect);
//Advanced tab
ypos = rect.y;
advanced_.set_location(rect.x,ypos);
@ -1046,10 +1087,18 @@ void preferences_dialog::process_event()
gamma_slider_.hide(hide_gamma);
gamma_label_.hide(hide_gamma);
}
if (sound_button_.pressed())
set_sound(sound_button_.checked());
set_sound_volume(sound_slider_.value());
if (music_button_.pressed())
set_music(music_button_.checked());
set_music_volume(music_slider_.value());
if (flip_time_button_.pressed())
set_flip_time(flip_time_button_.checked());
set_sound_volume(sound_slider_.value());
set_music_volume(music_slider_.value());
set_scroll_speed(scroll_slider_.value());
set_gamma(gamma_slider_.value());
@ -1142,8 +1191,10 @@ void preferences_dialog::set_selection(int index)
flip_time_button_.hide(hide_display);
const bool hide_sound = tab_ != SOUND_TAB;
music_button_.hide(hide_sound);
music_label_.hide(hide_sound);
music_slider_.hide(hide_sound);
sound_button_.hide(hide_sound);
sound_label_.hide(hide_sound);
sound_slider_.hide(hide_sound);

View File

@ -55,12 +55,18 @@ namespace preferences {
const std::string& language();
void set_language(const std::string& s);
int music_volume();
void set_music_volume(int vol);
bool sound();
void set_sound(bool ison);
int sound_volume();
void set_sound_volume(int vol);
bool music();
void set_music(bool ison);
int music_volume();
void set_music_volume(int vol);
void mute(bool muted);
bool is_muted();

View File

@ -16,6 +16,7 @@
#include "filesystem.hpp"
#include "game_config.hpp"
#include "log.hpp"
#include "preferences.hpp"
#include "sound.hpp"
#include "wesconfig.h"
@ -25,29 +26,27 @@
#include <iostream>
#include <map>
namespace {
#define LOG_AUDIO LOG_STREAM(info, audio)
#define ERR_AUDIO LOG_STREAM(err, audio)
namespace {
bool mix_ok = false;
std::map<std::string,Mix_Chunk*> sound_cache;
std::map<std::string,Mix_Music*> music_cache;
std::string current_music = "";
bool music_off = false;
bool sound_off = false;
}
namespace sound {
manager::manager(bool sound_on)
manager::manager()
{
if(!sound_on) {
return;
}
SDL_Init(SDL_INIT_AUDIO);
}
manager::~manager()
{
close_sound();
}
bool init_sound() {
//sounds don't sound good on Windows unless the buffer size is 4k,
//but this seems to cause crashes on other systems...
#ifdef WIN32
@ -55,153 +54,169 @@ manager::manager(bool sound_on)
#else
const size_t buf_size = 1024;
#endif
if(SDL_WasInit(SDL_INIT_AUDIO) == 0)
if(SDL_InitSubSystem(SDL_INIT_AUDIO) == -1)
return false;
if(!mix_ok) {
if(Mix_OpenAudio(MIX_DEFAULT_FREQUENCY,MIX_DEFAULT_FORMAT,2,buf_size) == -1) {
mix_ok = false;
ERR_AUDIO << "Could not initialize audio: " << SDL_GetError() << "\n";
return false;
}
const int res = Mix_OpenAudio(MIX_DEFAULT_FREQUENCY,MIX_DEFAULT_FORMAT,2,buf_size);
if(res >= 0) {
mix_ok = true;
Mix_AllocateChannels(16);
} else {
set_sound_volume(preferences::sound_volume());
set_music_volume(preferences::music_volume());
LOG_AUDIO << "Audio initialized.\n";
play_music(current_music);
return true;
}
return true;
}
void close_sound() {
int numtimesopened, frequency, channels;
Uint16 format;
if(mix_ok) {
stop_sound();
stop_music();
mix_ok = false;
std::cerr << "Could not initialize audio: " << SDL_GetError() << "\n";
numtimesopened = Mix_QuerySpec(&frequency, &format, &channels);
if(numtimesopened == 0) {
ERR_AUDIO << "Error closing audio device: " << Mix_GetError() << "\n";
}
while (numtimesopened) {
Mix_CloseAudio();
--numtimesopened;
}
}
if(SDL_WasInit(SDL_INIT_AUDIO) != 0)
SDL_QuitSubSystem(SDL_INIT_AUDIO);
LOG_AUDIO << "Audio device released.\n";
}
void stop_music() {
if(mix_ok) {
Mix_HaltMusic();
std::map<std::string,Mix_Music*>::iterator i;
for(i = music_cache.begin(); i != music_cache.end(); ++i)
Mix_FreeMusic(i->second);
music_cache.clear();
}
}
manager::~manager()
{
std::cerr << "closing audio...\n";
if(!mix_ok)
return;
void stop_sound() {
if(mix_ok) {
Mix_HaltChannel(-1);
Mix_HaltMusic();
Mix_HaltChannel(-1);
for(std::map<std::string,Mix_Chunk*>::iterator i = sound_cache.begin();
i != sound_cache.end(); ++i) {
Mix_FreeChunk(i->second);
std::map<std::string,Mix_Chunk*>::iterator i;
for(i = sound_cache.begin(); i != sound_cache.end(); ++i)
Mix_FreeChunk(i->second);
sound_cache.clear();
}
for(std::map<std::string,Mix_Music*>::iterator j = music_cache.begin();
j != music_cache.end(); ++j) {
Mix_FreeMusic(j->second);
}
std::cerr << "final closing audio...\n";
Mix_CloseAudio();
std::cerr << "done closing audio...\n";
}
void play_music(const std::string& file)
void play_music(std::string file)
{
if(!mix_ok || current_music == file)
if(Mix_PlayingMusic() && current_music == file)
return;
if(music_off) {
current_music = file;
else if(current_music.empty() && file.empty())
return;
}
std::map<std::string,Mix_Music*>::const_iterator itor = music_cache.find(file);
if(itor == music_cache.end()) {
const std::string& filename = get_binary_file_location("music",file);
if(filename.empty()) {
return;
}
Mix_Music* const music = Mix_LoadMUS(filename.c_str());
if(music == NULL) {
std::cerr << "Could not load music file '" << filename << "': "
<< SDL_GetError() << "\n";
return;
}
itor = music_cache.insert(std::pair<std::string,Mix_Music*>(file,music)).first;
}
if(Mix_PlayingMusic()) {
Mix_FadeOutMusic(500);
}
const int res = Mix_FadeInMusic(itor->second,-1,500);
if(res < 0) {
std::cerr << "Could not play music: " << SDL_GetError() << "\n";
if(file.empty()) {
file = current_music;
}
current_music = file;
if(preferences::music() && mix_ok) {
std::map<std::string,Mix_Music*>::const_iterator itor = music_cache.find(file);
if(itor == music_cache.end()) {
const std::string& filename = get_binary_file_location("music",file);
if(filename.empty()) {
return;
}
Mix_Music* const music = Mix_LoadMUS(filename.c_str());
if(music == NULL) {
ERR_AUDIO << "Could not load music file '" << filename << "': "
<< SDL_GetError() << "\n";
return;
}
itor = music_cache.insert(std::pair<std::string,Mix_Music*>(file,music)).first;
} else if(current_music == file)
return;
if(Mix_PlayingMusic()) {
Mix_FadeOutMusic(500);
}
const int res = Mix_FadeInMusic(itor->second,-1,500);
if(res < 0) {
ERR_AUDIO << "Could not play music: " << SDL_GetError() << " " << file <<" \n";
}
}
}
void play_sound(const std::string& file)
{
if(!mix_ok || sound_off)
return;
// the insertion will fail if there is already an element in the cache
std::pair< std::map< std::string, Mix_Chunk * >::iterator, bool >
it = sound_cache.insert(std::make_pair(file, (Mix_Chunk *)0));
Mix_Chunk *&cache = it.first->second;
if (it.second) {
std::string const &filename = get_binary_file_location("sounds", file);
if (!filename.empty()) {
if(preferences::sound() && mix_ok) {
// the insertion will fail if there is already an element in the cache
std::pair< std::map< std::string, Mix_Chunk * >::iterator, bool >
it = sound_cache.insert(std::make_pair(file, (Mix_Chunk *)0));
Mix_Chunk *&cache = it.first->second;
if (it.second) {
std::string const &filename = get_binary_file_location("sounds", file);
if (!filename.empty()) {
#ifdef USE_ZIPIOS
std::string const &s = read_file(filename);
if (!s.empty()) {
SDL_RWops* ops = SDL_RWFromMem((void*)s.c_str(), s.size());
cache = Mix_LoadWAV_RW(ops,0);
}
std::string const &s = read_file(filename);
if (!s.empty()) {
SDL_RWops* ops = SDL_RWFromMem((void*)s.c_str(), s.size());
cache = Mix_LoadWAV_RW(ops,0);
}
#else
cache = Mix_LoadWAV(filename.c_str());
cache = Mix_LoadWAV(filename.c_str());
#endif
}
if (cache == NULL) {
ERR_AUDIO << "Could not load sound file '" << filename << "': "
<< SDL_GetError() << "\n";
return;
}
}
if (cache == NULL) {
std::cerr << "Could not load sound file '" << filename << "': "
<< SDL_GetError() << "\n";
return;
//play on the first available channel
const int res = Mix_PlayChannel(-1, cache, 0);
if(res < 0) {
ERR_AUDIO << "error playing sound effect: " << SDL_GetError() << "\n";
}
}
//play on the first available channel
const int res = Mix_PlayChannel(-1, cache, 0);
if(res < 0) {
std::cerr << "error playing sound effect: " << SDL_GetError() << "\n";
}
}
void set_music_volume(double vol)
void set_music_volume(int vol)
{
if(!mix_ok)
return;
if(vol < 0.05) {
Mix_HaltMusic();
music_off = true;
return;
}
Mix_VolumeMusic(int(vol*double(MIX_MAX_VOLUME)));
//if the music was off completely, start playing it again now
if(music_off) {
music_off = false;
const std::string music = current_music;
current_music = "";
if(!music.empty()) {
play_music(music);
}
if(mix_ok && vol >= 0) {
if(vol > MIX_MAX_VOLUME)
vol = MIX_MAX_VOLUME;
Mix_VolumeMusic(vol);
}
}
void set_sound_volume(double vol)
void set_sound_volume(int vol)
{
if(!mix_ok)
return;
if(vol < 0.05) {
sound_off = true;
return;
} else {
sound_off = false;
Mix_Volume(-1,int(vol*double(MIX_MAX_VOLUME)));
if(mix_ok && vol >= 0) {
if(vol > MIX_MAX_VOLUME)
vol = MIX_MAX_VOLUME;
Mix_Volume(-1, vol);
}
}

View File

@ -18,15 +18,21 @@
namespace sound {
struct manager {
manager(bool sound_on);
manager();
~manager();
};
void play_music(const std::string& file);
bool init_sound();
void close_sound();
void stop_music();
void stop_sound();
void play_music(std::string file);
void play_sound(const std::string& file);
void set_music_volume(double vol);
void set_sound_volume(double vol);
void set_music_volume(int vol);
void set_sound_volume(int vol);
}