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