1 #include "core/calc.h"
2 #include "core/config.h"
3 #include "core/file.h"
4 #include "core/log.h"
5 #include "sound/device.h"
6 #include "game/settings.h"
7 #include "platform/platform.h"
8 #include "platform/vita/vita.h"
9
10 #include "SDL.h"
11 #include "SDL_mixer.h"
12
13 #include <stdlib.h>
14 #include <string.h>
15
16 #ifdef __vita__
17 #include <psp2/io/fcntl.h>
18 #endif
19
20 #define AUDIO_RATE 22050
21 #define AUDIO_FORMAT AUDIO_S16
22 #define AUDIO_CHANNELS 2
23 #define AUDIO_BUFFERS 1024
24
25 #define MAX_CHANNELS 160
26
27 #if SDL_VERSION_ATLEAST(2, 0, 7)
28 #define USE_SDL_AUDIOSTREAM
29 #endif
30 #define HAS_AUDIOSTREAM() (platform_sdl_version_at_least(2, 0, 7))
31
32 #ifdef __vita__
33 static struct {
34 char filename[FILE_NAME_MAX];
35 char *buffer;
36 int size;
37 } vita_music_data;
38 #endif
39
40 typedef struct {
41 const char *filename;
42 Mix_Chunk *chunk;
43 } sound_channel;
44
45 static struct {
46 int initialized;
47 Mix_Music *music;
48 sound_channel channels[MAX_CHANNELS];
49 } data;
50
51 static struct {
52 SDL_AudioFormat format;
53 SDL_AudioFormat dst_format;
54 #ifdef USE_SDL_AUDIOSTREAM
55 SDL_AudioStream *stream;
56 int use_audiostream;
57 #endif
58 SDL_AudioCVT cvt;
59 unsigned char *buffer;
60 int buffer_size;
61 int cur_read;
62 int cur_write;
63 } custom_music;
64
percentage_to_volume(int percentage)65 static int percentage_to_volume(int percentage)
66 {
67 int master_percentage = config_get(CONFIG_GENERAL_MASTER_VOLUME);
68 return calc_adjust_with_percentage(percentage, master_percentage) * SDL_MIX_MAXVOLUME / 100;
69 }
70
init_channels(void)71 static void init_channels(void)
72 {
73 data.initialized = 1;
74 for (int i = 0; i < MAX_CHANNELS; i++) {
75 data.channels[i].chunk = 0;
76 }
77 }
78
sound_device_open(void)79 void sound_device_open(void)
80 {
81 #ifdef USE_SDL_AUDIOSTREAM
82 custom_music.use_audiostream = HAS_AUDIOSTREAM();
83 #endif
84 if (0 == Mix_OpenAudio(AUDIO_RATE, AUDIO_FORMAT, AUDIO_CHANNELS, AUDIO_BUFFERS)) {
85 init_channels();
86 return;
87 }
88 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Sound failed to initialize using default driver: %s", Mix_GetError());
89 // Try to work around SDL choosing the wrong driver on Windows sometimes
90 for (int i = 0; i < SDL_GetNumAudioDrivers(); i++) {
91 const char *driver_name = SDL_GetAudioDriver(i);
92 if (SDL_strcmp(driver_name, "disk") == 0 || SDL_strcmp(driver_name, "dummy") == 0) {
93 // Skip "write-to-disk" and dummy drivers
94 continue;
95 }
96 if (0 == SDL_AudioInit(driver_name) &&
97 0 == Mix_OpenAudio(AUDIO_RATE, AUDIO_FORMAT, AUDIO_CHANNELS, AUDIO_BUFFERS)) {
98 SDL_Log("Using audio driver: %s", driver_name);
99 init_channels();
100 return;
101 } else {
102 SDL_Log("Not using audio driver %s, reason: %s", driver_name, SDL_GetError());
103 }
104 }
105 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Sound failed to initialize: %s", Mix_GetError());
106 int max = SDL_GetNumAudioDevices(0);
107 SDL_Log("Number of audio devices: %d", max);
108 for (int i = 0; i < max; i++) {
109 SDL_Log("Audio device: %s", SDL_GetAudioDeviceName(i, 0));
110 }
111 }
112
sound_device_close(void)113 void sound_device_close(void)
114 {
115 if (data.initialized) {
116 for (int i = 0; i < MAX_CHANNELS; i++) {
117 sound_device_stop_channel(i);
118 }
119 Mix_CloseAudio();
120 data.initialized = 0;
121 }
122 }
123
load_chunk(const char * filename)124 static Mix_Chunk *load_chunk(const char *filename)
125 {
126 if (filename[0]) {
127 #if defined(__vita__) || defined(__ANDROID__)
128 FILE *fp = file_open(filename, "rb");
129 if (!fp) {
130 return NULL;
131 }
132 SDL_RWops *sdl_fp = SDL_RWFromFP(fp, SDL_TRUE);
133 return Mix_LoadWAV_RW(sdl_fp, 1);
134 #else
135 return Mix_LoadWAV(filename);
136 #endif
137 } else {
138 return NULL;
139 }
140 }
141
load_channel(sound_channel * channel)142 static int load_channel(sound_channel *channel)
143 {
144 if (!channel->chunk && channel->filename) {
145 channel->chunk = load_chunk(channel->filename);
146 }
147 return channel->chunk ? 1 : 0;
148 }
149
sound_device_init_channels(int num_channels,char filenames[][CHANNEL_FILENAME_MAX])150 void sound_device_init_channels(int num_channels, char filenames[][CHANNEL_FILENAME_MAX])
151 {
152 if (data.initialized) {
153 if (num_channels > MAX_CHANNELS) {
154 num_channels = MAX_CHANNELS;
155 }
156 Mix_AllocateChannels(num_channels);
157 log_info("Loading audio files", 0, 0);
158 for (int i = 0; i < num_channels; i++) {
159 data.channels[i].chunk = 0;
160 data.channels[i].filename = filenames[i][0] ? filenames[i] : 0;
161 }
162 }
163 }
164
sound_device_is_channel_playing(int channel)165 int sound_device_is_channel_playing(int channel)
166 {
167 return data.channels[channel].chunk && Mix_Playing(channel);
168 }
169
sound_device_set_music_volume(int volume_pct)170 void sound_device_set_music_volume(int volume_pct)
171 {
172 Mix_VolumeMusic(percentage_to_volume(volume_pct));
173 }
174
sound_device_set_channel_volume(int channel,int volume_pct)175 void sound_device_set_channel_volume(int channel, int volume_pct)
176 {
177 if (data.channels[channel].chunk) {
178 Mix_VolumeChunk(data.channels[channel].chunk, percentage_to_volume(volume_pct));
179 }
180 }
181
182 #ifdef __vita__
load_music_for_vita(const char * filename)183 static void load_music_for_vita(const char *filename)
184 {
185 if (vita_music_data.buffer) {
186 if (strcmp(filename, vita_music_data.filename) == 0) {
187 return;
188 }
189 free(vita_music_data.buffer);
190 vita_music_data.buffer = 0;
191 }
192 strncpy(vita_music_data.filename, filename, FILE_NAME_MAX - 1);
193 SceUID fd = sceIoOpen(vita_prepend_path(filename), SCE_O_RDONLY, 0777);
194 if (fd < 0) {
195 return;
196 }
197 vita_music_data.size = sceIoLseek(fd, 0, SCE_SEEK_END);
198 sceIoLseek(fd, 0, SCE_SEEK_SET);
199 vita_music_data.buffer = malloc(sizeof(char) * vita_music_data.size);
200 sceIoRead(fd, vita_music_data.buffer, vita_music_data.size);
201 sceIoClose(fd);
202 }
203 #endif
204
sound_device_play_music(const char * filename,int volume_pct)205 int sound_device_play_music(const char *filename, int volume_pct)
206 {
207 if (data.initialized && config_get(CONFIG_GENERAL_ENABLE_AUDIO)) {
208 sound_device_stop_music();
209 if (!filename) {
210 return 0;
211 }
212 #ifdef __vita__
213 load_music_for_vita(filename);
214 if (!vita_music_data.buffer) {
215 return 0;
216 }
217 SDL_RWops *sdl_music = SDL_RWFromMem(vita_music_data.buffer, vita_music_data.size);
218 data.music = Mix_LoadMUSType_RW(sdl_music, file_has_extension(filename, "mp3") ? MUS_MP3 : MUS_WAV, SDL_TRUE);
219 #elif defined(__ANDROID__)
220 FILE *fp = file_open(filename, "rb");
221 if (!fp) {
222 return 0;
223 }
224 SDL_RWops *sdl_fp = SDL_RWFromFP(fp, SDL_TRUE);
225 data.music = Mix_LoadMUSType_RW(sdl_fp, file_has_extension(filename, "mp3") ? MUS_MP3 : MUS_WAV, SDL_TRUE);
226 #else
227 data.music = Mix_LoadMUS(filename);
228 #endif
229 if (!data.music) {
230 SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
231 "Error opening music file '%s'. Reason: %s", filename, Mix_GetError());
232 } else {
233 if (Mix_PlayMusic(data.music, -1) == -1) {
234 data.music = 0;
235 SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
236 "Error playing music file '%s'. Reason: %s", filename, Mix_GetError());
237 } else {
238 sound_device_set_music_volume(volume_pct);
239 }
240 }
241 return data.music ? 1 : 0;
242 }
243 return 0;
244 }
245
sound_device_play_file_on_channel(const char * filename,int channel,int volume_pct)246 void sound_device_play_file_on_channel(const char *filename, int channel, int volume_pct)
247 {
248 if (data.initialized && config_get(CONFIG_GENERAL_ENABLE_AUDIO)) {
249 sound_device_stop_channel(channel);
250 data.channels[channel].chunk = load_chunk(filename);
251 if (data.channels[channel].chunk) {
252 sound_device_set_channel_volume(channel, volume_pct);
253 Mix_PlayChannel(channel, data.channels[channel].chunk, 0);
254 }
255 }
256 }
257
sound_device_play_channel(int channel,int volume_pct)258 void sound_device_play_channel(int channel, int volume_pct)
259 {
260 if (data.initialized && config_get(CONFIG_GENERAL_ENABLE_AUDIO)) {
261 sound_channel *ch = &data.channels[channel];
262 if (load_channel(ch)) {
263 sound_device_set_channel_volume(channel, volume_pct);
264 Mix_PlayChannel(channel, ch->chunk, 0);
265 }
266 }
267 }
268
sound_device_play_channel_panned(int channel,int volume_pct,int left_pct,int right_pct)269 void sound_device_play_channel_panned(int channel, int volume_pct, int left_pct, int right_pct)
270 {
271 if (data.initialized && config_get(CONFIG_GENERAL_ENABLE_AUDIO)) {
272 sound_channel *ch = &data.channels[channel];
273 if (load_channel(ch)) {
274 Mix_SetPanning(channel, left_pct * 255 / 100, right_pct * 255 / 100);
275 sound_device_set_channel_volume(channel, volume_pct);
276 Mix_PlayChannel(channel, ch->chunk, 0);
277 }
278 }
279 }
280
sound_device_stop_music(void)281 void sound_device_stop_music(void)
282 {
283 if (data.initialized) {
284 if (data.music) {
285 Mix_HaltMusic();
286 Mix_FreeMusic(data.music);
287 data.music = 0;
288 }
289 }
290 }
291
sound_device_stop_channel(int channel)292 void sound_device_stop_channel(int channel)
293 {
294 if (data.initialized) {
295 sound_channel *ch = &data.channels[channel];
296 if (ch->chunk) {
297 Mix_HaltChannel(channel);
298 Mix_FreeChunk(ch->chunk);
299 ch->chunk = 0;
300 }
301 }
302 }
303
free_custom_audio_stream(void)304 static void free_custom_audio_stream(void)
305 {
306 #ifdef USE_SDL_AUDIOSTREAM
307 if (custom_music.use_audiostream) {
308 if (custom_music.stream) {
309 SDL_FreeAudioStream(custom_music.stream);
310 custom_music.stream = 0;
311 }
312 return;
313 }
314 #endif
315
316 if (custom_music.buffer) {
317 free(custom_music.buffer);
318 custom_music.buffer = 0;
319 }
320 }
321
create_custom_audio_stream(SDL_AudioFormat src_format,Uint8 src_channels,int src_rate,SDL_AudioFormat dst_format,Uint8 dst_channels,int dst_rate)322 static int create_custom_audio_stream(SDL_AudioFormat src_format, Uint8 src_channels, int src_rate,
323 SDL_AudioFormat dst_format, Uint8 dst_channels, int dst_rate)
324 {
325 free_custom_audio_stream();
326
327 custom_music.dst_format = dst_format;
328
329 #ifdef USE_SDL_AUDIOSTREAM
330 if (custom_music.use_audiostream) {
331 custom_music.stream = SDL_NewAudioStream(
332 src_format, src_channels, src_rate,
333 dst_format, dst_channels, dst_rate
334 );
335 return custom_music.stream != 0;
336 }
337 #endif
338
339 int result = SDL_BuildAudioCVT(
340 &custom_music.cvt, src_format, src_channels, src_rate,
341 dst_format, dst_channels, dst_rate
342 );
343 if (result < 0) {
344 return 0;
345 }
346
347 // Allocate buffer large enough for 2 seconds of 16-bit audio
348 custom_music.buffer_size = dst_rate * dst_channels * 2 * 2;
349 custom_music.buffer = malloc(custom_music.buffer_size);
350 if (!custom_music.buffer) {
351 return 0;
352 }
353 custom_music.cur_read = 0;
354 custom_music.cur_write = 0;
355 return 1;
356 }
357
custom_audio_stream_active(void)358 static int custom_audio_stream_active(void)
359 {
360 #ifdef USE_SDL_AUDIOSTREAM
361 if (custom_music.use_audiostream) {
362 return custom_music.stream != 0;
363 }
364 #endif
365 return custom_music.buffer != 0;
366 }
367
put_custom_audio_stream(const Uint8 * audio_data,int len)368 static int put_custom_audio_stream(const Uint8 *audio_data, int len)
369 {
370 if (!audio_data || len <= 0 || !custom_audio_stream_active()) {
371 return 0;
372 }
373
374 #ifdef USE_SDL_AUDIOSTREAM
375 if (custom_music.use_audiostream) {
376 return SDL_AudioStreamPut(custom_music.stream, audio_data, len) == 0;
377 }
378 #endif
379
380 // Convert audio to SDL format
381 custom_music.cvt.buf = (Uint8 *) malloc((size_t) (len * custom_music.cvt.len_mult));
382 if (!custom_music.cvt.buf) {
383 return 0;
384 }
385 memcpy(custom_music.cvt.buf, audio_data, len);
386 custom_music.cvt.len = len;
387 SDL_ConvertAudio(&custom_music.cvt);
388 int converted_len = custom_music.cvt.len_cvt;
389
390 // Copy data to circular buffer
391 if (converted_len + custom_music.cur_write <= custom_music.buffer_size) {
392 memcpy(&custom_music.buffer[custom_music.cur_write], custom_music.cvt.buf, converted_len);
393 } else {
394 int end_len = custom_music.buffer_size - custom_music.cur_write;
395 memcpy(&custom_music.buffer[custom_music.cur_write], custom_music.cvt.buf, end_len);
396 memcpy(custom_music.buffer, &custom_music.cvt.buf[end_len], converted_len - end_len);
397 }
398 custom_music.cur_write = (custom_music.cur_write + converted_len) % custom_music.buffer_size;
399
400 // Clean up
401 free(custom_music.cvt.buf);
402 custom_music.cvt.buf = 0;
403 custom_music.cvt.len = 0;
404
405 return 1;
406 }
407
custom_music_callback(void * dummy,Uint8 * dst,int len)408 static void custom_music_callback(void *dummy, Uint8 *dst, int len)
409 {
410 // Write silence
411 memset(dst, 0, len);
412
413 int volume = config_get(CONFIG_GENERAL_ENABLE_AUDIO) && config_get(CONFIG_GENERAL_ENABLE_VIDEO_SOUND) ?
414 percentage_to_volume(config_get(CONFIG_GENERAL_VIDEO_VOLUME)) : 0;
415
416 if (!dst || len <= 0 || volume == 0 || !custom_audio_stream_active()) {
417 return;
418 }
419 int bytes_copied = 0;
420
421 // Mix audio to sound effect volume
422 Uint8 *mix_buffer = (Uint8 *) malloc(len);
423 if (!mix_buffer) {
424 return;
425 }
426 memset(mix_buffer, 0, len);
427
428 #ifdef USE_SDL_AUDIOSTREAM
429 if (custom_music.use_audiostream) {
430 bytes_copied = SDL_AudioStreamGet(custom_music.stream, mix_buffer, len);
431 if (bytes_copied <= 0) {
432 return;
433 }
434 } else {
435 #endif
436 if (custom_music.cur_read < custom_music.cur_write) {
437 int bytes_available = custom_music.cur_write - custom_music.cur_read;
438 int bytes_to_copy = bytes_available < len ? bytes_available : len;
439 memcpy(mix_buffer, &custom_music.buffer[custom_music.cur_read], bytes_to_copy);
440 bytes_copied = bytes_to_copy;
441 } else {
442 int bytes_available = custom_music.buffer_size - custom_music.cur_read;
443 int bytes_to_copy = bytes_available < len ? bytes_available : len;
444 memcpy(mix_buffer, &custom_music.buffer[custom_music.cur_read], bytes_to_copy);
445 bytes_copied = bytes_to_copy;
446 if (bytes_copied < len) {
447 int second_part_len = len - bytes_copied;
448 bytes_available = custom_music.cur_write;
449 bytes_to_copy = bytes_available < second_part_len ? bytes_available : second_part_len;
450 memcpy(&mix_buffer[bytes_copied], custom_music.buffer, bytes_to_copy);
451 bytes_copied += bytes_to_copy;
452 }
453 }
454 custom_music.cur_read = (custom_music.cur_read + bytes_copied) % custom_music.buffer_size;
455 #ifdef USE_SDL_AUDIOSTREAM
456 }
457 #endif
458
459 SDL_MixAudioFormat(dst, mix_buffer, custom_music.dst_format, bytes_copied, volume);
460 free(mix_buffer);
461 }
462
sound_device_use_custom_music_player(int bitdepth,int num_channels,int rate,const unsigned char * audio_data,int len)463 void sound_device_use_custom_music_player(int bitdepth, int num_channels, int rate,
464 const unsigned char *audio_data, int len)
465 {
466 SDL_AudioFormat format;
467 if (bitdepth == 8) {
468 format = AUDIO_U8;
469 } else if (bitdepth == 16) {
470 format = AUDIO_S16;
471 } else {
472 log_error("Custom music bitdepth not supported:", 0, bitdepth);
473 return;
474 }
475 int device_rate;
476 Uint16 device_format;
477 int device_channels;
478 Mix_QuerySpec(&device_rate, &device_format, &device_channels);
479 custom_music.format = format;
480
481 int result = create_custom_audio_stream(
482 format, num_channels, rate,
483 device_format, device_channels, device_rate
484 );
485 if (!result) {
486 return;
487 }
488
489 sound_device_write_custom_music_data(audio_data, len);
490
491 Mix_HookMusic(custom_music_callback, 0);
492 }
493
sound_device_write_custom_music_data(const unsigned char * audio_data,int len)494 void sound_device_write_custom_music_data(const unsigned char *audio_data, int len)
495 {
496 if (!audio_data || len <= 0 || !custom_audio_stream_active()) {
497 return;
498 }
499 put_custom_audio_stream(audio_data, len);
500 }
501
sound_device_use_default_music_player(void)502 void sound_device_use_default_music_player(void)
503 {
504 Mix_HookMusic(0, 0);
505 free_custom_audio_stream();
506 }
507