From 4e329c4efaac8583536e9b817ecd119fd46ab5fd Mon Sep 17 00:00:00 2001 From: Chad Gauthier Date: Tue, 11 Jun 2024 01:33:47 -0500 Subject: [PATCH] try surround sound --- src/main/main.cpp | 67 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 54 insertions(+), 13 deletions(-) diff --git a/src/main/main.cpp b/src/main/main.cpp index b28f19c..30b6269 100644 --- a/src/main/main.cpp +++ b/src/main/main.cpp @@ -192,36 +192,70 @@ void queue_samples(int16_t* audio_data, size_t sample_count) { } // Copy the duplicated frames from last chunk into this chunk - for (size_t i = 0; i < duplicated_input_frames * input_channels; i++) { - swap_buffer[i] = duplicated_sample_buffer[i]; - } + copy_duplicated_frames(swap_buffer, duplicated_sample_buffer); // Convert the audio from 16-bit values to floats and swap the audio channels into the - // swap buffer to correct for the address xor caused by endianness handling. - float cur_main_volume = zelda64::get_main_volume() / 100.0f; // Get the current main volume, normalized to 0.0-1.0. - for (size_t i = 0; i < sample_count; i += input_channels) { - swap_buffer[i + 0 + duplicated_input_frames * input_channels] = audio_data[i + 1] * (0.5f / 32768.0f) * cur_main_volume; - swap_buffer[i + 1 + duplicated_input_frames * input_channels] = audio_data[i + 0] * (0.5f / 32768.0f) * cur_main_volume; - } - + // swap buffer to correct for the address XOR caused by endianness handling. + convert_and_swap_channels(audio_data, sample_count, swap_buffer); + // TODO handle cases where a chunk is smaller than the duplicated frame count. assert(sample_count > duplicated_input_frames * input_channels); // Copy the last converted samples into the duplicated sample buffer to reuse in resampling the next queued chunk. + copy_last_samples(swap_buffer, sample_count, duplicated_sample_buffer); + + // Set up the SDL audio converter + prepare_audio_converter(swap_buffer, sample_count); + + // Convert the audio to the output format. + convert_audio(); + + // Queue the converted audio to the device. + queue_audio_data(swap_buffer); +} + +void copy_duplicated_frames(std::vector& swap_buffer, const std::array& duplicated_sample_buffer) { + for (size_t i = 0; i < duplicated_input_frames * input_channels; i++) { + swap_buffer[i] = duplicated_sample_buffer[i]; + } +} + +void convert_and_swap_channels(int16_t* audio_data, size_t sample_count, std::vector& swap_buffer) { + float cur_main_volume = zelda64::get_main_volume() / 100.0f; // Get the current main volume, normalized to 0.0-1.0. + for (size_t i = 0; i < sample_count; i += input_channels) { + if (input_channels == 2) { // Stereo + swap_buffer[i + 0 + duplicated_input_frames * input_channels] = audio_data[i + 1] * (0.5f / 32768.0f) * cur_main_volume; + swap_buffer[i + 1 + duplicated_input_frames * input_channels] = audio_data[i + 0] * (0.5f / 32768.0f) * cur_main_volume; + } else if (input_channels == 4) { // Quadraphonic + swap_buffer[i + 0 + duplicated_input_frames * input_channels] = audio_data[i + 3] * (0.5f / 32768.0f) * cur_main_volume; // Rear left + swap_buffer[i + 1 + duplicated_input_frames * input_channels] = audio_data[i + 2] * (0.5f / 32768.0f) * cur_main_volume; // Rear right + swap_buffer[i + 2 + duplicated_input_frames * input_channels] = audio_data[i + 1] * (0.5f / 32768.0f) * cur_main_volume; // Front left + swap_buffer[i + 3 + duplicated_input_frames * input_channels] = audio_data[i + 0] * (0.5f / 32768.0f) * cur_main_volume; // Front right + } + } +} + +void copy_last_samples(std::vector& swap_buffer, size_t sample_count, std::array& duplicated_sample_buffer) { for (size_t i = 0; i < duplicated_input_frames * input_channels; i++) { duplicated_sample_buffer[i] = swap_buffer[i + sample_count]; } - +} + +void prepare_audio_converter(std::vector& swap_buffer, size_t sample_count) { audio_convert.buf = reinterpret_cast(swap_buffer.data()); audio_convert.len = (sample_count + duplicated_input_frames * input_channels) * sizeof(swap_buffer[0]); +} +void convert_audio() { int ret = SDL_ConvertAudio(&audio_convert); if (ret < 0) { printf("Error using SDL audio converter: %s\n", SDL_GetError()); throw std::runtime_error("Error using SDL audio converter"); } +} +void queue_audio_data(std::vector& swap_buffer) { uint64_t cur_queued_microseconds = uint64_t(SDL_GetQueuedAudioSize(audio_device)) / bytes_per_frame * 1000000 / sample_rate; uint32_t num_bytes_to_queue = audio_convert.len_cvt - output_channels * discarded_output_frames * sizeof(swap_buffer[0]); float* samples_to_queue = swap_buffer.data() + output_channels * discarded_output_frames / 2; @@ -233,8 +267,15 @@ void queue_samples(int16_t* audio_data, size_t sample_count) { uint32_t skip_ratio = 1 << skip_factor; num_bytes_to_queue /= skip_ratio; for (size_t i = 0; i < num_bytes_to_queue / (output_channels * sizeof(swap_buffer[0])); i++) { - samples_to_queue[2 * i + 0] = samples_to_queue[2 * skip_ratio * i + 0]; - samples_to_queue[2 * i + 1] = samples_to_queue[2 * skip_ratio * i + 1]; + if (input_channels == 2) { + samples_to_queue[2 * i + 0] = samples_to_queue[2 * skip_ratio * i + 0]; + samples_to_queue[2 * i + 1] = samples_to_queue[2 * skip_ratio * i + 1]; + } else if (input_channels == 4) { + samples_to_queue[4 * i + 0] = samples_to_queue[4 * skip_ratio * i + 0]; // Rear left + samples_to_queue[4 * i + 1] = samples_to_queue[4 * skip_ratio * i + 1]; // Rear right + samples_to_queue[4 * i + 2] = samples_to_queue[4 * skip_ratio * i + 2]; // Front left + samples_to_queue[4 * i + 3] = samples_to_queue[4 * skip_ratio * i + 3]; // Front right + } } }