proof of concept: control crackin'dj with traktor S4
This commit is contained in:
parent
a46dc71156
commit
1d4106968e
|
@ -448,7 +448,7 @@ if(NOT LIBRETRO)
|
|||
endif()
|
||||
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE USE_SDL USE_SDL_AUDIO)
|
||||
target_sources(${PROJECT_NAME} PRIVATE core/sdl/sdl.cpp core/sdl/sdl.h core/sdl/sdl_gamepad.h core/sdl/sdl_keyboard.h)
|
||||
target_sources(${PROJECT_NAME} PRIVATE core/sdl/sdl.cpp core/sdl/sdl.h core/sdl/sdl_gamepad.h core/sdl/sdl_keyboard.h core/sdl/hid.cpp)
|
||||
|
||||
if((UNIX AND NOT APPLE) OR NINTENDO_SWITCH)
|
||||
find_package(CURL REQUIRED)
|
||||
|
|
|
@ -30,6 +30,11 @@
|
|||
#include <array>
|
||||
#include <memory>
|
||||
|
||||
#define CRACKINDJ_TRAKTOR
|
||||
#ifdef CRACKINDJ_TRAKTOR
|
||||
#include "sdl/hid.h"
|
||||
#endif
|
||||
|
||||
#define LOGJVS(...) DEBUG_LOG(JVS, __VA_ARGS__)
|
||||
|
||||
u8 *EEPROM;
|
||||
|
@ -236,6 +241,9 @@ protected:
|
|||
networkOutput.output(name.c_str(), (newOutput >> i) & 1);
|
||||
}
|
||||
digOutput = newOutput;
|
||||
#ifdef CRACKINDJ_TRAKTOR
|
||||
hidOutput(*data & 0x80, *data & 8, *data & 0x20, *data & 0x40, *data & 4);
|
||||
#endif
|
||||
}
|
||||
|
||||
virtual void read_lightgun(int playerNum, u32 buttons, u16& x, u16& y)
|
||||
|
@ -482,6 +490,7 @@ protected:
|
|||
{
|
||||
jvs_io_board& outputBoard = *parent->io_boards[1];
|
||||
bool turntableOn = outputBoard.getDigitalOutput() & 0x10;
|
||||
#ifndef CRACKINDJ_TRAKTOR
|
||||
switch (channel)
|
||||
{
|
||||
case 0: // Left turntable
|
||||
|
@ -497,11 +506,28 @@ protected:
|
|||
default:
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
if (channel != 0 && channel != 2)
|
||||
return 0;
|
||||
channel /= 2;
|
||||
rotary[channel] -= jogWheelsDelta[channel];
|
||||
if (turntableOn && !jogWheelsTouched[channel])
|
||||
// should be around 10, possibly a bit less to match real hw (based on yt videos)
|
||||
// half a turn should skip 3 to 4 tunes (more like 4?)
|
||||
// currently half turn -> 7
|
||||
rotary[channel] -= 10;
|
||||
//printf("wheel[%d] %d motor %d\n", channel, rotary[channel], turntableOn);
|
||||
jogWheelsDelta[channel] = 0;
|
||||
return rotary[channel];
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
s16 motorRotation[2]{};
|
||||
s16 lastRel[2]{};
|
||||
#ifdef CRACKINDJ_TRAKTOR
|
||||
s16 rotary[2] {};
|
||||
#endif
|
||||
};
|
||||
|
||||
// Sega Marine Fishing, 18 Wheeler (TODO)
|
||||
|
@ -1978,6 +2004,10 @@ void maple_naomi_jamma::deserialize(Deserializer& deser)
|
|||
|
||||
u16 jvs_io_board::read_analog_axis(int player_num, int player_axis, bool inverted)
|
||||
{
|
||||
#ifdef CRACKINDJ_TRAKTOR
|
||||
if (player_num == 0 && player_axis == 0)
|
||||
return (2048 - std::clamp<int>(crossFader, -2030, 2030)) * 16;
|
||||
#endif
|
||||
u16 v;
|
||||
if (player_axis >= 0 && player_axis < 4)
|
||||
v = mapleInputState[player_num].fullAxes[player_axis] + 0x8000;
|
||||
|
|
|
@ -0,0 +1,144 @@
|
|||
int jogWheelsDelta[2];
|
||||
bool jogWheelsTouched[2];
|
||||
short crossFader;
|
||||
|
||||
#if defined(USE_SDL)
|
||||
#include "types.h"
|
||||
#include "hid.h"
|
||||
#include "input/gamepad_device.h"
|
||||
#include <SDL.h>
|
||||
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 18)
|
||||
static SDL_hid_device *device;
|
||||
static u8 lastJogTick[2];
|
||||
static u16 lastJogTime[2];
|
||||
|
||||
// need rw access to the hid device (sudo chmod o+rw /dev/hidraw4)
|
||||
void hidInit()
|
||||
{
|
||||
SDL_hid_init();
|
||||
|
||||
/*
|
||||
SDL_hid_device_info *devInfo = SDL_hid_enumerate(0, 0); // vendor id, product id
|
||||
while (devInfo != nullptr)
|
||||
{
|
||||
printf("path %s vendor/prod %04x/%04x manufact %S product %S\n", devInfo->path, devInfo->vendor_id, devInfo->product_id,
|
||||
devInfo->manufacturer_string, devInfo->product_string);
|
||||
devInfo = devInfo->next;
|
||||
}
|
||||
SDL_hid_free_enumeration(devInfo);
|
||||
*/
|
||||
|
||||
// 17cc/1310 is traktor s4
|
||||
device = SDL_hid_open(0x17cc, 0x1310, nullptr);
|
||||
if (device == nullptr)
|
||||
WARN_LOG(INPUT, "SDL_hid_open failed");
|
||||
else
|
||||
SDL_hid_set_nonblocking(device, 1);
|
||||
hidOutput(false, false, false, false, false);
|
||||
}
|
||||
|
||||
void hidTerm()
|
||||
{
|
||||
if (device != nullptr)
|
||||
{
|
||||
hidOutput(false, false, false, false, false);
|
||||
SDL_hid_close(device);
|
||||
device = nullptr;
|
||||
}
|
||||
SDL_hid_exit();
|
||||
}
|
||||
|
||||
void hidInput()
|
||||
{
|
||||
if (device == nullptr)
|
||||
return;
|
||||
u8 data[256];
|
||||
for (;;)
|
||||
{
|
||||
int read = SDL_hid_read(device, data, sizeof(data));
|
||||
if (read <= 0)
|
||||
{
|
||||
if (read < 0)
|
||||
WARN_LOG(INPUT, "hid_read failed");
|
||||
break;
|
||||
}
|
||||
if (read >= 10)
|
||||
{
|
||||
// addControl(group, name, offset, pack, bitmask, isEncoder, callback)
|
||||
// I: u32
|
||||
// H: u16
|
||||
if (data[0] == 1) // short msg
|
||||
{
|
||||
// MessageShort.addControl("deck1", "!jog_wheel", 0x01, "I")
|
||||
// MessageShort.addControl("deck2", "!jog_wheel", 0x05, "I")
|
||||
// MessageShort.addControl("deck1", "!jog_touch", 0x11, "B", 0x01)
|
||||
// MessageShort.addControl("deck2", "!jog_touch", 0x11, "B", 0x02)
|
||||
// MessageShort.addControl("deck1", "!play", 0x0D, "B", 0x01);
|
||||
// MessageShort.addControl("deck2", "!play", 0x0C, "B", 0x01);
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
u32 jog = *(u32 *)&data[i * 4 + 1];
|
||||
u8 tickval = jog & 0xff;
|
||||
u16 timeval = jog >> 16;
|
||||
if (lastJogTime[i] > timeval) {
|
||||
// We looped around. Adjust current time so that subtraction works.
|
||||
timeval += 0x10000;
|
||||
}
|
||||
int time_delta = timeval - lastJogTime[i];
|
||||
if (time_delta == 0)
|
||||
// Spinning too fast to detect speed! By not dividing we are guessing it took 1ms.
|
||||
time_delta = 1;
|
||||
int tick_delta = 0;
|
||||
if (lastJogTick[i] >= 200 && tickval <= 100)
|
||||
tick_delta = tickval + 256 - lastJogTick[i];
|
||||
else if (lastJogTick[i] <= 100 && tickval >= 200)
|
||||
tick_delta = tickval - lastJogTick[i] - 256;
|
||||
else
|
||||
tick_delta = tickval - lastJogTick[i];
|
||||
|
||||
lastJogTick[i] = tickval;
|
||||
lastJogTime[i] = timeval;
|
||||
jogWheelsDelta[i] += tick_delta;
|
||||
//printf("%s wheel %d\n", i == 0 ? "left" : "right", jogWheelsDelta[i]);
|
||||
|
||||
jogWheelsTouched[i] = data[0x11] & (1 << i);
|
||||
}
|
||||
if ((data[0xd] & 1) || (data[0xc] & 1))
|
||||
kcode[0] &= ~DC_BTN_START;
|
||||
else
|
||||
kcode[0] |= DC_BTN_START;
|
||||
}
|
||||
else
|
||||
{
|
||||
// reportID=2: long msg
|
||||
//MessageLong.addControl("[Master]", "crossfader", 0x07, "H");
|
||||
crossFader = *(u16 *)&data[7] - 2048;
|
||||
//printf("cross fader %d\n", crossFader);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void hidOutput(bool play, bool spotL, bool spotR, bool backL, bool backR)
|
||||
{
|
||||
if (device == nullptr)
|
||||
return;
|
||||
u8 msg[0x3E]{};
|
||||
msg[0] = 0x81;
|
||||
msg[0x20] = play ? 0xff : 0; // deck1 Play
|
||||
msg[0x28] = play ? 0xff : 0; // deck2 Play
|
||||
msg[0x2d] = spotL ? 0xff : 0; // deck1 on air
|
||||
msg[0x33] = spotR ? 0xff : 0; // deck2 on air
|
||||
msg[0x2e] = backL ? 0xff : 0; // deck A
|
||||
msg[0x34] = backR ? 0xff : 0; // deck B
|
||||
SDL_hid_write(device, msg, sizeof(msg));
|
||||
}
|
||||
|
||||
#else // SDL < 2.0.18
|
||||
void hidOutput(bool play, bool spotL, bool spotR, bool backL, bool backR) {}
|
||||
#endif
|
||||
|
||||
#else // !USE_SDL
|
||||
void hidOutput(bool play, bool spotL, bool spotR, bool backL, bool backR) {}
|
||||
#endif
|
|
@ -0,0 +1,9 @@
|
|||
#pragma once
|
||||
void hidInit();
|
||||
void hidTerm();
|
||||
void hidInput();
|
||||
void hidOutput(bool play, bool spotL, bool spotR, bool backL, bool backR);
|
||||
|
||||
extern int jogWheelsDelta[2];
|
||||
extern bool jogWheelsTouched[2];
|
||||
extern short crossFader;
|
|
@ -31,6 +31,7 @@
|
|||
#include "switch_gamepad.h"
|
||||
#endif
|
||||
#include <unordered_map>
|
||||
#include "hid.h"
|
||||
|
||||
static SDL_Window* window = NULL;
|
||||
static u32 windowFlags;
|
||||
|
@ -225,6 +226,7 @@ void input_sdl_init()
|
|||
SDL_InitSubSystem(SDL_INIT_HAPTIC);
|
||||
|
||||
SDL_SetRelativeMouseMode(SDL_FALSE);
|
||||
hidInit();
|
||||
|
||||
// Event::Start is called on a background thread, so we can't use it to change the window title (macOS)
|
||||
// However it's followed by Event::Resume which is fine.
|
||||
|
@ -269,6 +271,7 @@ void input_sdl_quit()
|
|||
EventManager::unlisten(Event::Resume, emuEventCallback);
|
||||
SDLGamepad::closeAllGamepads();
|
||||
SDL_QuitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC);
|
||||
hidTerm();
|
||||
}
|
||||
|
||||
inline void SDLMouse::setAbsPos(int x, int y)
|
||||
|
@ -293,6 +296,7 @@ static std::shared_ptr<SDLMouse> getMouse(u64 mouseId)
|
|||
void input_sdl_handle()
|
||||
{
|
||||
SDLGamepad::UpdateRumble();
|
||||
hidInput();
|
||||
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event))
|
||||
|
|
Loading…
Reference in New Issue