gs_audio_impl.h 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705
  1. /*==============================================================================================================
  2. * Copyright (c) 2020 John Jackson
  3. * File: gs_audio_impl.h
  4. * Github: https://github.com/MrFrenik/gunslinger
  5. * All Rights Reserved
  6. * MIT License
  7. * May all those that this source may reach be blessed by the LORD and find peace and joy in life.
  8. * Everyone who drinks of this water will be thirsty again; but whoever drinks of the water
  9. * that I will give him shall never thirst; John 4:13-14
  10. * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
  11. * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
  12. * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
  13. * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
  14. * The above copyright, blessing, biblical verse, notice and this permission notice shall be included in all
  15. * copies or substantial portions of the Software.
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
  17. * TO THE WARRANTIES OF MECHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  18. * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
  19. * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. * IN THE SOFTWARE.
  21. =================================================================================================================*/
  22. #ifndef GS_AUDIO_IMPL_H
  23. #define GS_AUDIO_IMPL_H
  24. // Define default platform implementation if certain platforms are enabled
  25. #if (defined GS_AUDIO_IMPL_MINIAUDIO)
  26. #define GS_AUDIO_IMPL_DEFAULT
  27. #endif
  28. /*=============================
  29. // Default Impl
  30. =============================*/
  31. #ifdef GS_AUDIO_IMPL_DEFAULT
  32. // Includes
  33. #include "../external/stb/stb_vorbis.c"
  34. #include "../external/dr_libs/dr_wav.h"
  35. #include "../external/dr_libs/dr_mp3.h"
  36. /* Audio Create, Destroy, Init, Shutdown, Submit */
  37. gs_audio_t* gs_audio_create()
  38. {
  39. // Construct new audio interface
  40. gs_audio_t* audio = gs_malloc_init(gs_audio_t);
  41. /* Audio source data cache */
  42. audio->sources = gs_slot_array_new(gs_audio_source_t);
  43. /* Audio instance data cache */
  44. audio->instances = gs_slot_array_new(gs_audio_instance_t);
  45. /* Max global volume setting */
  46. audio->max_audio_volume = 1.f;
  47. /* Min global volume setting */
  48. audio->min_audio_volume = 0.f;
  49. /* Set user data to null */
  50. audio->user_data = NULL;
  51. return audio;
  52. }
  53. void gs_audio_destroy(gs_audio_t* audio)
  54. {
  55. // Release all relevant memory
  56. if (audio)
  57. {
  58. gs_slot_array_free(audio->sources);
  59. gs_slot_array_free(audio->instances);
  60. gs_free(audio);
  61. audio = NULL;
  62. }
  63. }
  64. /* Resource Loading */
  65. bool32_t gs_audio_load_ogg_data_from_file
  66. (
  67. const char* file_path,
  68. int32_t* sample_count,
  69. int32_t* channels,
  70. int32_t* sample_rate,
  71. void** samples
  72. )
  73. {
  74. size_t len = 0;
  75. char* file_data = gs_platform_read_file_contents(file_path, "rb", &len);
  76. *sample_count = stb_vorbis_decode_memory((const unsigned char*)file_data, (size_t)len, channels, sample_rate, (s16**)samples);
  77. gs_free(file_data);
  78. if (!*samples || *sample_count == -1)
  79. {
  80. *samples = NULL;
  81. gs_println("WARNING: Could not load .ogg file: %s", file_path);
  82. return false;
  83. }
  84. *sample_count *= *channels;
  85. return true;
  86. }
  87. bool32_t gs_audio_load_wav_data_from_file
  88. (
  89. const char* file_path,
  90. int32_t* sample_count,
  91. int32_t* channels,
  92. int32_t* sample_rate,
  93. void** samples
  94. )
  95. {
  96. size_t len = 0;
  97. char* file_data = gs_platform_read_file_contents(file_path, "rb", &len);
  98. uint64_t total_pcm_frame_count = 0;
  99. *samples = drwav_open_memory_and_read_pcm_frames_s16(
  100. file_data, len, (uint32_t*)channels, (uint32_t*)sample_rate, &total_pcm_frame_count, NULL);
  101. gs_free(file_data);
  102. if (!*samples) {
  103. *samples = NULL;
  104. gs_println("WARNING: Could not load .wav file: %s", file_path);
  105. return false;
  106. }
  107. *sample_count = total_pcm_frame_count * *channels;
  108. return true;
  109. }
  110. bool32_t gs_audio_load_mp3_data_from_file
  111. (
  112. const char* file_path,
  113. int32_t* sample_count,
  114. int32_t* channels,
  115. int32_t* sample_rate,
  116. void** samples
  117. )
  118. {
  119. size_t len = 0;
  120. char* file_data = gs_platform_read_file_contents(file_path, "rb", &len);
  121. uint64_t total_pcm_frame_count = 0;
  122. drmp3_config cfg = gs_default_val();
  123. *samples = drmp3_open_memory_and_read_pcm_frames_s16(
  124. file_data, len, &cfg, (drmp3_uint64*)&total_pcm_frame_count, NULL);
  125. gs_free(file_data);
  126. if (!*samples) {
  127. *samples = NULL;
  128. gs_println("WARNING: Could not load .mp3 file: %s", file_path);
  129. return false;
  130. }
  131. *channels = cfg.channels;
  132. *sample_rate = cfg.sampleRate;
  133. *sample_count = total_pcm_frame_count * *channels;
  134. return true;
  135. }
  136. /* Audio create source */
  137. gs_handle(gs_audio_source_t) gs_audio_load_from_file(const char* file_path)
  138. {
  139. gs_audio_t* audio = gs_subsystem(audio);
  140. gs_audio_source_t src = gs_default_val();
  141. gs_handle(gs_audio_source_t) handle = gs_handle_invalid(gs_audio_source_t);
  142. bool32_t load_successful = false;
  143. if(!gs_platform_file_exists(file_path)) {
  144. gs_println("WARNING: Could not open file: %s", file_path);
  145. return handle;
  146. }
  147. char ext[64] = gs_default_val();
  148. gs_platform_file_extension(ext, sizeof(ext), file_path);
  149. gs_util_str_to_lower(ext, ext, sizeof(ext));
  150. gs_println("Audio: File Extension: %s", ext);
  151. // Load OGG data
  152. if (gs_string_compare_equal(ext, "ogg"))
  153. {
  154. load_successful = gs_audio_load_ogg_data_from_file (
  155. file_path,
  156. &src.sample_count,
  157. &src.channels,
  158. &src.sample_rate,
  159. &src.samples
  160. );
  161. }
  162. // Load WAV data
  163. if (gs_string_compare_equal(ext, "wav"))
  164. {
  165. gs_println("Audio: Loading Wav");
  166. load_successful = gs_audio_load_wav_data_from_file (
  167. file_path,
  168. &src.sample_count,
  169. &src.channels,
  170. &src.sample_rate,
  171. &src.samples
  172. );
  173. }
  174. if (gs_string_compare_equal(ext, "mp3"))
  175. {
  176. load_successful = gs_audio_load_mp3_data_from_file (
  177. file_path,
  178. &src.sample_count,
  179. &src.channels,
  180. &src.sample_rate,
  181. &src.samples
  182. );
  183. }
  184. // Load raw source into memory and return handle id
  185. if (load_successful)
  186. {
  187. gs_println("SUCCESS: Audio source loaded: %s", file_path);
  188. // Add to resource cache
  189. handle.id = gs_slot_array_insert(audio->sources, src);
  190. }
  191. else
  192. {
  193. gs_println("WARNING: Could not load audio source data: %s", file_path);
  194. }
  195. return handle;
  196. }
  197. /* Audio create instance */
  198. gs_handle(gs_audio_instance_t) gs_audio_instance_create(gs_audio_instance_decl_t* decl)
  199. {
  200. gs_audio_t* audio = gs_subsystem(audio);
  201. gs_audio_mutex_lock(audio);
  202. gs_handle(gs_audio_instance_t) hndl = gs_handle_create(gs_audio_instance_t, gs_slot_array_insert(audio->instances, *decl));
  203. gs_audio_mutex_unlock(audio);
  204. return hndl;
  205. }
  206. /* Audio play instance data */
  207. void gs_audio_play_source_with_pitch(gs_handle(gs_audio_source_t) src, float volume, float pitch)
  208. {
  209. // Construct instance data from source and play
  210. gs_audio_t* audio = gs_subsystem(audio);
  211. gs_audio_instance_decl_t decl = gs_default_val();
  212. decl.src = src;
  213. decl.volume = gs_clamp(volume, audio->min_audio_volume, audio->max_audio_volume);
  214. decl.pitch = gs_max(pitch, 0);
  215. decl.persistent = false;
  216. gs_handle(gs_audio_instance_t) inst = gs_audio_instance_create(&decl);
  217. gs_audio_play(inst);
  218. }
  219. void gs_audio_play_source(gs_handle(gs_audio_source_t) src, float volume)
  220. {
  221. gs_audio_play_source_with_pitch(src, volume, 1.0f);
  222. }
  223. // Helper macros
  224. #define __gs_audio_inst_valid(INST)\
  225. gs_slot_array_handle_valid(gs_subsystem(audio)->instances, INST.id)
  226. #define __gs_audio_src_valid(SRC)\
  227. gs_slot_array_handle_valid(gs_subsystem(audio)->sources, SRC.id)
  228. void gs_audio_play(gs_handle(gs_audio_instance_t) inst)
  229. {
  230. gs_audio_t* audio = gs_subsystem(audio);
  231. gs_audio_mutex_lock(audio);
  232. if (__gs_audio_inst_valid(inst)) {
  233. gs_slot_array_getp(audio->instances, inst.id)->playing = true;
  234. }
  235. gs_audio_mutex_unlock(audio);
  236. }
  237. void gs_audio_pause(gs_handle(gs_audio_instance_t) inst)
  238. {
  239. gs_audio_t* audio = gs_subsystem(audio);
  240. gs_audio_mutex_lock(audio);
  241. if (__gs_audio_inst_valid(inst))
  242. {
  243. gs_slot_array_getp(audio->instances, inst.id)->playing = false;
  244. }
  245. gs_audio_mutex_unlock(audio);
  246. }
  247. void gs_audio_stop(gs_handle(gs_audio_instance_t) inst)
  248. {
  249. gs_audio_t* audio = gs_subsystem(audio);
  250. gs_audio_mutex_lock(audio);
  251. if (__gs_audio_inst_valid(inst)) {
  252. gs_audio_instance_t* ip = gs_slot_array_getp(audio->instances, inst.id);
  253. ip->playing = false;
  254. ip->sample_position = 0;
  255. }
  256. gs_audio_mutex_unlock(audio);
  257. }
  258. void gs_audio_restart(gs_handle(gs_audio_instance_t) inst)
  259. {
  260. gs_audio_t* audio = gs_subsystem(audio);
  261. gs_audio_mutex_lock(audio);
  262. if (__gs_audio_inst_valid(inst))
  263. {
  264. gs_slot_array_getp(audio->instances, inst.id)->sample_position = 0;
  265. }
  266. gs_audio_mutex_unlock(audio);
  267. }
  268. bool32_t gs_audio_is_playing(gs_handle(gs_audio_instance_t) inst)
  269. {
  270. bool32_t playing = false;
  271. gs_audio_t* audio = gs_subsystem(audio);
  272. gs_audio_mutex_lock(audio);
  273. if (__gs_audio_inst_valid(inst))
  274. {
  275. playing = gs_slot_array_getp(audio->instances, inst.id)->playing;
  276. }
  277. gs_audio_mutex_unlock(audio);
  278. return playing;
  279. }
  280. /* Audio instance data */
  281. void gs_audio_set_instance_data(gs_handle(gs_audio_instance_t) inst, gs_audio_instance_decl_t decl)
  282. {
  283. if (__gs_audio_inst_valid(inst)) {
  284. *gs_slot_array_getp(gs_subsystem(audio)->instances, inst.id) = decl;
  285. }
  286. }
  287. gs_audio_instance_decl_t gs_audio_get_instance_data(gs_handle(gs_audio_instance_t) inst)
  288. {
  289. if (__gs_audio_inst_valid(inst)) {
  290. return gs_slot_array_get(gs_subsystem(audio)->instances, inst.id);
  291. }
  292. gs_audio_instance_decl_t decl = gs_default_val();
  293. return decl;
  294. }
  295. float gs_audio_get_volume(gs_handle(gs_audio_instance_t) inst)
  296. {
  297. if (__gs_audio_inst_valid(inst)) {
  298. return gs_slot_array_getp(gs_subsystem(audio)->instances, inst.id)->volume;
  299. }
  300. return 0.f;
  301. }
  302. void gs_audio_set_volume(gs_handle(gs_audio_instance_t) inst, float volume)
  303. {
  304. if (__gs_audio_inst_valid(inst)) {
  305. gs_slot_array_getp(gs_subsystem(audio)->instances, inst.id)->volume = volume;
  306. }
  307. }
  308. /* Audio source data */
  309. gs_audio_source_t* gs_audio_get_source_data(gs_handle(gs_audio_source_t) src)
  310. {
  311. if (__gs_audio_src_valid(src)) {
  312. return gs_slot_array_getp(gs_subsystem(audio)->sources, src.id);
  313. }
  314. return NULL;
  315. }
  316. void gs_audio_get_runtime(gs_handle(gs_audio_source_t) src, int32_t* minutes_out, int32_t* seconds_out)
  317. {
  318. if (__gs_audio_src_valid(src)) {
  319. gs_audio_t* audio = gs_subsystem(audio);
  320. gs_audio_source_t* sp = gs_slot_array_getp(audio->sources, src.id);
  321. if (sp)
  322. {
  323. // Calculate total length in seconds
  324. float64_t total_seconds = ((float32_t)sp->sample_count / (float32_t)sp->sample_rate) / sp->channels;
  325. int32_t seconds = (int32_t)(fmodf(total_seconds, 60.f));
  326. int32_t minutes = (int32_t)(total_seconds / 60.f);
  327. if (minutes_out) {
  328. *minutes_out = minutes;
  329. }
  330. if (seconds_out) {
  331. *seconds_out = seconds;
  332. }
  333. }
  334. }
  335. }
  336. 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)
  337. {
  338. // Calculate total length in seconds
  339. float64_t frac = (float64_t)position / (float64_t)sample_count;
  340. float64_t total_seconds = ((float64_t)sample_count / (float64_t)sample_rate) / num_channels;
  341. total_seconds = total_seconds * frac;
  342. int32_t seconds = (int32_t)(fmodf(total_seconds, 60.f));
  343. int32_t minutes = (int32_t)(total_seconds / 60.f);
  344. if (minutes_out) {
  345. *minutes_out = minutes;
  346. }
  347. if (seconds_out) {
  348. *seconds_out = seconds;
  349. }
  350. }
  351. int32_t gs_audio_get_sample_count(gs_handle(gs_audio_source_t) src)
  352. {
  353. if (__gs_audio_src_valid(src)) {
  354. return gs_slot_array_getp(gs_subsystem(audio)->sources, src.id)->sample_count;
  355. }
  356. return 0;
  357. }
  358. int32_t gs_audio_get_sample_rate(gs_handle(gs_audio_source_t) src)
  359. {
  360. if (__gs_audio_src_valid(src)) {
  361. return gs_slot_array_getp(gs_subsystem(audio)->sources, src.id)->sample_rate;
  362. }
  363. return 0;
  364. }
  365. int32_t gs_audio_get_num_channels(gs_handle(gs_audio_source_t) src)
  366. {
  367. if (__gs_audio_src_valid(src)) {
  368. return gs_slot_array_getp(gs_subsystem(audio)->sources, src.id)->channels;
  369. }
  370. return 0;
  371. }
  372. #undef GS_AUDIO_IMPL_DEFAULT
  373. #endif // GS_AUDIO_IMPL_DEFAULT
  374. /*=============================
  375. // Miniaudio Impl
  376. =============================*/
  377. #ifdef GS_AUDIO_IMPL_MINIAUDIO
  378. #define MINIAUDIO_IMPLEMENTATION
  379. #include "../external/miniaudio/miniaudio.h"
  380. typedef struct miniaudio_data_t
  381. {
  382. ma_context context;
  383. ma_device device;
  384. ma_device_config device_config;
  385. ma_mutex lock;
  386. } miniaudio_data_t;
  387. void gs_audio_mutex_lock(gs_audio_t* audio)
  388. {
  389. miniaudio_data_t* ma = (miniaudio_data_t*)audio->user_data;
  390. ma_mutex_lock(&ma->lock);
  391. }
  392. void gs_audio_mutex_unlock(gs_audio_t* audio)
  393. {
  394. miniaudio_data_t* ma = (miniaudio_data_t*)audio->user_data;
  395. ma_mutex_unlock(&ma->lock);
  396. }
  397. void ma_audio_commit(ma_device* device, void* output, const void* input, ma_uint32 frame_count)
  398. {
  399. gs_audio_t* audio = gs_subsystem(audio);
  400. miniaudio_data_t* ma = (miniaudio_data_t*)audio->user_data;
  401. memset(output, 0, frame_count * device->playback.channels * ma_get_bytes_per_sample(device->playback.format));
  402. // Only destroy 32 at a time
  403. u32 destroy_count = 0;
  404. uint32_t handles_to_destroy[32];
  405. if (!audio->instances)
  406. return;
  407. // Call user commit function
  408. if (audio->commit)
  409. {
  410. audio->commit((int16_t*)output, 2, ma->device_config.sampleRate, frame_count);
  411. }
  412. gs_audio_mutex_lock(audio);
  413. {
  414. for (
  415. gs_slot_array_iter it = gs_slot_array_iter_new(audio->instances);
  416. gs_slot_array_iter_valid(audio->instances, it);
  417. gs_slot_array_iter_advance(audio->instances, it)
  418. )
  419. {
  420. if (!gs_slot_array_handle_valid(audio->instances, it)) {
  421. continue;
  422. }
  423. gs_audio_instance_t* inst = gs_slot_array_iter_getp(audio->instances, it);
  424. // Get raw audio source from instance
  425. gs_audio_source_t* src = gs_slot_array_getp(audio->sources, inst->src.id);
  426. // Easy out if the instance is not playing currently or the source is invalid
  427. if (!src || (!inst->playing && !inst->persistent)) {
  428. if (destroy_count < gs_array_size(handles_to_destroy))
  429. handles_to_destroy[destroy_count++] = it;
  430. continue;
  431. }
  432. if (!inst->playing) continue;
  433. s16* sample_out = (s16*)output;
  434. s16* samples = (s16*)src->samples;
  435. u64 samples_to_write = (u64)frame_count;
  436. f64 sample_volume = inst->volume;
  437. // Write to channels
  438. for (u64 write_sample = 0; write_sample < samples_to_write; ++write_sample)
  439. {
  440. s32 channels = src->channels;
  441. f64 start_sample_position = inst->sample_position;
  442. s16 start_left_sample;
  443. s16 start_right_sample;
  444. // Not sure about this line of code...
  445. f64 target_sample_position = start_sample_position + (f64)channels * (f64)inst->pitch;
  446. if (target_sample_position >= src->sample_count)
  447. {
  448. target_sample_position -= src->sample_count;
  449. }
  450. s16 target_left_sample = 0;
  451. s16 target_right_sample = 0;
  452. {
  453. u64 left_idx = (u64)start_sample_position;
  454. if (channels > 1)
  455. {
  456. left_idx &= ~((u64)(0x01));
  457. }
  458. u64 right_idx = left_idx + (channels - 1);
  459. s16 first_left_sample = samples[left_idx];
  460. s16 first_right_sample = samples[right_idx];
  461. s16 second_left_sample = samples[left_idx + channels];
  462. s16 second_right_sample = samples[right_idx + channels];
  463. start_left_sample = (s16)(first_left_sample + (second_left_sample - first_left_sample) * (start_sample_position / channels - (u64)(start_sample_position / channels)));
  464. start_right_sample = (s16)(first_right_sample + (second_right_sample - first_right_sample) * (start_sample_position / channels - (u64)(start_sample_position / channels)));
  465. }
  466. s16 left_sample = (s16)((((s64)start_left_sample + (s64)target_left_sample) / 2) * sample_volume);
  467. s16 right_sample = (s16)((((s64)start_right_sample + (s64)target_right_sample) / 2) * sample_volume);
  468. *sample_out++ += left_sample; // Left
  469. *sample_out++ += right_sample; // Right
  470. // Possibly need fixed sampling instead
  471. inst->sample_position = target_sample_position;
  472. // Loop sound if necessary
  473. if(inst->sample_position >= src->sample_count - channels - 1)
  474. {
  475. if(inst->loop)
  476. {
  477. // inst->sample_position -= src->sample_count;
  478. inst->sample_position = 0;
  479. }
  480. else
  481. {
  482. // Need to destroy the instance at this point...
  483. inst->playing = false;
  484. inst->sample_position = 0;
  485. if (!inst->persistent && destroy_count < gs_array_size(handles_to_destroy))
  486. handles_to_destroy[destroy_count++] = it;
  487. break;
  488. }
  489. }
  490. }
  491. }
  492. // Destroy instances
  493. for (uint32_t i = 0; i < destroy_count; ++i) {
  494. gs_slot_array_erase(audio->instances, handles_to_destroy[i]);
  495. }
  496. }
  497. gs_audio_mutex_unlock(audio);
  498. }
  499. // Change this to fix sized audio instance buffer, then just use that internally.
  500. // The slot array isn't working across threads.
  501. // Or copy data over from one thread to another at a guaranteed sync point.
  502. gs_result gs_audio_init(gs_audio_t* audio)
  503. {
  504. // Set user data of audio to be miniaudio data
  505. audio->user_data = gs_malloc_init(miniaudio_data_t);
  506. gs_slot_array_reserve(audio->instances, 1024);
  507. miniaudio_data_t* output = (miniaudio_data_t*)audio->user_data;
  508. ma_result result = gs_default_val();
  509. // Init audio context
  510. ma_context_config ctx_config = ma_context_config_init();
  511. result = ma_context_init(NULL, 0, &ctx_config, &output->context);
  512. if (result != MA_SUCCESS) {
  513. gs_assert(false);
  514. return GS_RESULT_FAILURE;
  515. }
  516. // Init audio device
  517. // NOTE: Using the default device. Format is floating point because it simplifies mixing.
  518. ma_device_config config = ma_device_config_init(ma_device_type_playback);
  519. config.playback.pDeviceID = NULL; // NULL for the default playback AUDIO.System.device.
  520. config.playback.format = ma_format_s16;
  521. config.playback.channels = 2;
  522. config.capture.pDeviceID = NULL; // NULL for the default capture AUDIO.System.device.
  523. config.capture.format = ma_format_s16;
  524. config.capture.channels = 1;
  525. config.sampleRate = 44100;
  526. config.dataCallback = &ma_audio_commit;
  527. config.pUserData = NULL;
  528. ma_device_info* pPlaybackDeviceInfos;
  529. ma_uint32 playbackDeviceCount;
  530. ma_device_info* pCaptureDeviceInfos;
  531. ma_uint32 captureDeviceCount;
  532. ma_uint32 iDevice;
  533. result = ma_context_get_devices(&output->context, &pPlaybackDeviceInfos, &playbackDeviceCount, &pCaptureDeviceInfos, &captureDeviceCount);
  534. if (result != MA_SUCCESS) {
  535. gs_assert(false);
  536. }
  537. gs_println("Capture Device Count: %zu", captureDeviceCount);
  538. for (iDevice = 0; iDevice < captureDeviceCount; ++iDevice)
  539. {
  540. gs_println("%zu: %s", iDevice, pCaptureDeviceInfos[iDevice].name);
  541. }
  542. output->device_config = config;
  543. if ((ma_device_init(NULL, &output->device_config, &output->device)) != MA_SUCCESS) {
  544. gs_assert(false);
  545. }
  546. if ((ma_device_start(&output->device)) != MA_SUCCESS) {
  547. gs_assert(false);
  548. }
  549. // Initialize the mutex, ya dummy
  550. if (ma_mutex_init(&output->lock) != MA_SUCCESS) {
  551. gs_assert(false);
  552. }
  553. return GS_RESULT_SUCCESS;
  554. }
  555. // Register commit function
  556. GS_API_DECL void gs_audio_register_commit(gs_audio_commit commit)
  557. {
  558. gs_audio_t* audio = gs_subsystem(audio);
  559. audio->commit = commit;
  560. }
  561. gs_result gs_audio_shutdown(gs_audio_t* audio)
  562. {
  563. miniaudio_data_t* ma = (miniaudio_data_t*)audio->user_data;
  564. ma_context_uninit(&ma->context);
  565. ma_device_uninit(&ma->device);
  566. ma_mutex_uninit(&ma->lock);
  567. return GS_RESULT_SUCCESS;
  568. }
  569. #undef GS_AUDIO_IMPL_MINIAUDIO
  570. #endif // GS_AUDIO_IMPL_MINIAUDIO
  571. #endif // GS_AUDIO_IMPL_H