gs_audio_impl.h 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591
  1. /*================================================================
  2. * Copyright: 2020 John Jackson
  3. * File: gs_audio_impl.h
  4. All Rights Reserved
  5. =================================================================*/
  6. #ifndef __GS_AUDIO_IMPL_H__
  7. #define __GS_AUDIO_IMPL_H__
  8. // Define default platform implementation if certain platforms are enabled
  9. #if (defined GS_AUDIO_IMPL_MINIAUDIO)
  10. #define GS_AUDIO_IMPL_DEFAULT
  11. #endif
  12. /*=============================
  13. // Default Impl
  14. =============================*/
  15. #ifdef GS_AUDIO_IMPL_DEFAULT
  16. // Includes
  17. #include "../external/stb/stb_vorbis.c"
  18. #include "../external/dr_libs/dr_wav.h"
  19. #include "../external/dr_libs/dr_mp3.h"
  20. /* Audio Create, Destroy, Init, Shutdown, Submit */
  21. gs_audio_i* gs_audio_create()
  22. {
  23. // Construct new audio interface
  24. gs_audio_i* audio = gs_malloc_init(gs_audio_i);
  25. /* Audio source data cache */
  26. audio->sources = gs_slot_array_new(gs_audio_source_t);
  27. /* Audio instance data cache */
  28. audio->instances = gs_slot_array_new(gs_audio_instance_t);
  29. /* Max global volume setting */
  30. audio->max_audio_volume = 1.f;
  31. /* Min global volume setting */
  32. audio->min_audio_volume = 0.f;
  33. /* Set user data to null */
  34. audio->user_data = NULL;
  35. return audio;
  36. }
  37. void gs_audio_destroy(gs_audio_i* audio)
  38. {
  39. // Release all relevant memory
  40. if (audio)
  41. {
  42. gs_slot_array_free(audio->sources);
  43. gs_slot_array_free(audio->instances);
  44. gs_free(audio);
  45. audio = NULL;
  46. }
  47. }
  48. /* Resource Loading */
  49. bool32_t gs_audio_load_ogg_data_from_file
  50. (
  51. const char* file_path,
  52. int32_t* sample_count,
  53. int32_t* channels,
  54. int32_t* sample_rate,
  55. void** samples
  56. )
  57. {
  58. *sample_count = stb_vorbis_decode_filename(file_path, channels,
  59. sample_rate, (s16**)samples);
  60. if (!*samples || *sample_count == -1)
  61. {
  62. *samples = NULL;
  63. gs_println("WARNING: Could not load .ogg file: %s", file_path);
  64. return false;
  65. }
  66. *sample_count *= *channels;
  67. return true;
  68. }
  69. bool32_t gs_audio_load_wav_data_from_file
  70. (
  71. const char* file_path,
  72. int32_t* sample_count,
  73. int32_t* channels,
  74. int32_t* sample_rate,
  75. void** samples
  76. )
  77. {
  78. uint64_t total_pcm_frame_count = 0;
  79. *samples = drwav_open_file_and_read_pcm_frames_s16(
  80. file_path, (uint32_t*)channels, (uint32_t*)sample_rate,
  81. &total_pcm_frame_count, NULL);
  82. if (!*samples) {
  83. *samples = NULL;
  84. gs_println("WARNING: Could not load .ogg file: %s", file_path);
  85. return false;
  86. }
  87. *sample_count = total_pcm_frame_count * *channels;
  88. return true;
  89. }
  90. bool32_t gs_audio_load_mp3_data_from_file
  91. (
  92. const char* file_path,
  93. int32_t* sample_count,
  94. int32_t* channels,
  95. int32_t* sample_rate,
  96. void** samples
  97. )
  98. {
  99. // Decode entire mp3
  100. uint64_t total_pcm_frame_count = 0;
  101. drmp3_config cfg = gs_default_val();
  102. *samples = drmp3_open_file_and_read_pcm_frames_s16(
  103. file_path, &cfg, &total_pcm_frame_count, NULL);
  104. if (!*samples) {
  105. *samples = NULL;
  106. gs_println("WARNING: Could not load .ogg file: %s", file_path);
  107. return false;
  108. }
  109. *channels = cfg.channels;
  110. *sample_rate = cfg.sampleRate;
  111. *sample_count = total_pcm_frame_count * *channels;
  112. return true;
  113. }
  114. /* Audio create source */
  115. gs_handle(gs_audio_source_t) gs_audio_load_from_file(const char* file_path)
  116. {
  117. gs_audio_i* audio = gs_engine_subsystem(audio);
  118. gs_audio_source_t src = gs_default_val();
  119. gs_handle(gs_audio_source_t) handle = gs_handle_invalid(gs_audio_source_t);
  120. bool32_t load_successful = false;
  121. if(!gs_platform_file_exists(file_path))
  122. {
  123. gs_println("WARNING: Could not open file: %s", file_path);
  124. return handle;
  125. }
  126. char ext[64] = gs_default_val();
  127. gs_util_str_to_lower(file_path, ext, sizeof(ext));
  128. gs_platform_file_extension(ext, sizeof(ext), ext);
  129. // Load OGG data
  130. if (gs_string_compare_equal(ext, "ogg"))
  131. {
  132. load_successful = gs_audio_load_ogg_data_from_file (
  133. file_path,
  134. &src.sample_count,
  135. &src.channels,
  136. &src.sample_rate,
  137. &src.samples
  138. );
  139. }
  140. // Load WAV data
  141. if (gs_string_compare_equal(ext, "wav"))
  142. {
  143. load_successful = gs_audio_load_wav_data_from_file (
  144. file_path,
  145. &src.sample_count,
  146. &src.channels,
  147. &src.sample_rate,
  148. &src.samples
  149. );
  150. }
  151. if (gs_string_compare_equal(ext, "mp3"))
  152. {
  153. load_successful = gs_audio_load_mp3_data_from_file (
  154. file_path,
  155. &src.sample_count,
  156. &src.channels,
  157. &src.sample_rate,
  158. &src.samples
  159. );
  160. }
  161. // Load raw source into memory and return handle id
  162. if (load_successful)
  163. {
  164. gs_println("SUCCESS: Audio source loaded: %s", file_path);
  165. // Add to resource cache
  166. handle.id = gs_slot_array_insert(audio->sources, src);
  167. }
  168. else
  169. {
  170. gs_println("WARNING: Could not load audio source data: %s", file_path);
  171. }
  172. return handle;
  173. }
  174. /* Audio create instance */
  175. gs_handle(gs_audio_instance_t) gs_audio_instance_create(gs_audio_instance_decl_t* decl)
  176. {
  177. gs_audio_i* audio = gs_engine_subsystem(audio);
  178. return gs_handle_create(gs_audio_instance_t, gs_slot_array_insert(audio->instances, *decl));
  179. }
  180. /* Audio play instance data */
  181. void gs_audio_play_source(gs_handle(gs_audio_source_t) src, float volume)
  182. {
  183. // Construct instance data from source and play
  184. gs_audio_i* audio = gs_engine_subsystem(audio);
  185. gs_audio_instance_decl_t decl = gs_default_val();
  186. decl.volume = gs_clamp(volume, audio->min_audio_volume, audio->max_audio_volume);
  187. decl.persistent = false;
  188. gs_handle(gs_audio_instance_t) inst = gs_audio_instance_create(&decl);
  189. gs_audio_play(inst);
  190. }
  191. // Helper macros
  192. #define __gs_audio_inst_valid(INST)\
  193. gs_slot_array_handle_valid(gs_engine_subsystem(audio)->instances, INST.id)
  194. #define __gs_audio_src_valid(SRC)\
  195. gs_slot_array_handle_valid(gs_engine_subsystem(audio)->sources, SRC.id)
  196. void gs_audio_play(gs_handle(gs_audio_instance_t) inst)
  197. {
  198. if (__gs_audio_inst_valid(inst)) {
  199. gs_slot_array_getp(gs_engine_subsystem(audio)->instances, inst.id)->playing = true;
  200. }
  201. }
  202. void gs_audio_pause(gs_handle(gs_audio_instance_t) inst)
  203. {
  204. if (__gs_audio_inst_valid(inst)) {
  205. gs_slot_array_getp(gs_engine_subsystem(audio)->instances, inst.id)->playing = false;
  206. }
  207. }
  208. void gs_audio_stop(gs_handle(gs_audio_instance_t) inst)
  209. {
  210. if (__gs_audio_inst_valid(inst)) {
  211. gs_audio_instance_t* ip = gs_slot_array_getp(gs_engine_subsystem(audio)->instances, inst.id);
  212. ip->playing = false;
  213. ip->sample_position = 0;
  214. }
  215. }
  216. void gs_audio_restart(gs_handle(gs_audio_instance_t) inst)
  217. {
  218. if (__gs_audio_inst_valid(inst)) {
  219. gs_slot_array_getp(gs_engine_subsystem(audio)->instances, inst.id)->sample_position = 0;
  220. }
  221. }
  222. bool32_t gs_audio_is_playing(gs_handle(gs_audio_instance_t) inst)
  223. {
  224. if (__gs_audio_inst_valid(inst)) {
  225. return (gs_slot_array_getp(gs_engine_subsystem(audio)->instances, inst.id)->playing);
  226. }
  227. return false;
  228. }
  229. /* Audio instance data */
  230. void gs_audio_set_instance_data(gs_handle(gs_audio_instance_t) inst, gs_audio_instance_decl_t decl)
  231. {
  232. if (__gs_audio_inst_valid(inst)) {
  233. *gs_slot_array_getp(gs_engine_subsystem(audio)->instances, inst.id) = decl;
  234. }
  235. }
  236. gs_audio_instance_decl_t gs_audio_get_instance_data(gs_handle(gs_audio_instance_t) inst)
  237. {
  238. if (__gs_audio_inst_valid(inst)) {
  239. return gs_slot_array_get(gs_engine_subsystem(audio)->instances, inst.id);
  240. }
  241. gs_audio_instance_decl_t decl;
  242. return decl;
  243. }
  244. float gs_audio_get_volume(gs_handle(gs_audio_instance_t) inst)
  245. {
  246. if (__gs_audio_inst_valid(inst)) {
  247. return gs_slot_array_getp(gs_engine_subsystem(audio)->instances, inst.id)->volume;
  248. }
  249. return 0.f;
  250. }
  251. void gs_audio_set_volume(gs_handle(gs_audio_instance_t) inst, float volume)
  252. {
  253. if (__gs_audio_inst_valid(inst)) {
  254. gs_slot_array_getp(gs_engine_subsystem(audio)->instances, inst.id)->volume = volume;
  255. }
  256. }
  257. /* Audio source data */
  258. gs_audio_source_t* gs_audio_get_source_data(gs_handle(gs_audio_source_t) src)
  259. {
  260. if (__gs_audio_src_valid(src)) {
  261. return gs_slot_array_getp(gs_engine_subsystem(audio)->sources, src.id);
  262. }
  263. return NULL;
  264. }
  265. void gs_audio_get_runtime(gs_handle(gs_audio_source_t) src, int32_t* minutes_out, int32_t* seconds_out)
  266. {
  267. if (__gs_audio_src_valid(src)) {
  268. gs_audio_i* audio = gs_engine_subsystem(audio);
  269. gs_audio_source_t* sp = gs_slot_array_getp(audio->sources, src.id);
  270. if (sp)
  271. {
  272. // Calculate total length in seconds
  273. float64_t total_seconds = ((float32_t)sp->sample_count / (float32_t)sp->sample_rate) / sp->channels;
  274. int32_t seconds = (int32_t)(fmodf(total_seconds, 60.f));
  275. int32_t minutes = (int32_t)(total_seconds / 60.f);
  276. if (minutes_out) {
  277. *minutes_out = minutes;
  278. }
  279. if (seconds_out) {
  280. *seconds_out = seconds;
  281. }
  282. }
  283. }
  284. }
  285. void gs_audio_convert_to_runtime(int32_t sample_count, int32_t sample_rate, int32_t num_channels, int32_t position, int32_t* minutes_out, int32_t* seconds_out)
  286. {
  287. // Calculate total length in seconds
  288. float64_t frac = (float64_t)position / (float64_t)sample_count;
  289. float64_t total_seconds = ((float64_t)sample_count / (float64_t)sample_rate) / num_channels;
  290. total_seconds = total_seconds * frac;
  291. int32_t seconds = (int32_t)(fmodf(total_seconds, 60.f));
  292. int32_t minutes = (int32_t)(total_seconds / 60.f);
  293. if (minutes_out) {
  294. *minutes_out = minutes;
  295. }
  296. if (seconds_out) {
  297. *seconds_out = seconds;
  298. }
  299. }
  300. int32_t gs_audio_get_sample_count(gs_handle(gs_audio_source_t) src)
  301. {
  302. if (__gs_audio_src_valid(src)) {
  303. return gs_slot_array_getp(gs_engine_subsystem(audio)->sources, src.id)->sample_count;
  304. }
  305. return 0;
  306. }
  307. int32_t gs_audio_get_sample_rate(gs_handle(gs_audio_source_t) src)
  308. {
  309. if (__gs_audio_src_valid(src)) {
  310. return gs_slot_array_getp(gs_engine_subsystem(audio)->sources, src.id)->sample_rate;
  311. }
  312. return 0;
  313. }
  314. int32_t gs_audio_get_num_channels(gs_handle(gs_audio_source_t) src)
  315. {
  316. if (__gs_audio_src_valid(src)) {
  317. return gs_slot_array_getp(gs_engine_subsystem(audio)->sources, src.id)->channels;
  318. }
  319. return 0;
  320. }
  321. #undef GS_AUDIO_IMPL_DEFAULT
  322. #endif // GS_AUDIO_IMPL_DEFAULT
  323. /*=============================
  324. // Miniaudio Impl
  325. =============================*/
  326. #ifdef GS_AUDIO_IMPL_MINIAUDIO
  327. #define MINIAUDIO_IMPLEMENTATION
  328. #include "../external/miniaudio/miniaudio.h"
  329. typedef struct miniaudio_data_t
  330. {
  331. ma_context context;
  332. ma_device device;
  333. ma_device_config device_config;
  334. ma_mutex lock;
  335. } miniaudio_data_t;
  336. void ma_audio_commit(ma_device* device, void* output, const void* input, ma_uint32 frame_count)
  337. {
  338. gs_audio_i* audio = gs_engine_subsystem(audio);
  339. miniaudio_data_t* ma = (miniaudio_data_t*)audio->user_data;
  340. memset(output, 0, frame_count * device->playback.channels * ma_get_bytes_per_sample(device->playback.format));
  341. // Only destroy 32 at a time
  342. u32 destroy_count = 0;
  343. gs_handle(gs_audio_instance_t) handles_to_destroy[32];
  344. ma_mutex_lock(&ma->lock);
  345. {
  346. for
  347. (
  348. gs_slot_array_iter it = 0;
  349. gs_slot_array_iter_valid(audio->instances, it);
  350. gs_slot_array_iter_advance(audio->instances, it)
  351. )
  352. {
  353. gs_audio_instance_t* inst = gs_slot_array_iter_getp(audio->instances, it);
  354. // Get raw audio source from instance
  355. gs_audio_source_t* src = gs_slot_array_getp(audio->sources, inst->src.id);
  356. // Easy out if the instance is not playing currently or the source is invalid
  357. if (!inst->playing || !src)
  358. {
  359. if (inst->persistent != true && destroy_count < 32)
  360. {
  361. handles_to_destroy[destroy_count++].id = it;
  362. }
  363. continue;
  364. }
  365. int16_t* sample_out = (int16_t*)output;
  366. int16_t* samples = (int16_t*)src->samples;
  367. uint64_t samples_to_write = (uint64_t)frame_count;
  368. float64_t sample_volume = inst->volume;
  369. // Write to channels
  370. for (uint64_t write_sample = 0; write_sample < samples_to_write; ++write_sample)
  371. {
  372. int32_t channels = src->channels;
  373. float64_t start_sample_position = inst->sample_position;
  374. int16_t start_left_sample;
  375. int16_t start_right_sample;
  376. // Not sure about this line of code...
  377. float64_t target_sample_position = start_sample_position + (float64_t)channels * (float64_t)1.f;
  378. if (target_sample_position >= src->sample_count)
  379. {
  380. target_sample_position -= src->sample_count;
  381. }
  382. int16_t target_left_sample;
  383. int16_t target_right_sample;
  384. {
  385. uint64_t left_idx = (uint64_t)start_sample_position;
  386. if (channels > 1)
  387. {
  388. left_idx &= ~((uint64_t)(0x01));
  389. }
  390. uint64_t right_idx = left_idx + (channels - 1);
  391. int16_t first_left_sample = samples[left_idx];
  392. int16_t first_right_sample = samples[right_idx];
  393. int16_t second_left_sample = samples[left_idx + channels];
  394. int16_t second_right_sample = samples[right_idx + channels];
  395. start_left_sample = (int16_t)(first_left_sample + (second_left_sample - first_left_sample) * (start_sample_position / channels - (uint64_t)(start_sample_position / channels)));
  396. start_right_sample = (int16_t)(first_right_sample + (second_right_sample - first_right_sample) * (start_sample_position / channels - (uint64_t)(start_sample_position / channels)));
  397. }
  398. {
  399. uint64_t left_index = (uint64_t)target_sample_position;
  400. if(channels > 1)
  401. {
  402. left_index &= ~((uint64_t)(0x01));
  403. }
  404. uint64_t right_index = left_index + (channels - 1);
  405. int16_t first_left_sample = samples[left_index];
  406. int16_t first_right_sample = samples[right_index];
  407. int16_t second_left_sample = samples[left_index + channels];
  408. int16_t second_right_sample = samples[right_index + channels];
  409. target_left_sample = (int16_t)(first_left_sample + (second_left_sample - first_left_sample) * (target_sample_position / channels - (uint64_t)(target_sample_position / channels)));
  410. target_right_sample = (int16_t)(first_right_sample + (second_right_sample - first_right_sample) * (target_sample_position / channels - (uint64_t)(target_sample_position / channels)));
  411. }
  412. int16_t left_sample = (int16_t)((((s64)start_left_sample + (s64)target_left_sample) / 2) * sample_volume);
  413. int16_t right_sample = (int16_t)((((s64)start_right_sample + (s64)target_right_sample) / 2) * sample_volume);
  414. *sample_out++ += left_sample; // Left
  415. *sample_out++ += right_sample; // Right
  416. // Possibly need fixed sampling instead
  417. inst->sample_position = target_sample_position;
  418. // Loop sound if necessary
  419. if(inst->sample_position >= src->sample_count - channels - 1)
  420. {
  421. if(inst->loop)
  422. {
  423. inst->sample_position = 0;
  424. }
  425. else
  426. {
  427. // Need to destroy the instance at this point
  428. inst->playing = false;
  429. inst->sample_position = 0;
  430. if (inst->persistent != true && destroy_count < 32)
  431. {
  432. handles_to_destroy[destroy_count++].id = it;
  433. }
  434. break;
  435. }
  436. }
  437. }
  438. }
  439. gs_for_range_i(destroy_count)
  440. {
  441. gs_slot_array_erase(audio->instances, handles_to_destroy[i].id);
  442. }
  443. }
  444. ma_mutex_unlock(&ma->lock);
  445. }
  446. gs_result gs_audio_init(gs_audio_i* audio)
  447. {
  448. // Set user data of audio to be miniaudio data
  449. audio->user_data = gs_malloc_init(miniaudio_data_t);
  450. miniaudio_data_t* output = (miniaudio_data_t*)audio->user_data;
  451. ma_result result = gs_default_val();
  452. // Init audio device
  453. // NOTE: Using the default device. Format is floating point because it simplifies mixing.
  454. ma_device_config config = ma_device_config_init(ma_device_type_playback);
  455. config.playback.pDeviceID = NULL; // NULL for the default playback AUDIO.System.device.
  456. config.playback.format = ma_format_s16;
  457. config.playback.channels = 2;
  458. config.capture.pDeviceID = NULL; // NULL for the default capture AUDIO.System.device.
  459. config.capture.format = ma_format_s16;
  460. config.capture.channels = 1;
  461. config.sampleRate = 44100;
  462. config.dataCallback = &ma_audio_commit;
  463. config.pUserData = NULL;
  464. output->device_config = config;
  465. if ((ma_device_init(NULL, &output->device_config, &output->device)) != MA_SUCCESS) {
  466. gs_assert(false);
  467. }
  468. if ((ma_device_start(&output->device)) != MA_SUCCESS) {
  469. gs_assert(false);
  470. }
  471. return GS_RESULT_SUCCESS;
  472. }
  473. gs_result gs_audio_shutdown(gs_audio_i* audio)
  474. {
  475. return GS_RESULT_SUCCESS;
  476. }
  477. #undef GS_AUDIO_IMPL_MINIAUDIO
  478. #endif // GS_AUDIO_IMPL_MINIAUDIO
  479. #endif // __GS_AUDIO_IMPL_H__