mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 13:50:03 +00:00 
			
		
		
		
	audio_core: Implement OpenAL backend (#6450)
This commit is contained in:
		
							parent
							
								
									ce553ab995
								
							
						
					
					
						commit
						055a58f01e
					
				
					 48 changed files with 1042 additions and 576 deletions
				
			
		|  | @ -110,8 +110,6 @@ add_library(citra_core STATIC | |||
|     frontend/image_interface.cpp | ||||
|     frontend/image_interface.h | ||||
|     frontend/input.h | ||||
|     frontend/mic.cpp | ||||
|     frontend/mic.h | ||||
|     gdbstub/gdbstub.cpp | ||||
|     gdbstub/gdbstub.h | ||||
|     gdbstub/hio.cpp | ||||
|  |  | |||
|  | @ -411,8 +411,8 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window, | |||
| 
 | ||||
|     memory->SetDSP(*dsp_core); | ||||
| 
 | ||||
|     dsp_core->SetSink(Settings::values.sink_id.GetValue(), | ||||
|                       Settings::values.audio_device_id.GetValue()); | ||||
|     dsp_core->SetSink(Settings::values.output_type.GetValue(), | ||||
|                       Settings::values.output_device.GetValue()); | ||||
|     dsp_core->EnableStretching(Settings::values.enable_audio_stretching.GetValue()); | ||||
| 
 | ||||
|     telemetry_session = std::make_unique<Core::TelemetrySession>(); | ||||
|  |  | |||
|  | @ -304,6 +304,17 @@ public: | |||
|         return registered_image_interface; | ||||
|     } | ||||
| 
 | ||||
|     /// Function for checking OS microphone permissions.
 | ||||
| 
 | ||||
|     void RegisterMicPermissionCheck(const std::function<bool()>& permission_func) { | ||||
|         mic_permission_func = permission_func; | ||||
|     } | ||||
| 
 | ||||
|     [[nodiscard]] bool HasMicPermission() { | ||||
|         return !mic_permission_func || mic_permission_granted || | ||||
|                (mic_permission_granted = mic_permission_func()); | ||||
|     } | ||||
| 
 | ||||
|     void SaveState(u32 slot) const; | ||||
| 
 | ||||
|     void LoadState(u32 slot); | ||||
|  | @ -397,6 +408,9 @@ private: | |||
|     Signal current_signal; | ||||
|     u32 signal_param; | ||||
| 
 | ||||
|     std::function<bool()> mic_permission_func; | ||||
|     bool mic_permission_granted = false; | ||||
| 
 | ||||
|     friend class boost::serialization::access; | ||||
|     template <typename Archive> | ||||
|     void serialize(Archive& ar, const unsigned int file_version); | ||||
|  |  | |||
|  | @ -1,86 +0,0 @@ | |||
| // Copyright 2019 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include <array> | ||||
| #include "core/frontend/mic.h" | ||||
| 
 | ||||
| #ifdef HAVE_CUBEB | ||||
| #include "audio_core/cubeb_input.h" | ||||
| #endif | ||||
| 
 | ||||
| namespace Frontend::Mic { | ||||
| 
 | ||||
| constexpr std::array<u8, 16> NOISE_SAMPLE_8_BIT = {0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, | ||||
|                                                    0xFF, 0xF5, 0xFF, 0xFF, 0xFF, 0xFF, 0x8E, 0xFF}; | ||||
| 
 | ||||
| constexpr std::array<u8, 32> NOISE_SAMPLE_16_BIT = { | ||||
|     0x64, 0x61, 0x74, 0x61, 0x56, 0xD7, 0x00, 0x00, 0x48, 0xF7, 0x86, 0x05, 0x77, 0x1A, 0xF4, 0x1F, | ||||
|     0x28, 0x0F, 0x6B, 0xEB, 0x1C, 0xC0, 0xCB, 0x9D, 0x46, 0x90, 0xDF, 0x98, 0xEA, 0xAE, 0xB5, 0xC4}; | ||||
| 
 | ||||
| Interface::~Interface() = default; | ||||
| 
 | ||||
| void NullMic::StartSampling(const Parameters& params) { | ||||
|     parameters = params; | ||||
|     is_sampling = true; | ||||
| } | ||||
| 
 | ||||
| void NullMic::StopSampling() { | ||||
|     is_sampling = false; | ||||
| } | ||||
| 
 | ||||
| void NullMic::AdjustSampleRate(u32 sample_rate) { | ||||
|     parameters.sample_rate = sample_rate; | ||||
| } | ||||
| 
 | ||||
| Samples NullMic::Read() { | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| StaticMic::StaticMic() | ||||
|     : CACHE_8_BIT{NOISE_SAMPLE_8_BIT.begin(), NOISE_SAMPLE_8_BIT.end()}, | ||||
|       CACHE_16_BIT{NOISE_SAMPLE_16_BIT.begin(), NOISE_SAMPLE_16_BIT.end()} {} | ||||
| 
 | ||||
| StaticMic::~StaticMic() = default; | ||||
| 
 | ||||
| void StaticMic::StartSampling(const Parameters& params) { | ||||
|     sample_rate = params.sample_rate; | ||||
|     sample_size = params.sample_size; | ||||
| 
 | ||||
|     parameters = params; | ||||
|     is_sampling = true; | ||||
| } | ||||
| 
 | ||||
| void StaticMic::StopSampling() { | ||||
|     is_sampling = false; | ||||
| } | ||||
| 
 | ||||
| void StaticMic::AdjustSampleRate(u32 sample_rate) {} | ||||
| 
 | ||||
| Samples StaticMic::Read() { | ||||
|     return (sample_size == 8) ? CACHE_8_BIT : CACHE_16_BIT; | ||||
| } | ||||
| 
 | ||||
| RealMicFactory::~RealMicFactory() = default; | ||||
| 
 | ||||
| NullFactory::~NullFactory() = default; | ||||
| 
 | ||||
| std::unique_ptr<Interface> NullFactory::Create([[maybe_unused]] std::string mic_device_name) { | ||||
|     return std::make_unique<NullMic>(); | ||||
| } | ||||
| 
 | ||||
| #ifdef HAVE_CUBEB | ||||
| static std::unique_ptr<RealMicFactory> g_factory = std::make_unique<AudioCore::CubebFactory>(); | ||||
| #else | ||||
| static std::unique_ptr<RealMicFactory> g_factory = std::make_unique<NullFactory>(); | ||||
| #endif | ||||
| 
 | ||||
| void RegisterRealMicFactory(std::unique_ptr<RealMicFactory> factory) { | ||||
|     g_factory = std::move(factory); | ||||
| } | ||||
| 
 | ||||
| std::unique_ptr<Interface> CreateRealMic(std::string mic_device_name) { | ||||
|     return g_factory->Create(std::move(mic_device_name)); | ||||
| } | ||||
| 
 | ||||
| } // namespace Frontend::Mic
 | ||||
|  | @ -1,137 +0,0 @@ | |||
| // Copyright 2019 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <memory> | ||||
| #include <vector> | ||||
| #include "common/swap.h" | ||||
| #include "common/threadsafe_queue.h" | ||||
| 
 | ||||
| namespace Frontend::Mic { | ||||
| 
 | ||||
| constexpr char default_device_name[] = "Default"; | ||||
| 
 | ||||
| enum class Signedness : u8 { | ||||
|     Signed, | ||||
|     Unsigned, | ||||
| }; | ||||
| 
 | ||||
| using Samples = std::vector<u8>; | ||||
| 
 | ||||
| struct Parameters { | ||||
|     Signedness sign; | ||||
|     u8 sample_size; | ||||
|     bool buffer_loop; | ||||
|     u32 sample_rate; | ||||
|     u32 buffer_offset; | ||||
|     u32 buffer_size; | ||||
| }; | ||||
| 
 | ||||
| class Interface { | ||||
| public: | ||||
|     Interface() = default; | ||||
| 
 | ||||
|     virtual ~Interface(); | ||||
| 
 | ||||
|     /// Starts the microphone. Called by Core
 | ||||
|     virtual void StartSampling(const Parameters& params) = 0; | ||||
| 
 | ||||
|     /// Stops the microphone. Called by Core
 | ||||
|     virtual void StopSampling() = 0; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Called from the actual event timing at a constant period under a given sample rate. | ||||
|      * When sampling is enabled this function is expected to return a buffer of 16 samples in ideal | ||||
|      * conditions, but can be lax if the data is coming in from another source like a real mic. | ||||
|      */ | ||||
|     virtual Samples Read() = 0; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Adjusts the Parameters. Implementations should update the parameters field in addition to | ||||
|      * changing the mic to sample according to the new parameters. Called by Core | ||||
|      */ | ||||
|     virtual void AdjustSampleRate(u32 sample_rate) = 0; | ||||
| 
 | ||||
|     /// Value from 0 - 100 to adjust the mic gain setting. Called by Core
 | ||||
|     virtual void SetGain(u8 mic_gain) { | ||||
|         gain = mic_gain; | ||||
|     } | ||||
| 
 | ||||
|     u8 GetGain() const { | ||||
|         return gain; | ||||
|     } | ||||
| 
 | ||||
|     void SetPower(bool power) { | ||||
|         powered = power; | ||||
|     } | ||||
| 
 | ||||
|     bool GetPower() const { | ||||
|         return powered; | ||||
|     } | ||||
| 
 | ||||
|     bool IsSampling() const { | ||||
|         return is_sampling; | ||||
|     } | ||||
| 
 | ||||
|     const Parameters& GetParameters() const { | ||||
|         return parameters; | ||||
|     } | ||||
| 
 | ||||
| protected: | ||||
|     Parameters parameters; | ||||
|     u8 gain = 0; | ||||
|     bool is_sampling = false; | ||||
|     bool powered = false; | ||||
| }; | ||||
| 
 | ||||
| class NullMic final : public Interface { | ||||
| public: | ||||
|     void StartSampling(const Parameters& params) override; | ||||
| 
 | ||||
|     void StopSampling() override; | ||||
| 
 | ||||
|     void AdjustSampleRate(u32 sample_rate) override; | ||||
| 
 | ||||
|     Samples Read() override; | ||||
| }; | ||||
| 
 | ||||
| class StaticMic final : public Interface { | ||||
| public: | ||||
|     StaticMic(); | ||||
|     ~StaticMic() override; | ||||
| 
 | ||||
|     void StartSampling(const Parameters& params) override; | ||||
|     void StopSampling() override; | ||||
|     void AdjustSampleRate(u32 sample_rate) override; | ||||
| 
 | ||||
|     Samples Read() override; | ||||
| 
 | ||||
| private: | ||||
|     u16 sample_rate = 0; | ||||
|     u8 sample_size = 0; | ||||
|     std::vector<u8> CACHE_8_BIT; | ||||
|     std::vector<u8> CACHE_16_BIT; | ||||
| }; | ||||
| 
 | ||||
| /// Factory for creating a real Mic input device;
 | ||||
| class RealMicFactory { | ||||
| public: | ||||
|     virtual ~RealMicFactory(); | ||||
| 
 | ||||
|     virtual std::unique_ptr<Interface> Create(std::string mic_device_name) = 0; | ||||
| }; | ||||
| 
 | ||||
| class NullFactory final : public RealMicFactory { | ||||
| public: | ||||
|     ~NullFactory() override; | ||||
| 
 | ||||
|     std::unique_ptr<Interface> Create(std::string mic_device_name) override; | ||||
| }; | ||||
| 
 | ||||
| void RegisterRealMicFactory(std::unique_ptr<RealMicFactory> factory); | ||||
| 
 | ||||
| std::unique_ptr<Interface> CreateRealMic(std::string mic_device_name); | ||||
| 
 | ||||
| } // namespace Frontend::Mic
 | ||||
|  | @ -3,11 +3,12 @@ | |||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include <boost/serialization/weak_ptr.hpp> | ||||
| #include "audio_core/input.h" | ||||
| #include "audio_core/input_details.h" | ||||
| #include "common/archives.h" | ||||
| #include "common/logging/log.h" | ||||
| #include "common/settings.h" | ||||
| #include "core/core.h" | ||||
| #include "core/frontend/mic.h" | ||||
| #include "core/hle/ipc.h" | ||||
| #include "core/hle/ipc_helpers.h" | ||||
| #include "core/hle/kernel/event.h" | ||||
|  | @ -167,7 +168,7 @@ struct MIC_U::Impl { | |||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         Frontend::Mic::Samples samples = mic->Read(); | ||||
|         AudioCore::Samples samples = mic->Read(); | ||||
|         if (!samples.empty()) { | ||||
|             // write the samples to sharedmem page
 | ||||
|             state.WriteSamples(samples); | ||||
|  | @ -180,8 +181,8 @@ struct MIC_U::Impl { | |||
| 
 | ||||
|     void StartSampling() { | ||||
|         auto sign = encoding == Encoding::PCM8Signed || encoding == Encoding::PCM16Signed | ||||
|                         ? Frontend::Mic::Signedness::Signed | ||||
|                         : Frontend::Mic::Signedness::Unsigned; | ||||
|                         ? AudioCore::Signedness::Signed | ||||
|                         : AudioCore::Signedness::Unsigned; | ||||
|         mic->StartSampling({sign, state.sample_size, state.looped_buffer, | ||||
|                             GetSampleRateInHz(state.sample_rate), state.initial_offset, | ||||
|                             static_cast<u32>(state.size)}); | ||||
|  | @ -349,21 +350,9 @@ struct MIC_U::Impl { | |||
|     } | ||||
| 
 | ||||
|     void CreateMic() { | ||||
|         std::unique_ptr<Frontend::Mic::Interface> new_mic; | ||||
|         switch (Settings::values.mic_input_type.GetValue()) { | ||||
|         case Settings::MicInputType::None: | ||||
|             new_mic = std::make_unique<Frontend::Mic::NullMic>(); | ||||
|             break; | ||||
|         case Settings::MicInputType::Real: | ||||
|             new_mic = Frontend::Mic::CreateRealMic(Settings::values.mic_input_device.GetValue()); | ||||
|             break; | ||||
|         case Settings::MicInputType::Static: | ||||
|             new_mic = std::make_unique<Frontend::Mic::StaticMic>(); | ||||
|             break; | ||||
|         default: | ||||
|             LOG_CRITICAL(Audio, "Mic type not found. Defaulting to null mic"); | ||||
|             new_mic = std::make_unique<Frontend::Mic::NullMic>(); | ||||
|         } | ||||
|         std::unique_ptr<AudioCore::Input> new_mic = AudioCore::CreateInputFromID( | ||||
|             Settings::values.input_type.GetValue(), Settings::values.input_device.GetValue()); | ||||
| 
 | ||||
|         // If theres already a mic, copy over any data to the new mic impl
 | ||||
|         if (mic) { | ||||
|             new_mic->SetGain(mic->GetGain()); | ||||
|  | @ -386,7 +375,7 @@ struct MIC_U::Impl { | |||
|     u32 client_version = 0; | ||||
|     bool allow_shell_closed = false; | ||||
|     bool clamp = false; | ||||
|     std::unique_ptr<Frontend::Mic::Interface> mic; | ||||
|     std::unique_ptr<AudioCore::Input> mic; | ||||
|     Core::Timing& timing; | ||||
|     State state{}; | ||||
|     Encoding encoding{}; | ||||
|  |  | |||
|  | @ -26,7 +26,6 @@ | |||
| #include "common/settings.h" | ||||
| #include "core/core.h" | ||||
| #include "core/file_sys/plugin_3gx.h" | ||||
| #include "core/frontend/mic.h" | ||||
| #include "core/hle/ipc.h" | ||||
| #include "core/hle/ipc_helpers.h" | ||||
| #include "core/hle/kernel/event.h" | ||||
|  |  | |||
|  | @ -124,7 +124,8 @@ void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader) { | |||
|     Telemetry::AppendOSInfo(field_collection); | ||||
| 
 | ||||
|     // Log user configuration information
 | ||||
|     AddField(Telemetry::FieldType::UserConfig, "Audio_SinkId", Settings::values.sink_id.GetValue()); | ||||
|     AddField(Telemetry::FieldType::UserConfig, "Audio_SinkId", | ||||
|              static_cast<int>(Settings::values.output_type.GetValue())); | ||||
|     AddField(Telemetry::FieldType::UserConfig, "Audio_EnableAudioStretching", | ||||
|              Settings::values.enable_audio_stretching.GetValue()); | ||||
|     AddField(Telemetry::FieldType::UserConfig, "Core_UseCpuJit", | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue