1 #include "Sound.h"
2 
3 #include "AudioManager.h"
4 #include "Log.h"
5 #include "Settings.h"
6 #include "ThemeData.h"
7 
8 std::map< std::string, std::shared_ptr<Sound> > Sound::sMap;
9 
get(const std::string & path)10 std::shared_ptr<Sound> Sound::get(const std::string& path)
11 {
12 	auto it = sMap.find(path);
13 	if(it != sMap.cend())
14 		return it->second;
15 
16 	std::shared_ptr<Sound> sound = std::shared_ptr<Sound>(new Sound(path));
17 	AudioManager::getInstance()->registerSound(sound);
18 	sMap[path] = sound;
19 	return sound;
20 }
21 
getFromTheme(const std::shared_ptr<ThemeData> & theme,const std::string & view,const std::string & element)22 std::shared_ptr<Sound> Sound::getFromTheme(const std::shared_ptr<ThemeData>& theme, const std::string& view, const std::string& element)
23 {
24 	LOG(LogInfo) << " req sound [" << view << "." << element << "]";
25 
26 	const ThemeData::ThemeElement* elem = theme->getElement(view, element, "sound");
27 	if(!elem || !elem->has("path"))
28 	{
29 		LOG(LogInfo) << "   (missing)";
30 		return get("");
31 	}
32 
33 	return get(elem->get<std::string>("path"));
34 }
35 
Sound(const std::string & path)36 Sound::Sound(const std::string & path) : mSampleData(NULL), mSamplePos(0), mSampleLength(0), playing(false)
37 {
38 	loadFile(path);
39 }
40 
~Sound()41 Sound::~Sound()
42 {
43 	deinit();
44 }
45 
loadFile(const std::string & path)46 void Sound::loadFile(const std::string & path)
47 {
48 	mPath = path;
49 	init();
50 }
51 
init()52 void Sound::init()
53 {
54 	if(mSampleData != NULL)
55 		deinit();
56 
57 	if(mPath.empty())
58 		return;
59 
60 	//load wav file via SDL
61 	SDL_AudioSpec wave;
62 	Uint8 * data = NULL;
63     Uint32 dlen = 0;
64 	if (SDL_LoadWAV(mPath.c_str(), &wave, &data, &dlen) == NULL) {
65 		LOG(LogError) << "Error loading sound \"" << mPath << "\"!\n" << "	" << SDL_GetError();
66 		return;
67 	}
68 	//build conversion buffer
69 	SDL_AudioCVT cvt;
70     SDL_BuildAudioCVT(&cvt, wave.format, wave.channels, wave.freq, AUDIO_S16, 2, 44100);
71 	//copy data to conversion buffer
72 	cvt.len = dlen;
73     cvt.buf = new Uint8[cvt.len * cvt.len_mult];
74     memcpy(cvt.buf, data, dlen);
75 	//convert buffer to stereo, 16bit, 44.1kHz
76     if (SDL_ConvertAudio(&cvt) < 0) {
77 		LOG(LogError) << "Error converting sound \"" << mPath << "\" to 44.1kHz, 16bit, stereo format!\n" << "	" << SDL_GetError();
78 		delete[] cvt.buf;
79 	}
80 	else {
81 		//worked. set up member data
82 		SDL_LockAudio();
83 		mSampleData = cvt.buf;
84 		mSampleLength = cvt.len_cvt;
85 		mSamplePos = 0;
86 		mSampleFormat.channels = 2;
87 		mSampleFormat.freq = 44100;
88 		mSampleFormat.format = AUDIO_S16;
89 		SDL_UnlockAudio();
90 	}
91 	//free wav data now
92     SDL_FreeWAV(data);
93 }
94 
deinit()95 void Sound::deinit()
96 {
97 	playing = false;
98 
99 	if(mSampleData != NULL)
100 	{
101 		SDL_LockAudio();
102 		delete[] mSampleData;
103 		mSampleData = NULL;
104 		mSampleLength = 0;
105 		mSamplePos = 0;
106 		SDL_UnlockAudio();
107 	}
108 }
109 
play()110 void Sound::play()
111 {
112 	if(mSampleData == NULL)
113 		return;
114 
115 	if(!Settings::getInstance()->getBool("EnableSounds"))
116 		return;
117 
118 	AudioManager::getInstance();
119 
120 	SDL_LockAudio();
121 	if (playing)
122 	{
123 		//replay from start. rewind the sample to the beginning
124 		mSamplePos = 0;
125 
126 	}
127 	else
128 	{
129 		//flag our sample as playing
130 		playing = true;
131 	}
132 	SDL_UnlockAudio();
133 	//tell the AudioManager to start playing samples
134 	AudioManager::getInstance()->play();
135 }
136 
isPlaying() const137 bool Sound::isPlaying() const
138 {
139 	return playing;
140 }
141 
stop()142 void Sound::stop()
143 {
144 	//flag our sample as playing and rewind its position
145 	SDL_LockAudio();
146 	playing = false;
147 	mSamplePos = 0;
148 	SDL_UnlockAudio();
149 }
150 
getData() const151 const Uint8 * Sound::getData() const
152 {
153 	return mSampleData;
154 }
155 
getPosition() const156 Uint32 Sound::getPosition() const
157 {
158 	return mSamplePos;
159 }
160 
setPosition(Uint32 newPosition)161 void Sound::setPosition(Uint32 newPosition)
162 {
163 	mSamplePos = newPosition;
164 	if (mSamplePos >= mSampleLength) {
165 		//got to or beyond the end of the sample. stop playing
166 		playing = false;
167 		mSamplePos = 0;
168 	}
169 }
170 
getLength() const171 Uint32 Sound::getLength() const
172 {
173 	return mSampleLength;
174 }
175 
getLengthMS() const176 Uint32 Sound::getLengthMS() const
177 {
178 	//44100 samples per second, 2 channels (stereo)
179 	//I have no idea why the *0.75 is necessary, but otherwise it's inaccurate
180 	return (Uint32)((mSampleLength / 44100.0f / 2.0f * 0.75f) * 1000);
181 }
182