mirror of
				https://git.suyu.dev/suyu/suyu
				synced 2025-10-31 16:09:03 -05:00 
			
		
		
		
	Merge pull request #1729 from MerryMage/null-sink
Audio Config: Implement null sink and implement sink configuration
This commit is contained in:
		| @@ -5,6 +5,7 @@ set(SRCS | |||||||
|             hle/filter.cpp |             hle/filter.cpp | ||||||
|             hle/pipe.cpp |             hle/pipe.cpp | ||||||
|             interpolate.cpp |             interpolate.cpp | ||||||
|  |             sink_details.cpp | ||||||
|             ) |             ) | ||||||
|  |  | ||||||
| set(HEADERS | set(HEADERS | ||||||
| @@ -15,7 +16,9 @@ set(HEADERS | |||||||
|             hle/filter.h |             hle/filter.h | ||||||
|             hle/pipe.h |             hle/pipe.h | ||||||
|             interpolate.h |             interpolate.h | ||||||
|  |             null_sink.h | ||||||
|             sink.h |             sink.h | ||||||
|  |             sink_details.h | ||||||
|             ) |             ) | ||||||
|  |  | ||||||
| include_directories(../../externals/soundtouch/include) | include_directories(../../externals/soundtouch/include) | ||||||
|   | |||||||
| @@ -2,9 +2,15 @@ | |||||||
| // Licensed under GPLv2 or any later version | // Licensed under GPLv2 or any later version | ||||||
| // Refer to the license.txt file included. | // Refer to the license.txt file included. | ||||||
|  |  | ||||||
|  | #include <memory> | ||||||
|  | #include <string> | ||||||
|  |  | ||||||
| #include "audio_core/audio_core.h" | #include "audio_core/audio_core.h" | ||||||
| #include "audio_core/hle/dsp.h" | #include "audio_core/hle/dsp.h" | ||||||
| #include "audio_core/hle/pipe.h" | #include "audio_core/hle/pipe.h" | ||||||
|  | #include "audio_core/null_sink.h" | ||||||
|  | #include "audio_core/sink.h" | ||||||
|  | #include "audio_core/sink_details.h" | ||||||
|  |  | ||||||
| #include "core/core_timing.h" | #include "core/core_timing.h" | ||||||
| #include "core/hle/kernel/vm_manager.h" | #include "core/hle/kernel/vm_manager.h" | ||||||
| @@ -28,7 +34,6 @@ static void AudioTickCallback(u64 /*userdata*/, int cycles_late) { | |||||||
|     CoreTiming::ScheduleEvent(audio_frame_ticks - cycles_late, tick_event); |     CoreTiming::ScheduleEvent(audio_frame_ticks - cycles_late, tick_event); | ||||||
| } | } | ||||||
|  |  | ||||||
| /// Initialise Audio |  | ||||||
| void Init() { | void Init() { | ||||||
|     DSP::HLE::Init(); |     DSP::HLE::Init(); | ||||||
|  |  | ||||||
| @@ -36,7 +41,6 @@ void Init() { | |||||||
|     CoreTiming::ScheduleEvent(audio_frame_ticks, tick_event); |     CoreTiming::ScheduleEvent(audio_frame_ticks, tick_event); | ||||||
| } | } | ||||||
|  |  | ||||||
| /// Add DSP address spaces to Process's address space. |  | ||||||
| void AddAddressSpace(Kernel::VMManager& address_space) { | void AddAddressSpace(Kernel::VMManager& address_space) { | ||||||
|     auto r0_vma = address_space.MapBackingMemory(DSP::HLE::region0_base, reinterpret_cast<u8*>(&DSP::HLE::g_regions[0]), sizeof(DSP::HLE::SharedMemory), Kernel::MemoryState::IO).MoveFrom(); |     auto r0_vma = address_space.MapBackingMemory(DSP::HLE::region0_base, reinterpret_cast<u8*>(&DSP::HLE::g_regions[0]), sizeof(DSP::HLE::SharedMemory), Kernel::MemoryState::IO).MoveFrom(); | ||||||
|     address_space.Reprotect(r0_vma, Kernel::VMAPermission::ReadWrite); |     address_space.Reprotect(r0_vma, Kernel::VMAPermission::ReadWrite); | ||||||
| @@ -45,10 +49,31 @@ void AddAddressSpace(Kernel::VMManager& address_space) { | |||||||
|     address_space.Reprotect(r1_vma, Kernel::VMAPermission::ReadWrite); |     address_space.Reprotect(r1_vma, Kernel::VMAPermission::ReadWrite); | ||||||
| } | } | ||||||
|  |  | ||||||
| /// Shutdown Audio | void SelectSink(std::string sink_id) { | ||||||
|  |     if (sink_id == "auto") { | ||||||
|  |         // Auto-select. | ||||||
|  |         // g_sink_details is ordered in terms of desirability, with the best choice at the front. | ||||||
|  |         const auto& sink_detail = g_sink_details.front(); | ||||||
|  |         DSP::HLE::SetSink(sink_detail.factory()); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     auto iter = std::find_if(g_sink_details.begin(), g_sink_details.end(), [sink_id](const auto& sink_detail) { | ||||||
|  |         return sink_detail.id == sink_id; | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     if (iter == g_sink_details.end()) { | ||||||
|  |         LOG_ERROR(Audio, "AudioCore::SelectSink given invalid sink_id"); | ||||||
|  |         DSP::HLE::SetSink(std::make_unique<NullSink>()); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     DSP::HLE::SetSink(iter->factory()); | ||||||
|  | } | ||||||
|  |  | ||||||
| void Shutdown() { | void Shutdown() { | ||||||
|     CoreTiming::UnscheduleEvent(tick_event, 0); |     CoreTiming::UnscheduleEvent(tick_event, 0); | ||||||
|     DSP::HLE::Shutdown(); |     DSP::HLE::Shutdown(); | ||||||
| } | } | ||||||
|  |  | ||||||
| } //namespace | } // namespace AudioCore | ||||||
|   | |||||||
| @@ -4,6 +4,8 @@ | |||||||
|  |  | ||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
|  | #include <string> | ||||||
|  |  | ||||||
| namespace Kernel { | namespace Kernel { | ||||||
| class VMManager; | class VMManager; | ||||||
| } | } | ||||||
| @@ -18,6 +20,9 @@ void Init(); | |||||||
| /// Add DSP address spaces to a Process. | /// Add DSP address spaces to a Process. | ||||||
| void AddAddressSpace(Kernel::VMManager& vm_manager); | void AddAddressSpace(Kernel::VMManager& vm_manager); | ||||||
|  |  | ||||||
|  | /// Select the sink to use based on sink id. | ||||||
|  | void SelectSink(std::string sink_id); | ||||||
|  |  | ||||||
| /// Shutdown Audio Core | /// Shutdown Audio Core | ||||||
| void Shutdown(); | void Shutdown(); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -2,8 +2,11 @@ | |||||||
| // Licensed under GPLv2 or any later version | // Licensed under GPLv2 or any later version | ||||||
| // Refer to the license.txt file included. | // Refer to the license.txt file included. | ||||||
|  |  | ||||||
|  | #include <memory> | ||||||
|  |  | ||||||
| #include "audio_core/hle/dsp.h" | #include "audio_core/hle/dsp.h" | ||||||
| #include "audio_core/hle/pipe.h" | #include "audio_core/hle/pipe.h" | ||||||
|  | #include "audio_core/sink.h" | ||||||
|  |  | ||||||
| namespace DSP { | namespace DSP { | ||||||
| namespace HLE { | namespace HLE { | ||||||
| @@ -35,6 +38,8 @@ static SharedMemory& WriteRegion() { | |||||||
|     return g_regions[1 - CurrentRegionIndex()]; |     return g_regions[1 - CurrentRegionIndex()]; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | static std::unique_ptr<AudioCore::Sink> sink; | ||||||
|  |  | ||||||
| void Init() { | void Init() { | ||||||
|     DSP::HLE::ResetPipes(); |     DSP::HLE::ResetPipes(); | ||||||
| } | } | ||||||
| @@ -46,5 +51,9 @@ bool Tick() { | |||||||
|     return true; |     return true; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void SetSink(std::unique_ptr<AudioCore::Sink> sink_) { | ||||||
|  |     sink = std::move(sink_); | ||||||
|  | } | ||||||
|  |  | ||||||
| } // namespace HLE | } // namespace HLE | ||||||
| } // namespace DSP | } // namespace DSP | ||||||
|   | |||||||
| @@ -6,6 +6,7 @@ | |||||||
|  |  | ||||||
| #include <array> | #include <array> | ||||||
| #include <cstddef> | #include <cstddef> | ||||||
|  | #include <memory> | ||||||
| #include <type_traits> | #include <type_traits> | ||||||
|  |  | ||||||
| #include "audio_core/hle/common.h" | #include "audio_core/hle/common.h" | ||||||
| @@ -15,6 +16,10 @@ | |||||||
| #include "common/common_types.h" | #include "common/common_types.h" | ||||||
| #include "common/swap.h" | #include "common/swap.h" | ||||||
|  |  | ||||||
|  | namespace AudioCore { | ||||||
|  | class Sink; | ||||||
|  | } | ||||||
|  |  | ||||||
| namespace DSP { | namespace DSP { | ||||||
| namespace HLE { | namespace HLE { | ||||||
|  |  | ||||||
| @@ -535,5 +540,11 @@ void Shutdown(); | |||||||
|  */ |  */ | ||||||
| bool Tick(); | bool Tick(); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Set the output sink. This must be called before calling Tick(). | ||||||
|  |  * @param sink The sink to which audio will be output to. | ||||||
|  |  */ | ||||||
|  | void SetSink(std::unique_ptr<AudioCore::Sink> sink); | ||||||
|  |  | ||||||
| } // namespace HLE | } // namespace HLE | ||||||
| } // namespace DSP | } // namespace DSP | ||||||
|   | |||||||
							
								
								
									
										29
									
								
								src/audio_core/null_sink.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/audio_core/null_sink.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | |||||||
|  | // Copyright 2016 Citra Emulator Project | ||||||
|  | // Licensed under GPLv2 or any later version | ||||||
|  | // Refer to the license.txt file included. | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include <cstddef> | ||||||
|  |  | ||||||
|  | #include "audio_core/audio_core.h" | ||||||
|  | #include "audio_core/sink.h" | ||||||
|  |  | ||||||
|  | namespace AudioCore { | ||||||
|  |  | ||||||
|  | class NullSink final : public Sink { | ||||||
|  | public: | ||||||
|  |     ~NullSink() override = default; | ||||||
|  |  | ||||||
|  |     unsigned int GetNativeSampleRate() const override { | ||||||
|  |         return native_sample_rate; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void EnqueueSamples(const std::vector<s16>&) override {} | ||||||
|  |  | ||||||
|  |     size_t SamplesInQueue() const override { | ||||||
|  |         return 0; | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | } // namespace AudioCore | ||||||
							
								
								
									
										18
									
								
								src/audio_core/sink_details.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/audio_core/sink_details.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | |||||||
|  | // Copyright 2016 Citra Emulator Project | ||||||
|  | // Licensed under GPLv2 or any later version | ||||||
|  | // Refer to the license.txt file included. | ||||||
|  |  | ||||||
|  | #include <memory> | ||||||
|  | #include <vector> | ||||||
|  |  | ||||||
|  | #include "audio_core/null_sink.h" | ||||||
|  | #include "audio_core/sink_details.h" | ||||||
|  |  | ||||||
|  | namespace AudioCore { | ||||||
|  |  | ||||||
|  | // g_sink_details is ordered in terms of desirability, with the best choice at the top. | ||||||
|  | const std::vector<SinkDetails> g_sink_details = { | ||||||
|  |     { "null", []() { return std::make_unique<NullSink>(); } }, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | } // namespace AudioCore | ||||||
							
								
								
									
										27
									
								
								src/audio_core/sink_details.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								src/audio_core/sink_details.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | |||||||
|  | // Copyright 2016 Citra Emulator Project | ||||||
|  | // Licensed under GPLv2 or any later version | ||||||
|  | // Refer to the license.txt file included. | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include <functional> | ||||||
|  | #include <memory> | ||||||
|  | #include <vector> | ||||||
|  |  | ||||||
|  | namespace AudioCore { | ||||||
|  |  | ||||||
|  | class Sink; | ||||||
|  |  | ||||||
|  | struct SinkDetails { | ||||||
|  |     SinkDetails(const char* id_, std::function<std::unique_ptr<Sink>()> factory_) | ||||||
|  |         : id(id_), factory(factory_) {} | ||||||
|  |  | ||||||
|  |     /// Name for this sink. | ||||||
|  |     const char* id; | ||||||
|  |     /// A method to call to construct an instance of this type of sink. | ||||||
|  |     std::function<std::unique_ptr<Sink>()> factory; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | extern const std::vector<SinkDetails> g_sink_details; | ||||||
|  |  | ||||||
|  | } // namespace AudioCore | ||||||
| @@ -71,6 +71,9 @@ void Config::ReadValues() { | |||||||
|     Settings::values.bg_green = (float)sdl2_config->GetReal("Renderer", "bg_green", 1.0); |     Settings::values.bg_green = (float)sdl2_config->GetReal("Renderer", "bg_green", 1.0); | ||||||
|     Settings::values.bg_blue  = (float)sdl2_config->GetReal("Renderer", "bg_blue",  1.0); |     Settings::values.bg_blue  = (float)sdl2_config->GetReal("Renderer", "bg_blue",  1.0); | ||||||
|  |  | ||||||
|  |     // Audio | ||||||
|  |     Settings::values.sink_id = sdl2_config->Get("Audio", "output_engine", "auto"); | ||||||
|  |  | ||||||
|     // Data Storage |     // Data Storage | ||||||
|     Settings::values.use_virtual_sd = sdl2_config->GetBoolean("Data Storage", "use_virtual_sd", true); |     Settings::values.use_virtual_sd = sdl2_config->GetBoolean("Data Storage", "use_virtual_sd", true); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -56,6 +56,11 @@ bg_red = | |||||||
| bg_blue = | bg_blue = | ||||||
| bg_green = | bg_green = | ||||||
|  |  | ||||||
|  | [Audio] | ||||||
|  | # Which audio output engine to use. | ||||||
|  | # auto (default): Auto-select, null: No audio output | ||||||
|  | output_engine = | ||||||
|  |  | ||||||
| [Data Storage] | [Data Storage] | ||||||
| # Whether to create a virtual SD card. | # Whether to create a virtual SD card. | ||||||
| # 1 (default): Yes, 0: No | # 1 (default): Yes, 0: No | ||||||
|   | |||||||
| @@ -52,6 +52,10 @@ void Config::ReadValues() { | |||||||
|     Settings::values.bg_blue  = qt_config->value("bg_blue",  1.0).toFloat(); |     Settings::values.bg_blue  = qt_config->value("bg_blue",  1.0).toFloat(); | ||||||
|     qt_config->endGroup(); |     qt_config->endGroup(); | ||||||
|  |  | ||||||
|  |     qt_config->beginGroup("Audio"); | ||||||
|  |     Settings::values.sink_id = qt_config->value("output_engine", "auto").toString().toStdString(); | ||||||
|  |     qt_config->endGroup(); | ||||||
|  |  | ||||||
|     qt_config->beginGroup("Data Storage"); |     qt_config->beginGroup("Data Storage"); | ||||||
|     Settings::values.use_virtual_sd = qt_config->value("use_virtual_sd", true).toBool(); |     Settings::values.use_virtual_sd = qt_config->value("use_virtual_sd", true).toBool(); | ||||||
|     qt_config->endGroup(); |     qt_config->endGroup(); | ||||||
| @@ -138,6 +142,10 @@ void Config::SaveValues() { | |||||||
|     qt_config->setValue("bg_blue",  (double)Settings::values.bg_blue); |     qt_config->setValue("bg_blue",  (double)Settings::values.bg_blue); | ||||||
|     qt_config->endGroup(); |     qt_config->endGroup(); | ||||||
|  |  | ||||||
|  |     qt_config->beginGroup("Audio"); | ||||||
|  |     qt_config->setValue("output_engine", QString::fromStdString(Settings::values.sink_id)); | ||||||
|  |     qt_config->endGroup(); | ||||||
|  |  | ||||||
|     qt_config->beginGroup("Data Storage"); |     qt_config->beginGroup("Data Storage"); | ||||||
|     qt_config->setValue("use_virtual_sd", Settings::values.use_virtual_sd); |     qt_config->setValue("use_virtual_sd", Settings::values.use_virtual_sd); | ||||||
|     qt_config->endGroup(); |     qt_config->endGroup(); | ||||||
|   | |||||||
| @@ -4,6 +4,8 @@ | |||||||
|  |  | ||||||
| #include "settings.h" | #include "settings.h" | ||||||
|  |  | ||||||
|  | #include "audio_core/audio_core.h" | ||||||
|  |  | ||||||
| #include "core/gdbstub/gdbstub.h" | #include "core/gdbstub/gdbstub.h" | ||||||
|  |  | ||||||
| #include "video_core/video_core.h" | #include "video_core/video_core.h" | ||||||
| @@ -20,6 +22,9 @@ void Apply() { | |||||||
|     VideoCore::g_hw_renderer_enabled = values.use_hw_renderer; |     VideoCore::g_hw_renderer_enabled = values.use_hw_renderer; | ||||||
|     VideoCore::g_shader_jit_enabled = values.use_shader_jit; |     VideoCore::g_shader_jit_enabled = values.use_shader_jit; | ||||||
|     VideoCore::g_scaled_resolution_enabled = values.use_scaled_resolution; |     VideoCore::g_scaled_resolution_enabled = values.use_scaled_resolution; | ||||||
|  |  | ||||||
|  |     AudioCore::SelectSink(values.sink_id); | ||||||
|  |  | ||||||
| } | } | ||||||
|  |  | ||||||
| } // namespace | } // namespace | ||||||
|   | |||||||
| @@ -63,6 +63,9 @@ struct Values { | |||||||
|  |  | ||||||
|     std::string log_filter; |     std::string log_filter; | ||||||
|  |  | ||||||
|  |     // Audio | ||||||
|  |     std::string sink_id; | ||||||
|  |  | ||||||
|     // Debugging |     // Debugging | ||||||
|     bool use_gdbstub; |     bool use_gdbstub; | ||||||
|     u16 gdbstub_port; |     u16 gdbstub_port; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 bunnei
					bunnei