Mana
Loading...
Searching...
No Matches
sound.cpp
Go to the documentation of this file.
1/*
2 * The Mana Client
3 * Copyright (C) 2004-2009 The Mana World Development Team
4 * Copyright (C) 2009-2012 The Mana Developers
5 *
6 * This file is part of The Mana Client.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22#include <SDL.h>
23
24#include "configuration.h"
25#include "localplayer.h"
26#include "log.h"
27#include "sound.h"
28
29#include "resources/music.h"
32
36static bool sMusicFinished;
37static bool sChannelFinished[Sound::CHANNEL_COUNT];
38
39static void musicFinishedCallBack()
40{
41 sMusicFinished = true;
42}
43
44static void channelFinishedCallBack(int channel)
45{
46 sChannelFinished[channel] = true;
47}
48
50{
51 Mix_HookMusicFinished(musicFinishedCallBack);
52 Mix_ChannelFinished(channelFinishedCallBack);
53}
54
56{
57 Mix_HookMusicFinished(nullptr);
58 Mix_ChannelFinished(nullptr);
59}
60
62{
63 // Don't initialize sound engine twice
64 if (mInstalled)
65 return;
66
67 Log::info("Sound::init() Initializing sound...");
68
69 if (SDL_InitSubSystem(SDL_INIT_AUDIO) == -1)
70 {
71 Log::info("Sound::init() Failed to initialize audio subsystem");
72 return;
73 }
74
75 const size_t audioBuffer = 4096;
76
77 const int res = Mix_OpenAudio(MIX_DEFAULT_FREQUENCY, MIX_DEFAULT_FORMAT,
78 MIX_DEFAULT_CHANNELS, audioBuffer);
79 if (res < 0)
80 {
81 Log::info("Sound::init Could not initialize audio: %s",
82 Mix_GetError());
83 return;
84 }
85
86 Mix_AllocateChannels(CHANNEL_COUNT);
87 Mix_ReserveChannels(CHANNEL_RESERVED_COUNT);
88 Mix_VolumeMusic(mMusicVolume);
89 Mix_Volume(-1, mSfxVolume);
91
92 info();
93
94 mInstalled = true;
95
96 if (!mCurrentMusicFile.empty())
98}
99
101{
102 SDL_version compiledVersion;
103 const SDL_version *linkedVersion;
104 const char *format = "Unknown";
105 int rate = 0;
106 Uint16 audioFormat = 0;
107 int channels = 0;
108
109 MIX_VERSION(&compiledVersion);
110 linkedVersion = Mix_Linked_Version();
111
112 const char *driver = SDL_GetCurrentAudioDriver();
113
114 Mix_QuerySpec(&rate, &audioFormat, &channels);
115 switch (audioFormat)
116 {
117 case AUDIO_U8: format = "U8"; break;
118 case AUDIO_S8: format = "S8"; break;
119 case AUDIO_U16LSB: format = "U16LSB"; break;
120 case AUDIO_S16LSB: format = "S16LSB"; break;
121 case AUDIO_U16MSB: format = "U16MSB"; break;
122 case AUDIO_S16MSB: format = "S16MSB"; break;
123 }
124
125 Log::info("Sound::info() SDL_mixer: %i.%i.%i (compiled)",
126 compiledVersion.major,
127 compiledVersion.minor,
128 compiledVersion.patch);
129 Log::info("Sound::info() SDL_mixer: %i.%i.%i (linked)",
130 linkedVersion->major,
131 linkedVersion->minor,
132 linkedVersion->patch);
133 Log::info("Sound::info() Driver: %s", driver);
134 Log::info("Sound::info() Format: %s", format);
135 Log::info("Sound::info() Rate: %i", rate);
136 Log::info("Sound::info() Channels: %i", channels);
137}
138
139void Sound::setMusicVolume(int volume)
140{
141 mMusicVolume = volume;
142
143 if (mInstalled)
144 Mix_VolumeMusic(mMusicVolume);
145}
146
147void Sound::setSfxVolume(int volume)
148{
149 mSfxVolume = volume;
150
151 if (mInstalled)
152 {
153 Mix_Volume(-1, mSfxVolume);
155 }
156}
157
159{
160 mNotificationsVolume = volume;
161
162 if (mInstalled)
164}
165
166void Sound::playMusic(const std::string &fileName)
167{
168 fadeInMusic(fileName, 0);
169}
170
172{
173 if (!mInstalled)
174 return;
175
176 Log::info("Sound::stopMusic()");
177
178 haltMusic();
179}
180
181void Sound::fadeInMusic(const std::string &fileName, int ms)
182{
183 mCurrentMusicFile = fileName;
184
185 if (!mInstalled)
186 return;
187
188 haltMusic();
189
191 mMusic = resman->getMusic(paths.getStringValue("music") + fileName);
192
193 if (mMusic)
194 mMusic->play(-1, ms);
195}
196
198{
199 mCurrentMusicFile.clear();
200
201 if (!mInstalled)
202 return;
203
204 Log::info("Sound::fadeOutMusic() Fading-out (%i ms)", ms);
205
206 if (mMusic)
207 {
208 Mix_FadeOutMusic(ms);
209 // Note: The musicFinishedCallBack will take care about freeing
210 // the music file at fade out ending.
211 }
212 else
213 {
214 sMusicFinished = true;
215 }
216}
217
218void Sound::fadeOutAndPlayMusic(const std::string &fileName, int ms)
219{
220 mNextMusicFile = fileName;
221 fadeOutMusic(ms);
222}
223
225{
226 if (sMusicFinished)
227 {
228 sMusicFinished = false;
229 mMusic = nullptr;
230
231 if (!mNextMusicFile.empty())
232 {
234 mNextMusicFile.clear();
235 }
236 }
237
238 for (int i = 0; i < CHANNEL_COUNT; i++)
239 {
240 if (sChannelFinished[i])
241 {
242 sChannelFinished[i] = false;
243 mSounds[i] = nullptr;
244 }
245 }
246}
247
248void Sound::playSfx(const std::string &path, int x, int y)
249{
250 if (!mInstalled || path.empty())
251 return;
252
253 std::string tmpPath;
254 if (!path.compare(0, 4, "sfx/"))
255 tmpPath = path;
256 else
257 tmpPath = paths.getValue("sfx", "sfx/") + path;
258
260
261 if (ResourceRef<SoundEffect> sound = resman->getSoundEffect(tmpPath))
262 {
263 Log::info("Sound::playSfx() Playing: %s", path.c_str());
264 int vol = 120;
265
266 if (local_player && (x > 0 || y > 0))
267 {
268 const Vector &pos = local_player->getPosition();
269 const int dx = std::abs((int) pos.x - x);
270 const int dy = std::abs((int) pos.y - y);
271 const int dist = std::max(dx, dy);
272
273 // Volume goes down one level with each 4 pixels
274 vol -= std::min(120, dist / 4);
275 }
276
277 int channel = sound->play(0, vol);
278 if (channel != -1)
279 mSounds[channel] = sound;
280 }
281}
282
283void Sound::playNotification(const std::string &path)
284{
285 const std::string fullPath = paths.getValue("sfx", "sfx/") + path;
286
288 if (ResourceRef<SoundEffect> sound = resman->getSoundEffect(fullPath))
289 {
290 int channel = sound->play(0, MIX_MAX_VOLUME, CHANNEL_NOTIFICATIONS);
291 if (channel != -1)
292 mSounds[channel] = sound;
293 }
294}
295
297{
298 if (!mInstalled)
299 return;
300
301 haltMusic();
302 Log::info("Sound::close() Shutting down sound...");
303 Mix_CloseAudio();
304
305 mInstalled = false;
306}
307
309{
310 if (!mMusic)
311 return;
312
313 Mix_HaltMusic();
314 mMusic = nullptr;
315}
const Vector & getPosition() const
Returns the pixel position of this actor.
Definition actor.h:53
std::string getValue(const std::string &key, const std::string &deflt) const
Gets a value as string.
std::string getStringValue(const std::string &key) const
bool play(int loops=-1, int fadeIn=0)
Plays the music.
Definition music.cpp:47
A class for loading and managing resources.
static ResourceManager * getInstance()
Returns an instance of the class, creating one if it does not already exist.
ResourceRef< Music > getMusic(const std::string &path)
Loads the Music resource found at the given path.
ResourceRef< SoundEffect > getSoundEffect(const std::string &path)
Loads the SoundEffect resource found at the given path.
Automatically counting Resource reference.
Definition resource.h:74
void fadeOutAndPlayMusic(const std::string &fileName, int ms=1000)
Fades out a background music and play a new one.
Definition sound.cpp:218
~Sound()
Definition sound.cpp:55
void playMusic(const std::string &fileName)
Starts background music.
Definition sound.cpp:166
void fadeOutMusic(int ms=1000)
Fades out currently running background music track.
Definition sound.cpp:197
void init()
Installs the sound engine.
Definition sound.cpp:61
void fadeInMusic(const std::string &fileName, int ms=1000)
Fades in background music.
Definition sound.cpp:181
void setMusicVolume(int volume)
Definition sound.cpp:139
void info()
Logs various info about sound device.
Definition sound.cpp:100
Sound()
Definition sound.cpp:49
bool mInstalled
Definition sound.h:139
@ CHANNEL_NOTIFICATIONS
Definition sound.h:120
@ CHANNEL_COUNT
Definition sound.h:123
@ CHANNEL_RESERVED_COUNT
Definition sound.h:121
void haltMusic()
Halts and frees currently playing music.
Definition sound.cpp:308
void logic()
The sound logic.
Definition sound.cpp:224
int mNotificationsVolume
Definition sound.h:142
void stopMusic()
Stops currently running background music track.
Definition sound.cpp:171
void close()
Removes all sound functionalities.
Definition sound.cpp:296
void setSfxVolume(int volume)
Definition sound.cpp:147
std::string mCurrentMusicFile
Definition sound.h:145
void setNotificationsVolume(int volume)
Definition sound.cpp:158
void playSfx(const std::string &path, int x=0, int y=0)
Plays a sound at the specified location.
Definition sound.cpp:248
ResourceRef< Music > mMusic
Definition sound.h:146
void playNotification(const std::string &path)
Plays a sound on the notification channel.
Definition sound.cpp:283
int mMusicVolume
Definition sound.h:143
ResourceRef< SoundEffect > mSounds[CHANNEL_COUNT]
Definition sound.h:147
int mSfxVolume
Definition sound.h:141
std::string mNextMusicFile
When calling fadeOutAndPlayMusic(), the music file below will then be played.
Definition sound.h:137
Vector class.
Definition vector.h:33
float y
Definition vector.h:172
float x
Definition vector.h:171
Configuration paths
XML default paths information reader.
Definition client.cpp:99
LocalPlayer * local_player
void info(const char *log_text,...) LOG_PRINTF_ATTR
Sound sound
Definition client.cpp:109