Skip to content
Permalink
Browse files

WiimoteEmu: Add wiimote speaker logic to i2c bus. Temporarily break t…

…he "pan" setting.
  • Loading branch information...
jordan-woyak committed Nov 23, 2018
1 parent 62b6658 commit ec460da36d212b6d61fb9e5886b42130b630dc52
@@ -405,7 +405,10 @@ struct wm_write_data
u8 rumble : 1;
u8 space : 2; // see WM_SPACE_*
u8 : 5;
u8 address[3];
// used only for register space (i2c bus)
u8 slave_address;
// big endian:
u8 address[2];
u8 size;
u8 data[16];
};
@@ -424,8 +427,11 @@ struct wm_read_data
u8 rumble : 1;
u8 space : 2; // see WM_SPACE_*
u8 : 5;
u8 address[3];
u16 size;
// used only for register space (i2c bus)
u8 slave_address;
// big endian:
u8 address[2];
u8 size[2];
};
static_assert(sizeof(wm_read_data) == 6, "Wrong size");

@@ -44,8 +44,9 @@ void Wiimote::ReportMode(const wm_report_mode* const dr)
// DEBUG_LOG(WIIMOTE, " All The Time: %x", dr->all_the_time);
// DEBUG_LOG(WIIMOTE, " Mode: 0x%02x", dr->mode);

// TODO: what does the 'all_the_time' bit really do?
// m_reporting_auto = dr->all_the_time;
m_reporting_auto = dr->continuous; // this right?
m_reporting_auto = dr->continuous;
m_reporting_mode = dr->mode;
// m_reporting_channel = _channelID; // this is set in every Interrupt/Control Channel now

@@ -126,8 +127,14 @@ void Wiimote::HidOutputReport(const wm_report* const sr, const bool send_ack)
break;

case RT_WRITE_SPEAKER_DATA: // 0x18
// Not sure if speaker mute stops the bus write on real hardware, but it's not that important
if (!m_speaker_mute)
Wiimote::SpeakerData(reinterpret_cast<const wm_speaker_data*>(sr->data));
{
auto sd = reinterpret_cast<const wm_speaker_data*>(sr->data);
if (sd->length > 20)
PanicAlert("EmuWiimote: bad speaker data length!");
m_i2c_bus.BusWrite(0x51, 0x00, sd->length, sd->data);
}
return; // no ack
break;

