diff options
Diffstat (limited to 'src/audio_core')
| -rw-r--r-- | src/audio_core/audio_renderer.cpp | 89 | ||||
| -rw-r--r-- | src/audio_core/audio_renderer.h | 49 | ||||
| -rw-r--r-- | src/audio_core/cubeb_sink.cpp | 3 | ||||
| -rw-r--r-- | src/audio_core/time_stretch.cpp | 9 | ||||
| -rw-r--r-- | src/audio_core/time_stretch.h | 1 |
5 files changed, 129 insertions, 22 deletions
diff --git a/src/audio_core/audio_renderer.cpp b/src/audio_core/audio_renderer.cpp index 6f0ff953a..23e5d3f10 100644 --- a/src/audio_core/audio_renderer.cpp +++ b/src/audio_core/audio_renderer.cpp @@ -30,7 +30,7 @@ public: return info; } - VoiceInfo& Info() { + VoiceInfo& GetInfo() { return info; } @@ -51,9 +51,30 @@ private: VoiceInfo info{}; }; +class AudioRenderer::EffectState { +public: + const EffectOutStatus& GetOutStatus() const { + return out_status; + } + + const EffectInStatus& GetInfo() const { + return info; + } + + EffectInStatus& GetInfo() { + return info; + } + + void UpdateState(); + +private: + EffectOutStatus out_status{}; + EffectInStatus info{}; +}; AudioRenderer::AudioRenderer(AudioRendererParameter params, Kernel::SharedPtr<Kernel::Event> buffer_event) - : worker_params{params}, buffer_event{buffer_event}, voices(params.voice_count) { + : worker_params{params}, buffer_event{buffer_event}, voices(params.voice_count), + effects(params.effect_count) { audio_out = std::make_unique<AudioCore::AudioOut>(); stream = audio_out->OpenStream(STREAM_SAMPLE_RATE, STREAM_NUM_CHANNELS, "AudioRenderer", @@ -96,11 +117,29 @@ std::vector<u8> AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_ memory_pool_count * sizeof(MemoryPoolInfo)); // Copy VoiceInfo structs - std::size_t offset{sizeof(UpdateDataHeader) + config.behavior_size + config.memory_pools_size + - config.voice_resource_size}; + std::size_t voice_offset{sizeof(UpdateDataHeader) + config.behavior_size + + config.memory_pools_size + config.voice_resource_size}; for (auto& voice : voices) { - std::memcpy(&voice.Info(), input_params.data() + offset, sizeof(VoiceInfo)); - offset += sizeof(VoiceInfo); + std::memcpy(&voice.GetInfo(), input_params.data() + voice_offset, sizeof(VoiceInfo)); + voice_offset += sizeof(VoiceInfo); + } + + std::size_t effect_offset{sizeof(UpdateDataHeader) + config.behavior_size + + config.memory_pools_size + config.voice_resource_size + + config.voices_size}; + for (auto& effect : effects) { + std::memcpy(&effect.GetInfo(), input_params.data() + effect_offset, sizeof(EffectInStatus)); + effect_offset += sizeof(EffectInStatus); + } + + // Update memory pool state + std::vector<MemoryPoolEntry> memory_pool(memory_pool_count); + for (std::size_t index = 0; index < memory_pool.size(); ++index) { + if (mem_pool_info[index].pool_state == MemoryPoolStates::RequestAttach) { + memory_pool[index].state = MemoryPoolStates::Attached; + } else if (mem_pool_info[index].pool_state == MemoryPoolStates::RequestDetach) { + memory_pool[index].state = MemoryPoolStates::Detached; + } } // Update voices @@ -114,14 +153,8 @@ std::vector<u8> AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_ } } - // Update memory pool state - std::vector<MemoryPoolEntry> memory_pool(memory_pool_count); - for (std::size_t index = 0; index < memory_pool.size(); ++index) { - if (mem_pool_info[index].pool_state == MemoryPoolStates::RequestAttach) { - memory_pool[index].state = MemoryPoolStates::Attached; - } else if (mem_pool_info[index].pool_state == MemoryPoolStates::RequestDetach) { - memory_pool[index].state = MemoryPoolStates::Detached; - } + for (auto& effect : effects) { + effect.UpdateState(); } // Release previous buffers and queue next ones for playback @@ -144,6 +177,14 @@ std::vector<u8> AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_ voice_out_status_offset += sizeof(VoiceOutStatus); } + std::size_t effect_out_status_offset{ + sizeof(UpdateDataHeader) + response_data.memory_pools_size + response_data.voices_size + + response_data.voice_resource_size}; + for (const auto& effect : effects) { + std::memcpy(output_params.data() + effect_out_status_offset, &effect.GetOutStatus(), + sizeof(EffectOutStatus)); + effect_out_status_offset += sizeof(EffectOutStatus); + } return output_params; } @@ -244,11 +285,29 @@ void AudioRenderer::VoiceState::RefreshBuffer() { break; } - samples = Interpolate(interp_state, std::move(samples), Info().sample_rate, STREAM_SAMPLE_RATE); + samples = + Interpolate(interp_state, std::move(samples), GetInfo().sample_rate, STREAM_SAMPLE_RATE); is_refresh_pending = false; } +void AudioRenderer::EffectState::UpdateState() { + if (info.is_new) { + out_status.state = EffectStatus::New; + } else { + if (info.type == Effect::Aux) { + ASSERT_MSG(Memory::Read32(info.aux_info.return_buffer_info) == 0, + "Aux buffers tried to update"); + ASSERT_MSG(Memory::Read32(info.aux_info.send_buffer_info) == 0, + "Aux buffers tried to update"); + ASSERT_MSG(Memory::Read32(info.aux_info.return_buffer_base) == 0, + "Aux buffers tried to update"); + ASSERT_MSG(Memory::Read32(info.aux_info.send_buffer_base) == 0, + "Aux buffers tried to update"); + } + } +} + static constexpr s16 ClampToS16(s32 value) { return static_cast<s16>(std::clamp(value, -32768, 32767)); } diff --git a/src/audio_core/audio_renderer.h b/src/audio_core/audio_renderer.h index dfef89e1d..046417da3 100644 --- a/src/audio_core/audio_renderer.h +++ b/src/audio_core/audio_renderer.h @@ -28,6 +28,16 @@ enum class PlayState : u8 { Paused = 2, }; +enum class Effect : u8 { + None = 0, + Aux = 2, +}; + +enum class EffectStatus : u8 { + None = 0, + New = 1, +}; + struct AudioRendererParameter { u32_le sample_rate; u32_le sample_count; @@ -128,6 +138,43 @@ struct VoiceOutStatus { }; static_assert(sizeof(VoiceOutStatus) == 0x10, "VoiceOutStatus has wrong size"); +struct AuxInfo { + std::array<u8, 24> input_mix_buffers; + std::array<u8, 24> output_mix_buffers; + u32_le mix_buffer_count; + u32_le sample_rate; // Stored in the aux buffer currently + u32_le sampe_count; + u64_le send_buffer_info; + u64_le send_buffer_base; + + u64_le return_buffer_info; + u64_le return_buffer_base; +}; +static_assert(sizeof(AuxInfo) == 0x60, "AuxInfo is an invalid size"); + +struct EffectInStatus { + Effect type; + u8 is_new; + u8 is_enabled; + INSERT_PADDING_BYTES(1); + u32_le mix_id; + u64_le buffer_base; + u64_le buffer_sz; + s32_le priority; + INSERT_PADDING_BYTES(4); + union { + std::array<u8, 0xa0> raw; + AuxInfo aux_info; + }; +}; +static_assert(sizeof(EffectInStatus) == 0xc0, "EffectInStatus is an invalid size"); + +struct EffectOutStatus { + EffectStatus state; + INSERT_PADDING_BYTES(0xf); +}; +static_assert(sizeof(EffectOutStatus) == 0x10, "EffectOutStatus is an invalid size"); + struct UpdateDataHeader { UpdateDataHeader() {} @@ -173,11 +220,13 @@ public: Stream::State GetStreamState() const; private: + class EffectState; class VoiceState; AudioRendererParameter worker_params; Kernel::SharedPtr<Kernel::Event> buffer_event; std::vector<VoiceState> voices; + std::vector<EffectState> effects; std::unique_ptr<AudioOut> audio_out; AudioCore::StreamPtr stream; }; diff --git a/src/audio_core/cubeb_sink.cpp b/src/audio_core/cubeb_sink.cpp index 392039688..d31a1c844 100644 --- a/src/audio_core/cubeb_sink.cpp +++ b/src/audio_core/cubeb_sink.cpp @@ -121,7 +121,8 @@ CubebSink::CubebSink(std::string target_device_name) { const auto collection_end{collection.device + collection.count}; const auto device{ std::find_if(collection.device, collection_end, [&](const cubeb_device_info& info) { - return target_device_name == info.friendly_name; + return info.friendly_name != nullptr && + target_device_name == info.friendly_name; })}; if (device != collection_end) { output_device = device->devid; diff --git a/src/audio_core/time_stretch.cpp b/src/audio_core/time_stretch.cpp index d72d67994..2fe0b3aef 100644 --- a/src/audio_core/time_stretch.cpp +++ b/src/audio_core/time_stretch.cpp @@ -10,8 +10,7 @@ namespace AudioCore { -TimeStretcher::TimeStretcher(u32 sample_rate, u32 channel_count) - : m_sample_rate(sample_rate), m_channel_count(channel_count) { +TimeStretcher::TimeStretcher(u32 sample_rate, u32 channel_count) : m_sample_rate{sample_rate} { m_sound_touch.setChannels(channel_count); m_sound_touch.setSampleRate(sample_rate); m_sound_touch.setPitch(1.0); @@ -33,10 +32,10 @@ std::size_t TimeStretcher::Process(const s16* in, std::size_t num_in, s16* out, // We were given actual_samples number of samples, and num_samples were requested from us. double current_ratio = static_cast<double>(num_in) / static_cast<double>(num_out); - const double max_latency = 1.0; // seconds + const double max_latency = 0.25; // seconds const double max_backlog = m_sample_rate * max_latency; const double backlog_fullness = m_sound_touch.numSamples() / max_backlog; - if (backlog_fullness > 5.0) { + if (backlog_fullness > 4.0) { // Too many samples in backlog: Don't push anymore on num_in = 0; } @@ -50,7 +49,7 @@ std::size_t TimeStretcher::Process(const s16* in, std::size_t num_in, s16* out, // This low-pass filter smoothes out variance in the calculated stretch ratio. // The time-scale determines how responsive this filter is. - constexpr double lpf_time_scale = 2.0; // seconds + constexpr double lpf_time_scale = 0.712; // seconds const double lpf_gain = 1.0 - std::exp(-time_delta / lpf_time_scale); m_stretch_ratio += lpf_gain * (current_ratio - m_stretch_ratio); diff --git a/src/audio_core/time_stretch.h b/src/audio_core/time_stretch.h index decd760f1..bb2270b96 100644 --- a/src/audio_core/time_stretch.h +++ b/src/audio_core/time_stretch.h @@ -27,7 +27,6 @@ public: private: u32 m_sample_rate; - u32 m_channel_count; soundtouch::SoundTouch m_sound_touch; double m_stretch_ratio = 1.0; }; |
