diff --git a/include/Menus/AudioMenu.hpp b/include/Menus/AudioMenu.hpp index 4665880..c5f2c2d 100755 --- a/include/Menus/AudioMenu.hpp +++ b/include/Menus/AudioMenu.hpp @@ -14,6 +14,8 @@ enum AudioMenuOutAction{ AUDIO_MENU_MUTE, AUDIO_MENU_VOLUME_DEC, AUDIO_MENU_VOLUME_INC, + AUDIO_MENU_MAX_LATENCY_DEC, + AUDIO_MENU_MAX_LATENCY_INC, AUDIO_MENU_RESTART, }; diff --git a/include/audio_data.hpp b/include/audio_data.hpp index edd0104..a7f4157 100755 --- a/include/audio_data.hpp +++ b/include/audio_data.hpp @@ -2,14 +2,17 @@ #define __AUDIO_DATA_HPP #include +#define MAX_MAX_AUDIO_LATENCY 10 class AudioData { public: void reset(); + void set_max_audio_latency(int new_value); void change_audio_volume(bool is_change_positive); void change_audio_mute(); void request_audio_restart(); bool check_audio_restart_request(); + int get_max_audio_latency(); int get_final_volume(); bool has_text_to_print(); std::string text_to_print(); @@ -20,6 +23,7 @@ public: private: int volume; + int max_audio_latency; bool mute; bool restart_request = false; bool text_updated; @@ -27,6 +31,7 @@ private: void set_audio_volume(int new_volume); void set_audio_mute(bool new_mute); void update_text(std::string text); + const std::string max_audio_latency_str = "max_audio_latency"; const std::string volume_str = "volume"; const std::string mute_str = "mute"; }; diff --git a/include/hw_defs.hpp b/include/hw_defs.hpp index 8d37d85..f70dcfe 100755 --- a/include/hw_defs.hpp +++ b/include/hw_defs.hpp @@ -64,9 +64,12 @@ #define MAX_IN_VIDEO_SIZE (MAX_IN_VIDEO_WIDTH * MAX_IN_VIDEO_HEIGHT) #define MAX_IN_VIDEO_BPP_SIZE IN_VIDEO_BPP_SIZE_3DS -#define O3DS_SAMPLES_IN (1096 * 8) // This one can go beyond the normal amount, so factor in a buffer of sorts. 8x is way more than needed, but better being safe than sorry! -#define N3DSXL_SAMPLES_IN 1096 -#define DS_SAMPLES_IN 1096 +// 1096 is the value when things are ideal. However, it can actually happen that the transfer isn't 100% on time. +// When that happens, a bit more audio data may get transfered. It's a ton on O3DS when Windows underprioritizes USB... +// In general, it should be less than * 2, but you never know. For now, go for safety at x16... +#define O3DS_SAMPLES_IN (1096 * 16) +#define N3DSXL_SAMPLES_IN (1096 * 16) +#define DS_SAMPLES_IN (1096 * 16) #define MAX_SAMPLES_IN O3DS_SAMPLES_IN #endif diff --git a/source/Menus/AudioMenu.cpp b/source/Menus/AudioMenu.cpp index 5b83b6c..00b8d88 100755 --- a/source/Menus/AudioMenu.cpp +++ b/source/Menus/AudioMenu.cpp @@ -22,6 +22,11 @@ static const AudioMenuOptionInfo audio_mute_option = { .is_inc = false, .dec_str = "", .inc_str = "", .inc_out_action = AUDIO_MENU_NO_ACTION, .out_action = AUDIO_MENU_MUTE}; +static const AudioMenuOptionInfo audio_max_latency_option = { +.base_name = "Max Latency", .false_name = "", +.is_inc = true, .dec_str = "-", .inc_str = "+", .inc_out_action = AUDIO_MENU_MAX_LATENCY_INC, +.out_action = AUDIO_MENU_MAX_LATENCY_DEC}; + static const AudioMenuOptionInfo audio_restart_option = { .base_name = "Restart Audio", .false_name = "", .is_inc = false, .dec_str = "", .inc_str = "", .inc_out_action = AUDIO_MENU_NO_ACTION, @@ -30,6 +35,7 @@ static const AudioMenuOptionInfo audio_restart_option = { static const AudioMenuOptionInfo* pollable_options[] = { &audio_volume_option, &audio_mute_option, +&audio_max_latency_option, &audio_restart_option, }; @@ -114,6 +120,9 @@ void AudioMenu::prepare(float menu_scaling_factor, int view_size_x, int view_siz case AUDIO_MENU_VOLUME_DEC: this->labels[index]->setText(this->setTextOptionInt(real_index, audio_data->get_real_volume())); break; + case AUDIO_MENU_MAX_LATENCY_DEC: + this->labels[index]->setText(this->setTextOptionInt(real_index, audio_data->get_max_audio_latency())); + break; case AUDIO_MENU_MUTE: this->labels[index]->setText(this->setTextOptionBool(real_index, audio_data->get_mute())); break; diff --git a/source/WindowScreen_Menu.cpp b/source/WindowScreen_Menu.cpp index 9361177..a05b4b7 100755 --- a/source/WindowScreen_Menu.cpp +++ b/source/WindowScreen_Menu.cpp @@ -1176,6 +1176,12 @@ void WindowScreen::poll(bool do_everything) { case AUDIO_MENU_VOLUME_INC: this->audio_data->change_audio_volume(true); break; + case AUDIO_MENU_MAX_LATENCY_DEC: + this->audio_data->set_max_audio_latency(this->audio_data->get_max_audio_latency() - 1); + break; + case AUDIO_MENU_MAX_LATENCY_INC: + this->audio_data->set_max_audio_latency(this->audio_data->get_max_audio_latency() + 1); + break; case AUDIO_MENU_MUTE: this->audio_data->change_audio_mute(); break; diff --git a/source/audio.cpp b/source/audio.cpp index 2b2b01f..de468b4 100755 --- a/source/audio.cpp +++ b/source/audio.cpp @@ -17,7 +17,7 @@ Sample::Sample(sf::Int16 *bytes, std::size_t size, float time) : bytes(bytes), s Audio::Audio(AudioData *audio_data) { this->audio_data = audio_data; // Consume old events - this->buffer = new sf::Int16[MAX_SAMPLES_IN]; + this->buffer = new sf::Int16[MAX_SAMPLES_IN * (MAX_MAX_AUDIO_LATENCY + 1)]; this->audio_data->check_audio_restart_request(); sf::SoundStream::initialize(AUDIO_CHANNELS, SAMPLE_RATE); this->setPitch(PITCH_RATE); @@ -80,21 +80,22 @@ bool Audio::onGetData(sf::SoundStream::Chunk &data) { } data.samples = (const sf::Int16*)buffer; - while(loaded_samples > 2) { + while(loaded_samples > this->audio_data->get_max_audio_latency()) { samples.pop(); loaded_samples = samples.size(); } - const sf::Int16 *data_samples = samples.front().bytes; - int count = samples.front().size; - memcpy(buffer, data_samples, count * sizeof(sf::Int16)); + data.sampleCount = 0; - data.sampleCount = count; - - // Unused, but could be useful info - //double real_sample_rate = (1.0 / samples.front().time) * count / 2; - - samples.pop(); + for(int i = 0; i < loaded_samples; i++) { + const sf::Int16 *data_samples = samples.front().bytes; + int count = samples.front().size; + memcpy(buffer + data.sampleCount, data_samples, count * sizeof(sf::Int16)); + // Unused, but could be useful info + //double real_sample_rate = (1.0 / samples.front().time) * count / 2; + data.sampleCount += count; + samples.pop(); + } // Basically, look into how low the time between calls of the function is curr_time = std::chrono::high_resolution_clock::now(); diff --git a/source/audio_data.cpp b/source/audio_data.cpp index a3252aa..db47624 100755 --- a/source/audio_data.cpp +++ b/source/audio_data.cpp @@ -3,10 +3,20 @@ void AudioData::reset() { this->volume = 50; this->mute = false; + this->max_audio_latency = 2; this->restart_request = false; this->text_updated = false; } + +void AudioData::set_max_audio_latency(int new_value) { + if(new_value > MAX_MAX_AUDIO_LATENCY) + new_value = MAX_MAX_AUDIO_LATENCY; + if(new_value <= 0) + new_value = 1; + this->max_audio_latency = new_value; +} + void AudioData::change_audio_volume(bool is_change_positive) { bool initial_audio_mute = this->mute; int initial_audio_volume = this->volume; @@ -55,6 +65,10 @@ std::string AudioData::text_to_print() { return this->text; } +int AudioData::get_max_audio_latency() { + return this->max_audio_latency; +} + int AudioData::get_final_volume() { if(this->mute) return 0; @@ -88,6 +102,10 @@ bool AudioData::load_audio_data(std::string key, std::string value) { this->set_audio_volume(std::stoi(value)); return true; } + if (key == this->max_audio_latency_str) { + this->set_max_audio_latency(std::stoi(value)); + return true; + } return false; } @@ -95,6 +113,7 @@ std::string AudioData::save_audio_data() { std::string out_str = ""; out_str += this->mute_str + "=" + std::to_string(this->mute) + "\n"; out_str += this->volume_str + "=" + std::to_string(this->volume) + "\n"; + out_str += this->max_audio_latency_str + "=" + std::to_string(this->max_audio_latency) + "\n"; return out_str; } diff --git a/source/cc3dsfs.cpp b/source/cc3dsfs.cpp index b85e450..9fc39ae 100755 --- a/source/cc3dsfs.cpp +++ b/source/cc3dsfs.cpp @@ -26,8 +26,7 @@ #include "conversions.hpp" // Threshold to keep the audio latency limited in "amount of frames". -#define AUDIO_LATENCY_LIMIT 4 -#define NUM_CONCURRENT_AUDIO_BUFFERS ((AUDIO_LATENCY_LIMIT * 2) + 1) +#define NUM_CONCURRENT_AUDIO_BUFFERS ((MAX_MAX_AUDIO_LATENCY * 2) + 1) struct OutTextData { std::string full_text; @@ -220,7 +219,7 @@ static void soundCall(AudioData *audio_data, CaptureData* capture_data) { if((!capture_data->status.cooldown_curr_in) && (curr_out != prev_out)) { loaded_samples = audio.samples.size(); - if((capture_data->read[curr_out] > get_video_in_size(capture_data)) && (loaded_samples < AUDIO_LATENCY_LIMIT)) { + if((capture_data->read[curr_out] > get_video_in_size(capture_data)) && (loaded_samples < MAX_MAX_AUDIO_LATENCY)) { int n_samples = get_audio_n_samples(capture_data, capture_data->read[curr_out]); double out_time = capture_data->time_in_buf[curr_out]; convertAudioToOutput(&capture_data->capture_buf[curr_out], out_buf[audio_buf_counter], n_samples, endianness, capture_data);