1 /* --------------------------------------------------------------------
2 EXTREME TUXRACER
3
4 Copyright (C) 2010 Extreme Tux Racer Team
5
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation; either version 2
9 of the License, or (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15 ---------------------------------------------------------------------*/
16
17 #ifdef HAVE_CONFIG_H
18 #include <etr_config.h>
19 #endif
20
21 #include <SFML/Audio.hpp>
22
23 #include "audio.h"
24 #include "spx.h"
25
26 // the global instances of the 2 audio classes
27 CSound Sound;
28 CMusic Music;
29 #define MIX_MAX_VOLUME 100
30
31 struct TSound {
32 sf::SoundBuffer data;
33 sf::Sound player;
TSoundTSound34 explicit TSound(int volume) {
35 setVolume(volume);
36 }
setVolumeTSound37 void setVolume(int volume) {
38 player.setVolume(volume);
39 }
40
PlayTSound41 void Play(bool loop) {
42 if (player.getStatus() == sf::Sound::Playing) return;
43 player.setLoop(loop);
44 player.play();
45 }
46 };
47
48 // --------------------------------------------------------------------
49 // class CSound
50 // --------------------------------------------------------------------
51
~CSound()52 CSound::~CSound() {
53 FreeSounds();
54 }
55
LoadChunk(const std::string & name,const std::string & filename)56 bool CSound::LoadChunk(const std::string& name, const std::string& filename) {
57 sounds.emplace_back(new TSound(param.sound_volume));
58 if (!sounds.back()->data.loadFromFile(filename)) // Try loading sound buffer
59 return false;
60 sounds.back()->player.setBuffer(sounds.back()->data);
61 SoundIndex[name] = sounds.size()-1;
62 return true;
63 }
64
65 // Load all soundfiles listed in "/sounds/sounds.lst"
LoadSoundList()66 void CSound::LoadSoundList() {
67 CSPList list;
68 if (list.Load(param.sounds_dir, "sounds.lst")) {
69 for (CSPList::const_iterator line = list.cbegin(); line != list.cend(); ++line) {
70 std::string name = SPStrN(*line, "name");
71 std::string soundfile = SPStrN(*line, "file");
72 std::string path = MakePathStr(param.sounds_dir, soundfile);
73 LoadChunk(name, path);
74 }
75 }
76 }
77
FreeSounds()78 void CSound::FreeSounds() {
79 HaltAll();
80 for (std::size_t i = 0; i < sounds.size(); i++)
81 delete sounds[i];
82 sounds.clear();
83 SoundIndex.clear();
84 }
85
GetSoundIdx(const std::string & name) const86 std::size_t CSound::GetSoundIdx(const std::string& name) const {
87 try {
88 return SoundIndex.at(name);
89 } catch (...) {
90 return -1;
91 }
92 }
93
SetVolume(std::size_t soundid,int volume)94 void CSound::SetVolume(std::size_t soundid, int volume) {
95 if (soundid >= sounds.size()) return;
96
97 volume = clamp(0, volume, MIX_MAX_VOLUME);
98 sounds[soundid]->setVolume(volume);
99 }
100
SetVolume(const std::string & name,int volume)101 void CSound::SetVolume(const std::string& name, int volume) {
102 SetVolume(GetSoundIdx(name), volume);
103 }
104
105 // ------------------- play -------------------------------------------
106
Play(std::size_t soundid,bool loop)107 void CSound::Play(std::size_t soundid, bool loop) {
108 if (soundid >= sounds.size()) return;
109
110 sounds[soundid]->Play(loop);
111 }
112
Play(const std::string & name,bool loop)113 void CSound::Play(const std::string& name, bool loop) {
114 Play(GetSoundIdx(name), loop);
115 }
116
Play(std::size_t soundid,bool loop,int volume)117 void CSound::Play(std::size_t soundid, bool loop, int volume) {
118 if (soundid >= sounds.size()) return;
119
120 volume = clamp(0, volume, MIX_MAX_VOLUME);
121 sounds[soundid]->setVolume(volume);
122 sounds[soundid]->Play(loop);
123 }
124
Play(const std::string & name,bool loop,int volume)125 void CSound::Play(const std::string& name, bool loop, int volume) {
126 Play(GetSoundIdx(name), loop, volume);
127 }
128
Halt(std::size_t soundid)129 void CSound::Halt(std::size_t soundid) {
130 if (soundid >= sounds.size()) return;
131
132 // loop_count must be -1 (endless loop) for halt
133 if (sounds[soundid]->player.getLoop())
134 sounds[soundid]->player.stop();
135 }
136
Halt(const std::string & name)137 void CSound::Halt(const std::string& name) {
138 Halt(GetSoundIdx(name));
139 }
140
HaltAll()141 void CSound::HaltAll() {
142 for (std::size_t i = 0; i < sounds.size(); i++) {
143 sounds[i]->player.stop();
144 }
145 }
146
147 // --------------------------------------------------------------------
148 // class CMusic
149 // --------------------------------------------------------------------
150
CMusic()151 CMusic::CMusic() {
152 curr_music = 0;
153 curr_volume = 10;
154 }
~CMusic()155 CMusic::~CMusic() {
156 FreeMusics();
157 }
158
LoadPiece(const std::string & name,const std::string & filename)159 bool CMusic::LoadPiece(const std::string& name, const std::string& filename) {
160 sf::Music* m = new sf::Music();
161 if (!m->openFromFile(filename)) {
162 Message("could not load music", filename);
163 return false;
164 }
165 MusicIndex[name] = musics.size();
166 musics.push_back(m);
167 return true;
168 }
169
LoadMusicList()170 void CMusic::LoadMusicList() {
171 // --- music ---
172 CSPList list;
173 if (list.Load(param.music_dir, "music.lst")) {
174 musics.reserve(list.size());
175 for (CSPList::const_iterator line = list.cbegin(); line != list.cend(); ++line) {
176 std::string name = SPStrN(*line, "name");
177 std::string musicfile = SPStrN(*line, "file");
178 std::string path = MakePathStr(param.music_dir, musicfile);
179 LoadPiece(name, path);
180 }
181 } else {
182 Message("could not load music.lst");
183 return;
184 }
185
186 // --- racing themes ---
187 list.clear();
188 ThemesIndex.clear();
189 if (list.Load(param.music_dir, "racing_themes.lst")) {
190 themes.resize(list.size());
191 std::size_t i = 0;
192 for (CSPList::const_iterator line = list.cbegin(); line != list.cend(); ++line, i++) {
193 std::string name = SPStrN(*line, "name");
194 ThemesIndex[name] = i;
195 std::string item = SPStrN(*line, "race", "race_1");
196 themes[i].situation[0] = musics[MusicIndex[item]];
197 item = SPStrN(*line, "wonrace", "wonrace_1");
198 themes[i].situation[1] = musics[MusicIndex[item]];
199 item = SPStrN(*line, "lostrace", "lostrace_1");
200 themes[i].situation[2] = musics[MusicIndex[item]];
201 }
202 } else Message("could not load racing_themes.lst");
203 }
204
FreeMusics()205 void CMusic::FreeMusics() {
206 Halt();
207 for (std::size_t i = 0; i < musics.size(); i++)
208 delete musics[i];
209 musics.clear();
210 MusicIndex.clear();
211
212 themes.clear();
213 ThemesIndex.clear();
214
215 curr_music = nullptr;
216 }
217
GetMusicIdx(const std::string & name) const218 std::size_t CMusic::GetMusicIdx(const std::string& name) const {
219 try {
220 return MusicIndex.at(name);
221 } catch (...) {
222 return -1;
223 }
224 }
225
GetThemeIdx(const std::string & theme) const226 std::size_t CMusic::GetThemeIdx(const std::string& theme) const {
227 try {
228 return ThemesIndex.at(theme);
229 } catch (...) {
230 return -1;
231 }
232 }
233
SetVolume(int volume)234 void CMusic::SetVolume(int volume) {
235 volume = clamp(0, volume, MIX_MAX_VOLUME);
236 if (curr_music)
237 curr_music->setVolume(volume);
238 curr_volume = volume;
239 }
240
Play(sf::Music * music,bool loop,int volume)241 bool CMusic::Play(sf::Music* music, bool loop, int volume) {
242 if (!music)
243 return false;
244
245 volume = clamp(0, volume, MIX_MAX_VOLUME);
246 if (music != curr_music) {
247 music->setVolume(volume);
248 music->setLoop(loop);
249 if (curr_music)
250 curr_music->stop();
251 curr_music = music;
252 music->play();
253 }
254 return true;
255 }
256
Play(std::size_t musid,bool loop)257 bool CMusic::Play(std::size_t musid, bool loop) {
258 if (musid >= musics.size()) return false;
259 sf::Music* music = musics[musid];
260 return Play(music, loop, curr_volume);
261 }
262
Play(const std::string & name,bool loop)263 bool CMusic::Play(const std::string& name, bool loop) {
264 return Play(GetMusicIdx(name), loop);
265 }
266
Play(std::size_t musid,bool loop,int volume)267 bool CMusic::Play(std::size_t musid, bool loop, int volume) {
268 if (musid >= musics.size()) return false;
269 sf::Music* music = musics[musid];
270 return Play(music, loop, volume);
271 }
272
Play(const std::string & name,bool loop,int volume)273 bool CMusic::Play(const std::string& name, bool loop, int volume) {
274 return Play(GetMusicIdx(name), loop, volume);
275 }
276
PlayTheme(std::size_t theme,ESituation situation)277 bool CMusic::PlayTheme(std::size_t theme, ESituation situation) {
278 if (theme >= themes.size()) return false;
279 if (situation >= SITUATION_COUNT) return false;
280 sf::Music* music = themes[theme].situation[situation];
281 return Play(music, true, curr_volume);
282 }
283
Halt()284 void CMusic::Halt() {
285 if (curr_music) {
286 curr_music->stop();
287 curr_music = nullptr;
288 }
289 }
290