1 //---------------------------------------------------------------------------
2 #include "stdafx.h"
3
4 #include "sound.h"
5 #include "utils.h"
6 #include "game.h"
7 #include "gamestate.h"
8 //---------------------------------------------------------------------------
9
10 bool error_occurred = false;
11 bool have_sound = false;
12
errorSound()13 bool errorSound() {
14 bool rtn = error_occurred;
15 return rtn;
16 }
17
resetErrorSound()18 void resetErrorSound() {
19 error_occurred = false;
20 }
21
~Sample()22 Sample::~Sample() {
23 if( music != NULL )
24 Mix_FreeMusic(music);
25 if( chunk != NULL )
26 Mix_FreeChunk(chunk);
27 }
28
initSound()29 bool initSound() {
30 // important to reinitialise for Android, where globals aren't reinitialised when native app is restarted
31 error_occurred = false;
32 have_sound = false;
33
34 if( SDL_InitSubSystem(SDL_INIT_AUDIO) != 0 ) {
35 LOG("failed to init SDL audio subsystem");
36 return false;
37 }
38 if( Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 1024) == -1 ) {
39 LOG("Mix_OpenAudio failed: %s\n", Mix_GetError());
40 SDL_QuitSubSystem(SDL_INIT_AUDIO);
41 return false;
42 }
43 #ifdef _WIN32
44 // not yet available on Linux!
45 Mix_Init(0);
46 #endif
47
48 have_sound = true;
49 return true;
50 }
51
updateSound()52 void updateSound() {
53 }
54
freeSound()55 void freeSound() {
56 if( have_sound ) {
57 Mix_CloseAudio();
58 #ifdef _WIN32
59 // not yet available on Linux!
60 Mix_Quit();
61 #endif
62 SDL_QuitSubSystem(SDL_INIT_AUDIO);
63 }
64 }
65
loadSample(const char * filename,bool iff)66 Sample *Sample::loadSample(const char *filename, bool iff) {
67 //LOG("loadSample %s\n", filename); // disabled logging to improve performance on startup
68 Mix_Chunk *chunk = NULL;
69 if( have_sound ) {
70 chunk = Mix_LoadWAV(filename);
71 if( chunk == NULL ) {
72 LOG("Mix_LoadWAV failed: %s\n", Mix_GetError());
73 error_occurred = true;
74 }
75 }
76
77 // we still create the structure even if no sample is loaded, as we also use for displaying the associated text; also means we don't have to check for NULL pointers every time we want to play a sample
78 Sample *sample = new Sample(false, NULL, chunk);
79 return sample;
80 }
81
loadSample(string filename,bool iff)82 Sample *Sample::loadSample(string filename, bool iff) {
83 return loadSample(filename.c_str(), iff);
84 }
85
loadMusic(const char * filename)86 Sample *Sample::loadMusic(const char *filename) {
87 LOG("loadMusic %s\n", filename);
88 Mix_Music *music = NULL;
89 if( have_sound ) {
90 // Mix_LoadMUS doesn't support RWops, so won't work on Android (but only available in SDL 2)
91 #if SDL_MAJOR_VERSION == 1
92 music = Mix_LoadMUS(filename);
93 #else
94 music = Mix_LoadMUSType_RW(SDL_RWFromFile(filename, "rb"), MUS_OGG, 1);
95 #endif
96 if( music == NULL ) {
97 LOG("Mix_LoadMUS failed: %s\n", Mix_GetError());
98 error_occurred = true;
99 }
100 }
101 // we still create the structure even if no sample is loaded, as means we don't have to check for NULL pointers every time we want to play a sample
102 Sample *sample = new Sample(true, music, NULL);
103 return sample;
104 }
105
play(int ch,int loops)106 void Sample::play(int ch, int loops) {
107 if( have_sound ) {
108 if( is_music && game_g->isPrefMusicOn() ) {
109 if( Mix_PlayMusic(music, loops) == -1 ) {
110 //if( Mix_FadeInMusic(music, -1, 2000) == -1 ) {
111 LOG("Mix_PlayMusic failed: %s\n", Mix_GetError());
112 }
113 Mix_VolumeMusic(MIX_MAX_VOLUME);
114 }
115 else if( !is_music && game_g->isPrefSoundOn() ) {
116 if( chunk != NULL ) {
117 bool done = false;
118 if( channel != -1 ) {
119 if( Mix_Paused(channel) ) {
120 // sound was paused, so let's just resume
121 Mix_Resume(channel);
122 done = true;
123 }
124 // otherwise, let's stop the currently playing sound
125 Mix_HaltChannel(channel);
126 }
127 if( !done ) {
128 channel = Mix_PlayChannel(ch, chunk, loops);
129 if( channel == -1 ) {
130 LOG("Failed to play sound: %s\n", Mix_GetError());
131 }
132 else {
133 Mix_Volume(channel, MIX_MAX_VOLUME);
134 }
135 }
136 }
137 }
138 }
139 if( this->text.length() > 0 ) {
140 //const int ypos = 216;
141 const int ypos = 224;
142 TextEffect *effect = new TextEffect(this->text, 160, ypos, 2000);
143 game_g->addTextEffect(effect);
144 }
145 }
146
147 /*bool Sample::isPlaying() const {
148 // also returns true if the channel is paused - this is about whether the sample has finished (or not yet started)
149 if( channel != -1 ) {
150 // still need to check in case sample ended
151 if( Mix_Playing(channel) != 0 ) {
152 return true;
153 }
154 }
155 return false;
156 }*/
157
pauseMusic()158 void Sample::pauseMusic() {
159 if( have_sound ) {
160 Mix_PauseMusic();
161 }
162 }
163
unpauseMusic()164 void Sample::unpauseMusic() {
165 if( have_sound ) {
166 Mix_ResumeMusic();
167 }
168 }
169
pauseChannel(int ch)170 void Sample::pauseChannel(int ch) {
171 if( have_sound ) {
172 Mix_Pause(ch);
173 }
174 }
175
unpauseChannel(int ch)176 void Sample::unpauseChannel(int ch) {
177 if( have_sound ) {
178 Mix_Resume(ch);
179 }
180 }
181
fadeOut(int duration_ms)182 void Sample::fadeOut(int duration_ms) {
183 if( have_sound ) {
184 if( is_music && music != NULL ) {
185 Mix_FadeOutMusic(duration_ms);
186 }
187 else if( channel != -1 ) {
188 Mix_FadeOutChannel(channel, duration_ms);
189 }
190 }
191 }
192
setVolume(float volume)193 void Sample::setVolume(float volume) {
194 if( have_sound ) {
195 if( is_music ) {
196 Mix_VolumeMusic((int)(MIX_MAX_VOLUME*volume));
197 }
198 else if( channel != -1 ) {
199 Mix_Volume(channel, (int)(MIX_MAX_VOLUME*volume));
200 }
201 }
202 }
203
isPlaying(int ch)204 bool isPlaying(int ch) {
205 bool is_playing = false;
206 if( have_sound ) {
207 if( Mix_Playing(ch) != 0 ) {
208 is_playing = true;
209 }
210 }
211 return is_playing;
212 }
213