1 /* GemRB - Infinity Engine Emulator
2 * Copyright (C) 2003 The GemRB Project
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 *
18 *
19 */
20
21 #include "SDLAudio.h"
22
23 #include "AmbientMgr.h"
24 #include "GameData.h"
25 #include "Interface.h" // GetMusicMgr()
26 #include "MusicMgr.h"
27 #include "SoundMgr.h"
28
29 #include <SDL.h>
30 #include <SDL_mixer.h>
31 #include <cmath>
32
33 using namespace GemRB;
34
SetChannelPosition(int listenerXPos,int listenerYPos,int XPos,int YPos,int channel)35 static void SetChannelPosition(int listenerXPos, int listenerYPos, int XPos, int YPos, int channel)
36 {
37 int x = listenerXPos - XPos;
38 int y = listenerYPos - YPos;
39 int16_t angle = atan2(y, x) * 180 / M_PI - 90;
40 if (angle < 0) {
41 angle += 360;
42 }
43 uint8_t distance = std::min(static_cast<int32_t>(sqrt(x * x + y * y) / AUDIO_DISTANCE_ROLLOFF_MOD), 255);
44 Mix_SetPosition(channel, angle, distance);
45 }
46
SetPos(int XPos,int YPos)47 void SDLAudioSoundHandle::SetPos(int XPos, int YPos)
48 {
49 if (sndRelative)
50 return;
51
52 int listenerXPos = 0;
53 int listenerYPos = 0;
54 core->GetAudioDrv()->GetListenerPos(listenerXPos, listenerYPos);
55 SetChannelPosition(listenerXPos, listenerYPos, XPos, YPos, chunkChannel);
56 }
57
Playing()58 bool SDLAudioSoundHandle::Playing()
59 {
60 return (mixChunk && Mix_Playing(chunkChannel) && Mix_GetChunk(chunkChannel) == mixChunk);
61 }
62
Stop()63 void SDLAudioSoundHandle::Stop()
64 {
65 // Mix_FadeOutChannel is not as agressive sounding (especially when stopping spellcasting) as Mix_HaltChannel
66 Mix_FadeOutChannel(chunkChannel, 500);
67 }
68
StopLooping()69 void SDLAudioSoundHandle::StopLooping()
70 {
71 // No way to stop looping. Fading out instead..
72 Mix_FadeOutChannel(chunkChannel, 1000);
73 }
74
SDLAudio(void)75 SDLAudio::SDLAudio(void)
76 {
77 ambim = new AmbientMgr();
78 MusicPlaying = false;
79 curr_buffer_offset = 0;
80 audio_rate = audio_format = audio_channels = 0;
81 }
82
~SDLAudio(void)83 SDLAudio::~SDLAudio(void)
84 {
85 // TODO
86 Mix_HaltChannel(-1);
87 clearBufferCache();
88 delete ambim;
89 Mix_HookMusic(NULL, NULL);
90 FreeBuffers();
91 Mix_ChannelFinished(NULL);
92 }
93
Init(void)94 bool SDLAudio::Init(void)
95 {
96 // TODO: we assume SDLVideo already got loaded
97 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) {
98 return false;
99 }
100 #ifdef RPI
101 if (Mix_OpenAudio(22050, MIX_DEFAULT_FORMAT, 2, 512) < 0) {
102 #else
103 if (Mix_OpenAudio(22050, MIX_DEFAULT_FORMAT, 2, 8192) < 0) {
104 #endif
105 return false;
106 }
107
108 int result = Mix_AllocateChannels(MIXER_CHANNELS);
109 if (result < 0) {
110 Log(ERROR, "SDLAudio", "Unable to allocate mixing channels: %s\n", SDL_GetError());
111 return false;
112 }
113
114 Mix_QuerySpec(&audio_rate, (Uint16 *)&audio_format, &audio_channels);
115
116 Mix_ReserveChannels(1); // for speech
117 return true;
118 }
119
120 void SDLAudio::SetAudioStreamVolume(uint8_t *stream, int len, int volume)
121 {
122 // since it's at max volume by default
123 if (volume == MIX_MAX_VOLUME)
124 return;
125 uint8_t *mixData = new uint8_t[len];
126 memcpy(mixData, stream, len * sizeof(uint8_t));
127 memset(stream, 0, len); // mix audio data against silence
128 SDL_MixAudio(stream, mixData, len, volume);
129 delete[] mixData;
130 }
131
132 void SDLAudio::music_callback(void *udata, uint8_t *stream, int len)
133 {
134 ieDword volume = 100;
135 core->GetDictionary()->Lookup("Volume Music", volume);
136
137 // No point of bothering if it's off anyway
138 if (volume == 0) {
139 return;
140 }
141
142 uint8_t *mixerStream = stream;
143 int mixerLen = len;
144
145 SDLAudio *driver = (SDLAudio *)udata;
146
147 do {
148 std::lock_guard<std::recursive_mutex> l(driver->MusicMutex);
149
150 int num_samples = len / 2;
151 int cnt = driver->MusicReader->read_samples(( short* ) stream, num_samples);
152
153 // Done?
154 if (cnt == num_samples)
155 break;
156
157 // TODO: this shouldn't be in the callback (see also the openal thread)
158 Log(MESSAGE, "SDLAudio", "Playing Next Music");
159 core->GetMusicMgr()->PlayNext();
160
161 stream = stream + (cnt * 2);
162 len = len - (cnt * 2);
163
164 if (!driver->MusicPlaying) {
165 Log(MESSAGE, "SDLAudio", "No Other Music to play");
166 memset(stream, 0, len);
167 Mix_HookMusic(NULL, NULL);
168 break;
169 }
170 } while(true);
171
172 SetAudioStreamVolume(mixerStream, mixerLen, MIX_MAX_VOLUME * volume / 100);
173 }
174
175 bool SDLAudio::evictBuffer()
176 {
177 // Note: this function assumes the caller holds bufferMutex
178
179 // Room for optimization: this is O(n^2) in the number of buffers
180 // at the tail that are used. It can be O(n) if LRUCache supports it.
181 unsigned int n = 0;
182 void *p;
183 const char *k;
184 bool res;
185
186 while ((res = buffercache.getLRU(n, k, p)) == true && buffercache.GetCount() >= BUFFER_CACHE_SIZE) {
187 CacheEntry *e = (CacheEntry*)p;
188 bool chunkPlaying = false;
189 int numChannels = Mix_AllocateChannels(-1);
190
191 for (int i = 0; i < numChannels; ++i) {
192 if (Mix_Playing(i) && Mix_GetChunk(i) == e->chunk) {
193 chunkPlaying = true;
194 break;
195 }
196 }
197
198 if (chunkPlaying) {
199 ++n;
200 } else {
201 //Mix_FreeChunk(e->chunk) fails to free anything here
202 free(e->chunk->abuf);
203 free(e->chunk);
204 delete e;
205 buffercache.Remove(k);
206 }
207 }
208
209 return res;
210 }
211
212 void SDLAudio::clearBufferCache()
213 {
214 // Room for optimization: any method of iterating over the buffers
215 // would suffice. It doesn't have to be in LRU-order.
216 void *p;
217 const char *k;
218 int n = 0;
219 while (buffercache.getLRU(n, k, p)) {
220 CacheEntry *e = (CacheEntry*)p;
221 free(e->chunk->abuf);
222 free(e->chunk);
223 delete e;
224 buffercache.Remove(k);
225 }
226 }
227
228 Mix_Chunk* SDLAudio::loadSound(const char *ResRef, unsigned int &time_length)
229 {
230 Mix_Chunk *chunk = nullptr;
231 CacheEntry *e;
232 void *p;
233
234 if (!ResRef[0]) {
235 return chunk;
236 }
237
238 if (buffercache.Lookup(ResRef, p)) {
239 e = (CacheEntry*) p;
240 time_length = e->Length;
241 return e->chunk;
242 }
243
244 ResourceHolder<SoundMgr> acm = GetResourceHolder<SoundMgr>(ResRef);
245 if (!acm) {
246 print("failed acm load");
247 return chunk;
248 }
249 int cnt = acm->get_length();
250 int riff_chans = acm->get_channels();
251 int samplerate = acm->get_samplerate();
252 // Use 16-bit word for memory allocation because read_samples takes a 16 bit alignment
253 short *memory = (short*) malloc(cnt*2);
254 //multiply always with 2 because it is in 16 bits
255 int cnt1 = acm->read_samples( memory, cnt ) * 2;
256 //Sound Length in milliseconds
257 time_length = ((cnt / riff_chans) * 1000) / samplerate;
258
259 // convert our buffer, if necessary
260 SDL_AudioCVT cvt;
261 SDL_BuildAudioCVT(&cvt, AUDIO_S16SYS, riff_chans, samplerate,
262 audio_format, audio_channels, audio_rate);
263 cvt.buf = (Uint8*)malloc(cnt1*cvt.len_mult);
264 memcpy(cvt.buf, (char*)memory, cnt1);
265 cvt.len = cnt1;
266 SDL_ConvertAudio(&cvt);
267
268 // free old buffer
269 free(memory);
270
271 // make SDL_mixer chunk
272 chunk = Mix_QuickLoad_RAW(cvt.buf, cvt.len*cvt.len_ratio);
273 if (!chunk) {
274 print("error loading chunk");
275 free(cvt.buf);
276 return chunk;
277 }
278
279 e = new CacheEntry;
280 e->chunk = chunk;
281 e->Length = time_length;
282
283 if (buffercache.GetCount() >= BUFFER_CACHE_SIZE) {
284 evictBuffer();
285 }
286
287 buffercache.SetAt(ResRef, (void*)e);
288
289 return chunk;
290 }
291
292 Holder<SoundHandle> SDLAudio::Play(const char* ResRef, unsigned int channel,
293 int XPos, int YPos, unsigned int flags, unsigned int *length)
294 {
295 Mix_Chunk *chunk;
296 unsigned int time_length;
297
298 if (!ResRef) {
299 if (flags & GEM_SND_SPEECH) {
300 Mix_HaltChannel(0);
301 }
302 return Holder<SoundHandle>();
303 }
304
305 int chan = -1;
306 int loop = (flags & GEM_SND_LOOPING) ? -1 : 0;
307 ieDword volume = 100;
308
309 if (flags & GEM_SND_SPEECH) {
310 chan = 0;
311 loop = 0; // Speech ignores GEM_SND_LOOPING
312 core->GetDictionary()->Lookup("Volume Voices", volume);
313 } else {
314 core->GetDictionary()->Lookup("Volume SFX", volume);
315 }
316
317 if (volume == 0) {
318 return Holder<SoundHandle>();
319 }
320
321 chunk = loadSound(ResRef, time_length);
322 if (chunk == nullptr) {
323 return Holder<SoundHandle>();
324 }
325
326 if (length) {
327 *length = time_length;
328 }
329
330 Mix_VolumeChunk(chunk, MIX_MAX_VOLUME * (GetVolume(channel) * volume / 10000.0f));
331
332 chan = Mix_PlayChannel(chan, chunk, loop);
333 if (chan < 0) {
334 print("error playing channel");
335 return Holder<SoundHandle>();
336 }
337
338 if (!(flags & GEM_SND_RELATIVE)) {
339 SetChannelPosition(listenerPos.x, listenerPos.y, XPos, YPos, chan);
340 }
341
342 return new SDLAudioSoundHandle(chunk, chan, flags & GEM_SND_RELATIVE);
343 }
344
345 int SDLAudio::CreateStream(Holder<SoundMgr> newMusic)
346 {
347 std::lock_guard<std::recursive_mutex> l(MusicMutex);
348
349 print("SDLAudio setting new music");
350 MusicReader = newMusic;
351
352 return 0;
353 }
354
355 bool SDLAudio::Stop()
356 {
357 MusicPlaying = false;
358 Mix_HookMusic(NULL, NULL);
359 return true;
360 }
361
362 bool SDLAudio::Play()
363 {
364 std::lock_guard<std::recursive_mutex> l(MusicMutex);
365
366 if (!MusicReader) {
367 return false;
368 }
369 MusicPlaying = true;
370 Mix_HookMusic((void (*)(void*, Uint8*, int))music_callback, this);
371 return true;
372 }
373
374 void SDLAudio::ResetMusics()
375 {
376 MusicPlaying = false;
377 Mix_HookMusic(NULL, NULL);
378 }
379
380 bool SDLAudio::CanPlay()
381 {
382 return true;
383 }
384
385 void SDLAudio::UpdateListenerPos(int x, int y)
386 {
387 listenerPos.x = x;
388 listenerPos.y = y;
389 }
390
391 void SDLAudio::GetListenerPos(int& x, int& y)
392 {
393 x = listenerPos.x;
394 y = listenerPos.y;
395 }
396
397 void SDLAudio::buffer_callback(void *udata, uint8_t *stream, int len)
398 {
399 ieDword volume = 100;
400 // Check only movie volume, since ambiens aren't supported right now
401 core->GetDictionary()->Lookup("Volume Movie", volume);
402
403 // No point of bothering if it's off anyway
404 if (volume == 0) {
405 return;
406 }
407
408 uint8_t *mixerStream = stream;
409 int mixerLen = len;
410
411 SDLAudio *driver = (SDLAudio *)udata;
412 unsigned int remaining = len;
413
414 while (remaining && !driver->buffers.empty()) {
415 std::lock_guard<std::recursive_mutex> l(driver->MusicMutex);
416
417 unsigned int avail = driver->buffers[0].size - driver->curr_buffer_offset;
418 if (avail > remaining) {
419 // more data available in this buffer than we need
420 avail = remaining;
421 memcpy(stream, driver->buffers[0].buf + driver->curr_buffer_offset, avail);
422 driver->curr_buffer_offset += avail;
423 } else {
424 // exhausted this buffer, move to the next one
425 memcpy(stream, driver->buffers[0].buf + driver->curr_buffer_offset, avail);
426 driver->curr_buffer_offset = 0;
427 free(driver->buffers[0].buf);
428 // TODO: inefficient
429 driver->buffers.erase(driver->buffers.begin());
430 }
431 remaining -= avail;
432 stream = stream + avail;
433 }
434
435 if (remaining > 0) {
436 // underrun (out of buffers)
437 memset(stream, 0, remaining);
438 }
439 SetAudioStreamVolume(mixerStream, mixerLen, MIX_MAX_VOLUME * volume / 100);
440 }
441
442 int SDLAudio::SetupNewStream(ieWord x, ieWord y, ieWord z,
443 ieWord gain, bool point, int ambientRange)
444 {
445 std::lock_guard<std::recursive_mutex> l(MusicMutex);
446
447 if (ambientRange) {
448 // TODO: ambient sounds
449 return -1;
450 }
451
452 // TODO: maybe don't ignore these
453 (void)x;
454 (void)y;
455 (void)z;
456 (void)gain;
457 (void)point;
458
459 print("SDLAudio allocating stream");
460
461 // TODO: buggy
462 MusicPlaying = false;
463 curr_buffer_offset = 0;
464 Mix_HookMusic((void (*)(void*, Uint8*, int))buffer_callback, this);
465 return 0;
466 }
467
468 int SDLAudio::QueueAmbient(int, const char*)
469 {
470 // TODO: ambient sounds
471 return -1;
472 }
473
474 bool SDLAudio::ReleaseStream(int stream, bool HardStop)
475 {
476 if (stream != 0) {
477 return false;
478 }
479
480 print("SDLAudio releasing stream");
481
482 (void)HardStop;
483
484 assert(!MusicPlaying);
485
486 Mix_HookMusic(NULL, NULL);
487 FreeBuffers();
488
489 return true;
490 }
491
492 void SDLAudio::FreeBuffers()
493 {
494 std::lock_guard<std::recursive_mutex> l(MusicMutex);
495 for (unsigned int i = 0; i < buffers.size(); i++) {
496 free(buffers[i].buf);
497 }
498 buffers.clear();
499 }
500
501 void SDLAudio::SetAmbientStreamVolume(int, int)
502 {
503 // TODO: ambient sounds
504 }
505
506 void SDLAudio::SetAmbientStreamPitch(int, int)
507 {
508 // TODO: ambient sounds
509 }
510
511 void SDLAudio::QueueBuffer(int stream, unsigned short bits,
512 int channels, short* memory, int size, int samplerate)
513 {
514 if (stream != 0) {
515 return;
516 }
517
518 assert(!MusicPlaying);
519
520 BufferedData d;
521
522 // convert our buffer, if necessary
523 if (bits != 16 || channels != audio_channels || samplerate != audio_rate) {
524 SDL_AudioCVT cvt;
525 if (SDL_BuildAudioCVT(&cvt, (bits == 8 ? AUDIO_S8 : AUDIO_S16SYS), channels, samplerate,
526 audio_format, audio_channels, audio_rate) == 0) {
527 Log(ERROR, "SDLAudio", "Couldn't convert video stream! trying to convert %d bits, %d channels, %d rate",
528 bits, channels, samplerate);
529 return;
530 }
531 cvt.buf = (Uint8*)malloc(size*cvt.len_mult);
532 memcpy(cvt.buf, memory, size);
533 cvt.len = size;
534 SDL_ConvertAudio(&cvt);
535
536 d.size = cvt.len*cvt.len_ratio;
537 d.buf = (char *)cvt.buf;
538 } else {
539 d.size = size;
540 d.buf = (char *)malloc(d.size);
541 memcpy(d.buf, memory, d.size);
542 }
543
544 MusicMutex.lock();
545 buffers.push_back(d);
546 MusicMutex.unlock();
547 }
548
549 #include "plugindef.h"
550
551 GEMRB_PLUGIN(0x52C524E, "SDL Audio Driver")
552 PLUGIN_DRIVER(SDLAudio, "SDLAudio")
553 END_PLUGIN()
554