2 #include "system/stacktrace.h"
7 #include "sound_samples.h"
9 #include "system/log.h"
10 #include "system/lt.h"
11 #include "system/nth_alloc.h"
13 // TODO(#863): Sound_samples is not implemented
14 // TODO: Volume control?
19 SDL_AudioDeviceID dev;
20 Dynarray *audio_buf_array;
21 Dynarray *audio_buf_size_array;
26 static int init_buffer_and_device(Sound_samples*, const char **);
27 Sound_samples *create_sound_samples(const char *sample_files[],
28 size_t sample_files_count)
30 trace_assert(sample_files);
31 trace_assert(sample_files_count > 0);
35 Sound_samples *sound_samples = PUSH_LT(lt, nth_calloc(1, sizeof(Sound_samples)), free);
36 if (sound_samples == NULL) {
39 sound_samples->lt = lt;
41 sound_samples->samples_count = sample_files_count;
42 if (init_buffer_and_device(sound_samples, sample_files) < 0) {
43 log_fail("init_buffer_and_device failed\n");
47 sound_samples->paused = 0;
48 SDL_PauseAudioDevice(sound_samples->dev, 0);
54 int init_buffer_and_device(Sound_samples *sound_samples,
55 const char *sample_files[])
57 // TODO: Select audio specification from a menu
58 // TODO: Use a seperate callback function
59 SDL_AudioSpec destination_spec = { // stereo float32 44100Hz
64 // TODO: a return value by SDL_GetNumAudioDevices that is <= 0 may not indicate an error
65 if (SDL_GetNumAudioDevices(0) <= 0) {
66 log_fail("No audio in 2019 LULW\n");
70 sound_samples->audio_buf_array = PUSH_LT(sound_samples->lt, create_dynarray(sizeof(uint8_t*)), destroy_dynarray);
71 if (sound_samples->audio_buf_array == NULL) {
72 log_fail("Failed to allocate memory for audio buffer pointer array\n");
75 sound_samples->audio_buf_size_array = PUSH_LT(sound_samples->lt, create_dynarray(sizeof(uint32_t)), destroy_dynarray);
76 if (sound_samples->audio_buf_size_array == NULL) {
77 log_fail("Failed to allocate memory for audio buffer size array\n");
80 for (size_t i = 0; i < sound_samples->samples_count; ++i) {
81 uint8_t *wav_buf; uint32_t wav_buf_len; SDL_AudioSpec wav_spec;
83 log_info("Loading audio file %s...\n", sample_files[i]);
84 if (SDL_LoadWAV(sample_files[i], &wav_spec, &wav_buf, &wav_buf_len) == NULL) {
85 log_fail("Load WAV file failed: %s\n", SDL_GetError());
88 PUSH_LT(sound_samples->lt, wav_buf, SDL_FreeWAV);
90 int result = SDL_BuildAudioCVT(&cvt, wav_spec.format, (uint8_t)wav_spec.channels, (int)wav_spec.freq,
91 destination_spec.format, (uint8_t)destination_spec.channels, (int)destination_spec.freq);
93 log_fail("SDL_BuildAudioCVT failed: %s\n", SDL_GetError());
95 } else if (result == 0) { // no need to do conversion
96 if (dynarray_push(sound_samples->audio_buf_array, &wav_buf) != 0) {
97 log_fail("Failed to push to audio buffer pointer array\n");
100 if (dynarray_push(sound_samples->audio_buf_size_array, &wav_buf_len) != 0) {
101 log_fail("Failed to push to audio buffer size array\n");
105 cvt.len = (int)wav_buf_len;
106 cvt.buf = PUSH_LT(sound_samples->lt, malloc((size_t)(cvt.len * cvt.len_mult)), free);
107 if (cvt.buf == NULL) {
108 log_fail("Allocating buffer for conversion failed\n");
111 memcpy(cvt.buf, wav_buf, (size_t)cvt.len);
112 SDL_FreeWAV(wav_buf);
113 RELEASE_LT(sound_samples->lt, wav_buf);
114 if (SDL_ConvertAudio(&cvt) < 0) {
115 log_fail("SDL_ConvertAudio failed: %s\n", SDL_GetError());
118 if (dynarray_push(sound_samples->audio_buf_array, &cvt.buf) != 0) {
119 log_fail("Failed to push to audio buffer pointer array\n");
122 if (dynarray_push(sound_samples->audio_buf_size_array, &cvt.len_cvt) != 0) {
123 log_fail("Failed to push to audio buffer size array\n");
129 sound_samples->dev = SDL_OpenAudioDevice(NULL, 0, &destination_spec, &actual, 0);
130 if (sound_samples->dev == 0) {
131 log_fail("SDL_OpenAudioDevice failed: %s\n", SDL_GetError());
132 log_info("The audio device may not support the hardcoded format\n");
135 log_info("Audio device ID %u opened\n", sound_samples->dev);
139 void destroy_sound_samples(Sound_samples *sound_samples)
141 // TODO: Use a seperate callback function for processing audio
142 trace_assert(sound_samples);
143 trace_assert(sound_samples->dev);
144 SDL_PauseAudioDevice(sound_samples->dev, 1);
145 SDL_ClearQueuedAudio(sound_samples->dev);
146 SDL_CloseAudioDevice(sound_samples->dev);
147 RETURN_LT0(sound_samples->lt);
150 int sound_samples_play_sound(Sound_samples *sound_samples,
153 trace_assert(sound_samples);
154 trace_assert(sound_index < sound_samples->samples_count);
155 uint8_t *audio_buf = *(uint8_t**)dynarray_pointer_at(sound_samples->audio_buf_array, sound_index);
156 uint32_t audio_buf_size = *(uint32_t*)dynarray_pointer_at(sound_samples->audio_buf_size_array, sound_index);
157 trace_assert(sound_samples->dev);
158 SDL_ClearQueuedAudio(sound_samples->dev);
159 if (SDL_QueueAudio(sound_samples->dev, audio_buf, audio_buf_size) < 0) {
160 log_warn("Failed to queue audio data of sound index %zu to device: %s\n", sound_index, SDL_GetError());
163 SDL_PauseAudioDevice(sound_samples->dev, 0);
167 int sound_samples_toggle_pause(Sound_samples *sound_samples)
169 trace_assert(sound_samples);
170 sound_samples->paused = !sound_samples->paused;
171 SDL_PauseAudioDevice(sound_samples->dev, sound_samples->paused);