#include "system/log.h"
#include "system/lt.h"
#include "system/nth_alloc.h"
+#include "config.h"
-// TODO(#863): Sound_samples is not implemented
-// TODO: Sound_samples does not implement volume control.
+// TODO(#1022): Sound_samples does not implement volume control.
struct Sound_samples
{
SDL_AudioDeviceID dev;
uint8_t **audio_buf_array;
uint32_t *audio_buf_size_array;
+ uint8_t **active_audio_buf_array;
size_t samples_count;
int paused;
+ float volume;
+ // TODO(#1127): A better solution for optional sound support
+ int failed; // This is hackish
};
-static
-int init_buffer_and_device(Sound_samples *sound_samples,
- const char *sample_files[])
+static
+int init_buffer_and_device(Sound_samples *sound_samples,
+ const char *sample_files[])
{
- // TODO: init_buffer_and_device uses hard-coded audio specification
+ // TODO(#1023): init_buffer_and_device uses hard-coded audio specification
SDL_AudioSpec destination_spec = { // stereo float32 44100Hz
.format = AUDIO_F32,
.channels = 2,
.freq = 44100
};
- // TODO: a return value by SDL_GetNumAudioDevices that is <= 0 may not indicate an error
+ // TODO(#1024): a return value by SDL_GetNumAudioDevices that is <= 0 may not indicate an error
if (SDL_GetNumAudioDevices(0) <= 0) {
log_fail("No audio in 2019 LULW\n");
return -1;
}
-
+
sound_samples->audio_buf_array = PUSH_LT(sound_samples->lt, nth_calloc(sound_samples->samples_count, sizeof(uint8_t*)), free);
if (sound_samples->audio_buf_array == NULL) {
log_fail("Failed to allocate memory for audio buffer pointer array\n");
}
PUSH_LT(sound_samples->lt, wav_buf, SDL_FreeWAV);
SDL_AudioCVT cvt;
- int result = SDL_BuildAudioCVT(&cvt, wav_spec.format, (uint8_t)wav_spec.channels, (int)wav_spec.freq,
+ int result = SDL_BuildAudioCVT(&cvt, wav_spec.format, (uint8_t)wav_spec.channels, (int)wav_spec.freq,
destination_spec.format, (uint8_t)destination_spec.channels, (int)destination_spec.freq);
if (result < 0) {
log_fail("SDL_BuildAudioCVT failed: %s\n", SDL_GetError());
sound_samples->audio_buf_size_array[i] = (uint32_t)cvt.len_cvt;
}
}
-
+
+ /* Allocating active audio buffer location*/
+ //TODO(#1072): Allocate one huge active audio buffer with length of the maximum of all audio buffer, instead of one active buffer for each audio
+ sound_samples->active_audio_buf_array = PUSH_LT(sound_samples->lt, nth_calloc(sound_samples->samples_count, sizeof(uint8_t*)), free);
+ if (sound_samples->active_audio_buf_array == NULL) {
+ log_fail("Failed to allocate memory for active audio buffer pointer array\n");
+ return -1;
+ }
+ for (size_t i = 0; i < sound_samples->samples_count; ++i) {
+ sound_samples->active_audio_buf_array[i] = PUSH_LT(sound_samples->lt, nth_calloc(sound_samples->audio_buf_size_array[i],
+ sizeof(uint8_t)), free);
+ if (sound_samples->active_audio_buf_array == NULL) {
+ log_fail("Failed to allocate memory for active audio buffer array\n");
+ return -1;
+ }
+ }
+
+ /* Opening the device*/
sound_samples->dev = SDL_OpenAudioDevice(NULL, 0, &destination_spec, NULL, 0);
if (sound_samples->dev == 0) {
log_fail("SDL_OpenAudioDevice failed: %s\n", SDL_GetError());
RETURN_LT(lt, NULL);
}
sound_samples->lt = lt;
+ sound_samples->volume = SOUND_SAMPLES_DEFAULT_VOLUME;
sound_samples->samples_count = sample_files_count;
if (init_buffer_and_device(sound_samples, sample_files) < 0) {
log_fail("init_buffer_and_device failed\n");
- RETURN_LT(lt, NULL);
+ sound_samples->failed = 1;
}
sound_samples->paused = 0;
void destroy_sound_samples(Sound_samples *sound_samples)
{
- // TODO: Use a seperate callback function for audio handling and pass that into SDL_OpenAudioDevice
+ // TODO(#1025): Use a seperate callback function for audio handling and pass that into SDL_OpenAudioDevice
+ if (sound_samples->failed) return;
trace_assert(sound_samples);
trace_assert(sound_samples->dev);
SDL_CloseAudioDevice(sound_samples->dev);
size_t sound_index)
{
trace_assert(sound_samples);
+ if (sound_samples->failed) return 0;
trace_assert(sound_index < sound_samples->samples_count);
trace_assert(sound_samples->dev);
+
+ /* Premix the audio volume */
+ memset(sound_samples->active_audio_buf_array[sound_index], 0, sound_samples->audio_buf_size_array[sound_index]);
+
+ //TODO(#1073): replace this linear scaling volume with logarithmic scale for better audio perception
+ SDL_MixAudioFormat(sound_samples->active_audio_buf_array[sound_index],
+ sound_samples->audio_buf_array[sound_index],
+ AUDIO_F32, //Hardcoded format just like in issue #1023
+ sound_samples->audio_buf_size_array[sound_index],
+ (int)((float)SDL_MIX_MAXVOLUME * sound_samples->volume / 100.0f));
+
+ /* Play the audio*/
SDL_ClearQueuedAudio(sound_samples->dev);
- if (SDL_QueueAudio(sound_samples->dev, sound_samples->audio_buf_array[sound_index],
+ if (SDL_QueueAudio(sound_samples->dev, sound_samples->active_audio_buf_array[sound_index],
sound_samples->audio_buf_size_array[sound_index]) < 0) {
log_warn("Failed to queue audio data of sound index %zu to device: %s\n", sound_index, SDL_GetError());
return 0;
int sound_samples_toggle_pause(Sound_samples *sound_samples)
{
trace_assert(sound_samples);
+ if (sound_samples->failed) return 0;
sound_samples->paused = !sound_samples->paused;
trace_assert(sound_samples->dev);
SDL_PauseAudioDevice(sound_samples->dev, sound_samples->paused);
return 0;
}
+
+void sound_samples_update_volume(Sound_samples *sound_samples,
+ float volume)
+{
+ trace_assert(sound_samples);
+ if (sound_samples->failed) return;
+ sound_samples->volume = volume;
+}