@@ -218,10 +225,9 @@ void Wiimote::RequestStatus(const wm_request_status* const rs)
/* Write data to Wiimote and Extensions registers. */
void Wiimote::WriteData(const wm_write_data* const wd)
{
u32 address = Common::swap24(wd->address);
u16 address = Common::swap16(wd->address);

// ignore the 0x010000 bit
address &= ~0x010000;
INFO_LOG(WIIMOTE, "Wiimote::WriteData: 0x%02x @ 0x%02x (%d)", wd->space, address, wd->size);

if (wd->size > 16)
{
@@ -261,8 +267,8 @@ void Wiimote::WriteData(const wm_write_data* const wd)
{
// Write to Control Register

// TODO: generate a writedata error reply for wrong number of bytes written..
m_i2c_bus.BusWrite(address >> 17, address & 0xff, wd->size, wd->data);
// TODO: generate a writedata error reply, 7 == no such slave (no ack)
m_i2c_bus.BusWrite(wd->slave_address >> 1, address & 0xff, wd->size, wd->data);

return;

@@ -290,11 +296,10 @@ void Wiimote::WriteData(const wm_write_data* const wd)
/* Read data from Wiimote and Extensions registers. */
void Wiimote::ReadData(const wm_read_data* const rd)
{
u32 address = Common::swap24(rd->address);
u16 address = Common::swap16(rd->address);
u16 size = Common::swap16(rd->size);

// ignore the 0x010000 bit
address &= 0xFEFFFF;
//INFO_LOG(WIIMOTE, "Wiimote::ReadData: %d @ 0x%02x @ 0x%02x (%d)", rd->space, rd->slave_address, address, size);

ReadRequest rr;
u8* const block = new u8[size];
@@ -312,7 +317,8 @@ void Wiimote::ReadData(const wm_read_data* const rd)
delete[] block;
return;
}
// generate a read error

// generate a read error, even if the start of the block is readable a real wiimote just sends error code 8
size = 0;
}

@@ -337,23 +343,24 @@ void Wiimote::ReadData(const wm_read_data* const rd)
{
// Read from Control Register

m_i2c_bus.BusRead(address >> 17, address & 0xff, rd->size, block);
// TODO: generate read errors
m_i2c_bus.BusRead(rd->slave_address >> 1, address & 0xff, size, block);
// TODO: generate read errors, 7 == no such slave (no ack)
}
break;

default:
PanicAlert("WmReadData: unimplemented parameters (size: %i, address: 0x%x)!", size, rd->space);
PanicAlert("Wiimote::ReadData: unimplemented address space (space: 0x%x)!", rd->space);
break;
}

// want the requested address, not the above modified one
rr.address = Common::swap24(rd->address);
rr.address = address;
rr.size = size;
// rr.channel = _channelID;
rr.position = 0;
rr.data = block;

// TODO: read requests suppress normal input reports
// TODO: if there is currently an active read request ignore new ones

// send up to 16 bytes
SendReadDataReply(rr);

@@ -391,7 +398,7 @@ void Wiimote::SendReadDataReply(ReadRequest& request)
{
// Limit the amt to 16 bytes
// AyuanX: the MTU is 640B though... what a waste!
const int amt = std::min((unsigned int)16, request.size);
const int amt = std::min((u16)16, request.size);

// no error
reply->error = 0;
@@ -432,13 +439,13 @@ void Wiimote::DoState(PointerWrap& p)
p.Do(m_shake_step);
p.Do(m_sensor_bar_on_top);
p.Do(m_status);
p.Do(m_adpcm_state);
p.Do(m_speaker_logic.adpcm_state);
p.Do(m_ext_logic.ext_key);
p.DoArray(m_eeprom);
p.Do(m_reg_motion_plus);
p.Do(m_camera_logic.reg_data);
p.Do(m_ext_logic.reg_data);
p.Do(m_reg_speaker);
p.Do(m_speaker_logic.reg_data);

// Do 'm_read_requests' queue
{
@@ -68,39 +68,40 @@ void stopdamnwav()
}
#endif

void Wiimote::SpeakerData(const wm_speaker_data* sd)
void Wiimote::SpeakerLogic::SpeakerData(const u8* data, int length)
{
if (!SConfig::GetInstance().m_WiimoteEnableSpeaker)
return;
if (m_reg_speaker.volume == 0 || m_reg_speaker.sample_rate == 0 || sd->length == 0)
if (reg_data.volume == 0 || reg_data.sample_rate == 0 ||
length == 0)
return;

// TODO consider using static max size instead of new
std::unique_ptr<s16[]> samples(new s16[sd->length * 2]);
std::unique_ptr<s16[]> samples(new s16[length * 2]);

unsigned int sample_rate_dividend, sample_length;
u8 volume_divisor;

if (m_reg_speaker.format == 0x40)
if (reg_data.format == 0x40)
{
// 8 bit PCM
for (int i = 0; i < sd->length; ++i)
for (int i = 0; i < length; ++i)
{
samples[i] = ((s16)(s8)sd->data[i]) << 8;
samples[i] = ((s16)(s8)data[i]) << 8;
}

// Following details from http://wiibrew.org/wiki/Wiimote#Speaker
sample_rate_dividend = 12000000;
volume_divisor = 0xff;
sample_length = (unsigned int)sd->length;
sample_length = (unsigned int)length;
}
else if (m_reg_speaker.format == 0x00)
else if (reg_data.format == 0x00)
{
// 4 bit Yamaha ADPCM (same as dreamcast)
for (int i = 0; i < sd->length; ++i)
for (int i = 0; i < length; ++i)
{
samples[i * 2] = adpcm_yamaha_expand_nibble(m_adpcm_state, (sd->data[i] >> 4) & 0xf);
samples[i * 2 + 1] = adpcm_yamaha_expand_nibble(m_adpcm_state, sd->data[i] & 0xf);
samples[i * 2] = adpcm_yamaha_expand_nibble(adpcm_state, (data[i] >> 4) & 0xf);
samples[i * 2 + 1] = adpcm_yamaha_expand_nibble(adpcm_state, data[i] & 0xf);
}

// Following details from http://wiibrew.org/wiki/Wiimote#Speaker
@@ -109,19 +110,20 @@ void Wiimote::SpeakerData(const wm_speaker_data* sd)
// 0 - 127
// TODO: does it go beyond 127 for format == 0x40?
volume_divisor = 0x7F;
sample_length = (unsigned int)sd->length * 2;
sample_length = (unsigned int)length * 2;
}
else
{
ERROR_LOG(IOS_WIIMOTE, "Unknown speaker format %x", m_reg_speaker.format);
ERROR_LOG(IOS_WIIMOTE, "Unknown speaker format %x", reg_data.format);
return;
}

// Speaker Pan
unsigned int vol = (unsigned int)(m_options->numeric_settings[0]->GetValue() * 100);
// TODO: fix
unsigned int vol = 0;//(unsigned int)(m_options->numeric_settings[0]->GetValue() * 100);

unsigned int sample_rate = sample_rate_dividend / m_reg_speaker.sample_rate;
float speaker_volume_ratio = (float)m_reg_speaker.volume / volume_divisor;
unsigned int sample_rate = sample_rate_dividend / reg_data.sample_rate;
float speaker_volume_ratio = (float)reg_data.volume / volume_divisor;
unsigned int left_volume = (unsigned int)((128 + vol) * speaker_volume_ratio);
unsigned int right_volume = (unsigned int)((128 - vol) * speaker_volume_ratio);

@@ -147,12 +149,12 @@ void Wiimote::SpeakerData(const wm_speaker_data* sd)
File::OpenFStream(ofile, "rmtdump.bin", ofile.binary | ofile.out);
wav.Start("rmtdump.wav", 6000);
}
wav.AddMonoSamples(samples.get(), sd->length * 2);
wav.AddMonoSamples(samples.get(), length * 2);
if (ofile.good())
{
for (int i = 0; i < sd->length; i++)
for (int i = 0; i < length; i++)
{
ofile << sd->data[i];
ofile << data[i];
}
}
num++;
@@ -328,9 +328,9 @@ void Wiimote::Reset()
memcpy(m_eeprom + 0x16D0, eeprom_data_16D0, sizeof(eeprom_data_16D0));

// set up the register
memset(&m_reg_speaker, 0, sizeof(m_reg_speaker));

// TODO: kill/move these
memset(&m_speaker_logic.reg_data, 0, sizeof(m_speaker_logic.reg_data));
memset(&m_camera_logic.reg_data, 0, sizeof(m_camera_logic.reg_data));
memset(&m_ext_logic.reg_data, 0, sizeof(m_ext_logic.reg_data));

@@ -361,14 +361,15 @@ void Wiimote::Reset()
}

// Yamaha ADPCM state initialize
m_adpcm_state.predictor = 0;
m_adpcm_state.step = 127;
m_speaker_logic.adpcm_state.predictor = 0;
m_speaker_logic.adpcm_state.step = 127;

// Initialize i2c bus
// TODO: kill magic numbers
m_i2c_bus.Reset();
m_i2c_bus.AddSlave(0x58, &m_camera_logic);
m_i2c_bus.AddSlave(0x52, &m_ext_logic);
m_i2c_bus.AddSlave(0x51, &m_speaker_logic);
}

