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