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