303 lines
7.6 KiB
C++
303 lines
7.6 KiB
C++
/* --------------------------------------------------------------------
|
|
EXTREME TUXRACER
|
|
|
|
Copyright (C) 2010 Extreme Tuxracer Team
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
---------------------------------------------------------------------*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <etr_config.h>
|
|
#endif
|
|
|
|
#include <SFML/Audio.hpp>
|
|
|
|
#include "audio.h"
|
|
#include "depot.h"
|
|
#include "spx.h"
|
|
|
|
// the global instances of the 2 audio classes
|
|
CSound Sound;
|
|
CMusic Music;
|
|
#define MIX_MAX_VOLUME 100
|
|
|
|
struct TSound {
|
|
sf::SoundBuffer data;
|
|
sf::Sound player;
|
|
explicit TSound(int volume) {
|
|
setVolume(volume);
|
|
}
|
|
void setVolume(int volume) {
|
|
player.setVolume(volume);
|
|
}
|
|
|
|
void Play(bool loop) {
|
|
if (player.getStatus() == sf::Sound::Playing) return;
|
|
player.setLoop(loop);
|
|
player.play();
|
|
}
|
|
};
|
|
|
|
// --------------------------------------------------------------------
|
|
// class CSound
|
|
// --------------------------------------------------------------------
|
|
|
|
CSound::~CSound() {
|
|
FreeSounds();
|
|
}
|
|
|
|
bool CSound::LoadChunk(const std::string& name, const std::string& filename) {
|
|
sounds.emplace_back(new TSound(param.sound_volume));
|
|
if (!sounds.back()->data.loadFromFile(filename)) // Try loading sound buffer
|
|
return false;
|
|
sounds.back()->player.setBuffer(sounds.back()->data);
|
|
SoundIndex[name] = sounds.size()-1;
|
|
return true;
|
|
}
|
|
|
|
bool CSound::LoadChunkDepot(const std::string &name, const std::string &depotpath) {
|
|
auto path = DepotMustResolveFile(depotpath);
|
|
return LoadChunk(name, path);
|
|
}
|
|
|
|
// Load all soundfiles listed in "/sounds/sounds.lst"
|
|
void CSound::LoadSoundList() {
|
|
CSPList list;
|
|
if (list.LoadDepot("//data/sounds/sounds.lst")) {
|
|
sounds.reserve(list.size());
|
|
SoundIndex.reserve(list.size());
|
|
for (CSPList::const_iterator line = list.cbegin(); line != list.cend(); ++line) {
|
|
std::string name = SPStrN(*line, "name");
|
|
std::string depotpath = SPStrN(*line, "file");
|
|
LoadChunkDepot(name, depotpath);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CSound::FreeSounds() {
|
|
HaltAll();
|
|
for (std::size_t i = 0; i < sounds.size(); i++)
|
|
delete sounds[i];
|
|
sounds.clear();
|
|
SoundIndex.clear();
|
|
}
|
|
|
|
std::size_t CSound::GetSoundIdx(const std::string& name) const {
|
|
try {
|
|
return SoundIndex.at(name);
|
|
} catch (...) {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
void CSound::SetVolume(std::size_t soundid, int volume) {
|
|
if (soundid >= sounds.size()) return;
|
|
|
|
volume = clamp(0, volume, MIX_MAX_VOLUME);
|
|
sounds[soundid]->setVolume(volume);
|
|
}
|
|
|
|
void CSound::SetVolume(const std::string& name, int volume) {
|
|
SetVolume(GetSoundIdx(name), volume);
|
|
}
|
|
|
|
// ------------------- play -------------------------------------------
|
|
|
|
void CSound::Play(std::size_t soundid, bool loop) {
|
|
if (soundid >= sounds.size()) return;
|
|
|
|
sounds[soundid]->Play(loop);
|
|
}
|
|
|
|
void CSound::Play(const std::string& name, bool loop) {
|
|
Play(GetSoundIdx(name), loop);
|
|
}
|
|
|
|
void CSound::Play(std::size_t soundid, bool loop, int volume) {
|
|
if (soundid >= sounds.size()) return;
|
|
|
|
volume = clamp(0, volume, MIX_MAX_VOLUME);
|
|
sounds[soundid]->setVolume(volume);
|
|
sounds[soundid]->Play(loop);
|
|
}
|
|
|
|
void CSound::Play(const std::string& name, bool loop, int volume) {
|
|
Play(GetSoundIdx(name), loop, volume);
|
|
}
|
|
|
|
void CSound::Halt(std::size_t soundid) {
|
|
if (soundid >= sounds.size()) return;
|
|
|
|
// loop_count must be -1 (endless loop) for halt
|
|
if (sounds[soundid]->player.getLoop())
|
|
sounds[soundid]->player.stop();
|
|
}
|
|
|
|
void CSound::Halt(const std::string& name) {
|
|
Halt(GetSoundIdx(name));
|
|
}
|
|
|
|
void CSound::HaltAll() {
|
|
for (std::size_t i = 0; i < sounds.size(); i++) {
|
|
sounds[i]->player.stop();
|
|
}
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
// class CMusic
|
|
// --------------------------------------------------------------------
|
|
|
|
CMusic::CMusic() {
|
|
curr_music = 0;
|
|
curr_volume = 10;
|
|
}
|
|
CMusic::~CMusic() {
|
|
FreeMusics();
|
|
}
|
|
|
|
bool CMusic::LoadPiece(const std::string& name, const std::string& filename) {
|
|
sf::Music* m = new sf::Music();
|
|
if (!m->openFromFile(filename)) {
|
|
Message("could not load music", filename);
|
|
return false;
|
|
}
|
|
MusicIndex[name] = musics.size();
|
|
musics.push_back(m);
|
|
return true;
|
|
}
|
|
|
|
bool CMusic::LoadPieceDepot(const std::string &name, const std::string &depotpath) {
|
|
auto path = DepotMustResolveFile(depotpath);
|
|
return LoadPiece(name, path);
|
|
}
|
|
|
|
void CMusic::LoadMusicList() {
|
|
// --- music ---
|
|
CSPList list;
|
|
if (list.LoadDepot("//data/music/music.lst")) {
|
|
musics.reserve(list.size());
|
|
MusicIndex.reserve(list.size());
|
|
for (CSPList::const_iterator line = list.cbegin(); line != list.cend(); ++line) {
|
|
std::string name = SPStrN(*line, "name");
|
|
std::string depotpath = SPStrN(*line, "file");
|
|
LoadPieceDepot(name, depotpath);
|
|
}
|
|
} else {
|
|
Message("could not load music.lst");
|
|
return;
|
|
}
|
|
|
|
// --- racing themes ---
|
|
list.clear();
|
|
ThemesIndex.clear();
|
|
if (list.LoadDepot("//data/music/racing_themes.lst")) {
|
|
themes.resize(list.size());
|
|
ThemesIndex.reserve(list.size());
|
|
std::size_t i = 0;
|
|
for (CSPList::const_iterator line = list.cbegin(); line != list.cend(); ++line, i++) {
|
|
std::string name = SPStrN(*line, "name");
|
|
ThemesIndex[name] = i;
|
|
std::string item = SPStrN(*line, "race", "race_1");
|
|
themes[i].situation[0] = musics[MusicIndex[item]];
|
|
item = SPStrN(*line, "wonrace", "wonrace_1");
|
|
themes[i].situation[1] = musics[MusicIndex[item]];
|
|
item = SPStrN(*line, "lostrace", "lostrace_1");
|
|
themes[i].situation[2] = musics[MusicIndex[item]];
|
|
}
|
|
} else Message("could not load racing_themes.lst");
|
|
}
|
|
|
|
void CMusic::FreeMusics() {
|
|
Halt();
|
|
for (std::size_t i = 0; i < musics.size(); i++)
|
|
delete musics[i];
|
|
musics.clear();
|
|
MusicIndex.clear();
|
|
|
|
themes.clear();
|
|
ThemesIndex.clear();
|
|
|
|
curr_music = nullptr;
|
|
}
|
|
|
|
std::size_t CMusic::GetMusicIdx(const std::string& name) const {
|
|
try {
|
|
return MusicIndex.at(name);
|
|
} catch (...) {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
std::size_t CMusic::GetThemeIdx(const std::string& theme) const {
|
|
try {
|
|
return ThemesIndex.at(theme);
|
|
} catch (...) {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
void CMusic::SetVolume(int volume) {
|
|
volume = clamp(0, volume, MIX_MAX_VOLUME);
|
|
if (curr_music)
|
|
curr_music->setVolume(volume);
|
|
curr_volume = volume;
|
|
}
|
|
|
|
bool CMusic::Play(sf::Music* music, bool loop, int volume) {
|
|
if (!music)
|
|
return false;
|
|
|
|
volume = clamp(0, volume, MIX_MAX_VOLUME);
|
|
if (music != curr_music) {
|
|
music->setVolume(volume);
|
|
music->setLoop(loop);
|
|
if (curr_music)
|
|
curr_music->stop();
|
|
curr_music = music;
|
|
music->play();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool CMusic::Play(std::size_t musid, bool loop) {
|
|
if (musid >= musics.size()) return false;
|
|
sf::Music* music = musics[musid];
|
|
return Play(music, loop, curr_volume);
|
|
}
|
|
|
|
bool CMusic::Play(const std::string& name, bool loop) {
|
|
return Play(GetMusicIdx(name), loop);
|
|
}
|
|
|
|
bool CMusic::Play(std::size_t musid, bool loop, int volume) {
|
|
if (musid >= musics.size()) return false;
|
|
sf::Music* music = musics[musid];
|
|
return Play(music, loop, volume);
|
|
}
|
|
|
|
bool CMusic::Play(const std::string& name, bool loop, int volume) {
|
|
return Play(GetMusicIdx(name), loop, volume);
|
|
}
|
|
|
|
bool CMusic::PlayTheme(std::size_t theme, ESituation situation) {
|
|
if (theme >= themes.size()) return false;
|
|
if (situation >= SITUATION_COUNT) return false;
|
|
sf::Music* music = themes[theme].situation[situation];
|
|
return Play(music, true, curr_volume);
|
|
}
|
|
|
|
void CMusic::Halt() {
|
|
if (curr_music) {
|
|
curr_music->stop();
|
|
curr_music = nullptr;
|
|
}
|
|
}
|