Wiimote::Wiimote(const unsigned int index) : m_index(index), ir_sin(0), ir_cos(1)
@@ -255,6 +255,8 @@ class I2CBus
{
INFO_LOG(WIIMOTE, "i2c bus read: 0x%02x @ 0x%02x (%d)", slave_addr, addr, count);

// TODO: reads loop around at end of address space (0xff)

auto it = m_slaves.find(slave_addr);
if (m_slaves.end() != it)
return it->second->BusRead(addr, count, data_out);
@@ -266,6 +268,8 @@ class I2CBus
{
INFO_LOG(WIIMOTE, "i2c bus write: 0x%02x @ 0x%02x (%d)", slave_addr, addr, count);

// TODO: writes loop around at end of address space (0xff)

auto it = m_slaves.find(slave_addr);
if (m_slaves.end() != it)
return it->second->BusWrite(addr, count, data_in);
@@ -396,10 +400,49 @@ class Wiimote : public ControllerEmu::EmulatedController

} m_ext_logic;

struct SpeakerLogic : public I2CSlave
{
struct
{
// Speaker reports result in a write of samples to addr 0x00 (which also plays sound)
u8 speaker_data;
u8 unk_1;
u8 format;
// seems to always play at 6khz no matter what this is set to?
// or maybe it only applies to pcm input
u16 sample_rate;
u8 volume;
u8 unk_6;
u8 unk_7;
u8 play;
u8 unk_9;
} reg_data;

ADPCMState adpcm_state;

void SpeakerData(const u8* data, int length);

int BusRead(u8 addr, int count, u8* data_out) override
{
return raw_read(&reg_data, addr, count, data_out);
}

int BusWrite(u8 addr, int count, const u8* data_in) override
{
if (0x00 == addr)
{
SpeakerData(data_in, count);
return count;
}
else
return raw_write(&reg_data, addr, count, data_in);
}

} m_speaker_logic;

struct ReadRequest
{
// u16 channel;
u32 address, size, position;
u16 address, size, position;
u8* data;
};

@@ -409,7 +452,6 @@ class Wiimote : public ControllerEmu::EmulatedController
void ReadData(const wm_read_data* rd);
void WriteData(const wm_write_data* wd);
void SendReadDataReply(ReadRequest& request);
void SpeakerData(const wm_speaker_data* sd);
bool NetPlay_GetWiimoteData(int wiimote, u8* data, u8 size, u8 reporting_mode);

// control groups
@@ -463,8 +505,6 @@ class Wiimote : public ControllerEmu::EmulatedController

wm_status_report m_status;

ADPCMState m_adpcm_state;

// read data request queue
// maybe it isn't actually a queue
// maybe read requests cancel any current requests
@@ -485,21 +525,6 @@ class Wiimote : public ControllerEmu::EmulatedController
u8 ext_identifier[6];
} m_reg_motion_plus;

struct SpeakerReg
{
u8 unused_0;
u8 unk_1;
u8 format;
// seems to always play at 6khz no matter what this is set to?
// or maybe it only applies to pcm input
u16 sample_rate;
u8 volume;
u8 unk_6;
u8 unk_7;
u8 play;
u8 unk_9;
} m_reg_speaker;

#pragma pack(pop)
};
} // namespace WiimoteEmu

0 comments on commit ec460da

Please sign in to comment.
You can’t perform that action at this time.