I recently got a Moondrop FreeDSP which is an IEM cable with a USB-C termination, comprising both a balanced DAC and a DSP. It's plug and play and the last used DSP profile is automatically carried forward & applied without the need of any software. However, the software you need to configure the DSP in the first place is hot garbage for so many reasons; least of all, being mobile only. This got me thinking whether the DSP profile could be read & subsequently adapted using a PC.
I do a little coding now & then and found the opensource library 'libusb' which looked promising. Better still, I found its Python wrapper 'pyusb' which promises easy USB access. Now, I've never worked with USB from a dev/engineering perspective, so I didn't find it very user friendly at all. Anyhow, after a couple of hours I could find the device, it's endpoints & read their data. I was hoping that'd be a springboard moment enabling me to do something useful. Alas, I can't see anything meaningful in the data & I suspect that I'm missing something fundamental.
My code:
And it's output:
That endpoint is the only one which returns anything but zeros and I've ruled out interfaces 0 & 3 as being the audio device and inline remote respectively. Furthermore, if I disconnect, reconnect & try again, it often gives a different response.
Any help would be appreciated. Even if it's to say that this isn't how it's done - it'd at least save me the headache...
I do a little coding now & then and found the opensource library 'libusb' which looked promising. Better still, I found its Python wrapper 'pyusb' which promises easy USB access. Now, I've never worked with USB from a dev/engineering perspective, so I didn't find it very user friendly at all. Anyhow, after a couple of hours I could find the device, it's endpoints & read their data. I was hoping that'd be a springboard moment enabling me to do something useful. Alas, I can't see anything meaningful in the data & I suspect that I'm missing something fundamental.
My code:
Python:
#!/usr/bin/python
import sys
import usb.core
import usb.util
# hexidecimal vendor and product values
device = usb.core.find(idVendor=0x35d8, idProduct=0x1496)
# was it found?
if device is None:
raise ValueError('FreeDSP not found')
sys.exit(1)
else: print(device)
# endpoints
interface = 2
alternate = 1
endpoint = device[0][(interface,alternate)][0]
print('-------------')
print('OUR ENDPOINT:')
print('-------------')
print(endpoint) # this is the only one that gives us anything.
# free resources
for cfg in device:
for intf in cfg:
if device.is_kernel_driver_active(intf.bInterfaceNumber):
try:
device.detach_kernel_driver(intf.bInterfaceNumber)
except usb.core.USBError as e:
sys.exit("Could not detach kernel driver from interface({0}): {1}".format(intf.bInterfaceNumber, str(e)))
# check/set configuration
try:
cfg = device.get_active_configuration()
except usb.core.USBError:
cfg = None
if cfg is None :
device.set_configuration()
# set alts & claim interface.
device.set_interface_altsetting(interface, alternate)
usb.util.claim_interface(device, interface)
# read 512 bytes from endpoint
data = device.read(endpoint.bEndpointAddress,512)
print('---------')
print('OUR DATA:')
print('---------')
print(data) # can't see any relevance in this.... :'(
# release the device
usb.util.release_interface(device, interface)
# Dispose the device resource
usb.util.dispose_resources(device)
# reattach the device to the OS kernel
# 0 is the audio device, including mic.
device.attach_kernel_driver(0)
# 3 (the HID) is the remote control
device.attach_kernel_driver(3)
# That leaves interfaces 1 & 2 for DSP?
print('done')
And it's output:
Code:
DEVICE ID 35d8:1496 on Bus 003 Address 008 =================
bLength : 0x12 (18 bytes)
bDescriptorType : 0x1 Device
bcdUSB : 0x200 USB 2.0
bDeviceClass : 0xef Miscellaneous
bDeviceSubClass : 0x2
bDeviceProtocol : 0x1
bMaxPacketSize0 : 0x40 (64 bytes)
idVendor : 0x35d8
idProduct : 0x1496
bcdDevice : 0x9 Device 0.09
iManufacturer : 0x1 MOONDROP
iProduct : 0x2 FreeDSP
iSerialNumber : 0x0
bNumConfigurations : 0x1
CONFIGURATION 1: 100 mA ==================================
bLength : 0x9 (9 bytes)
bDescriptorType : 0x2 Configuration
wTotalLength : 0x1a6 (422 bytes)
bNumInterfaces : 0x4
bConfigurationValue : 0x1
iConfiguration : 0x4 Headset
bmAttributes : 0xa0 Bus Powered, Remote Wakeup
bMaxPower : 0x32 (100 mA)
INTERFACE 0: Audio =====================================
bLength : 0x9 (9 bytes)
bDescriptorType : 0x4 Interface
bInterfaceNumber : 0x0
bAlternateSetting : 0x0
bNumEndpoints : 0x0
bInterfaceClass : 0x1 Audio
bInterfaceSubClass : 0x1
bInterfaceProtocol : 0x20
iInterface : 0x0
INTERFACE 1: Audio =====================================
bLength : 0x9 (9 bytes)
bDescriptorType : 0x4 Interface
bInterfaceNumber : 0x1
bAlternateSetting : 0x0
bNumEndpoints : 0x0
bInterfaceClass : 0x1 Audio
bInterfaceSubClass : 0x2
bInterfaceProtocol : 0x20
iInterface : 0x0
INTERFACE 1, 1: Audio ==================================
bLength : 0x9 (9 bytes)
bDescriptorType : 0x4 Interface
bInterfaceNumber : 0x1
bAlternateSetting : 0x1
bNumEndpoints : 0x1
bInterfaceClass : 0x1 Audio
bInterfaceSubClass : 0x2
bInterfaceProtocol : 0x20
iInterface : 0x0
ENDPOINT 0x1: Isochronous OUT ========================
bLength : 0x7 (7 bytes)
bDescriptorType : 0x5 Endpoint
bEndpointAddress : 0x1 OUT
bmAttributes : 0xd Isochronous
wMaxPacketSize : 0xc0 (192 bytes)
bInterval : 0x1
INTERFACE 1, 2: Audio ==================================
bLength : 0x9 (9 bytes)
bDescriptorType : 0x4 Interface
bInterfaceNumber : 0x1
bAlternateSetting : 0x2
bNumEndpoints : 0x1
bInterfaceClass : 0x1 Audio
bInterfaceSubClass : 0x2
bInterfaceProtocol : 0x20
iInterface : 0x0
ENDPOINT 0x1: Isochronous OUT ========================
bLength : 0x7 (7 bytes)
bDescriptorType : 0x5 Endpoint
bEndpointAddress : 0x1 OUT
bmAttributes : 0xd Isochronous
wMaxPacketSize : 0x120 (288 bytes)
bInterval : 0x1
INTERFACE 1, 3: Audio ==================================
bLength : 0x9 (9 bytes)
bDescriptorType : 0x4 Interface
bInterfaceNumber : 0x1
bAlternateSetting : 0x3
bNumEndpoints : 0x1
bInterfaceClass : 0x1 Audio
bInterfaceSubClass : 0x2
bInterfaceProtocol : 0x20
iInterface : 0x0
ENDPOINT 0x1: Isochronous OUT ========================
bLength : 0x7 (7 bytes)
bDescriptorType : 0x5 Endpoint
bEndpointAddress : 0x1 OUT
bmAttributes : 0xd Isochronous
wMaxPacketSize : 0x180 (384 bytes)
bInterval : 0x1
INTERFACE 2: Audio =====================================
bLength : 0x9 (9 bytes)
bDescriptorType : 0x4 Interface
bInterfaceNumber : 0x2
bAlternateSetting : 0x0
bNumEndpoints : 0x0
bInterfaceClass : 0x1 Audio
bInterfaceSubClass : 0x2
bInterfaceProtocol : 0x20
iInterface : 0x0
INTERFACE 2, 1: Audio ==================================
bLength : 0x9 (9 bytes)
bDescriptorType : 0x4 Interface
bInterfaceNumber : 0x2
bAlternateSetting : 0x1
bNumEndpoints : 0x1
bInterfaceClass : 0x1 Audio
bInterfaceSubClass : 0x2
bInterfaceProtocol : 0x20
iInterface : 0x0
ENDPOINT 0x81: Isochronous IN ========================
bLength : 0x7 (7 bytes)
bDescriptorType : 0x5 Endpoint
bEndpointAddress : 0x81 IN
bmAttributes : 0xd Isochronous
wMaxPacketSize : 0xc (12 bytes)
bInterval : 0x1
INTERFACE 2, 2: Audio ==================================
bLength : 0x9 (9 bytes)
bDescriptorType : 0x4 Interface
bInterfaceNumber : 0x2
bAlternateSetting : 0x2
bNumEndpoints : 0x1
bInterfaceClass : 0x1 Audio
bInterfaceSubClass : 0x2
bInterfaceProtocol : 0x20
iInterface : 0x0
ENDPOINT 0x81: Isochronous IN ========================
bLength : 0x7 (7 bytes)
bDescriptorType : 0x5 Endpoint
bEndpointAddress : 0x81 IN
bmAttributes : 0xd Isochronous
wMaxPacketSize : 0x12 (18 bytes)
bInterval : 0x1
INTERFACE 3: Human Interface Device ====================
bLength : 0x9 (9 bytes)
bDescriptorType : 0x4 Interface
bInterfaceNumber : 0x3
bAlternateSetting : 0x0
bNumEndpoints : 0x1
bInterfaceClass : 0x3 Human Interface Device
bInterfaceSubClass : 0x0
bInterfaceProtocol : 0x0
iInterface : 0x0
ENDPOINT 0x83: Interrupt IN ==========================
bLength : 0x7 (7 bytes)
bDescriptorType : 0x5 Endpoint
bEndpointAddress : 0x83 IN
bmAttributes : 0x3 Interrupt
wMaxPacketSize : 0x40 (64 bytes)
bInterval : 0x7
-------------
OUR ENDPOINT:
-------------
ENDPOINT 0x81: Isochronous IN ========================
bLength : 0x7 (7 bytes)
bDescriptorType : 0x5 Endpoint
bEndpointAddress : 0x81 IN
bmAttributes : 0xd Isochronous
wMaxPacketSize : 0xc (12 bytes)
bInterval : 0x1
---------
OUR DATA:
---------
array('B', [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 0, 0, 255, 255, 1, 0, 253, 255, 5, 0, 4, 0, 251, 255, 0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
done
That endpoint is the only one which returns anything but zeros and I've ruled out interfaces 0 & 3 as being the audio device and inline remote respectively. Furthermore, if I disconnect, reconnect & try again, it often gives a different response.
Any help would be appreciated. Even if it's to say that this isn't how it's done - it'd at least save me the headache...