mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-06-28 01:49:33 -06:00
IOS/USB: Try to fix the Wii Speak Channel record/playback feature
1. Fix Wii Speak SAMPLER_MUTE register: The register should be 12 (i.e. 0x0c) instead of 0xc0. 2. Fix Wii Speak buffer memcpy size parameter: It seems to fix random echoes and reduce noises when nobody is speaking. 3. Change the isochronous transfer timing: It is based on empirical testing.
This commit is contained in:
@ -193,6 +193,7 @@ long Microphone::DataCallback(const s16* input_buffer, long nframes)
|
||||
m_samples_avail += nframes;
|
||||
if (m_samples_avail > STREAM_SIZE)
|
||||
{
|
||||
WARN_LOG_FMT(IOS_USB, "Wii Speak ring buffer is full, data will be lost!");
|
||||
m_samples_avail = STREAM_SIZE;
|
||||
}
|
||||
|
||||
@ -202,18 +203,30 @@ long Microphone::DataCallback(const s16* input_buffer, long nframes)
|
||||
|
||||
void Microphone::ReadIntoBuffer(u8* dst, u32 size)
|
||||
{
|
||||
static constexpr u32 SINGLE_READ_SIZE = BUFF_SIZE_SAMPLES * sizeof(SampleType);
|
||||
|
||||
// Avoid buffer overflow during memcpy
|
||||
static_assert((STREAM_SIZE % BUFF_SIZE_SAMPLES) == 0,
|
||||
"The STREAM_SIZE isn't a multiple of BUFF_SIZE_SAMPLES");
|
||||
|
||||
std::lock_guard lock(m_ring_lock);
|
||||
|
||||
if (m_samples_avail >= BUFF_SIZE_SAMPLES)
|
||||
for (u8* end = dst + size; dst < end; dst += SINGLE_READ_SIZE, size -= SINGLE_READ_SIZE)
|
||||
{
|
||||
u8* last_buffer = reinterpret_cast<u8*>(&m_stream_buffer[m_stream_rpos]);
|
||||
std::memcpy(dst, static_cast<u8*>(last_buffer), size);
|
||||
if (size < SINGLE_READ_SIZE || m_samples_avail < BUFF_SIZE_SAMPLES)
|
||||
break;
|
||||
|
||||
SampleType* last_buffer = &m_stream_buffer[m_stream_rpos];
|
||||
std::memcpy(dst, last_buffer, SINGLE_READ_SIZE);
|
||||
|
||||
m_samples_avail -= BUFF_SIZE_SAMPLES;
|
||||
|
||||
m_stream_rpos += BUFF_SIZE_SAMPLES;
|
||||
m_stream_rpos %= STREAM_SIZE;
|
||||
}
|
||||
if (size != 0)
|
||||
{
|
||||
std::memset(dst, 0, size);
|
||||
}
|
||||
}
|
||||
|
||||
bool Microphone::HasData() const
|
||||
|
@ -42,11 +42,11 @@ private:
|
||||
void StreamStop();
|
||||
|
||||
static constexpr u32 SAMPLING_RATE = 8000;
|
||||
static constexpr u32 BUFFER_SIZE = SAMPLING_RATE / 2;
|
||||
using SampleType = s16;
|
||||
static constexpr u32 BUFF_SIZE_SAMPLES = 16;
|
||||
static constexpr u32 STREAM_SIZE = BUFF_SIZE_SAMPLES * 500;
|
||||
|
||||
std::array<s16, STREAM_SIZE> m_stream_buffer{};
|
||||
std::array<SampleType, STREAM_SIZE> m_stream_buffer{};
|
||||
u32 m_stream_wpos = 0;
|
||||
u32 m_stream_rpos = 0;
|
||||
u32 m_samples_avail = 0;
|
||||
|
@ -190,16 +190,35 @@ int WiiSpeak::SubmitTransfer(std::unique_ptr<IsoMessage> cmd)
|
||||
break;
|
||||
}
|
||||
|
||||
// Anything more causes the visual cue to not appear.
|
||||
// Anything less is more choppy audio.
|
||||
// Transferring too slow causes the visual cue to not appear,
|
||||
// while transferring too fast results in more choppy audio.
|
||||
DEBUG_LOG_FMT(IOS_USB,
|
||||
"Wii Speak isochronous transfer: length={:04x} endpoint={:02x} num_packets={:02x}",
|
||||
cmd->length, cmd->endpoint, cmd->num_packets);
|
||||
|
||||
// According to the Wii Speak specs on wiibrew, it's "USB 2.0 Full-speed Device Module",
|
||||
// so the length of a single frame should be 1 ms.
|
||||
// TODO: Find a proper way to compute the transfer timing.
|
||||
const u32 transfer_timing = 2500; // 2.5 ms
|
||||
//
|
||||
// Monster Hunter 3 and the Wii Speak Channel use cmd->length=0x100, allowing 256/2 samples
|
||||
// (i.e. 128 samples in 16-bit mono) per frame transfer. The Microphone class is using cubeb
|
||||
// configured with a sample rate of 8000.
|
||||
//
|
||||
// Based on these numbers, here are some theoretical speeds:
|
||||
// - fastest transfer speed would be 8000 samples in 63 ms (i.e. 8000 * 1/128 = 62.5)
|
||||
// * using a timing of 1 ms per frame of 128 samples
|
||||
// * here cubeb sample rate is the bottleneck
|
||||
// - slowest transfer speed would be 8000 samples in 1000 ms (i.e. 128 * 1000/8000 = 16)
|
||||
// * using a timing of 16 ms per frame of 128 samples
|
||||
// * matching cubeb sampling rate
|
||||
//
|
||||
// A decent timing would be 16ms. However, it seems that the Wii Speak Channel record feature is
|
||||
// broken if the timing is less than 32ms and that the record playback is broken when around 34ms
|
||||
// and above. Monster Hunter 3 doesn't seem affected by this timing issue.
|
||||
//
|
||||
// TODO: Investigate and ensure that's the proper way to fix it.
|
||||
// Maybe it's related to the Wii DSP and its stereo/mono mode?
|
||||
// If so, what would be the impact of using DSP LLE/HLE in mono/stereo?
|
||||
const u32 transfer_timing = 32000;
|
||||
cmd->ScheduleTransferCompletion(IPC_SUCCESS, transfer_timing);
|
||||
return IPC_SUCCESS;
|
||||
}
|
||||
@ -215,22 +234,6 @@ void WiiSpeak::SetRegister(const std::unique_ptr<CtrlMessage>& cmd)
|
||||
DEBUG_LOG_FMT(IOS_USB, "Wii Speak register set (reg={:02x}, arg1={:04x}, arg2={:04x})", reg, arg1,
|
||||
arg2);
|
||||
|
||||
// TODO
|
||||
//
|
||||
// - On Wii Speak Channel start
|
||||
// W[IOS_USB]: Wii Speak unsupported register set (reg=0c, arg1=0000, arg2=0000)
|
||||
// W[IOS_USB]: Wii Speak unsupported register get (reg=0c, arg1=109091e2, arg2=109091e4)
|
||||
//
|
||||
// - On Wii Speak Channel close
|
||||
// W[IOS_USB]: Wii Speak unsupported register set (reg=0c, arg1=0001, arg2=0000)
|
||||
// W[IOS_USB]: Wii Speak unsupported register get (reg=0c, arg1=109091e2, arg2=109091e4)
|
||||
//
|
||||
// - On Monster Hunter 3 (RMHE08) online start
|
||||
// N[OSREPORT_HLE]: 80450a20->80418adc| ok to call PMICStartAsync() -> 0
|
||||
// W[IOS_USB]: Wii Speak unsupported register set (reg=0c, arg1=0000, arg2=0000)
|
||||
// W[IOS_USB]: Wii Speak unsupported register get (reg=0c, arg1=10037f62, arg2=10037f64)
|
||||
// N[OSREPORT_HLE]: 80450a94->80418adc| ok to start P-Mic -> 0.
|
||||
|
||||
switch (reg)
|
||||
{
|
||||
case SAMPLER_STATE:
|
||||
|
@ -49,7 +49,7 @@ private:
|
||||
enum Registers
|
||||
{
|
||||
SAMPLER_STATE = 0,
|
||||
SAMPLER_MUTE = 0xc0,
|
||||
SAMPLER_MUTE = 0x0c,
|
||||
|
||||
SAMPLER_FREQ = 2,
|
||||
FREQ_8KHZ = 0,
|
||||
|
Reference in New Issue
Block a user