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