From 959e331c7ea3a22008e99a40382117989ef56258 Mon Sep 17 00:00:00 2001 From: Sketch <75850871+SketchMaster2001@users.noreply.github.com> Date: Tue, 6 Feb 2024 22:06:40 -0500 Subject: [PATCH 1/4] Compile for Windows --- Source/Core/Core/CMakeLists.txt | 4 + Source/Core/Core/Config/MainSettings.cpp | 3 + Source/Core/Core/Config/MainSettings.h | 1 + .../Core/Core/IOS/USB/Emulated/Microphone.cpp | 91 +++++ .../Core/Core/IOS/USB/Emulated/Microphone.h | 110 ++++++ .../Core/Core/IOS/USB/Emulated/WiiSpeak.cpp | 348 ++++++++++++++++++ Source/Core/Core/IOS/USB/Emulated/WiiSpeak.h | 95 +++++ Source/Core/Core/IOS/USB/Host.cpp | 4 + Source/Core/DolphinQt/CMakeLists.txt | 2 + .../DolphinQt/EmulatedUSB/WiiSpeakWindow.cpp | 84 +++++ .../DolphinQt/EmulatedUSB/WiiSpeakWindow.h | 34 ++ Source/Core/DolphinQt/MainWindow.cpp | 14 + Source/Core/DolphinQt/MainWindow.h | 3 + Source/Core/DolphinQt/MenuBar.cpp | 1 + Source/Core/DolphinQt/MenuBar.h | 1 + 15 files changed, 795 insertions(+) create mode 100644 Source/Core/Core/IOS/USB/Emulated/Microphone.cpp create mode 100644 Source/Core/Core/IOS/USB/Emulated/Microphone.h create mode 100644 Source/Core/Core/IOS/USB/Emulated/WiiSpeak.cpp create mode 100644 Source/Core/Core/IOS/USB/Emulated/WiiSpeak.h create mode 100644 Source/Core/DolphinQt/EmulatedUSB/WiiSpeakWindow.cpp create mode 100644 Source/Core/DolphinQt/EmulatedUSB/WiiSpeakWindow.h diff --git a/Source/Core/Core/CMakeLists.txt b/Source/Core/Core/CMakeLists.txt index 1dcbc14ce7ba..14b4424a767c 100644 --- a/Source/Core/Core/CMakeLists.txt +++ b/Source/Core/Core/CMakeLists.txt @@ -419,12 +419,16 @@ add_library(core IOS/USB/Common.h IOS/USB/Emulated/Infinity.cpp IOS/USB/Emulated/Infinity.h + IOS/USB/Emulated/Microphone.cpp + IOS/USB/Emulated/Microphone.h IOS/USB/Emulated/Skylanders/Skylander.cpp IOS/USB/Emulated/Skylanders/Skylander.h IOS/USB/Emulated/Skylanders/SkylanderCrypto.cpp IOS/USB/Emulated/Skylanders/SkylanderCrypto.h IOS/USB/Emulated/Skylanders/SkylanderFigure.cpp IOS/USB/Emulated/Skylanders/SkylanderFigure.h + IOS/USB/Emulated/WiiSpeak.cpp + IOS/USB/Emulated/WiiSpeak.h IOS/USB/Host.cpp IOS/USB/Host.h IOS/USB/OH0/OH0.cpp diff --git a/Source/Core/Core/Config/MainSettings.cpp b/Source/Core/Core/Config/MainSettings.cpp index 21c453b6c775..2ae286cff085 100644 --- a/Source/Core/Core/Config/MainSettings.cpp +++ b/Source/Core/Core/Config/MainSettings.cpp @@ -566,6 +566,9 @@ const Info MAIN_EMULATE_SKYLANDER_PORTAL{ const Info MAIN_EMULATE_INFINITY_BASE{ {System::Main, "EmulatedUSBDevices", "EmulateInfinityBase"}, false}; +const Info MAIN_EMULATE_WII_SPEAK{{System::Main, "EmulatedUSBDevices", "EmulateWiiSpeak"}, + false}; + // The reason we need this function is because some memory card code // expects to get a non-NTSC-K region even if we're emulating an NTSC-K Wii. DiscIO::Region ToGameCubeRegion(DiscIO::Region region) diff --git a/Source/Core/Core/Config/MainSettings.h b/Source/Core/Core/Config/MainSettings.h index dddda8ae7a3b..226325f96038 100644 --- a/Source/Core/Core/Config/MainSettings.h +++ b/Source/Core/Core/Config/MainSettings.h @@ -351,6 +351,7 @@ void SetUSBDeviceWhitelist(const std::set>& devices); extern const Info MAIN_EMULATE_SKYLANDER_PORTAL; extern const Info MAIN_EMULATE_INFINITY_BASE; +extern const Info MAIN_EMULATE_WII_SPEAK; // GameCube path utility functions diff --git a/Source/Core/Core/IOS/USB/Emulated/Microphone.cpp b/Source/Core/Core/IOS/USB/Emulated/Microphone.cpp new file mode 100644 index 000000000000..62a886e3b796 --- /dev/null +++ b/Source/Core/Core/IOS/USB/Emulated/Microphone.cpp @@ -0,0 +1,91 @@ +// +// Created by Noah Pistilli on 2023-07-09. +// + +#include "Microphone.h" +#include "Common/swap.h" + +#include + +namespace IOS::HLE::USB +{ +std::vector Microphone::ListDevices() +{ + std::vector devices{}; + const ALchar* pDeviceList = alcGetString(nullptr, ALC_CAPTURE_DEVICE_SPECIFIER); + while (*pDeviceList) + { + devices.emplace_back(pDeviceList); + pDeviceList += strlen(pDeviceList) + 1; + } + + return devices; +} + +int Microphone::OpenMicrophone() +{ + m_device = alcCaptureOpenDevice(nullptr, SAMPLING_RATE, AL_FORMAT_MONO16, BUFFER_SIZE); + m_dsp_data.resize(BUFFER_SIZE, 0); + m_temp_buffer.resize(BUFFER_SIZE, 0); + return static_cast(alcGetError(m_device)); +} + +int Microphone::StartCapture() +{ + alcCaptureStart(m_device); + return static_cast(alcGetError(m_device)); +} + +void Microphone::StopCapture() +{ + alcCaptureStop(m_device); +} + +void Microphone::PerformAudioCapture() +{ + m_num_of_samples = BUFFER_SIZE / 2; + + ALCint samples_in{}; + alcGetIntegerv(m_device, ALC_CAPTURE_SAMPLES, 1, &samples_in); + m_num_of_samples = std::min(m_num_of_samples, static_cast(samples_in)); + + if (m_num_of_samples == 0) + return; + + alcCaptureSamples(m_device, m_dsp_data.data(), m_num_of_samples); +} + +void Microphone::ByteSwap(const void* src, void* dst) const +{ + *static_cast(dst) = Common::swap16(*static_cast(src)); +} + +void Microphone::GetSoundData() +{ + if (m_num_of_samples == 0) + return; + + u8* ptr = const_cast(m_temp_buffer.data()); + // Convert LE to BE + for (u32 i = 0; i < m_num_of_samples; i++) + { + for (u32 indchan = 0; indchan < 1; indchan++) + { + const u32 curindex = (i * 2) + indchan * (16 / 8); + ByteSwap(m_dsp_data.data() + curindex, ptr + curindex); + } + } + + m_rbuf_dsp.write_bytes(ptr, m_num_of_samples * 2); +} + +void Microphone::ReadIntoBuffer(u8* dst, u32 size) +{ + m_rbuf_dsp.read_bytes(dst, size); +} + +bool Microphone::HasData() const +{ + return m_num_of_samples != 0; +} +} // namespace IOS::HLE::USB \ No newline at end of file diff --git a/Source/Core/Core/IOS/USB/Emulated/Microphone.h b/Source/Core/Core/IOS/USB/Emulated/Microphone.h new file mode 100644 index 000000000000..daa1d175d623 --- /dev/null +++ b/Source/Core/Core/IOS/USB/Emulated/Microphone.h @@ -0,0 +1,110 @@ +#pragma once + +#include +#include + +#include +#include + +#include "Common/CommonTypes.h" + +namespace IOS::HLE::USB +{ +template +class simple_ringbuf +{ +public: + simple_ringbuf() { m_container.resize(S); } + + bool has_data() const { return m_used != 0; } + + u32 read_bytes(u8* buf, const u32 size) + { + u32 to_read = size > m_used ? m_used : size; + if (!to_read) + return 0; + + u8* data = m_container.data(); + u32 new_tail = m_tail + to_read; + + if (new_tail >= S) + { + u32 first_chunk_size = S - m_tail; + std::memcpy(buf, data + m_tail, first_chunk_size); + std::memcpy(buf + first_chunk_size, data, to_read - first_chunk_size); + m_tail = (new_tail - S); + } + else + { + std::memcpy(buf, data + m_tail, to_read); + m_tail = new_tail; + } + + m_used -= to_read; + + return to_read; + } + + void write_bytes(const u8* buf, const u32 size) + { + if (u32 over_size = m_used + size; over_size > S) + { + m_tail += (over_size - S); + if (m_tail > S) + m_tail -= S; + + m_used = S; + } + else + { + m_used = over_size; + } + + u8* data = m_container.data(); + u32 new_head = m_head + size; + + if (new_head >= S) + { + u32 first_chunk_size = S - m_head; + std::memcpy(data + m_head, buf, first_chunk_size); + std::memcpy(data, buf + first_chunk_size, size - first_chunk_size); + m_head = (new_head - S); + } + else + { + std::memcpy(data + m_head, buf, size); + m_head = new_head; + } + } + +protected: + std::vector m_container; + u32 m_head = 0, m_tail = 0, m_used = 0; +}; + +class Microphone final +{ +public: + static std::vector ListDevices(); + + int OpenMicrophone(); + int StartCapture(); + void StopCapture(); + void PerformAudioCapture(); + void GetSoundData(); + void ReadIntoBuffer(u8* dst, u32 size); + bool HasData() const; + +private: + void ByteSwap(const void* src, void* dst) const; + + static constexpr u32 SAMPLING_RATE = 8000; + static constexpr u32 BUFFER_SIZE = SAMPLING_RATE / 2; + + ALCdevice* m_device; + u32 m_num_of_samples{}; + std::vector m_dsp_data{}; + std::vector m_temp_buffer{}; + simple_ringbuf m_rbuf_dsp; +}; +} // namespace IOS::HLE::USB diff --git a/Source/Core/Core/IOS/USB/Emulated/WiiSpeak.cpp b/Source/Core/Core/IOS/USB/Emulated/WiiSpeak.cpp new file mode 100644 index 000000000000..ad3427ad6416 --- /dev/null +++ b/Source/Core/Core/IOS/USB/Emulated/WiiSpeak.cpp @@ -0,0 +1,348 @@ +// Copyright 2023 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "Core/IOS/USB/Emulated/WiiSpeak.h" +#include "Core/HW/Memmap.h" +#include "Core/System.h" + +namespace IOS::HLE::USB +{ +WiiSpeak::WiiSpeak(IOS::HLE::EmulationKernel& ios, const std::string& device_name) : m_ios(ios) +{ + m_vid = 0x57E; + m_pid = 0x0308; + m_id = (u64(m_vid) << 32 | u64(m_pid) << 16 | u64(9) << 8 | u64(1)); + m_device_descriptor = + DeviceDescriptor{0x12, 0x1, 0x200, 0, 0, 0, 0x10, 0x57E, 0x0308, 0x0214, 0x1, 0x2, 0x0, 0x1}; + m_config_descriptor.emplace_back(ConfigDescriptor{0x9, 0x2, 0x0030, 0x1, 0x1, 0x0, 0x80, 0x32}); + m_interface_descriptor.emplace_back( + InterfaceDescriptor{0x9, 0x4, 0x0, 0x0, 0x0, 0xFF, 0xFF, 0xFF, 0x0}); + m_interface_descriptor.emplace_back( + InterfaceDescriptor{0x9, 0x4, 0x0, 0x01, 0x03, 0xFF, 0xFF, 0xFF, 0x0}); + m_endpoint_descriptor.emplace_back(EndpointDescriptor{0x7, 0x5, 0x81, 0x1, 0x0020, 0x1}); + m_endpoint_descriptor.emplace_back(EndpointDescriptor{0x7, 0x5, 0x2, 0x2, 0x0020, 0}); + m_endpoint_descriptor.emplace_back(EndpointDescriptor{0x7, 0x5, 0x3, 0x1, 0x0040, 1}); + + m_microphone = Microphone(); + m_microphone.OpenMicrophone(); + m_microphone.StartCapture(); + + m_microphone_thread = std::thread([this] { + u64 timeout{}; + constexpr u64 TIMESTEP = 256ull * 1'000'000ull / 48000ull; + while (true) + { + if (m_shutdown_event.WaitFor(std::chrono::microseconds{timeout})) + return; + + std::lock_guard lg(m_mutex); + timeout = TIMESTEP - (std::chrono::duration_cast( + std::chrono::steady_clock::now().time_since_epoch()) + .count() % + TIMESTEP); + m_microphone.PerformAudioCapture(); + m_microphone.GetSoundData(); + } + }); +} + +WiiSpeak::~WiiSpeak() +{ + { + std::lock_guard lg(m_mutex); + if (!m_microphone_thread.joinable()) + return; + + m_shutdown_event.Set(); + } + + m_microphone_thread.join(); + m_microphone.StopCapture(); +} + +DeviceDescriptor WiiSpeak::GetDeviceDescriptor() const +{ + return m_device_descriptor; +} + +std::vector WiiSpeak::GetConfigurations() const +{ + return m_config_descriptor; +} + +std::vector WiiSpeak::GetInterfaces(u8 config) const +{ + return m_interface_descriptor; +} + +std::vector WiiSpeak::GetEndpoints(u8 config, u8 interface, u8 alt) const +{ + return m_endpoint_descriptor; +} + +bool WiiSpeak::Attach() +{ + if (m_device_attached) + return true; + + DEBUG_LOG_FMT(IOS_USB, "[{:04x}:{:04x}] Opening device", m_vid, m_pid); + m_device_attached = true; + return true; +} + +bool WiiSpeak::AttachAndChangeInterface(const u8 interface) +{ + if (!Attach()) + return false; + + if (interface != m_active_interface) + return ChangeInterface(interface) == 0; + + return true; +} + +int WiiSpeak::CancelTransfer(const u8 endpoint) +{ + INFO_LOG_FMT(IOS_USB, "[{:04x}:{:04x} {}] Cancelling transfers (endpoint {:#x})", m_vid, m_pid, + m_active_interface, endpoint); + + return IPC_SUCCESS; +} + +int WiiSpeak::ChangeInterface(const u8 interface) +{ + DEBUG_LOG_FMT(IOS_USB, "[{:04x}:{:04x} {}] Changing interface to {}", m_vid, m_pid, + m_active_interface, interface); + m_active_interface = interface; + return 0; +} + +int WiiSpeak::GetNumberOfAltSettings(u8 interface) +{ + return 0; +} + +int WiiSpeak::SetAltSetting(u8 alt_setting) +{ + return 0; +} + +int WiiSpeak::SubmitTransfer(std::unique_ptr cmd) +{ + DEBUG_LOG_FMT(IOS_USB, + "[{:04x}:{:04x} {}] Control: bRequestType={:02x} bRequest={:02x} wValue={:04x}" + " wIndex={:04x} wLength={:04x}", + m_vid, m_pid, m_active_interface, cmd->request_type, cmd->request, cmd->value, + cmd->index, cmd->length); + + switch (cmd->request_type << 8 | cmd->request) + { + case USBHDR(DIR_DEVICE2HOST, TYPE_STANDARD, REC_INTERFACE, REQUEST_GET_INTERFACE): + { + std::array data{1}; + cmd->FillBuffer(data.data(), 1); + cmd->ScheduleTransferCompletion(1, 100); + break; + } + case USBHDR(DIR_HOST2DEVICE, TYPE_VENDOR, REC_INTERFACE, 0): + { + init = false; + m_ios.EnqueueIPCReply(cmd->ios_request, IPC_SUCCESS); + break; + } + case USBHDR(DIR_DEVICE2HOST, TYPE_VENDOR, REC_INTERFACE, REQUEST_GET_DESCRIPTOR): + { + if (!init) + { + std::array data{0}; + cmd->FillBuffer(data.data(), 1); + m_ios.EnqueueIPCReply(cmd->ios_request, IPC_SUCCESS); + init = true; + } + else + { + std::array data{1}; + cmd->FillBuffer(data.data(), 1); + m_ios.EnqueueIPCReply(cmd->ios_request, IPC_SUCCESS); + } + break; + } + case USBHDR(DIR_HOST2DEVICE, TYPE_VENDOR, REC_INTERFACE, 1): + SetRegister(cmd); + m_ios.EnqueueIPCReply(cmd->ios_request, IPC_SUCCESS); + break; + case USBHDR(DIR_DEVICE2HOST, TYPE_VENDOR, REC_INTERFACE, 2): + GetRegister(cmd); + m_ios.EnqueueIPCReply(cmd->ios_request, IPC_SUCCESS); + break; + default: + NOTICE_LOG_FMT(IOS_USB, "Unknown command"); + m_ios.EnqueueIPCReply(cmd->ios_request, IPC_SUCCESS); + } + + return IPC_SUCCESS; +}; +int WiiSpeak::SubmitTransfer(std::unique_ptr cmd) +{ + m_ios.EnqueueIPCReply(cmd->ios_request, IPC_SUCCESS); + return IPC_SUCCESS; +}; +int WiiSpeak::SubmitTransfer(std::unique_ptr cmd) +{ + m_ios.EnqueueIPCReply(cmd->ios_request, IPC_SUCCESS); + return IPC_SUCCESS; +}; + +int WiiSpeak::SubmitTransfer(std::unique_ptr cmd) +{ + auto& system = m_ios.GetSystem(); + auto& memory = system.GetMemory(); + + u8* packets = memory.GetPointer(cmd->data_address); + if (cmd->endpoint == 0x81 && m_microphone.HasData()) + m_microphone.ReadIntoBuffer(packets, cmd->length); + + // Anything more causes the visual cue to not appear. + // Anything less is more choppy audio. + cmd->ScheduleTransferCompletion(IPC_SUCCESS, 20000); + return IPC_SUCCESS; +}; + +void WiiSpeak::SetRegister(std::unique_ptr& cmd) +{ + auto& system = m_ios.GetSystem(); + auto& memory = system.GetMemory(); + const u8 reg = memory.Read_U8(cmd->data_address + 1) & ~1; + const u16 arg1 = memory.Read_U16(cmd->data_address + 2); + const u16 arg2 = memory.Read_U16(cmd->data_address + 4); + + switch (reg) + { + case SAMPLER_STATE: + sampler.sample_on = !!arg1; + break; + case SAMPLER_FREQ: + switch (arg1) + { + case FREQ_8KHZ: + sampler.freq = 8000; + break; + case FREQ_11KHZ: + sampler.freq = 11025; + break; + case FREQ_RESERVED: + case FREQ_16KHZ: + default: + sampler.freq = 16000; + break; + } + break; + case SAMPLER_GAIN: + switch (arg1 & ~0x300) + { + case GAIN_00dB: + sampler.gain = 0; + break; + case GAIN_15dB: + sampler.gain = 15; + break; + case GAIN_30dB: + sampler.gain = 30; + break; + case GAIN_36dB: + default: + sampler.gain = 36; + break; + } + break; + case EC_STATE: + sampler.ec_reset = !!arg1; + break; + case SP_STATE: + switch (arg1) + { + case SP_ENABLE: + sampler.sp_on = arg2 == 0; + break; + case SP_SIN: + case SP_SOUT: + case SP_RIN: + break; + } + break; + case SAMPLER_MUTE: + sampler.mute = !!arg1; + break; + } +} + +void WiiSpeak::GetRegister(std::unique_ptr& cmd) +{ + auto& system = m_ios.GetSystem(); + auto& memory = system.GetMemory(); + const u8 reg = memory.Read_U8(cmd->data_address + 1) & ~1; + const u32 arg1 = cmd->data_address + 2; + const u32 arg2 = cmd->data_address + 4; + + switch (reg) + { + case SAMPLER_STATE: + memory.Write_U16(sampler.sample_on ? 1 : 0, arg1); + break; + case SAMPLER_FREQ: + switch (sampler.freq) + { + case 8000: + memory.Write_U16(FREQ_8KHZ, arg1); + break; + case 11025: + memory.Write_U16(FREQ_11KHZ, arg1); + break; + case 16000: + default: + memory.Write_U16(FREQ_16KHZ, arg1); + break; + } + break; + case SAMPLER_GAIN: + switch (sampler.gain) + { + case 0: + memory.Write_U16(0x300 | GAIN_00dB, arg1); + break; + case 15: + memory.Write_U16(0x300 | GAIN_15dB, arg1); + break; + case 30: + memory.Write_U16(0x300 | GAIN_30dB, arg1); + break; + case 36: + default: + memory.Write_U16(0x300 | GAIN_36dB, arg1); + break; + } + break; + case EC_STATE: + memory.Write_U16(sampler.ec_reset ? 1 : 0, arg1); + break; + case SP_STATE: + switch (memory.Read_U16(arg1)) + { + case SP_ENABLE: + memory.Write_U16(1, arg2); + break; + case SP_SIN: + break; + case SP_SOUT: + memory.Write_U16(0x39B0, arg2); // 6dB + break; + case SP_RIN: + break; + } + break; + case SAMPLER_MUTE: + memory.Write_U16(sampler.mute ? 1 : 0, arg1); + break; + } +} +} // namespace IOS::HLE::USB \ No newline at end of file diff --git a/Source/Core/Core/IOS/USB/Emulated/WiiSpeak.h b/Source/Core/Core/IOS/USB/Emulated/WiiSpeak.h new file mode 100644 index 000000000000..e3e1ed776fdb --- /dev/null +++ b/Source/Core/Core/IOS/USB/Emulated/WiiSpeak.h @@ -0,0 +1,95 @@ +// Copyright 2023 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include + +#include "Common/CommonTypes.h" +#include "Common/Event.h" +#include "Common/WorkQueueThread.h" +#include "Core/HW/Memmap.h" +#include "Core/IOS/USB/Common.h" +#include "Core/IOS/USB/Emulated/Microphone.h" +#include "Core/System.h" + +namespace IOS::HLE::USB +{ +class WiiSpeak final : public Device +{ +public: + WiiSpeak(EmulationKernel& ios, const std::string& device_name); + ~WiiSpeak(); + DeviceDescriptor GetDeviceDescriptor() const override; + std::vector GetConfigurations() const override; + std::vector GetInterfaces(u8 config) const override; + std::vector GetEndpoints(u8 config, u8 interface, u8 alt) const override; + bool Attach() override; + bool AttachAndChangeInterface(u8 interface) override; + int CancelTransfer(u8 endpoint) override; + int ChangeInterface(u8 interface) override; + int GetNumberOfAltSettings(u8 interface) override; + int SetAltSetting(u8 alt_setting) override; + int SubmitTransfer(std::unique_ptr message) override; + int SubmitTransfer(std::unique_ptr message) override; + int SubmitTransfer(std::unique_ptr message) override; + int SubmitTransfer(std::unique_ptr message) override; + +private: + struct WSState + { + bool sample_on; + bool mute; + int freq; + int gain; + bool ec_reset; + bool sp_on; + }; + + WSState sampler{}; + + enum Registers + { + SAMPLER_STATE = 0, + SAMPLER_MUTE = 0xc0, + + SAMPLER_FREQ = 2, + FREQ_8KHZ = 0, + FREQ_11KHZ = 1, + FREQ_RESERVED = 2, + FREQ_16KHZ = 3, // default + + SAMPLER_GAIN = 4, + GAIN_00dB = 0, + GAIN_15dB = 1, + GAIN_30dB = 2, + GAIN_36dB = 3, // default + + EC_STATE = 0x14, + + SP_STATE = 0x38, + SP_ENABLE = 0x1010, + SP_SIN = 0x2001, + SP_SOUT = 0x2004, + SP_RIN = 0x200d + }; + + void GetRegister(std::unique_ptr& cmd); + void SetRegister(std::unique_ptr& cmd); + + EmulationKernel& m_ios; + u16 m_vid = 0; + u16 m_pid = 0; + u8 m_active_interface = 0; + bool m_device_attached = false; + bool init = false; + Microphone m_microphone; + DeviceDescriptor m_device_descriptor{}; + std::vector m_config_descriptor; + std::vector m_interface_descriptor; + std::vector m_endpoint_descriptor; + std::thread m_microphone_thread; + std::mutex m_mutex; + Common::Event m_shutdown_event; +}; +} // namespace IOS::HLE::USB \ No newline at end of file diff --git a/Source/Core/Core/IOS/USB/Host.cpp b/Source/Core/Core/IOS/USB/Host.cpp index c2641932ac57..330000ef74a5 100644 --- a/Source/Core/Core/IOS/USB/Host.cpp +++ b/Source/Core/Core/IOS/USB/Host.cpp @@ -24,6 +24,7 @@ #include "Core/IOS/USB/Common.h" #include "Core/IOS/USB/Emulated/Infinity.h" #include "Core/IOS/USB/Emulated/Skylanders/Skylander.h" +#include "Core/IOS/USB/Emulated/WiiSpeak.h" #include "Core/IOS/USB/LibusbDevice.h" #include "Core/NetPlayProto.h" #include "Core/System.h" @@ -196,6 +197,9 @@ void USBHost::AddEmulatedDevices(std::set& new_devices, DeviceChangeHooks& auto infinity_base = std::make_unique(GetEmulationKernel(), "Infinity Base"); CheckAndAddDevice(std::move(infinity_base), new_devices, hooks, always_add_hooks); } + + auto wii_speak = std::make_unique(GetEmulationKernel(), "Wii Speak"); + CheckAndAddDevice(std::move(wii_speak), new_devices, hooks, always_add_hooks); } void USBHost::CheckAndAddDevice(std::unique_ptr device, std::set& new_devices, diff --git a/Source/Core/DolphinQt/CMakeLists.txt b/Source/Core/DolphinQt/CMakeLists.txt index 8285c17d4ae7..caad6d804806 100644 --- a/Source/Core/DolphinQt/CMakeLists.txt +++ b/Source/Core/DolphinQt/CMakeLists.txt @@ -240,6 +240,8 @@ add_executable(dolphin-emu DiscordHandler.h DiscordJoinRequestDialog.cpp DiscordJoinRequestDialog.h + EmulatedUSB/WiiSpeakWindow.cpp + EmulatedUSB/WiiSpeakWindow.h FIFO/FIFOAnalyzer.cpp FIFO/FIFOAnalyzer.h FIFO/FIFOPlayerWindow.cpp diff --git a/Source/Core/DolphinQt/EmulatedUSB/WiiSpeakWindow.cpp b/Source/Core/DolphinQt/EmulatedUSB/WiiSpeakWindow.cpp new file mode 100644 index 000000000000..f3770047a77e --- /dev/null +++ b/Source/Core/DolphinQt/EmulatedUSB/WiiSpeakWindow.cpp @@ -0,0 +1,84 @@ +// Copyright 2023 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "DolphinQt/EmulatedUSB/WiiSpeakWindow.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Common/IOFile.h" + +#include "Core/Config/MainSettings.h" +#include "Core/Core.h" +#include "Core/IOS/USB/Emulated/Microphone.h" +#include "Core/System.h" + +#include "DolphinQt/QtUtils/DolphinFileDialog.h" +#include "DolphinQt/Settings.h" + +WiiSpeakWindow::WiiSpeakWindow(QWidget* parent) : QWidget(parent) +{ + setWindowTitle(tr("Wii Speak Manager")); + setObjectName(QStringLiteral("wii_speak_manager")); + setMinimumSize(QSize(700, 200)); + + CreateMainWindow(); + + connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, + &WiiSpeakWindow::OnEmulationStateChanged); + + installEventFilter(this); + + OnEmulationStateChanged(Core::GetState()); +}; + +WiiSpeakWindow::~WiiSpeakWindow() = default; + +void WiiSpeakWindow::CreateMainWindow() +{ + auto* main_layout = new QVBoxLayout(); + + auto* checkbox_group = new QGroupBox(); + auto* checkbox_layout = new QHBoxLayout(); + checkbox_layout->setAlignment(Qt::AlignLeft); + m_checkbox = new QCheckBox(tr("Emulate Wii Speak"), this); + m_checkbox->setChecked(Config::Get(Config::MAIN_EMULATE_WII_SPEAK)); + connect(m_checkbox, &QCheckBox::toggled, this, &WiiSpeakWindow::EmulateWiiSpeak); + checkbox_layout->addWidget(m_checkbox); + checkbox_group->setLayout(checkbox_layout); + + m_combobox_microphones = new QComboBox(); + for (const std::string& device : IOS::HLE::USB::Microphone::ListDevices()) + { + m_combobox_microphones->addItem(QString::fromStdString(device)); + } + + checkbox_layout->addWidget(m_combobox_microphones); + + main_layout->addWidget(checkbox_group); + setLayout(main_layout); +} + +void WiiSpeakWindow::EmulateWiiSpeak(bool emulate) +{ + Config::SetBaseOrCurrent(Config::MAIN_EMULATE_WII_SPEAK, emulate); +} + +void WiiSpeakWindow::OnEmulationStateChanged(Core::State state) +{ + const bool running = state != Core::State::Uninitialized; + + m_checkbox->setEnabled(!running); +} diff --git a/Source/Core/DolphinQt/EmulatedUSB/WiiSpeakWindow.h b/Source/Core/DolphinQt/EmulatedUSB/WiiSpeakWindow.h new file mode 100644 index 000000000000..f37c82be96d4 --- /dev/null +++ b/Source/Core/DolphinQt/EmulatedUSB/WiiSpeakWindow.h @@ -0,0 +1,34 @@ +// Copyright 2023 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include + +#include +#include + +#include "Common/CommonTypes.h" +#include "Core/Core.h" + +class QCheckBox; +class QGroupBox; +class QLineEdit; +class QVBoxLayout; +class QComboBox; + +class WiiSpeakWindow : public QWidget +{ + Q_OBJECT +public: + explicit WiiSpeakWindow(QWidget* parent = nullptr); + ~WiiSpeakWindow() override; + +private: + void CreateMainWindow(); + void OnEmulationStateChanged(Core::State state); + void EmulateWiiSpeak(bool emulate); + + QCheckBox* m_checkbox; + QComboBox* m_combobox_microphones; +}; diff --git a/Source/Core/DolphinQt/MainWindow.cpp b/Source/Core/DolphinQt/MainWindow.cpp index 72b075f12b44..6996ef83a0b3 100644 --- a/Source/Core/DolphinQt/MainWindow.cpp +++ b/Source/Core/DolphinQt/MainWindow.cpp @@ -92,6 +92,7 @@ #include "DolphinQt/Debugger/ThreadWidget.h" #include "DolphinQt/Debugger/WatchWidget.h" #include "DolphinQt/DiscordHandler.h" +#include "DolphinQt/EmulatedUSB/WiiSpeakWindow.h" #include "DolphinQt/FIFO/FIFOPlayerWindow.h" #include "DolphinQt/GCMemcardManager.h" #include "DolphinQt/GameList/GameList.h" @@ -558,6 +559,7 @@ void MainWindow::ConnectMenuBar() connect(m_menu_bar, &MenuBar::ShowFIFOPlayer, this, &MainWindow::ShowFIFOPlayer); connect(m_menu_bar, &MenuBar::ShowSkylanderPortal, this, &MainWindow::ShowSkylanderPortal); connect(m_menu_bar, &MenuBar::ShowInfinityBase, this, &MainWindow::ShowInfinityBase); + connect(m_menu_bar, &MenuBar::ShowWiiSpeakWindow, this, &MainWindow::ShowWiiSpeakWindow); connect(m_menu_bar, &MenuBar::ConnectWiiRemote, this, &MainWindow::OnConnectWiiRemote); #ifdef USE_RETRO_ACHIEVEMENTS @@ -1402,6 +1404,18 @@ void MainWindow::ShowInfinityBase() m_infinity_window->activateWindow(); } +void MainWindow::ShowWiiSpeakWindow() +{ + if (!m_wii_speak_window) + { + m_wii_speak_window = new WiiSpeakWindow(); + } + + m_wii_speak_window->show(); + m_wii_speak_window->raise(); + m_wii_speak_window->activateWindow(); +} + void MainWindow::StateLoad() { QString path = diff --git a/Source/Core/DolphinQt/MainWindow.h b/Source/Core/DolphinQt/MainWindow.h index ede238012518..28027f32eb31 100644 --- a/Source/Core/DolphinQt/MainWindow.h +++ b/Source/Core/DolphinQt/MainWindow.h @@ -52,6 +52,7 @@ class ThreadWidget; class ToolBar; class WatchWidget; class WiiTASInputWindow; +class WiiSpeakWindow; struct WindowSystemInfo; namespace DiscIO @@ -169,6 +170,7 @@ class MainWindow final : public QMainWindow void ShowFIFOPlayer(); void ShowSkylanderPortal(); void ShowInfinityBase(); + void ShowWiiSpeakWindow(); void ShowMemcardManager(); void ShowResourcePackManager(); void ShowCheatsManager(); @@ -244,6 +246,7 @@ class MainWindow final : public QMainWindow FIFOPlayerWindow* m_fifo_window = nullptr; SkylanderPortalWindow* m_skylander_window = nullptr; InfinityBaseWindow* m_infinity_window = nullptr; + WiiSpeakWindow* m_wii_speak_window = nullptr; MappingWindow* m_hotkey_window = nullptr; FreeLookWindow* m_freelook_window = nullptr; diff --git a/Source/Core/DolphinQt/MenuBar.cpp b/Source/Core/DolphinQt/MenuBar.cpp index 07d4d21cbb7d..003306a94388 100644 --- a/Source/Core/DolphinQt/MenuBar.cpp +++ b/Source/Core/DolphinQt/MenuBar.cpp @@ -237,6 +237,7 @@ void MenuBar::AddToolsMenu() auto* usb_device_menu = new QMenu(tr("Emulated USB Devices"), tools_menu); usb_device_menu->addAction(tr("&Skylanders Portal"), this, &MenuBar::ShowSkylanderPortal); usb_device_menu->addAction(tr("&Infinity Base"), this, &MenuBar::ShowInfinityBase); + usb_device_menu->addAction(tr("&Wii Speak"), this, &MenuBar::ShowWiiSpeakWindow); tools_menu->addMenu(usb_device_menu); tools_menu->addSeparator(); diff --git a/Source/Core/DolphinQt/MenuBar.h b/Source/Core/DolphinQt/MenuBar.h index d13e8ae4b310..9061d184daab 100644 --- a/Source/Core/DolphinQt/MenuBar.h +++ b/Source/Core/DolphinQt/MenuBar.h @@ -91,6 +91,7 @@ class MenuBar final : public QMenuBar void ShowResourcePackManager(); void ShowSkylanderPortal(); void ShowInfinityBase(); + void ShowWiiSpeakWindow(); void ConnectWiiRemote(int id); #ifdef USE_RETRO_ACHIEVEMENTS From f43f3a0bfdf78805b9e212f864bb282a112eefde Mon Sep 17 00:00:00 2001 From: Sketch <75850871+SketchMaster2001@users.noreply.github.com> Date: Sat, 15 Jul 2023 19:55:22 -0400 Subject: [PATCH 2/4] Config stuff --- Source/Core/Core/Config/MainSettings.cpp | 3 +++ Source/Core/Core/Config/MainSettings.h | 1 + .../Core/Core/IOS/USB/Emulated/WiiSpeak.cpp | 21 +++++++++++++++++-- Source/Core/Core/IOS/USB/Emulated/WiiSpeak.h | 1 + 4 files changed, 24 insertions(+), 2 deletions(-) diff --git a/Source/Core/Core/Config/MainSettings.cpp b/Source/Core/Core/Config/MainSettings.cpp index 2ae286cff085..818707ca8d36 100644 --- a/Source/Core/Core/Config/MainSettings.cpp +++ b/Source/Core/Core/Config/MainSettings.cpp @@ -569,6 +569,9 @@ const Info MAIN_EMULATE_INFINITY_BASE{ const Info MAIN_EMULATE_WII_SPEAK{{System::Main, "EmulatedUSBDevices", "EmulateWiiSpeak"}, false}; +const Info MAIN_WII_SPEAK_MICROPHONE{{System::Main, "General", "WiiSpeakMicrophone"}, + ""}; + // The reason we need this function is because some memory card code // expects to get a non-NTSC-K region even if we're emulating an NTSC-K Wii. DiscIO::Region ToGameCubeRegion(DiscIO::Region region) diff --git a/Source/Core/Core/Config/MainSettings.h b/Source/Core/Core/Config/MainSettings.h index 226325f96038..7e6754bff0f3 100644 --- a/Source/Core/Core/Config/MainSettings.h +++ b/Source/Core/Core/Config/MainSettings.h @@ -352,6 +352,7 @@ void SetUSBDeviceWhitelist(const std::set>& devices); extern const Info MAIN_EMULATE_SKYLANDER_PORTAL; extern const Info MAIN_EMULATE_INFINITY_BASE; extern const Info MAIN_EMULATE_WII_SPEAK; +extern const Info MAIN_WII_SPEAK_MICROPHONE; // GameCube path utility functions diff --git a/Source/Core/Core/IOS/USB/Emulated/WiiSpeak.cpp b/Source/Core/Core/IOS/USB/Emulated/WiiSpeak.cpp index ad3427ad6416..4e763585c386 100644 --- a/Source/Core/Core/IOS/USB/Emulated/WiiSpeak.cpp +++ b/Source/Core/Core/IOS/USB/Emulated/WiiSpeak.cpp @@ -24,8 +24,19 @@ WiiSpeak::WiiSpeak(IOS::HLE::EmulationKernel& ios, const std::string& device_nam m_endpoint_descriptor.emplace_back(EndpointDescriptor{0x7, 0x5, 0x3, 0x1, 0x0040, 1}); m_microphone = Microphone(); - m_microphone.OpenMicrophone(); - m_microphone.StartCapture(); + if (m_microphone.OpenMicrophone() != 0) + { + ERROR_LOG_FMT(IOS_USB, "Error opening the microphone."); + b_is_mic_connected = false; + return; + } + + if (m_microphone.StartCapture() != 0) + { + ERROR_LOG_FMT(IOS_USB, "Error starting captures."); + b_is_mic_connected = false; + return; + } m_microphone_thread = std::thread([this] { u64 timeout{}; @@ -135,6 +146,9 @@ int WiiSpeak::SubmitTransfer(std::unique_ptr cmd) m_vid, m_pid, m_active_interface, cmd->request_type, cmd->request, cmd->value, cmd->index, cmd->length); + if (!b_is_mic_connected) + return IPC_ENOENT; + switch (cmd->request_type << 8 | cmd->request) { case USBHDR(DIR_DEVICE2HOST, TYPE_STANDARD, REC_INTERFACE, REQUEST_GET_INTERFACE): @@ -195,6 +209,9 @@ int WiiSpeak::SubmitTransfer(std::unique_ptr cmd) int WiiSpeak::SubmitTransfer(std::unique_ptr cmd) { + if (!b_is_mic_connected) + return IPC_ENOENT; + auto& system = m_ios.GetSystem(); auto& memory = system.GetMemory(); diff --git a/Source/Core/Core/IOS/USB/Emulated/WiiSpeak.h b/Source/Core/Core/IOS/USB/Emulated/WiiSpeak.h index e3e1ed776fdb..2b9d468bf850 100644 --- a/Source/Core/Core/IOS/USB/Emulated/WiiSpeak.h +++ b/Source/Core/Core/IOS/USB/Emulated/WiiSpeak.h @@ -83,6 +83,7 @@ class WiiSpeak final : public Device u8 m_active_interface = 0; bool m_device_attached = false; bool init = false; + bool b_is_mic_connected = true; Microphone m_microphone; DeviceDescriptor m_device_descriptor{}; std::vector m_config_descriptor; From c308aa817cb7627bf8441e476fe0bf8067ce2d6d Mon Sep 17 00:00:00 2001 From: Sketch <75850871+SketchMaster2001@users.noreply.github.com> Date: Mon, 5 Feb 2024 17:29:21 -0500 Subject: [PATCH 3/4] Convert to cubeb --- .../Core/Core/IOS/USB/Emulated/Microphone.cpp | 191 +++++++++++++++--- .../Core/Core/IOS/USB/Emulated/Microphone.h | 109 +++------- .../Core/Core/IOS/USB/Emulated/WiiSpeak.cpp | 51 +---- Source/Core/Core/IOS/USB/Emulated/WiiSpeak.h | 3 +- .../DolphinQt/EmulatedUSB/WiiSpeakWindow.cpp | 7 - .../DolphinQt/EmulatedUSB/WiiSpeakWindow.h | 1 - 6 files changed, 201 insertions(+), 161 deletions(-) diff --git a/Source/Core/Core/IOS/USB/Emulated/Microphone.cpp b/Source/Core/Core/IOS/USB/Emulated/Microphone.cpp index 62a886e3b796..cb3d90f00b99 100644 --- a/Source/Core/Core/IOS/USB/Emulated/Microphone.cpp +++ b/Source/Core/Core/IOS/USB/Emulated/Microphone.cpp @@ -2,48 +2,180 @@ // Created by Noah Pistilli on 2023-07-09. // +#include + +#include "AudioCommon/CubebUtils.h" +#include + #include "Microphone.h" -#include "Common/swap.h" +#include "Common/Swap.h" #include +#include namespace IOS::HLE::USB { -std::vector Microphone::ListDevices() +Microphone::Microphone() { + StreamInit(); +} + +Microphone::~Microphone() { + StreamTerminate(); + +#ifdef _WIN32 + if (m_should_couninit) + { + Common::Event sync_event; + m_work_queue.EmplaceItem([this, &sync_event] { + Common::ScopeGuard sync_event_guard([&sync_event] { sync_event.Set(); }); + m_should_couninit = false; + CoUninitialize(); + }); + sync_event.Wait(); + } + m_coinit_success = false; +#endif +} + +void Microphone::StreamInit() +{ +#ifdef _WIN32 + if (!m_coinit_success) + return; + Common::Event sync_event; + m_work_queue.EmplaceItem([this, &sync_event] { + Common::ScopeGuard sync_event_guard([&sync_event] { sync_event.Set(); }); +#endif + m_cubeb_ctx = CubebUtils::GetContext(); +#ifdef _WIN32 + }); + sync_event.Wait(); +#endif + + // TODO: Not here but rather inside the WiiSpeak device if possible? + StreamStart(); +} + +void Microphone::StreamTerminate() { - std::vector devices{}; - const ALchar* pDeviceList = alcGetString(nullptr, ALC_CAPTURE_DEVICE_SPECIFIER); - while (*pDeviceList) + StopStream(); + + if (m_cubeb_ctx) { - devices.emplace_back(pDeviceList); - pDeviceList += strlen(pDeviceList) + 1; +#ifdef _WIN32 + if (!m_coinit_success) + return; + Common::Event sync_event; + m_work_queue.EmplaceItem([this, &sync_event] { + Common::ScopeGuard sync_event_guard([&sync_event] { sync_event.Set(); }); +#endif + m_cubeb_ctx.reset(); +#ifdef _WIN32 + }); + sync_event.Wait(); +#endif } +} - return devices; +static void state_callback(cubeb_stream* stream, void* user_data, cubeb_state state) +{ } -int Microphone::OpenMicrophone() +void Microphone::StreamStart() { - m_device = alcCaptureOpenDevice(nullptr, SAMPLING_RATE, AL_FORMAT_MONO16, BUFFER_SIZE); - m_dsp_data.resize(BUFFER_SIZE, 0); - m_temp_buffer.resize(BUFFER_SIZE, 0); - return static_cast(alcGetError(m_device)); + if (!m_cubeb_ctx) + return; + +#ifdef _WIN32 + if (!m_coinit_success) + return; + Common::Event sync_event; + m_work_queue.EmplaceItem([this, &sync_event] { + Common::ScopeGuard sync_event_guard([&sync_event] { sync_event.Set(); }); +#endif + stream_size = buff_size_samples * 500; + stream_buffer = new s16[stream_size]; + + cubeb_stream_params params{}; + params.format = CUBEB_SAMPLE_S16LE; + params.rate = SAMPLING_RATE; + params.channels = 1; + params.layout = CUBEB_LAYOUT_MONO; + + u32 minimum_latency; + if (cubeb_get_min_latency(m_cubeb_ctx.get(), ¶ms, &minimum_latency) != CUBEB_OK) + { + WARN_LOG_FMT(EXPANSIONINTERFACE, "Error getting minimum latency"); + } + + if (cubeb_stream_init(m_cubeb_ctx.get(), &m_cubeb_stream, + "Dolphin Emulated GameCube Microphone", nullptr, ¶ms, nullptr, + nullptr, std::max(16, minimum_latency), DataCallback, + state_callback, this) != CUBEB_OK) + { + ERROR_LOG_FMT(IOS_USB, "Error initializing cubeb stream"); + return; + } + + if (cubeb_stream_start(m_cubeb_stream) != CUBEB_OK) + { + ERROR_LOG_FMT(EXPANSIONINTERFACE, "Error starting cubeb stream"); + return; + } + + INFO_LOG_FMT(EXPANSIONINTERFACE, "started cubeb stream"); +#ifdef _WIN32 + }); + sync_event.Wait(); +#endif } -int Microphone::StartCapture() +void Microphone::StopStream() { - alcCaptureStart(m_device); - return static_cast(alcGetError(m_device)); + if (m_cubeb_stream) + { +#ifdef _WIN32 + Common::Event sync_event; + m_work_queue.EmplaceItem([this, &sync_event] { + Common::ScopeGuard sync_event_guard([&sync_event] { sync_event.Set(); }); +#endif + if (cubeb_stream_stop(m_cubeb_stream) != CUBEB_OK) + ERROR_LOG_FMT(IOS_USB, "Error stopping cubeb stream"); + cubeb_stream_destroy(m_cubeb_stream); + m_cubeb_stream = nullptr; +#ifdef _WIN32 + }); + sync_event.Wait(); +#endif + } } -void Microphone::StopCapture() +long Microphone::DataCallback(cubeb_stream* stream, void* user_data, const void* input_buffer, + void* /*output_buffer*/, long nframes) { - alcCaptureStop(m_device); + auto* mic = static_cast(user_data); + + std::lock_guard lk(mic->ring_lock); + + const s16* buff_in = static_cast(input_buffer); + for (long i = 0; i < nframes; i++) + { + mic->stream_buffer[mic->stream_wpos] = Common::swap16(buff_in[i]); + mic->stream_wpos = (mic->stream_wpos + 1) % mic->stream_size; + } + + mic->samples_avail += nframes; + if (mic->samples_avail > mic->stream_size) + { + mic->samples_avail = 0; + } + + return nframes; } void Microphone::PerformAudioCapture() { - m_num_of_samples = BUFFER_SIZE / 2; + /*m_num_of_samples = BUFFER_SIZE / 2; ALCint samples_in{}; alcGetIntegerv(m_device, ALC_CAPTURE_SAMPLES, 1, &samples_in); @@ -52,7 +184,7 @@ void Microphone::PerformAudioCapture() if (m_num_of_samples == 0) return; - alcCaptureSamples(m_device, m_dsp_data.data(), m_num_of_samples); + alcCaptureSamples(m_device, m_dsp_data.data(), m_num_of_samples);*/ } void Microphone::ByteSwap(const void* src, void* dst) const @@ -62,7 +194,7 @@ void Microphone::ByteSwap(const void* src, void* dst) const void Microphone::GetSoundData() { - if (m_num_of_samples == 0) + /*if (m_num_of_samples == 0) return; u8* ptr = const_cast(m_temp_buffer.data()); @@ -76,16 +208,27 @@ void Microphone::GetSoundData() } } - m_rbuf_dsp.write_bytes(ptr, m_num_of_samples * 2); + m_rbuf_dsp.write_bytes(ptr, m_num_of_samples * 2);*/ } void Microphone::ReadIntoBuffer(u8* dst, u32 size) { - m_rbuf_dsp.read_bytes(dst, size); + std::lock_guard lk(ring_lock); + + if (samples_avail >= buff_size_samples) + { + u8* last_buffer = reinterpret_cast(&stream_buffer[stream_rpos]); + std::memcpy(dst, static_cast(last_buffer), size); + + samples_avail -= buff_size_samples; + + stream_rpos += buff_size_samples; + stream_rpos %= stream_size; + } } bool Microphone::HasData() const { - return m_num_of_samples != 0; + return samples_avail > 0; } } // namespace IOS::HLE::USB \ No newline at end of file diff --git a/Source/Core/Core/IOS/USB/Emulated/Microphone.h b/Source/Core/Core/IOS/USB/Emulated/Microphone.h index daa1d175d623..11db0000bbda 100644 --- a/Source/Core/Core/IOS/USB/Emulated/Microphone.h +++ b/Source/Core/Core/IOS/USB/Emulated/Microphone.h @@ -5,106 +5,55 @@ #include #include +#include #include "Common/CommonTypes.h" +struct cubeb; +struct cubeb_stream; + namespace IOS::HLE::USB { -template -class simple_ringbuf -{ -public: - simple_ringbuf() { m_container.resize(S); } - - bool has_data() const { return m_used != 0; } - - u32 read_bytes(u8* buf, const u32 size) - { - u32 to_read = size > m_used ? m_used : size; - if (!to_read) - return 0; - - u8* data = m_container.data(); - u32 new_tail = m_tail + to_read; - - if (new_tail >= S) - { - u32 first_chunk_size = S - m_tail; - std::memcpy(buf, data + m_tail, first_chunk_size); - std::memcpy(buf + first_chunk_size, data, to_read - first_chunk_size); - m_tail = (new_tail - S); - } - else - { - std::memcpy(buf, data + m_tail, to_read); - m_tail = new_tail; - } - - m_used -= to_read; - - return to_read; - } - - void write_bytes(const u8* buf, const u32 size) - { - if (u32 over_size = m_used + size; over_size > S) - { - m_tail += (over_size - S); - if (m_tail > S) - m_tail -= S; - - m_used = S; - } - else - { - m_used = over_size; - } - - u8* data = m_container.data(); - u32 new_head = m_head + size; - - if (new_head >= S) - { - u32 first_chunk_size = S - m_head; - std::memcpy(data + m_head, buf, first_chunk_size); - std::memcpy(data, buf + first_chunk_size, size - first_chunk_size); - m_head = (new_head - S); - } - else - { - std::memcpy(data + m_head, buf, size); - m_head = new_head; - } - } - -protected: - std::vector m_container; - u32 m_head = 0, m_tail = 0, m_used = 0; -}; - class Microphone final { public: - static std::vector ListDevices(); + Microphone(); + ~Microphone(); - int OpenMicrophone(); - int StartCapture(); - void StopCapture(); + void StreamInit(); + void StreamTerminate(); void PerformAudioCapture(); void GetSoundData(); void ReadIntoBuffer(u8* dst, u32 size); bool HasData() const; private: + static long DataCallback(cubeb_stream* stream, void* user_data, const void* input_buffer, + void* output_buffer, long nframes); + + void StreamStart(); + void StopStream(); void ByteSwap(const void* src, void* dst) const; static constexpr u32 SAMPLING_RATE = 8000; static constexpr u32 BUFFER_SIZE = SAMPLING_RATE / 2; - ALCdevice* m_device; - u32 m_num_of_samples{}; - std::vector m_dsp_data{}; + s16* stream_buffer; + std::mutex ring_lock; + std::shared_ptr m_cubeb_ctx = nullptr; + cubeb_stream* m_cubeb_stream = nullptr; std::vector m_temp_buffer{}; - simple_ringbuf m_rbuf_dsp; + + int stream_size; + int stream_wpos; + int stream_rpos; + int samples_avail; + int buff_size_samples = 16; + +#ifdef _WIN32 + Common::WorkQueueThread> m_work_queue; + bool m_coinit_success = false; + bool m_should_couninit = false; +#endif }; } // namespace IOS::HLE::USB diff --git a/Source/Core/Core/IOS/USB/Emulated/WiiSpeak.cpp b/Source/Core/Core/IOS/USB/Emulated/WiiSpeak.cpp index 4e763585c386..e328355cad73 100644 --- a/Source/Core/Core/IOS/USB/Emulated/WiiSpeak.cpp +++ b/Source/Core/Core/IOS/USB/Emulated/WiiSpeak.cpp @@ -23,52 +23,12 @@ WiiSpeak::WiiSpeak(IOS::HLE::EmulationKernel& ios, const std::string& device_nam m_endpoint_descriptor.emplace_back(EndpointDescriptor{0x7, 0x5, 0x2, 0x2, 0x0020, 0}); m_endpoint_descriptor.emplace_back(EndpointDescriptor{0x7, 0x5, 0x3, 0x1, 0x0040, 1}); - m_microphone = Microphone(); - if (m_microphone.OpenMicrophone() != 0) - { - ERROR_LOG_FMT(IOS_USB, "Error opening the microphone."); - b_is_mic_connected = false; - return; - } - - if (m_microphone.StartCapture() != 0) - { - ERROR_LOG_FMT(IOS_USB, "Error starting captures."); - b_is_mic_connected = false; - return; - } - - m_microphone_thread = std::thread([this] { - u64 timeout{}; - constexpr u64 TIMESTEP = 256ull * 1'000'000ull / 48000ull; - while (true) - { - if (m_shutdown_event.WaitFor(std::chrono::microseconds{timeout})) - return; - - std::lock_guard lg(m_mutex); - timeout = TIMESTEP - (std::chrono::duration_cast( - std::chrono::steady_clock::now().time_since_epoch()) - .count() % - TIMESTEP); - m_microphone.PerformAudioCapture(); - m_microphone.GetSoundData(); - } - }); + m_microphone = std::make_unique(); } WiiSpeak::~WiiSpeak() { - { - std::lock_guard lg(m_mutex); - if (!m_microphone_thread.joinable()) - return; - m_shutdown_event.Set(); - } - - m_microphone_thread.join(); - m_microphone.StopCapture(); } DeviceDescriptor WiiSpeak::GetDeviceDescriptor() const @@ -209,19 +169,16 @@ int WiiSpeak::SubmitTransfer(std::unique_ptr cmd) int WiiSpeak::SubmitTransfer(std::unique_ptr cmd) { - if (!b_is_mic_connected) - return IPC_ENOENT; - auto& system = m_ios.GetSystem(); auto& memory = system.GetMemory(); u8* packets = memory.GetPointer(cmd->data_address); - if (cmd->endpoint == 0x81 && m_microphone.HasData()) - m_microphone.ReadIntoBuffer(packets, cmd->length); + if (cmd->endpoint == 0x81 && m_microphone->HasData()) + m_microphone->ReadIntoBuffer(packets, cmd->length); // Anything more causes the visual cue to not appear. // Anything less is more choppy audio. - cmd->ScheduleTransferCompletion(IPC_SUCCESS, 20000); + cmd->ScheduleTransferCompletion(IPC_SUCCESS, 2500); return IPC_SUCCESS; }; diff --git a/Source/Core/Core/IOS/USB/Emulated/WiiSpeak.h b/Source/Core/Core/IOS/USB/Emulated/WiiSpeak.h index 2b9d468bf850..203435483663 100644 --- a/Source/Core/Core/IOS/USB/Emulated/WiiSpeak.h +++ b/Source/Core/Core/IOS/USB/Emulated/WiiSpeak.h @@ -84,12 +84,11 @@ class WiiSpeak final : public Device bool m_device_attached = false; bool init = false; bool b_is_mic_connected = true; - Microphone m_microphone; + std::unique_ptr m_microphone; DeviceDescriptor m_device_descriptor{}; std::vector m_config_descriptor; std::vector m_interface_descriptor; std::vector m_endpoint_descriptor; - std::thread m_microphone_thread; std::mutex m_mutex; Common::Event m_shutdown_event; }; diff --git a/Source/Core/DolphinQt/EmulatedUSB/WiiSpeakWindow.cpp b/Source/Core/DolphinQt/EmulatedUSB/WiiSpeakWindow.cpp index f3770047a77e..05cbd6d86c9a 100644 --- a/Source/Core/DolphinQt/EmulatedUSB/WiiSpeakWindow.cpp +++ b/Source/Core/DolphinQt/EmulatedUSB/WiiSpeakWindow.cpp @@ -59,13 +59,6 @@ void WiiSpeakWindow::CreateMainWindow() checkbox_layout->addWidget(m_checkbox); checkbox_group->setLayout(checkbox_layout); - m_combobox_microphones = new QComboBox(); - for (const std::string& device : IOS::HLE::USB::Microphone::ListDevices()) - { - m_combobox_microphones->addItem(QString::fromStdString(device)); - } - - checkbox_layout->addWidget(m_combobox_microphones); main_layout->addWidget(checkbox_group); setLayout(main_layout); diff --git a/Source/Core/DolphinQt/EmulatedUSB/WiiSpeakWindow.h b/Source/Core/DolphinQt/EmulatedUSB/WiiSpeakWindow.h index f37c82be96d4..df0d6a3bd581 100644 --- a/Source/Core/DolphinQt/EmulatedUSB/WiiSpeakWindow.h +++ b/Source/Core/DolphinQt/EmulatedUSB/WiiSpeakWindow.h @@ -30,5 +30,4 @@ class WiiSpeakWindow : public QWidget void EmulateWiiSpeak(bool emulate); QCheckBox* m_checkbox; - QComboBox* m_combobox_microphones; }; From 99e60d2c824ae38e8abcdd9e5ffb3f17c7c91e45 Mon Sep 17 00:00:00 2001 From: Sketch <75850871+SketchMaster2001@users.noreply.github.com> Date: Tue, 6 Feb 2024 22:08:04 -0500 Subject: [PATCH 4/4] Compile for Windows --- Source/Core/Core/Config/MainSettings.cpp | 6 -- Source/Core/Core/Config/MainSettings.h | 2 - .../Core/Core/IOS/USB/Emulated/Microphone.cpp | 66 ++++------------ .../Core/Core/IOS/USB/Emulated/Microphone.h | 13 ++-- .../Core/Core/IOS/USB/Emulated/WiiSpeak.cpp | 16 +--- Source/Core/Core/IOS/USB/Emulated/WiiSpeak.h | 10 +-- Source/Core/DolphinLib.props | 4 + Source/Core/DolphinQt/CMakeLists.txt | 2 - .../DolphinQt/EmulatedUSB/WiiSpeakWindow.cpp | 77 ------------------- .../DolphinQt/EmulatedUSB/WiiSpeakWindow.h | 33 -------- Source/Core/DolphinQt/MainWindow.cpp | 14 ---- Source/Core/DolphinQt/MainWindow.h | 3 - Source/Core/DolphinQt/MenuBar.cpp | 1 - Source/Core/DolphinQt/MenuBar.h | 1 - 14 files changed, 35 insertions(+), 213 deletions(-) delete mode 100644 Source/Core/DolphinQt/EmulatedUSB/WiiSpeakWindow.cpp delete mode 100644 Source/Core/DolphinQt/EmulatedUSB/WiiSpeakWindow.h diff --git a/Source/Core/Core/Config/MainSettings.cpp b/Source/Core/Core/Config/MainSettings.cpp index 818707ca8d36..21c453b6c775 100644 --- a/Source/Core/Core/Config/MainSettings.cpp +++ b/Source/Core/Core/Config/MainSettings.cpp @@ -566,12 +566,6 @@ const Info MAIN_EMULATE_SKYLANDER_PORTAL{ const Info MAIN_EMULATE_INFINITY_BASE{ {System::Main, "EmulatedUSBDevices", "EmulateInfinityBase"}, false}; -const Info MAIN_EMULATE_WII_SPEAK{{System::Main, "EmulatedUSBDevices", "EmulateWiiSpeak"}, - false}; - -const Info MAIN_WII_SPEAK_MICROPHONE{{System::Main, "General", "WiiSpeakMicrophone"}, - ""}; - // The reason we need this function is because some memory card code // expects to get a non-NTSC-K region even if we're emulating an NTSC-K Wii. DiscIO::Region ToGameCubeRegion(DiscIO::Region region) diff --git a/Source/Core/Core/Config/MainSettings.h b/Source/Core/Core/Config/MainSettings.h index 7e6754bff0f3..dddda8ae7a3b 100644 --- a/Source/Core/Core/Config/MainSettings.h +++ b/Source/Core/Core/Config/MainSettings.h @@ -351,8 +351,6 @@ void SetUSBDeviceWhitelist(const std::set>& devices); extern const Info MAIN_EMULATE_SKYLANDER_PORTAL; extern const Info MAIN_EMULATE_INFINITY_BASE; -extern const Info MAIN_EMULATE_WII_SPEAK; -extern const Info MAIN_WII_SPEAK_MICROPHONE; // GameCube path utility functions diff --git a/Source/Core/Core/IOS/USB/Emulated/Microphone.cpp b/Source/Core/Core/IOS/USB/Emulated/Microphone.cpp index cb3d90f00b99..fce14c55d4d0 100644 --- a/Source/Core/Core/IOS/USB/Emulated/Microphone.cpp +++ b/Source/Core/Core/IOS/USB/Emulated/Microphone.cpp @@ -1,25 +1,31 @@ -// -// Created by Noah Pistilli on 2023-07-09. -// +// Copyright 2024 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #include #include "AudioCommon/CubebUtils.h" -#include +#include "Common/Logging/Log.h" -#include "Microphone.h" +#include "Common/ScopeGuard.h" #include "Common/Swap.h" +#include "Core/IOS/USB/Emulated/Microphone.h" #include #include +#ifdef _WIN32 +#include +#endif + namespace IOS::HLE::USB { -Microphone::Microphone() { +Microphone::Microphone() +{ StreamInit(); } -Microphone::~Microphone() { +Microphone::~Microphone() +{ StreamTerminate(); #ifdef _WIN32 @@ -110,8 +116,8 @@ void Microphone::StreamStart() if (cubeb_stream_init(m_cubeb_ctx.get(), &m_cubeb_stream, "Dolphin Emulated GameCube Microphone", nullptr, ¶ms, nullptr, - nullptr, std::max(16, minimum_latency), DataCallback, - state_callback, this) != CUBEB_OK) + nullptr, std::max(16, minimum_latency), DataCallback, state_callback, + this) != CUBEB_OK) { ERROR_LOG_FMT(IOS_USB, "Error initializing cubeb stream"); return; @@ -151,7 +157,7 @@ void Microphone::StopStream() } long Microphone::DataCallback(cubeb_stream* stream, void* user_data, const void* input_buffer, - void* /*output_buffer*/, long nframes) + void* /*output_buffer*/, long nframes) { auto* mic = static_cast(user_data); @@ -173,44 +179,6 @@ long Microphone::DataCallback(cubeb_stream* stream, void* user_data, const void* return nframes; } -void Microphone::PerformAudioCapture() -{ - /*m_num_of_samples = BUFFER_SIZE / 2; - - ALCint samples_in{}; - alcGetIntegerv(m_device, ALC_CAPTURE_SAMPLES, 1, &samples_in); - m_num_of_samples = std::min(m_num_of_samples, static_cast(samples_in)); - - if (m_num_of_samples == 0) - return; - - alcCaptureSamples(m_device, m_dsp_data.data(), m_num_of_samples);*/ -} - -void Microphone::ByteSwap(const void* src, void* dst) const -{ - *static_cast(dst) = Common::swap16(*static_cast(src)); -} - -void Microphone::GetSoundData() -{ - /*if (m_num_of_samples == 0) - return; - - u8* ptr = const_cast(m_temp_buffer.data()); - // Convert LE to BE - for (u32 i = 0; i < m_num_of_samples; i++) - { - for (u32 indchan = 0; indchan < 1; indchan++) - { - const u32 curindex = (i * 2) + indchan * (16 / 8); - ByteSwap(m_dsp_data.data() + curindex, ptr + curindex); - } - } - - m_rbuf_dsp.write_bytes(ptr, m_num_of_samples * 2);*/ -} - void Microphone::ReadIntoBuffer(u8* dst, u32 size) { std::lock_guard lk(ring_lock); @@ -231,4 +199,4 @@ bool Microphone::HasData() const { return samples_avail > 0; } -} // namespace IOS::HLE::USB \ No newline at end of file +} // namespace IOS::HLE::USB diff --git a/Source/Core/Core/IOS/USB/Emulated/Microphone.h b/Source/Core/Core/IOS/USB/Emulated/Microphone.h index 11db0000bbda..9ab3e7004e8b 100644 --- a/Source/Core/Core/IOS/USB/Emulated/Microphone.h +++ b/Source/Core/Core/IOS/USB/Emulated/Microphone.h @@ -1,13 +1,15 @@ -#pragma once +// Copyright 2024 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later -#include -#include +#pragma once +#include #include #include -#include #include "Common/CommonTypes.h" +#include "Common/Event.h" +#include "Common/WorkQueueThread.h" struct cubeb; struct cubeb_stream; @@ -22,8 +24,6 @@ class Microphone final void StreamInit(); void StreamTerminate(); - void PerformAudioCapture(); - void GetSoundData(); void ReadIntoBuffer(u8* dst, u32 size); bool HasData() const; @@ -33,7 +33,6 @@ class Microphone final void StreamStart(); void StopStream(); - void ByteSwap(const void* src, void* dst) const; static constexpr u32 SAMPLING_RATE = 8000; static constexpr u32 BUFFER_SIZE = SAMPLING_RATE / 2; diff --git a/Source/Core/Core/IOS/USB/Emulated/WiiSpeak.cpp b/Source/Core/Core/IOS/USB/Emulated/WiiSpeak.cpp index e328355cad73..06d4469e386c 100644 --- a/Source/Core/Core/IOS/USB/Emulated/WiiSpeak.cpp +++ b/Source/Core/Core/IOS/USB/Emulated/WiiSpeak.cpp @@ -1,4 +1,4 @@ -// Copyright 2023 Dolphin Emulator Project +// Copyright 2024 Dolphin Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include "Core/IOS/USB/Emulated/WiiSpeak.h" @@ -26,11 +26,6 @@ WiiSpeak::WiiSpeak(IOS::HLE::EmulationKernel& ios, const std::string& device_nam m_microphone = std::make_unique(); } -WiiSpeak::~WiiSpeak() -{ - -} - DeviceDescriptor WiiSpeak::GetDeviceDescriptor() const { return m_device_descriptor; @@ -106,9 +101,6 @@ int WiiSpeak::SubmitTransfer(std::unique_ptr cmd) m_vid, m_pid, m_active_interface, cmd->request_type, cmd->request, cmd->value, cmd->index, cmd->length); - if (!b_is_mic_connected) - return IPC_ENOENT; - switch (cmd->request_type << 8 | cmd->request) { case USBHDR(DIR_DEVICE2HOST, TYPE_STANDARD, REC_INTERFACE, REQUEST_GET_INTERFACE): @@ -176,8 +168,7 @@ int WiiSpeak::SubmitTransfer(std::unique_ptr cmd) if (cmd->endpoint == 0x81 && m_microphone->HasData()) m_microphone->ReadIntoBuffer(packets, cmd->length); - // Anything more causes the visual cue to not appear. - // Anything less is more choppy audio. + // TODO: Figure out proper timings. cmd->ScheduleTransferCompletion(IPC_SUCCESS, 2500); return IPC_SUCCESS; }; @@ -199,6 +190,7 @@ void WiiSpeak::SetRegister(std::unique_ptr& cmd) switch (arg1) { case FREQ_8KHZ: + // TODO: I have never seen it not be 8000 kHz sampler.freq = 8000; break; case FREQ_11KHZ: @@ -319,4 +311,4 @@ void WiiSpeak::GetRegister(std::unique_ptr& cmd) break; } } -} // namespace IOS::HLE::USB \ No newline at end of file +} // namespace IOS::HLE::USB diff --git a/Source/Core/Core/IOS/USB/Emulated/WiiSpeak.h b/Source/Core/Core/IOS/USB/Emulated/WiiSpeak.h index 203435483663..ff2fa0af83c3 100644 --- a/Source/Core/Core/IOS/USB/Emulated/WiiSpeak.h +++ b/Source/Core/Core/IOS/USB/Emulated/WiiSpeak.h @@ -1,4 +1,4 @@ -// Copyright 2023 Dolphin Emulator Project +// Copyright 2024 Dolphin Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once @@ -19,7 +19,6 @@ class WiiSpeak final : public Device { public: WiiSpeak(EmulationKernel& ios, const std::string& device_name); - ~WiiSpeak(); DeviceDescriptor GetDeviceDescriptor() const override; std::vector GetConfigurations() const override; std::vector GetInterfaces(u8 config) const override; @@ -57,13 +56,13 @@ class WiiSpeak final : public Device FREQ_8KHZ = 0, FREQ_11KHZ = 1, FREQ_RESERVED = 2, - FREQ_16KHZ = 3, // default + FREQ_16KHZ = 3, SAMPLER_GAIN = 4, GAIN_00dB = 0, GAIN_15dB = 1, GAIN_30dB = 2, - GAIN_36dB = 3, // default + GAIN_36dB = 3, EC_STATE = 0x14, @@ -83,7 +82,6 @@ class WiiSpeak final : public Device u8 m_active_interface = 0; bool m_device_attached = false; bool init = false; - bool b_is_mic_connected = true; std::unique_ptr m_microphone; DeviceDescriptor m_device_descriptor{}; std::vector m_config_descriptor; @@ -92,4 +90,4 @@ class WiiSpeak final : public Device std::mutex m_mutex; Common::Event m_shutdown_event; }; -} // namespace IOS::HLE::USB \ No newline at end of file +} // namespace IOS::HLE::USB diff --git a/Source/Core/DolphinLib.props b/Source/Core/DolphinLib.props index 59cecdf5dc67..17845ad3699f 100644 --- a/Source/Core/DolphinLib.props +++ b/Source/Core/DolphinLib.props @@ -395,9 +395,11 @@ + + @@ -1051,9 +1053,11 @@ + + diff --git a/Source/Core/DolphinQt/CMakeLists.txt b/Source/Core/DolphinQt/CMakeLists.txt index caad6d804806..8285c17d4ae7 100644 --- a/Source/Core/DolphinQt/CMakeLists.txt +++ b/Source/Core/DolphinQt/CMakeLists.txt @@ -240,8 +240,6 @@ add_executable(dolphin-emu DiscordHandler.h DiscordJoinRequestDialog.cpp DiscordJoinRequestDialog.h - EmulatedUSB/WiiSpeakWindow.cpp - EmulatedUSB/WiiSpeakWindow.h FIFO/FIFOAnalyzer.cpp FIFO/FIFOAnalyzer.h FIFO/FIFOPlayerWindow.cpp diff --git a/Source/Core/DolphinQt/EmulatedUSB/WiiSpeakWindow.cpp b/Source/Core/DolphinQt/EmulatedUSB/WiiSpeakWindow.cpp deleted file mode 100644 index 05cbd6d86c9a..000000000000 --- a/Source/Core/DolphinQt/EmulatedUSB/WiiSpeakWindow.cpp +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2023 Dolphin Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "DolphinQt/EmulatedUSB/WiiSpeakWindow.h" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "Common/IOFile.h" - -#include "Core/Config/MainSettings.h" -#include "Core/Core.h" -#include "Core/IOS/USB/Emulated/Microphone.h" -#include "Core/System.h" - -#include "DolphinQt/QtUtils/DolphinFileDialog.h" -#include "DolphinQt/Settings.h" - -WiiSpeakWindow::WiiSpeakWindow(QWidget* parent) : QWidget(parent) -{ - setWindowTitle(tr("Wii Speak Manager")); - setObjectName(QStringLiteral("wii_speak_manager")); - setMinimumSize(QSize(700, 200)); - - CreateMainWindow(); - - connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, - &WiiSpeakWindow::OnEmulationStateChanged); - - installEventFilter(this); - - OnEmulationStateChanged(Core::GetState()); -}; - -WiiSpeakWindow::~WiiSpeakWindow() = default; - -void WiiSpeakWindow::CreateMainWindow() -{ - auto* main_layout = new QVBoxLayout(); - - auto* checkbox_group = new QGroupBox(); - auto* checkbox_layout = new QHBoxLayout(); - checkbox_layout->setAlignment(Qt::AlignLeft); - m_checkbox = new QCheckBox(tr("Emulate Wii Speak"), this); - m_checkbox->setChecked(Config::Get(Config::MAIN_EMULATE_WII_SPEAK)); - connect(m_checkbox, &QCheckBox::toggled, this, &WiiSpeakWindow::EmulateWiiSpeak); - checkbox_layout->addWidget(m_checkbox); - checkbox_group->setLayout(checkbox_layout); - - - main_layout->addWidget(checkbox_group); - setLayout(main_layout); -} - -void WiiSpeakWindow::EmulateWiiSpeak(bool emulate) -{ - Config::SetBaseOrCurrent(Config::MAIN_EMULATE_WII_SPEAK, emulate); -} - -void WiiSpeakWindow::OnEmulationStateChanged(Core::State state) -{ - const bool running = state != Core::State::Uninitialized; - - m_checkbox->setEnabled(!running); -} diff --git a/Source/Core/DolphinQt/EmulatedUSB/WiiSpeakWindow.h b/Source/Core/DolphinQt/EmulatedUSB/WiiSpeakWindow.h deleted file mode 100644 index df0d6a3bd581..000000000000 --- a/Source/Core/DolphinQt/EmulatedUSB/WiiSpeakWindow.h +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2023 Dolphin Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include - -#include -#include - -#include "Common/CommonTypes.h" -#include "Core/Core.h" - -class QCheckBox; -class QGroupBox; -class QLineEdit; -class QVBoxLayout; -class QComboBox; - -class WiiSpeakWindow : public QWidget -{ - Q_OBJECT -public: - explicit WiiSpeakWindow(QWidget* parent = nullptr); - ~WiiSpeakWindow() override; - -private: - void CreateMainWindow(); - void OnEmulationStateChanged(Core::State state); - void EmulateWiiSpeak(bool emulate); - - QCheckBox* m_checkbox; -}; diff --git a/Source/Core/DolphinQt/MainWindow.cpp b/Source/Core/DolphinQt/MainWindow.cpp index 6996ef83a0b3..72b075f12b44 100644 --- a/Source/Core/DolphinQt/MainWindow.cpp +++ b/Source/Core/DolphinQt/MainWindow.cpp @@ -92,7 +92,6 @@ #include "DolphinQt/Debugger/ThreadWidget.h" #include "DolphinQt/Debugger/WatchWidget.h" #include "DolphinQt/DiscordHandler.h" -#include "DolphinQt/EmulatedUSB/WiiSpeakWindow.h" #include "DolphinQt/FIFO/FIFOPlayerWindow.h" #include "DolphinQt/GCMemcardManager.h" #include "DolphinQt/GameList/GameList.h" @@ -559,7 +558,6 @@ void MainWindow::ConnectMenuBar() connect(m_menu_bar, &MenuBar::ShowFIFOPlayer, this, &MainWindow::ShowFIFOPlayer); connect(m_menu_bar, &MenuBar::ShowSkylanderPortal, this, &MainWindow::ShowSkylanderPortal); connect(m_menu_bar, &MenuBar::ShowInfinityBase, this, &MainWindow::ShowInfinityBase); - connect(m_menu_bar, &MenuBar::ShowWiiSpeakWindow, this, &MainWindow::ShowWiiSpeakWindow); connect(m_menu_bar, &MenuBar::ConnectWiiRemote, this, &MainWindow::OnConnectWiiRemote); #ifdef USE_RETRO_ACHIEVEMENTS @@ -1404,18 +1402,6 @@ void MainWindow::ShowInfinityBase() m_infinity_window->activateWindow(); } -void MainWindow::ShowWiiSpeakWindow() -{ - if (!m_wii_speak_window) - { - m_wii_speak_window = new WiiSpeakWindow(); - } - - m_wii_speak_window->show(); - m_wii_speak_window->raise(); - m_wii_speak_window->activateWindow(); -} - void MainWindow::StateLoad() { QString path = diff --git a/Source/Core/DolphinQt/MainWindow.h b/Source/Core/DolphinQt/MainWindow.h index 28027f32eb31..ede238012518 100644 --- a/Source/Core/DolphinQt/MainWindow.h +++ b/Source/Core/DolphinQt/MainWindow.h @@ -52,7 +52,6 @@ class ThreadWidget; class ToolBar; class WatchWidget; class WiiTASInputWindow; -class WiiSpeakWindow; struct WindowSystemInfo; namespace DiscIO @@ -170,7 +169,6 @@ class MainWindow final : public QMainWindow void ShowFIFOPlayer(); void ShowSkylanderPortal(); void ShowInfinityBase(); - void ShowWiiSpeakWindow(); void ShowMemcardManager(); void ShowResourcePackManager(); void ShowCheatsManager(); @@ -246,7 +244,6 @@ class MainWindow final : public QMainWindow FIFOPlayerWindow* m_fifo_window = nullptr; SkylanderPortalWindow* m_skylander_window = nullptr; InfinityBaseWindow* m_infinity_window = nullptr; - WiiSpeakWindow* m_wii_speak_window = nullptr; MappingWindow* m_hotkey_window = nullptr; FreeLookWindow* m_freelook_window = nullptr; diff --git a/Source/Core/DolphinQt/MenuBar.cpp b/Source/Core/DolphinQt/MenuBar.cpp index 003306a94388..07d4d21cbb7d 100644 --- a/Source/Core/DolphinQt/MenuBar.cpp +++ b/Source/Core/DolphinQt/MenuBar.cpp @@ -237,7 +237,6 @@ void MenuBar::AddToolsMenu() auto* usb_device_menu = new QMenu(tr("Emulated USB Devices"), tools_menu); usb_device_menu->addAction(tr("&Skylanders Portal"), this, &MenuBar::ShowSkylanderPortal); usb_device_menu->addAction(tr("&Infinity Base"), this, &MenuBar::ShowInfinityBase); - usb_device_menu->addAction(tr("&Wii Speak"), this, &MenuBar::ShowWiiSpeakWindow); tools_menu->addMenu(usb_device_menu); tools_menu->addSeparator(); diff --git a/Source/Core/DolphinQt/MenuBar.h b/Source/Core/DolphinQt/MenuBar.h index 9061d184daab..d13e8ae4b310 100644 --- a/Source/Core/DolphinQt/MenuBar.h +++ b/Source/Core/DolphinQt/MenuBar.h @@ -91,7 +91,6 @@ class MenuBar final : public QMenuBar void ShowResourcePackManager(); void ShowSkylanderPortal(); void ShowInfinityBase(); - void ShowWiiSpeakWindow(); void ConnectWiiRemote(int id); #ifdef USE_RETRO_ACHIEVEMENTS