87 lines
3.5 KiB
Python
87 lines
3.5 KiB
Python
import usb_hid
|
|
import supervisor
|
|
import storage
|
|
import usb_midi
|
|
|
|
DEFAULT_REPORT_ID = 1
|
|
HANDSHAKE_REPORT_ID = 2
|
|
VENDOR_ID = 0x0359
|
|
PRODUCT_ID = 0x6497 # T9 MIXR
|
|
|
|
RESOLUTION = 100 # Voicemeeter sliders go from 12.0 to -60.0 in 0.1 increments
|
|
|
|
REPORT_DESCRIPTOR = bytes([
|
|
0x05, 0x01, # Usage Page (Generic Desktop Controls)
|
|
0x09, 0x08, # Usage (Multi-Axis Controller)
|
|
#0x09, 0x04, # Joystick usage (for windows to pick up as usb controller)
|
|
0xA1, 0x01, # Collection (Application)
|
|
# BUTTONS
|
|
0x05, 0x09, # Usage Page (Button)
|
|
0x19, 0x01, # Usage Minimum (Button 1)
|
|
0x29, 0x30, # Usage Maximum (Button 48)
|
|
0x15, 0x00, # Logical Minimum (0)
|
|
0x25, 0x01, # Logical Maximum (1)
|
|
0x75, 0x01, # Report Size (1 bit)
|
|
0x95, 0x30, # Report Count (48)
|
|
0x81, 0x02, # Input (Data, Variable, Absolute)
|
|
# SLIDERS
|
|
0x15, 0x00, # Logical Minimum (0)
|
|
0x26, 0xFF, 0xFF, # Logical Maximum (RESOLUTION (720))
|
|
0x75, 0x10, # Report Size (16-bit)
|
|
#0x85, DEFAULT_REPORT_ID, # Report ID (DEFAULT_REPORT_ID)
|
|
0x95, 0x05, # Report Count (5)
|
|
0x09, 0x30, # Usage (X)
|
|
0x09, 0x31, # Usage (Y)
|
|
0x09, 0x32, # Usage (Z)
|
|
0x09, 0x33, # Usage (Rx)
|
|
0x09, 0x34, # Usage (Ry)
|
|
0x81, 0x00, # Input (Data, Array, Absolute)
|
|
0xC0, # End Collection
|
|
#0x05, 0x06, # Usage Page (Generic Device Controls)
|
|
#0x09, 0x01, # Usage (Background/Nonuser controls)
|
|
#0xA1, 0x01, # Collection (Application)
|
|
#0x75, 0x20, # Report Size (32-bit)
|
|
#0x95, 0x01, # Report Count (1)
|
|
#0x85, HANDSHAKE_REPORT_ID,# Report ID (HANDSHAKE_REPORT_ID)
|
|
#0x81, 0x01, # Input (Constant, Array, Absolute)
|
|
#0xC0, # End Collection
|
|
])
|
|
|
|
def initUsb():
|
|
if supervisor.runtime.usb_connected:
|
|
raise RuntimeError("USB cannot be initialized post-boot")
|
|
supervisor.set_usb_identification(manufacturer="TechAbsol", product="USB Mixer", vid=VENDOR_ID, pid=PRODUCT_ID)
|
|
|
|
usb_midi.disable()
|
|
usb_hid.set_interface_name("CircuitPython Mixer")
|
|
sliders = usb_hid.Device(
|
|
report_descriptor = REPORT_DESCRIPTOR,
|
|
usage_page=0x01,
|
|
usage=0x08,
|
|
report_ids=(0,),
|
|
in_report_lengths=(16,),
|
|
out_report_lengths=(0,),
|
|
)
|
|
|
|
#storage.disable_usb_drive()
|
|
#storage.remount("/", False)
|
|
usb_hid.enable((sliders,))
|
|
|
|
class UsbMixer():
|
|
def __init__(self):
|
|
if not supervisor.runtime.usb_connected:
|
|
raise RuntimeError("USB is not connected")
|
|
self._device = next((dev for dev in usb_hid.devices if dev.usage_page == 0x01 and dev.usage == 0x08))
|
|
if self._device is None:
|
|
raise RuntimeError("USB mixer doesn't appear to be initialized")
|
|
|
|
def _valToBytes(self, value):
|
|
return bytes([value & 0xFF, (value >> 8) & 0xFF])
|
|
|
|
def _keysToBytes(self, keys):
|
|
return bytes([keys[0], keys[1], keys[2], keys[3], keys[4], keys[5]])
|
|
|
|
def send_values(self, slider1, slider2, slider3, slider4, slider5, keys):
|
|
report = self._keysToBytes(keys) + self._valToBytes(slider1) + self._valToBytes(slider2) + self._valToBytes(slider3) + self._valToBytes(slider4) + self._valToBytes(slider5)
|
|
self._device.send_report(report)
|