mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-13 02:08:49 +12:00
DJ Hero does not register input if the turntable is 0, so force it to 1. This will happen if you map it to the left stick and push it all the way down, or if you use a keyboard, which sends the max value on key press.
288 lines
8.5 KiB
C++
288 lines
8.5 KiB
C++
// DJ Hero Turntable controller emulator
|
|
|
|
#include "stdafx.h"
|
|
#include "Turntable.h"
|
|
#include "Emu/Cell/lv2/sys_usbd.h"
|
|
#include "Emu/Io/turntable_config.h"
|
|
#include "Input/pad_thread.h"
|
|
|
|
LOG_CHANNEL(turntable_log, "TURN");
|
|
|
|
template <>
|
|
void fmt_class_string<turntable_btn>::format(std::string& out, u64 arg)
|
|
{
|
|
format_enum(out, arg, [](turntable_btn value)
|
|
{
|
|
switch (value)
|
|
{
|
|
case turntable_btn::blue: return "Blue";
|
|
case turntable_btn::green: return "Green";
|
|
case turntable_btn::red: return "Red";
|
|
case turntable_btn::dpad_up: return "D-Pad Up";
|
|
case turntable_btn::dpad_down: return "D-Pad Down";
|
|
case turntable_btn::dpad_left: return "D-Pad Left";
|
|
case turntable_btn::dpad_right: return "D-Pad Right";
|
|
case turntable_btn::start: return "Start";
|
|
case turntable_btn::select: return "Select";
|
|
case turntable_btn::square: return "Square";
|
|
case turntable_btn::circle: return "Circle";
|
|
case turntable_btn::cross: return "Cross";
|
|
case turntable_btn::triangle: return "Triangle";
|
|
case turntable_btn::right_turntable: return "Right Turntable";
|
|
case turntable_btn::crossfader: return "Crossfader";
|
|
case turntable_btn::effects_dial: return "Effects Dial";
|
|
case turntable_btn::count: return "Count";
|
|
}
|
|
|
|
return unknown;
|
|
});
|
|
}
|
|
|
|
usb_device_turntable::usb_device_turntable(u32 controller_index, const std::array<u8, 7>& location)
|
|
: usb_device_emulated(location), m_controller_index(controller_index)
|
|
{
|
|
device = UsbDescriptorNode(USB_DESCRIPTOR_DEVICE, UsbDeviceDescriptor{0x0100, 0x00, 0x00, 0x00, 0x40, 0x12BA, 0x0140, 0x0005, 0x01, 0x02, 0x00, 0x01});
|
|
auto& config0 = device.add_node(UsbDescriptorNode(USB_DESCRIPTOR_CONFIG, UsbDeviceConfiguration{0x0029, 0x01, 0x01, 0x00, 0x80, 0x19}));
|
|
config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_INTERFACE, UsbDeviceInterface{0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00}));
|
|
config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_HID, UsbDeviceHID{0x0110, 0x00, 0x01, 0x22, 0x0089}));
|
|
config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ENDPOINT, UsbDeviceEndpoint{0x81, 0x03, 0x0040, 0x0a}));
|
|
config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ENDPOINT, UsbDeviceEndpoint{0x02, 0x03, 0x0040, 0x0a}));
|
|
}
|
|
|
|
usb_device_turntable::~usb_device_turntable()
|
|
{
|
|
}
|
|
|
|
void usb_device_turntable::control_transfer(u8 bmRequestType, u8 bRequest, u16 wValue, u16 wIndex, u16 wLength, u32 buf_size, u8* buf, UsbTransfer* transfer)
|
|
{
|
|
transfer->fake = true;
|
|
|
|
// Control transfers are nearly instant
|
|
switch (bmRequestType)
|
|
{
|
|
case 0x21:
|
|
switch (bRequest)
|
|
{
|
|
case 0x09:
|
|
// Do nothing here - not sure what it should do.
|
|
break;
|
|
default:
|
|
turntable_log.error("Unhandled Query: buf_size=0x%02X, Type=0x%02X, bRequest=0x%02X, bmRequestType=0x%02X", buf_size, (buf_size > 0) ? buf[0] : -1, bRequest, bmRequestType);
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
usb_device_emulated::control_transfer(bmRequestType, bRequest, wValue, wIndex, wLength, buf_size, buf, transfer);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void usb_device_turntable::interrupt_transfer(u32 buf_size, u8* buf, u32 /*endpoint*/, UsbTransfer* transfer)
|
|
{
|
|
ensure(buf_size >= 27);
|
|
|
|
transfer->fake = true;
|
|
transfer->expected_count = buf_size;
|
|
transfer->expected_result = HC_CC_NOERR;
|
|
// Turntable runs at 100hz --> 10ms
|
|
// But make the emulated table go at 1ms for better input behavior
|
|
transfer->expected_time = get_timestamp() + 1'000;
|
|
|
|
memset(buf, 0, buf_size);
|
|
|
|
buf[0] = 0x00; // Face Buttons
|
|
// FACE BUTTON HEXMASK:
|
|
// 0x01 = Square
|
|
// 0x02 = Cross
|
|
// 0x04 = Circle
|
|
// 0x08 = Triangle / Euphoria
|
|
|
|
buf[1] = 0x00; // Start/Select Buttons
|
|
// START/SELECT HEXMASK:
|
|
// 0x01 = Select
|
|
// 0x02 = Start
|
|
// 0x10 = PS Button
|
|
|
|
buf[2] = 0x0F; // D-Pad
|
|
// DPAD VALUES:
|
|
// 0x00 = Up
|
|
// 0x01 = Up-Right
|
|
// 0x02 = Right
|
|
// 0x03 = Right-Down
|
|
// 0x04 = Down
|
|
// 0x05 = Down-Left
|
|
// 0x06 = Left
|
|
// 0x07 = Up-Left
|
|
// 0x0F = None
|
|
|
|
buf[3] = 0x80; // Unknown, always 0x80
|
|
buf[4] = 0x80; // Unknown, always 0x80
|
|
|
|
buf[5] = 0x80; // Left Turntable
|
|
buf[6] = 0x80; // Right Turntable
|
|
|
|
// The following bytes are NOTed (set to 0xFF) when active.
|
|
// If multiple buttons are pressed for one byte, the byte is NOTed twice (reset to 0x00).
|
|
buf[7] = 0x00; // Square Button / D-Pad Right
|
|
buf[8] = 0x00; // D-Pad Left
|
|
buf[9] = 0x00; // Cross Button / D-Pad Up
|
|
buf[10] = 0x00; // D-Pad Down
|
|
buf[11] = 0x00; // Triangle / Euphoria Button
|
|
buf[12] = 0x00; // Circle Button
|
|
|
|
buf[19] = 0x00; // Effects Dial, lower 8 bits
|
|
buf[20] = 0x02; // Effects Dial, upper 2 bits
|
|
|
|
buf[21] = 0x00; // Crossfader, lower 8 bits
|
|
buf[22] = 0x02; // Crossfader, upper 2 bits
|
|
|
|
buf[23] = 0x00; // Platter Buttons
|
|
// PLATTER BUTTON VALUES:
|
|
// 0x01 = Right Platter, Green
|
|
// 0x02 = Right Platter, Red
|
|
// 0x04 = Right Platter, Blue
|
|
// 0x10 = Left Platter, Green
|
|
// 0x20 = Left Platter, Red
|
|
// 0x40 = Left Platter, Blue
|
|
|
|
buf[24] = 0x02; // Unknown, always 0x02
|
|
buf[26] = 0x02; // Unknown, always 0x02
|
|
|
|
// All other bufs are always 0x00
|
|
|
|
std::lock_guard lock(pad::g_pad_mutex);
|
|
const auto handler = pad::get_current_handler();
|
|
const auto& pads = handler->GetPads();
|
|
const auto& pad = ::at32(pads, m_controller_index);
|
|
|
|
if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED))
|
|
return;
|
|
|
|
const auto& cfg = ::at32(g_cfg_turntable.players, m_controller_index);
|
|
cfg->handle_input(pad, true, [&buf](turntable_btn btn, u16 value, bool pressed)
|
|
{
|
|
if (!pressed)
|
|
return;
|
|
|
|
switch (btn)
|
|
{
|
|
case turntable_btn::blue:
|
|
buf[0] |= 0x01; // Square Button
|
|
buf[7] = ~buf[7]; // Square Button
|
|
buf[23] |= 0x04; // Right Platter Blue
|
|
break;
|
|
case turntable_btn::green:
|
|
buf[0] |= 0x02; // Cross Button
|
|
buf[9] = ~buf[9]; // Cross Button
|
|
buf[23] |= 0x01; // Right Platter Green
|
|
break;
|
|
case turntable_btn::red:
|
|
buf[0] |= 0x04; // Circle Button
|
|
buf[12] = ~buf[12]; // Circle Button
|
|
buf[23] |= 0x02; // Right Platter Red
|
|
break;
|
|
case turntable_btn::triangle:
|
|
buf[0] |= 0x08; // Triangle Button / Euphoria
|
|
buf[11] = ~buf[11]; // Triangle Button / Euphoria
|
|
break;
|
|
case turntable_btn::cross:
|
|
buf[0] |= 0x02; // Cross Button Only
|
|
buf[9] = ~buf[9]; // Cross Button Only
|
|
break;
|
|
case turntable_btn::circle:
|
|
buf[0] |= 0x04; // Circle Button Only
|
|
buf[12] = ~buf[12]; // Circle Button Only
|
|
break;
|
|
case turntable_btn::square:
|
|
buf[0] |= 0x01; // Square Button Only
|
|
buf[7] = ~buf[7]; // Square Button Only
|
|
break;
|
|
case turntable_btn::dpad_down:
|
|
if (buf[2] == 0x02) // Right D-Pad
|
|
{
|
|
buf[2] = 0x03; // Right-Down D-Pad
|
|
}
|
|
else if (buf[2] == 0x06) // Left D-Pad
|
|
{
|
|
buf[2] = 0x05; // Left-Down D-Pad
|
|
}
|
|
else
|
|
{
|
|
buf[2] = 0x04; // Down D-Pad
|
|
}
|
|
buf[10] = ~buf[10]; // Down D-Pad;
|
|
break;
|
|
case turntable_btn::dpad_up:
|
|
if (buf[2] == 0x02) // Right D-Pad
|
|
{
|
|
buf[2] = 0x01; // Right-Up D-Pad
|
|
}
|
|
else if (buf[2] == 0x06) // Left D-Pad
|
|
{
|
|
buf[2] = 0x07; // Left-Up D-Pad
|
|
}
|
|
else
|
|
{
|
|
buf[2] = 0x00; // Up D-Pad
|
|
}
|
|
buf[9] = ~buf[9]; // Up D-Pad;
|
|
break;
|
|
case turntable_btn::dpad_left:
|
|
if (buf[2] == 0x00) // Up D-Pad
|
|
{
|
|
buf[2] = 0x07; // Left-Up D-Pad
|
|
}
|
|
else if (buf[2] == 0x04) // Down D-Pad
|
|
{
|
|
buf[2] = 0x05; // Left-Down D-Pad
|
|
}
|
|
else
|
|
{
|
|
buf[2] = 0x06; // Left D-Pad
|
|
}
|
|
buf[8] = ~buf[8]; // Left D-Pad;
|
|
break;
|
|
case turntable_btn::dpad_right:
|
|
if (buf[2] == 0x00) // Up D-Pad
|
|
{
|
|
buf[2] = 0x01; // Right-Up D-Pad
|
|
}
|
|
else if (buf[2] == 0x04) // Down D-Pad
|
|
{
|
|
buf[2] = 0x03; // Right-Down D-Pad
|
|
}
|
|
else
|
|
{
|
|
buf[2] = 0x02; // Right D-Pad
|
|
}
|
|
buf[7] = ~buf[7]; // Right D-Pad
|
|
break;
|
|
case turntable_btn::start:
|
|
buf[1] |= 0x02; // Start
|
|
break;
|
|
case turntable_btn::select:
|
|
buf[1] |= 0x01; // Select
|
|
break;
|
|
case turntable_btn::right_turntable:
|
|
// DJ Hero does not register input if the turntable is 0, so force it to 1.
|
|
buf[6] = std::max(1, 255 - value); // Right Turntable
|
|
// DJ Hero requires turntables to be centered at 128.
|
|
// If this axis ends up centered at 127, force it to 128.
|
|
if (buf[6] == 127)
|
|
{
|
|
buf[6] = 128;
|
|
}
|
|
break;
|
|
case turntable_btn::crossfader:
|
|
buf[21] = ((255 - value) & 0x3F) << 2; // Crossfader, lower 6 bits
|
|
buf[22] = ((255 - value) & 0xC0) >> 6; // Crossfader, upper 2 bits
|
|
break;
|
|
case turntable_btn::effects_dial:
|
|
buf[19] = (value & 0x3F) << 2; // Effects Dial, lower 6 bits
|
|
buf[20] = (value & 0xC0) >> 6; // Effects Dial, upper 2 bits
|
|
break;
|
|
case turntable_btn::count:
|
|
break;
|
|
}
|
|
});
|
|
}
|