Compare commits
4 Commits
efdbb11f92
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 1e78421829 | |||
| 0fb69b0fbc | |||
| 0b8893d433 | |||
| 700e87f807 |
File diff suppressed because it is too large
Load Diff
@@ -4147,6 +4147,28 @@
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
(global_label "MCP_CS"
|
||||||
|
(shape input)
|
||||||
|
(at 245.11 138.43 0)
|
||||||
|
(fields_autoplaced yes)
|
||||||
|
(effects
|
||||||
|
(font
|
||||||
|
(size 1.27 1.27)
|
||||||
|
)
|
||||||
|
(justify left)
|
||||||
|
)
|
||||||
|
(uuid "110d57d2-9a85-4aeb-9b6a-69c907ecb067")
|
||||||
|
(property "Intersheetrefs" "${INTERSHEET_REFS}"
|
||||||
|
(at 255.5337 138.43 0)
|
||||||
|
(effects
|
||||||
|
(font
|
||||||
|
(size 1.27 1.27)
|
||||||
|
)
|
||||||
|
(justify left)
|
||||||
|
(hide yes)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
(global_label "Pot3"
|
(global_label "Pot3"
|
||||||
(shape input)
|
(shape input)
|
||||||
(at 245.11 120.65 0)
|
(at 245.11 120.65 0)
|
||||||
@@ -4213,6 +4235,28 @@
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
(global_label "MCP_CS"
|
||||||
|
(shape input)
|
||||||
|
(at 127 124.46 180)
|
||||||
|
(fields_autoplaced yes)
|
||||||
|
(effects
|
||||||
|
(font
|
||||||
|
(size 1.27 1.27)
|
||||||
|
)
|
||||||
|
(justify right)
|
||||||
|
)
|
||||||
|
(uuid "18abe3ae-619d-4ea9-a26d-baf9ec2f3ec9")
|
||||||
|
(property "Intersheetrefs" "${INTERSHEET_REFS}"
|
||||||
|
(at 116.5763 124.46 0)
|
||||||
|
(effects
|
||||||
|
(font
|
||||||
|
(size 1.27 1.27)
|
||||||
|
)
|
||||||
|
(justify right)
|
||||||
|
(hide yes)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
(global_label "Pot4"
|
(global_label "Pot4"
|
||||||
(shape input)
|
(shape input)
|
||||||
(at 245.11 123.19 0)
|
(at 245.11 123.19 0)
|
||||||
@@ -4675,28 +4719,6 @@
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
(global_label "Gnd"
|
|
||||||
(shape input)
|
|
||||||
(at 127 124.46 180)
|
|
||||||
(fields_autoplaced yes)
|
|
||||||
(effects
|
|
||||||
(font
|
|
||||||
(size 1.27 1.27)
|
|
||||||
)
|
|
||||||
(justify right)
|
|
||||||
)
|
|
||||||
(uuid "47bd9f65-0e2a-4fc6-bd4e-d5f3d0725d71")
|
|
||||||
(property "Intersheetrefs" "${INTERSHEET_REFS}"
|
|
||||||
(at 120.4468 124.46 0)
|
|
||||||
(effects
|
|
||||||
(font
|
|
||||||
(size 1.27 1.27)
|
|
||||||
)
|
|
||||||
(justify right)
|
|
||||||
(hide yes)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
(global_label "USB_5v"
|
(global_label "USB_5v"
|
||||||
(shape input)
|
(shape input)
|
||||||
(at 214.63 138.43 180)
|
(at 214.63 138.43 180)
|
||||||
@@ -4895,6 +4917,28 @@
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
(global_label "MCP_CS"
|
||||||
|
(shape input)
|
||||||
|
(at 127 167.64 180)
|
||||||
|
(fields_autoplaced yes)
|
||||||
|
(effects
|
||||||
|
(font
|
||||||
|
(size 1.27 1.27)
|
||||||
|
)
|
||||||
|
(justify right)
|
||||||
|
)
|
||||||
|
(uuid "60a88f2d-666a-4237-80f4-f94f107c2781")
|
||||||
|
(property "Intersheetrefs" "${INTERSHEET_REFS}"
|
||||||
|
(at 116.5763 167.64 0)
|
||||||
|
(effects
|
||||||
|
(font
|
||||||
|
(size 1.27 1.27)
|
||||||
|
)
|
||||||
|
(justify right)
|
||||||
|
(hide yes)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
(global_label "Ch1Zero"
|
(global_label "Ch1Zero"
|
||||||
(shape input)
|
(shape input)
|
||||||
(at 214.63 133.35 180)
|
(at 214.63 133.35 180)
|
||||||
@@ -5665,28 +5709,6 @@
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
(global_label "Gnd"
|
|
||||||
(shape input)
|
|
||||||
(at 127 167.64 180)
|
|
||||||
(fields_autoplaced yes)
|
|
||||||
(effects
|
|
||||||
(font
|
|
||||||
(size 1.27 1.27)
|
|
||||||
)
|
|
||||||
(justify right)
|
|
||||||
)
|
|
||||||
(uuid "c18809a2-710c-49cd-8166-9b76e2516110")
|
|
||||||
(property "Intersheetrefs" "${INTERSHEET_REFS}"
|
|
||||||
(at 120.4468 167.64 0)
|
|
||||||
(effects
|
|
||||||
(font
|
|
||||||
(size 1.27 1.27)
|
|
||||||
)
|
|
||||||
(justify right)
|
|
||||||
(hide yes)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
(global_label "3v3"
|
(global_label "3v3"
|
||||||
(shape input)
|
(shape input)
|
||||||
(at 135.89 22.86 180)
|
(at 135.89 22.86 180)
|
||||||
@@ -8261,10 +8283,10 @@
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
(pin "2"
|
(pin "2"
|
||||||
(uuid "266096b0-0722-468b-b667-02afdd8ba748")
|
(uuid "266096b0-0722-468b-b667-02afdd8ba749")
|
||||||
)
|
)
|
||||||
(pin "1"
|
(pin "1"
|
||||||
(uuid "a9d6408d-fc4c-4df3-b784-212408267add")
|
(uuid "a9d6408d-fc4c-4df3-b784-212408267ade")
|
||||||
)
|
)
|
||||||
(instances
|
(instances
|
||||||
(project "ControlMixer"
|
(project "ControlMixer"
|
||||||
|
|||||||
12
ControlMixerPython/boot.py
Normal file
12
ControlMixerPython/boot.py
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import board
|
||||||
|
import digitalio
|
||||||
|
import usb_mixer
|
||||||
|
recovery_pin = digitalio.DigitalInOut(board.D3)
|
||||||
|
recovery_pin.direction = digitalio.Direction.INPUT
|
||||||
|
recovery_pin.pull = digitalio.Pull.UP
|
||||||
|
|
||||||
|
if recovery_pin.value == True:
|
||||||
|
print("Booting normal mode")
|
||||||
|
usb_mixer.initUsb()
|
||||||
|
else:
|
||||||
|
print("Booting recovery mode")
|
||||||
63
ControlMixerPython/code.py
Normal file
63
ControlMixerPython/code.py
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
import usb_mixer
|
||||||
|
import board
|
||||||
|
import adafruit_dotstar
|
||||||
|
import analogio
|
||||||
|
import time
|
||||||
|
import math
|
||||||
|
import ulab.numpy
|
||||||
|
import supervisor
|
||||||
|
import key_interface
|
||||||
|
import storage
|
||||||
|
|
||||||
|
ANALOG_SAMPLE_SIZE=150
|
||||||
|
|
||||||
|
pixel = adafruit_dotstar.DotStar(board.DOTSTAR_CLOCK, board.DOTSTAR_DATA, 1)
|
||||||
|
slider_in = [
|
||||||
|
analogio.AnalogIn(board.A0),
|
||||||
|
analogio.AnalogIn(board.A1),
|
||||||
|
analogio.AnalogIn(board.A2),
|
||||||
|
analogio.AnalogIn(board.A3),
|
||||||
|
analogio.AnalogIn(board.A4)
|
||||||
|
]
|
||||||
|
|
||||||
|
i2c = board.I2C()
|
||||||
|
keys = key_interface.KeyInterface(i2c)
|
||||||
|
|
||||||
|
slider_vals = [0,0,0,0,0]
|
||||||
|
buttons = [0,0,0,0,0]
|
||||||
|
|
||||||
|
def readSlider(num):
|
||||||
|
vals = []
|
||||||
|
for i in range(0, ANALOG_SAMPLE_SIZE):
|
||||||
|
vals.append((slider_in[num].value / 0xFFFF) * 0xFFF) # Scale analogio back to ADC resolution
|
||||||
|
val_median = ulab.numpy.mean(ulab.numpy.ndarray(vals))
|
||||||
|
return math.floor((val_median / 0xFFF) * usb_mixer.RESOLUTION)
|
||||||
|
|
||||||
|
try:
|
||||||
|
pixel.fill((0,0,32))
|
||||||
|
while not supervisor.runtime.usb_connected:
|
||||||
|
time.sleep(0.5)
|
||||||
|
|
||||||
|
mixer = usb_mixer.UsbMixer()
|
||||||
|
pixel.fill((0,32,0))
|
||||||
|
while True:
|
||||||
|
new_values = [
|
||||||
|
readSlider(0),
|
||||||
|
readSlider(1),
|
||||||
|
readSlider(2),
|
||||||
|
readSlider(3),
|
||||||
|
readSlider(4)
|
||||||
|
]
|
||||||
|
new_buttons = keys.scan()
|
||||||
|
if new_values != slider_vals or new_buttons != buttons:
|
||||||
|
mixer.send_values(new_values[0], new_values[1], new_values[2], new_values[3], new_values[4], new_buttons)
|
||||||
|
pixel.fill((32,32,32))
|
||||||
|
slider_vals = new_values
|
||||||
|
buttons = new_buttons
|
||||||
|
pixel.fill((0,32,0))
|
||||||
|
time.sleep(0.001)
|
||||||
|
except Exception as ex:
|
||||||
|
pixel.fill((255,0,0))
|
||||||
|
with open("/runtime_ex.txt", "w") as fp:
|
||||||
|
fp.write(ex)
|
||||||
|
print(ex)
|
||||||
40
ControlMixerPython/key_interface.py
Normal file
40
ControlMixerPython/key_interface.py
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import board
|
||||||
|
import busio
|
||||||
|
import digitalio
|
||||||
|
from adafruit_mcp230xx.mcp23017 import MCP23017
|
||||||
|
|
||||||
|
class KeyInterface:
|
||||||
|
_MCP23017_OLATA = 0x14
|
||||||
|
_MCP23017_OLATB = 0x15
|
||||||
|
|
||||||
|
def set_olata(self, val: int):
|
||||||
|
self.mcp._write_u8(self._MCP23017_OLATA, val)
|
||||||
|
|
||||||
|
def set_olatb(self, val: int):
|
||||||
|
self.mcp._write_u8(self._MCP23017_OLATB, val)
|
||||||
|
|
||||||
|
def __init__(self, i2c):
|
||||||
|
self._i2c = i2c
|
||||||
|
|
||||||
|
# Turn on MCP
|
||||||
|
self._mcp_reset_pin = digitalio.DigitalInOut(board.D4)
|
||||||
|
self._mcp_reset_pin.direction = digitalio.Direction.OUTPUT
|
||||||
|
self._mcp_reset_pin.value = True
|
||||||
|
|
||||||
|
# Initialize MCP
|
||||||
|
self.mcp = MCP23017(self._i2c)
|
||||||
|
|
||||||
|
# Set up MCP pins
|
||||||
|
self.mcp.iodirb = 255 # GPIO B (rows) all input
|
||||||
|
self.mcp.ipolb = 255 # GPIO B inverted polarity
|
||||||
|
self.mcp.gppub = 255 # GPIO B all pulled up
|
||||||
|
self.set_olata(0) # GPIO A all output low
|
||||||
|
|
||||||
|
def scan(self):
|
||||||
|
result = []
|
||||||
|
for i in range(0, 6):
|
||||||
|
self.mcp.iodira = 0xFF ^ (0x01 << i)
|
||||||
|
result.append(self.mcp.gpiob)
|
||||||
|
self.mcp.iodira = 0xFF
|
||||||
|
return result
|
||||||
|
|
||||||
BIN
ControlMixerPython/lib/adafruit_bus_device/i2c_device.mpy
Normal file
BIN
ControlMixerPython/lib/adafruit_bus_device/i2c_device.mpy
Normal file
Binary file not shown.
BIN
ControlMixerPython/lib/adafruit_bus_device/spi_device.mpy
Normal file
BIN
ControlMixerPython/lib/adafruit_bus_device/spi_device.mpy
Normal file
Binary file not shown.
BIN
ControlMixerPython/lib/adafruit_dotstar.mpy
Normal file
BIN
ControlMixerPython/lib/adafruit_dotstar.mpy
Normal file
Binary file not shown.
BIN
ControlMixerPython/lib/adafruit_husb238.mpy
Normal file
BIN
ControlMixerPython/lib/adafruit_husb238.mpy
Normal file
Binary file not shown.
BIN
ControlMixerPython/lib/adafruit_mcp230xx/__init__.mpy
Normal file
BIN
ControlMixerPython/lib/adafruit_mcp230xx/__init__.mpy
Normal file
Binary file not shown.
BIN
ControlMixerPython/lib/adafruit_mcp230xx/digital_inout.mpy
Normal file
BIN
ControlMixerPython/lib/adafruit_mcp230xx/digital_inout.mpy
Normal file
Binary file not shown.
BIN
ControlMixerPython/lib/adafruit_mcp230xx/mcp23008.mpy
Normal file
BIN
ControlMixerPython/lib/adafruit_mcp230xx/mcp23008.mpy
Normal file
Binary file not shown.
BIN
ControlMixerPython/lib/adafruit_mcp230xx/mcp23016.mpy
Normal file
BIN
ControlMixerPython/lib/adafruit_mcp230xx/mcp23016.mpy
Normal file
Binary file not shown.
BIN
ControlMixerPython/lib/adafruit_mcp230xx/mcp23017.mpy
Normal file
BIN
ControlMixerPython/lib/adafruit_mcp230xx/mcp23017.mpy
Normal file
Binary file not shown.
BIN
ControlMixerPython/lib/adafruit_mcp230xx/mcp230xx.mpy
Normal file
BIN
ControlMixerPython/lib/adafruit_mcp230xx/mcp230xx.mpy
Normal file
Binary file not shown.
BIN
ControlMixerPython/lib/adafruit_mcp230xx/mcp23s08.mpy
Normal file
BIN
ControlMixerPython/lib/adafruit_mcp230xx/mcp23s08.mpy
Normal file
Binary file not shown.
BIN
ControlMixerPython/lib/adafruit_mcp230xx/mcp23s17.mpy
Normal file
BIN
ControlMixerPython/lib/adafruit_mcp230xx/mcp23s17.mpy
Normal file
Binary file not shown.
BIN
ControlMixerPython/lib/adafruit_mcp230xx/mcp23sxx.mpy
Normal file
BIN
ControlMixerPython/lib/adafruit_mcp230xx/mcp23sxx.mpy
Normal file
Binary file not shown.
BIN
ControlMixerPython/lib/adafruit_mcp230xx/mcp23xxx.mpy
Normal file
BIN
ControlMixerPython/lib/adafruit_mcp230xx/mcp23xxx.mpy
Normal file
Binary file not shown.
BIN
ControlMixerPython/lib/adafruit_register/i2c_bcd_alarm.mpy
Normal file
BIN
ControlMixerPython/lib/adafruit_register/i2c_bcd_alarm.mpy
Normal file
Binary file not shown.
BIN
ControlMixerPython/lib/adafruit_register/i2c_bcd_datetime.mpy
Normal file
BIN
ControlMixerPython/lib/adafruit_register/i2c_bcd_datetime.mpy
Normal file
Binary file not shown.
BIN
ControlMixerPython/lib/adafruit_register/i2c_bit.mpy
Normal file
BIN
ControlMixerPython/lib/adafruit_register/i2c_bit.mpy
Normal file
Binary file not shown.
BIN
ControlMixerPython/lib/adafruit_register/i2c_bits.mpy
Normal file
BIN
ControlMixerPython/lib/adafruit_register/i2c_bits.mpy
Normal file
Binary file not shown.
BIN
ControlMixerPython/lib/adafruit_register/i2c_struct.mpy
Normal file
BIN
ControlMixerPython/lib/adafruit_register/i2c_struct.mpy
Normal file
Binary file not shown.
BIN
ControlMixerPython/lib/adafruit_register/i2c_struct_array.mpy
Normal file
BIN
ControlMixerPython/lib/adafruit_register/i2c_struct_array.mpy
Normal file
Binary file not shown.
BIN
ControlMixerPython/lib/neopixel.mpy
Normal file
BIN
ControlMixerPython/lib/neopixel.mpy
Normal file
Binary file not shown.
111
ControlMixerPython/mixer_leds.py
Normal file
111
ControlMixerPython/mixer_leds.py
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
from power import HUSB238
|
||||||
|
import board
|
||||||
|
import neopixel
|
||||||
|
|
||||||
|
VM_GREEN = (32,255,32)
|
||||||
|
VM_RED = (255,16,16)
|
||||||
|
|
||||||
|
LED1 = 1 << 0 # 1
|
||||||
|
LED2 = 1 << 1 # 2
|
||||||
|
LED3 = 1 << 2 # 4
|
||||||
|
LED4 = 1 << 3 # 8
|
||||||
|
LED5 = 1 << 4 # 16
|
||||||
|
LED6 = 1 << 5 # 32
|
||||||
|
LED7 = 1 << 6 # 64
|
||||||
|
LED8 = 1 << 7 # 128
|
||||||
|
LED9 = 1 << 8 # 256
|
||||||
|
LED10 = 1 << 9 # 512
|
||||||
|
LED11 = 1 << 10 # 1024
|
||||||
|
LED12 = 1 << 11 # 2048
|
||||||
|
LED13 = 1 << 12 # 4096
|
||||||
|
LED14 = 1 << 13 # 8192
|
||||||
|
LED15 = 1 << 14 # 16384
|
||||||
|
LED16 = 1 << 15 # 32768
|
||||||
|
LED17 = 1 << 16 # 65536
|
||||||
|
LED18 = 1 << 17 # 131072
|
||||||
|
LED19 = 1 << 18 # 262144
|
||||||
|
LED20 = 1 << 19 # 524288
|
||||||
|
LED21 = 1 << 20 # 1048576
|
||||||
|
LED22 = 1 << 21 # 2097152
|
||||||
|
LED23 = 1 << 22 # 4194304
|
||||||
|
LED24 = 1 << 23 # 8388608
|
||||||
|
LED25 = 1 << 24 # 16777216
|
||||||
|
LED26 = 1 << 25 # 33554432
|
||||||
|
LED27 = 1 << 26 # 67108864
|
||||||
|
LED28 = 1 << 27 # 134217728
|
||||||
|
LED29 = 1 << 28 # 268435456
|
||||||
|
LED30 = 1 << 29 # 536870912
|
||||||
|
LED31 = 1 << 30 # 1073741824
|
||||||
|
LED32 = 1 << 31 # 2147483648
|
||||||
|
LED33 = 1 << 32 # 4294967296
|
||||||
|
LED34 = 1 << 33 # 8589934592
|
||||||
|
LED35 = 1 << 34 # 17179869184
|
||||||
|
LED36 = 1 << 35 # 34359738368
|
||||||
|
LED37 = 1 << 36 # 68719476736
|
||||||
|
LED38 = 1 << 37 # 137438953472
|
||||||
|
LED39 = 1 << 38 # 274877906944
|
||||||
|
LED40 = 1 << 39 # 549755813888
|
||||||
|
LED41 = 1 << 40 # 1099511627776
|
||||||
|
LED42 = 1 << 41 # 2199023255552
|
||||||
|
LED43 = 1 << 42 # 4398046511104
|
||||||
|
LED44 = 1 << 43 # 8796093022208
|
||||||
|
LED45 = 1 << 44 # 17592186044416
|
||||||
|
|
||||||
|
leds = [
|
||||||
|
LED1, LED2, LED3, LED4, LED5,
|
||||||
|
LED6, LED7, LED8, LED9, LED10,
|
||||||
|
LED11, LED12, LED13, LED14, LED15,
|
||||||
|
LED16, LED17, LED18, LED19, LED20,
|
||||||
|
LED21, LED22, LED23, LED24, LED25,
|
||||||
|
LED26, LED27, LED28, LED29, LED30,
|
||||||
|
LED31, LED32, LED33, LED34, LED35,
|
||||||
|
LED36, LED37, LED38, LED39, LED40,
|
||||||
|
LED41, LED42, LED43, LED44, LED45
|
||||||
|
]
|
||||||
|
|
||||||
|
def get_led_states(value):
|
||||||
|
return [(value & led) != 0 for led in leds]
|
||||||
|
|
||||||
|
|
||||||
|
_COLORS = [
|
||||||
|
VM_RED, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN,
|
||||||
|
VM_RED, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN,
|
||||||
|
VM_RED, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN,
|
||||||
|
VM_RED, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN,
|
||||||
|
VM_RED, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN, VM_GREEN
|
||||||
|
]
|
||||||
|
|
||||||
|
class MixerLeds:
|
||||||
|
def __init__(self, i2c, max_brightness = 1):
|
||||||
|
self._i2c = i2c
|
||||||
|
self._pd = HUSB238(i2c)
|
||||||
|
self._pixels = neopixel.NeoPixel(board.D5, 45, auto_write=False, brightness=max_brightness)
|
||||||
|
self._known_wattage = 0
|
||||||
|
self._max_brightness = max_brightness
|
||||||
|
|
||||||
|
def _init_pd(self):
|
||||||
|
if not self._pd.connect():
|
||||||
|
print('Init PD failed to start connection')
|
||||||
|
return False
|
||||||
|
if self._known_wattage == self._pd.wattage:
|
||||||
|
return True
|
||||||
|
available_wattage = self._pd.attempt_wattage(30)
|
||||||
|
self._known_wattage = available_wattage[1]
|
||||||
|
if not available_wattage[0]:
|
||||||
|
self._pixels.deinit()
|
||||||
|
available_brightness = max(available_wattage[1]/30.0, self._max_brightness)
|
||||||
|
self._pixels = neopixel.NeoPixel(board.D5, 45, brightness=available_brightness, auto_write=False)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def set_state(self, state):
|
||||||
|
if not self._init_pd():
|
||||||
|
return False
|
||||||
|
|
||||||
|
for idx, led_state in enumerate(get_led_states(state)):
|
||||||
|
if (led_state):
|
||||||
|
self._pixels[idx] = _COLORS[idx]
|
||||||
|
else:
|
||||||
|
self._pixels[idx] = (0,0,0)
|
||||||
|
self._pixels.show()
|
||||||
|
return True
|
||||||
88
ControlMixerPython/power.py
Normal file
88
ControlMixerPython/power.py
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
import adafruit_husb238
|
||||||
|
import time
|
||||||
|
|
||||||
|
class HUSB238:
|
||||||
|
_pd = None
|
||||||
|
|
||||||
|
def __init__(self, i2c):
|
||||||
|
self._i2c = i2c
|
||||||
|
|
||||||
|
def connect(self):
|
||||||
|
if (self.is_connected()):
|
||||||
|
try:
|
||||||
|
return self._pd.attached
|
||||||
|
except Exception as e:
|
||||||
|
return False
|
||||||
|
try:
|
||||||
|
self._pd = adafruit_husb238.Adafruit_HUSB238(self._i2c)
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
self._pd = None
|
||||||
|
return False
|
||||||
|
|
||||||
|
def is_connected(self):
|
||||||
|
if self._pd is not None:
|
||||||
|
try:
|
||||||
|
return self._pd.attached
|
||||||
|
except Exception as e:
|
||||||
|
self._pd = None
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def attempt_wattage(self, watts):
|
||||||
|
if not self.is_connected():
|
||||||
|
return False, 0
|
||||||
|
if self.wattage >= watts:
|
||||||
|
return True, self.wattage
|
||||||
|
voltages = self.available_voltages
|
||||||
|
next_voltage_index = voltages.index(self.voltage) + 1
|
||||||
|
while self.wattage < watts and next_voltage_index < len(voltages):
|
||||||
|
if not self.is_connected():
|
||||||
|
print('Connection lost')
|
||||||
|
return False, 0
|
||||||
|
target = voltages[next_voltage_index]
|
||||||
|
self.voltage = target
|
||||||
|
time.sleep(1)
|
||||||
|
if (self._pd.voltage != target):
|
||||||
|
print(f'Voltage did not switch to {target}v')
|
||||||
|
return False, self.wattage
|
||||||
|
next_voltage_index += 1
|
||||||
|
resulting_wattage = self.wattage
|
||||||
|
return resulting_wattage >= watts, resulting_wattage
|
||||||
|
|
||||||
|
@property
|
||||||
|
def wattage(self):
|
||||||
|
return self.voltage * self.current
|
||||||
|
|
||||||
|
@property
|
||||||
|
def available_voltages(self):
|
||||||
|
return self._safe_pd_call(lambda: self._pd.available_voltages, [])
|
||||||
|
|
||||||
|
@property
|
||||||
|
def voltage(self):
|
||||||
|
return self._safe_pd_call(lambda: self._pd.voltage, 0);
|
||||||
|
|
||||||
|
@voltage.setter
|
||||||
|
def voltage(self, value):
|
||||||
|
self._pd.voltage = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def current(self):
|
||||||
|
return self._safe_pd_call(lambda: self._pd.current, 0)
|
||||||
|
|
||||||
|
def _unsafe_pd_call(self, func, default_val, attempts=20):
|
||||||
|
attempt_count = 0
|
||||||
|
while attempt_count < attempts:
|
||||||
|
try:
|
||||||
|
return func()
|
||||||
|
except Exception as e:
|
||||||
|
print('unsafe waiting')
|
||||||
|
time.sleep(0.5)
|
||||||
|
return default_val
|
||||||
|
|
||||||
|
def _safe_pd_call(self, func, default_val):
|
||||||
|
if self.is_connected():
|
||||||
|
return func()
|
||||||
|
else:
|
||||||
|
return default_val
|
||||||
1
ControlMixerPython/sd/placeholder.txt
Normal file
1
ControlMixerPython/sd/placeholder.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
SD cards mounted at /sd will hide this file from Python. SD cards are not visible via USB CIRCUITPY.
|
||||||
0
ControlMixerPython/settings.toml
Normal file
0
ControlMixerPython/settings.toml
Normal file
86
ControlMixerPython/usb_mixer.py
Normal file
86
ControlMixerPython/usb_mixer.py
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
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)
|
||||||
44
HidSliders.Gui/Form1.Designer.cs
generated
44
HidSliders.Gui/Form1.Designer.cs
generated
@@ -108,6 +108,7 @@
|
|||||||
mixerAutoConnectCheckbox = new CheckBox();
|
mixerAutoConnectCheckbox = new CheckBox();
|
||||||
mixerLabel = new Label();
|
mixerLabel = new Label();
|
||||||
notifyIcon1 = new NotifyIcon(components);
|
notifyIcon1 = new NotifyIcon(components);
|
||||||
|
listBox1 = new ListBox();
|
||||||
groupBox1.SuspendLayout();
|
groupBox1.SuspendLayout();
|
||||||
((System.ComponentModel.ISupportInitialize)trackBar1).BeginInit();
|
((System.ComponentModel.ISupportInitialize)trackBar1).BeginInit();
|
||||||
((System.ComponentModel.ISupportInitialize)trackBar2).BeginInit();
|
((System.ComponentModel.ISupportInitialize)trackBar2).BeginInit();
|
||||||
@@ -480,6 +481,7 @@
|
|||||||
checkBox5.TabIndex = 38;
|
checkBox5.TabIndex = 38;
|
||||||
checkBox5.Text = "B3";
|
checkBox5.Text = "B3";
|
||||||
checkBox5.UseVisualStyleBackColor = true;
|
checkBox5.UseVisualStyleBackColor = true;
|
||||||
|
checkBox5.CheckedChanged += busCheckbox_CheckedChanged;
|
||||||
//
|
//
|
||||||
// checkBox6
|
// checkBox6
|
||||||
//
|
//
|
||||||
@@ -491,6 +493,7 @@
|
|||||||
checkBox6.TabIndex = 37;
|
checkBox6.TabIndex = 37;
|
||||||
checkBox6.Text = "B2";
|
checkBox6.Text = "B2";
|
||||||
checkBox6.UseVisualStyleBackColor = true;
|
checkBox6.UseVisualStyleBackColor = true;
|
||||||
|
checkBox6.CheckedChanged += busCheckbox_CheckedChanged;
|
||||||
//
|
//
|
||||||
// checkBox7
|
// checkBox7
|
||||||
//
|
//
|
||||||
@@ -502,6 +505,7 @@
|
|||||||
checkBox7.TabIndex = 36;
|
checkBox7.TabIndex = 36;
|
||||||
checkBox7.Text = "B1";
|
checkBox7.Text = "B1";
|
||||||
checkBox7.UseVisualStyleBackColor = true;
|
checkBox7.UseVisualStyleBackColor = true;
|
||||||
|
checkBox7.CheckedChanged += busCheckbox_CheckedChanged;
|
||||||
//
|
//
|
||||||
// checkBox8
|
// checkBox8
|
||||||
//
|
//
|
||||||
@@ -513,6 +517,7 @@
|
|||||||
checkBox8.TabIndex = 35;
|
checkBox8.TabIndex = 35;
|
||||||
checkBox8.Text = "A5";
|
checkBox8.Text = "A5";
|
||||||
checkBox8.UseVisualStyleBackColor = true;
|
checkBox8.UseVisualStyleBackColor = true;
|
||||||
|
checkBox8.CheckedChanged += busCheckbox_CheckedChanged;
|
||||||
//
|
//
|
||||||
// checkBox9
|
// checkBox9
|
||||||
//
|
//
|
||||||
@@ -524,6 +529,7 @@
|
|||||||
checkBox9.TabIndex = 34;
|
checkBox9.TabIndex = 34;
|
||||||
checkBox9.Text = "A4";
|
checkBox9.Text = "A4";
|
||||||
checkBox9.UseVisualStyleBackColor = true;
|
checkBox9.UseVisualStyleBackColor = true;
|
||||||
|
checkBox9.CheckedChanged += busCheckbox_CheckedChanged;
|
||||||
//
|
//
|
||||||
// checkBox10
|
// checkBox10
|
||||||
//
|
//
|
||||||
@@ -535,6 +541,7 @@
|
|||||||
checkBox10.TabIndex = 33;
|
checkBox10.TabIndex = 33;
|
||||||
checkBox10.Text = "A3";
|
checkBox10.Text = "A3";
|
||||||
checkBox10.UseVisualStyleBackColor = true;
|
checkBox10.UseVisualStyleBackColor = true;
|
||||||
|
checkBox10.CheckedChanged += busCheckbox_CheckedChanged;
|
||||||
//
|
//
|
||||||
// checkBox11
|
// checkBox11
|
||||||
//
|
//
|
||||||
@@ -547,6 +554,7 @@
|
|||||||
checkBox11.Tag = "A2";
|
checkBox11.Tag = "A2";
|
||||||
checkBox11.Text = "A2";
|
checkBox11.Text = "A2";
|
||||||
checkBox11.UseVisualStyleBackColor = true;
|
checkBox11.UseVisualStyleBackColor = true;
|
||||||
|
checkBox11.CheckedChanged += busCheckbox_CheckedChanged;
|
||||||
//
|
//
|
||||||
// checkBox12
|
// checkBox12
|
||||||
//
|
//
|
||||||
@@ -559,6 +567,7 @@
|
|||||||
checkBox12.Tag = "";
|
checkBox12.Tag = "";
|
||||||
checkBox12.Text = "A1";
|
checkBox12.Text = "A1";
|
||||||
checkBox12.UseVisualStyleBackColor = true;
|
checkBox12.UseVisualStyleBackColor = true;
|
||||||
|
checkBox12.CheckedChanged += busCheckbox_CheckedChanged;
|
||||||
//
|
//
|
||||||
// checkBox13
|
// checkBox13
|
||||||
//
|
//
|
||||||
@@ -594,6 +603,7 @@
|
|||||||
checkBox15.TabIndex = 48;
|
checkBox15.TabIndex = 48;
|
||||||
checkBox15.Text = "B3";
|
checkBox15.Text = "B3";
|
||||||
checkBox15.UseVisualStyleBackColor = true;
|
checkBox15.UseVisualStyleBackColor = true;
|
||||||
|
checkBox15.CheckedChanged += busCheckbox_CheckedChanged;
|
||||||
//
|
//
|
||||||
// checkBox16
|
// checkBox16
|
||||||
//
|
//
|
||||||
@@ -605,6 +615,7 @@
|
|||||||
checkBox16.TabIndex = 47;
|
checkBox16.TabIndex = 47;
|
||||||
checkBox16.Text = "B2";
|
checkBox16.Text = "B2";
|
||||||
checkBox16.UseVisualStyleBackColor = true;
|
checkBox16.UseVisualStyleBackColor = true;
|
||||||
|
checkBox16.CheckedChanged += busCheckbox_CheckedChanged;
|
||||||
//
|
//
|
||||||
// checkBox17
|
// checkBox17
|
||||||
//
|
//
|
||||||
@@ -616,6 +627,7 @@
|
|||||||
checkBox17.TabIndex = 46;
|
checkBox17.TabIndex = 46;
|
||||||
checkBox17.Text = "B1";
|
checkBox17.Text = "B1";
|
||||||
checkBox17.UseVisualStyleBackColor = true;
|
checkBox17.UseVisualStyleBackColor = true;
|
||||||
|
checkBox17.CheckedChanged += busCheckbox_CheckedChanged;
|
||||||
//
|
//
|
||||||
// checkBox18
|
// checkBox18
|
||||||
//
|
//
|
||||||
@@ -627,6 +639,7 @@
|
|||||||
checkBox18.TabIndex = 45;
|
checkBox18.TabIndex = 45;
|
||||||
checkBox18.Text = "A5";
|
checkBox18.Text = "A5";
|
||||||
checkBox18.UseVisualStyleBackColor = true;
|
checkBox18.UseVisualStyleBackColor = true;
|
||||||
|
checkBox18.CheckedChanged += busCheckbox_CheckedChanged;
|
||||||
//
|
//
|
||||||
// checkBox19
|
// checkBox19
|
||||||
//
|
//
|
||||||
@@ -638,6 +651,7 @@
|
|||||||
checkBox19.TabIndex = 44;
|
checkBox19.TabIndex = 44;
|
||||||
checkBox19.Text = "A4";
|
checkBox19.Text = "A4";
|
||||||
checkBox19.UseVisualStyleBackColor = true;
|
checkBox19.UseVisualStyleBackColor = true;
|
||||||
|
checkBox19.CheckedChanged += busCheckbox_CheckedChanged;
|
||||||
//
|
//
|
||||||
// checkBox20
|
// checkBox20
|
||||||
//
|
//
|
||||||
@@ -649,6 +663,7 @@
|
|||||||
checkBox20.TabIndex = 43;
|
checkBox20.TabIndex = 43;
|
||||||
checkBox20.Text = "A3";
|
checkBox20.Text = "A3";
|
||||||
checkBox20.UseVisualStyleBackColor = true;
|
checkBox20.UseVisualStyleBackColor = true;
|
||||||
|
checkBox20.CheckedChanged += busCheckbox_CheckedChanged;
|
||||||
//
|
//
|
||||||
// checkBox21
|
// checkBox21
|
||||||
//
|
//
|
||||||
@@ -661,6 +676,7 @@
|
|||||||
checkBox21.Tag = "A2";
|
checkBox21.Tag = "A2";
|
||||||
checkBox21.Text = "A2";
|
checkBox21.Text = "A2";
|
||||||
checkBox21.UseVisualStyleBackColor = true;
|
checkBox21.UseVisualStyleBackColor = true;
|
||||||
|
checkBox21.CheckedChanged += busCheckbox_CheckedChanged;
|
||||||
//
|
//
|
||||||
// checkBox22
|
// checkBox22
|
||||||
//
|
//
|
||||||
@@ -673,6 +689,7 @@
|
|||||||
checkBox22.Tag = "";
|
checkBox22.Tag = "";
|
||||||
checkBox22.Text = "A1";
|
checkBox22.Text = "A1";
|
||||||
checkBox22.UseVisualStyleBackColor = true;
|
checkBox22.UseVisualStyleBackColor = true;
|
||||||
|
checkBox22.CheckedChanged += busCheckbox_CheckedChanged;
|
||||||
//
|
//
|
||||||
// checkBox23
|
// checkBox23
|
||||||
//
|
//
|
||||||
@@ -708,6 +725,7 @@
|
|||||||
checkBox25.TabIndex = 58;
|
checkBox25.TabIndex = 58;
|
||||||
checkBox25.Text = "B3";
|
checkBox25.Text = "B3";
|
||||||
checkBox25.UseVisualStyleBackColor = true;
|
checkBox25.UseVisualStyleBackColor = true;
|
||||||
|
checkBox25.CheckedChanged += busCheckbox_CheckedChanged;
|
||||||
//
|
//
|
||||||
// checkBox26
|
// checkBox26
|
||||||
//
|
//
|
||||||
@@ -719,6 +737,7 @@
|
|||||||
checkBox26.TabIndex = 57;
|
checkBox26.TabIndex = 57;
|
||||||
checkBox26.Text = "B2";
|
checkBox26.Text = "B2";
|
||||||
checkBox26.UseVisualStyleBackColor = true;
|
checkBox26.UseVisualStyleBackColor = true;
|
||||||
|
checkBox26.CheckedChanged += busCheckbox_CheckedChanged;
|
||||||
//
|
//
|
||||||
// checkBox27
|
// checkBox27
|
||||||
//
|
//
|
||||||
@@ -730,6 +749,7 @@
|
|||||||
checkBox27.TabIndex = 56;
|
checkBox27.TabIndex = 56;
|
||||||
checkBox27.Text = "B1";
|
checkBox27.Text = "B1";
|
||||||
checkBox27.UseVisualStyleBackColor = true;
|
checkBox27.UseVisualStyleBackColor = true;
|
||||||
|
checkBox27.CheckedChanged += busCheckbox_CheckedChanged;
|
||||||
//
|
//
|
||||||
// checkBox28
|
// checkBox28
|
||||||
//
|
//
|
||||||
@@ -741,6 +761,7 @@
|
|||||||
checkBox28.TabIndex = 55;
|
checkBox28.TabIndex = 55;
|
||||||
checkBox28.Text = "A5";
|
checkBox28.Text = "A5";
|
||||||
checkBox28.UseVisualStyleBackColor = true;
|
checkBox28.UseVisualStyleBackColor = true;
|
||||||
|
checkBox28.CheckedChanged += busCheckbox_CheckedChanged;
|
||||||
//
|
//
|
||||||
// checkBox29
|
// checkBox29
|
||||||
//
|
//
|
||||||
@@ -752,6 +773,7 @@
|
|||||||
checkBox29.TabIndex = 54;
|
checkBox29.TabIndex = 54;
|
||||||
checkBox29.Text = "A4";
|
checkBox29.Text = "A4";
|
||||||
checkBox29.UseVisualStyleBackColor = true;
|
checkBox29.UseVisualStyleBackColor = true;
|
||||||
|
checkBox29.CheckedChanged += busCheckbox_CheckedChanged;
|
||||||
//
|
//
|
||||||
// checkBox30
|
// checkBox30
|
||||||
//
|
//
|
||||||
@@ -763,6 +785,7 @@
|
|||||||
checkBox30.TabIndex = 53;
|
checkBox30.TabIndex = 53;
|
||||||
checkBox30.Text = "A3";
|
checkBox30.Text = "A3";
|
||||||
checkBox30.UseVisualStyleBackColor = true;
|
checkBox30.UseVisualStyleBackColor = true;
|
||||||
|
checkBox30.CheckedChanged += busCheckbox_CheckedChanged;
|
||||||
//
|
//
|
||||||
// checkBox31
|
// checkBox31
|
||||||
//
|
//
|
||||||
@@ -775,6 +798,7 @@
|
|||||||
checkBox31.Tag = "A2";
|
checkBox31.Tag = "A2";
|
||||||
checkBox31.Text = "A2";
|
checkBox31.Text = "A2";
|
||||||
checkBox31.UseVisualStyleBackColor = true;
|
checkBox31.UseVisualStyleBackColor = true;
|
||||||
|
checkBox31.CheckedChanged += busCheckbox_CheckedChanged;
|
||||||
//
|
//
|
||||||
// checkBox32
|
// checkBox32
|
||||||
//
|
//
|
||||||
@@ -787,6 +811,7 @@
|
|||||||
checkBox32.Tag = "";
|
checkBox32.Tag = "";
|
||||||
checkBox32.Text = "A1";
|
checkBox32.Text = "A1";
|
||||||
checkBox32.UseVisualStyleBackColor = true;
|
checkBox32.UseVisualStyleBackColor = true;
|
||||||
|
checkBox32.CheckedChanged += busCheckbox_CheckedChanged;
|
||||||
//
|
//
|
||||||
// checkBox33
|
// checkBox33
|
||||||
//
|
//
|
||||||
@@ -822,6 +847,7 @@
|
|||||||
checkBox35.TabIndex = 68;
|
checkBox35.TabIndex = 68;
|
||||||
checkBox35.Text = "B3";
|
checkBox35.Text = "B3";
|
||||||
checkBox35.UseVisualStyleBackColor = true;
|
checkBox35.UseVisualStyleBackColor = true;
|
||||||
|
checkBox35.CheckedChanged += busCheckbox_CheckedChanged;
|
||||||
//
|
//
|
||||||
// checkBox36
|
// checkBox36
|
||||||
//
|
//
|
||||||
@@ -833,6 +859,7 @@
|
|||||||
checkBox36.TabIndex = 67;
|
checkBox36.TabIndex = 67;
|
||||||
checkBox36.Text = "B2";
|
checkBox36.Text = "B2";
|
||||||
checkBox36.UseVisualStyleBackColor = true;
|
checkBox36.UseVisualStyleBackColor = true;
|
||||||
|
checkBox36.CheckedChanged += busCheckbox_CheckedChanged;
|
||||||
//
|
//
|
||||||
// checkBox37
|
// checkBox37
|
||||||
//
|
//
|
||||||
@@ -844,6 +871,7 @@
|
|||||||
checkBox37.TabIndex = 66;
|
checkBox37.TabIndex = 66;
|
||||||
checkBox37.Text = "B1";
|
checkBox37.Text = "B1";
|
||||||
checkBox37.UseVisualStyleBackColor = true;
|
checkBox37.UseVisualStyleBackColor = true;
|
||||||
|
checkBox37.CheckedChanged += busCheckbox_CheckedChanged;
|
||||||
//
|
//
|
||||||
// checkBox38
|
// checkBox38
|
||||||
//
|
//
|
||||||
@@ -855,6 +883,7 @@
|
|||||||
checkBox38.TabIndex = 65;
|
checkBox38.TabIndex = 65;
|
||||||
checkBox38.Text = "A5";
|
checkBox38.Text = "A5";
|
||||||
checkBox38.UseVisualStyleBackColor = true;
|
checkBox38.UseVisualStyleBackColor = true;
|
||||||
|
checkBox38.CheckedChanged += busCheckbox_CheckedChanged;
|
||||||
//
|
//
|
||||||
// checkBox39
|
// checkBox39
|
||||||
//
|
//
|
||||||
@@ -866,6 +895,7 @@
|
|||||||
checkBox39.TabIndex = 64;
|
checkBox39.TabIndex = 64;
|
||||||
checkBox39.Text = "A4";
|
checkBox39.Text = "A4";
|
||||||
checkBox39.UseVisualStyleBackColor = true;
|
checkBox39.UseVisualStyleBackColor = true;
|
||||||
|
checkBox39.CheckedChanged += busCheckbox_CheckedChanged;
|
||||||
//
|
//
|
||||||
// checkBox40
|
// checkBox40
|
||||||
//
|
//
|
||||||
@@ -877,6 +907,7 @@
|
|||||||
checkBox40.TabIndex = 63;
|
checkBox40.TabIndex = 63;
|
||||||
checkBox40.Text = "A3";
|
checkBox40.Text = "A3";
|
||||||
checkBox40.UseVisualStyleBackColor = true;
|
checkBox40.UseVisualStyleBackColor = true;
|
||||||
|
checkBox40.CheckedChanged += busCheckbox_CheckedChanged;
|
||||||
//
|
//
|
||||||
// checkBox41
|
// checkBox41
|
||||||
//
|
//
|
||||||
@@ -889,6 +920,7 @@
|
|||||||
checkBox41.Tag = "A2";
|
checkBox41.Tag = "A2";
|
||||||
checkBox41.Text = "A2";
|
checkBox41.Text = "A2";
|
||||||
checkBox41.UseVisualStyleBackColor = true;
|
checkBox41.UseVisualStyleBackColor = true;
|
||||||
|
checkBox41.CheckedChanged += busCheckbox_CheckedChanged;
|
||||||
//
|
//
|
||||||
// checkBox42
|
// checkBox42
|
||||||
//
|
//
|
||||||
@@ -901,6 +933,7 @@
|
|||||||
checkBox42.Tag = "";
|
checkBox42.Tag = "";
|
||||||
checkBox42.Text = "A1";
|
checkBox42.Text = "A1";
|
||||||
checkBox42.UseVisualStyleBackColor = true;
|
checkBox42.UseVisualStyleBackColor = true;
|
||||||
|
checkBox42.CheckedChanged += busCheckbox_CheckedChanged;
|
||||||
//
|
//
|
||||||
// slider1Label
|
// slider1Label
|
||||||
//
|
//
|
||||||
@@ -986,11 +1019,21 @@
|
|||||||
notifyIcon1.Visible = true;
|
notifyIcon1.Visible = true;
|
||||||
notifyIcon1.Click += notifyIcon1_Click;
|
notifyIcon1.Click += notifyIcon1_Click;
|
||||||
//
|
//
|
||||||
|
// listBox1
|
||||||
|
//
|
||||||
|
listBox1.FormattingEnabled = true;
|
||||||
|
listBox1.ItemHeight = 15;
|
||||||
|
listBox1.Location = new Point(12, 278);
|
||||||
|
listBox1.Name = "listBox1";
|
||||||
|
listBox1.Size = new Size(200, 64);
|
||||||
|
listBox1.TabIndex = 77;
|
||||||
|
//
|
||||||
// Form1
|
// Form1
|
||||||
//
|
//
|
||||||
AutoScaleDimensions = new SizeF(7F, 15F);
|
AutoScaleDimensions = new SizeF(7F, 15F);
|
||||||
AutoScaleMode = AutoScaleMode.Font;
|
AutoScaleMode = AutoScaleMode.Font;
|
||||||
ClientSize = new Size(780, 363);
|
ClientSize = new Size(780, 363);
|
||||||
|
Controls.Add(listBox1);
|
||||||
Controls.Add(groupBox2);
|
Controls.Add(groupBox2);
|
||||||
Controls.Add(slider5Label);
|
Controls.Add(slider5Label);
|
||||||
Controls.Add(slider4Label);
|
Controls.Add(slider4Label);
|
||||||
@@ -1160,5 +1203,6 @@
|
|||||||
private CheckBox mixerAutoConnectCheckbox;
|
private CheckBox mixerAutoConnectCheckbox;
|
||||||
private Label mixerLabel;
|
private Label mixerLabel;
|
||||||
private NotifyIcon notifyIcon1;
|
private NotifyIcon notifyIcon1;
|
||||||
|
private ListBox listBox1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,21 @@
|
|||||||
using System.Diagnostics;
|
using HidSliders.Hid;
|
||||||
using System.Reflection;
|
|
||||||
using HidLibrary;
|
|
||||||
using Voicemeeter;
|
using Voicemeeter;
|
||||||
using VoiceMeeter;
|
using VoiceMeeter;
|
||||||
|
using Timer = System.Windows.Forms.Timer;
|
||||||
|
|
||||||
namespace HidSliders.Gui
|
namespace HidSliders.Gui
|
||||||
{
|
{
|
||||||
public partial class Form1 : Form
|
public partial class Form1 : Form
|
||||||
{
|
{
|
||||||
private IDisposable? _vmClient;
|
private IDisposable? _vmClient;
|
||||||
private IHidDevice? _hidDevice;
|
private bool _mixerConnected;
|
||||||
private const float Resolution = 72.0f;
|
private List<MixerButton> _previousButtons = [];
|
||||||
|
private readonly HidInterface _hidInterface;
|
||||||
|
private const int ZeroPercent = 90;
|
||||||
private readonly List<ChannelControlCollection> _channels;
|
private readonly List<ChannelControlCollection> _channels;
|
||||||
|
private bool _suppressCheckboxUpdate = false;
|
||||||
|
private Timer _syncTimer = new();
|
||||||
|
|
||||||
public Form1()
|
public Form1()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
@@ -44,24 +48,134 @@ namespace HidSliders.Gui
|
|||||||
_channels[3].ChannelSelector.Value = Properties.Settings.Default.Channel4Strip;
|
_channels[3].ChannelSelector.Value = Properties.Settings.Default.Channel4Strip;
|
||||||
_channels[4].ChannelSelector.Value = Properties.Settings.Default.Channel5Strip;
|
_channels[4].ChannelSelector.Value = Properties.Settings.Default.Channel5Strip;
|
||||||
|
|
||||||
|
_syncTimer.Tick += SyncVM;
|
||||||
|
_syncTimer.Interval = 100;
|
||||||
|
_syncTimer.Enabled = true;
|
||||||
if (Properties.Settings.Default.AutoConnect)
|
if (Properties.Settings.Default.AutoConnect)
|
||||||
{
|
{
|
||||||
autoConnectCheckBox.Checked = true;
|
autoConnectCheckBox.Checked = true;
|
||||||
Task.Run(ConnectVoicemeeter).Wait();
|
Task.Run(ConnectVoicemeeter).Wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
var enumerator = new HidEnumerator();
|
_hidInterface = new HidInterface();
|
||||||
var hidDevices = enumerator.Enumerate(0x0359, [0x6497]);
|
mixerLabel.Text = "Mixer not connected";
|
||||||
_hidDevice = hidDevices.FirstOrDefault();
|
|
||||||
voicemeeterStatusLabel.Text = $"Mixer {(_hidDevice?.IsConnected == true ? "" : "not ")}connected";
|
|
||||||
|
|
||||||
if (_hidDevice?.IsConnected == true && Properties.Settings.Default.MixerAutoConnect)
|
if (Properties.Settings.Default.MixerAutoConnect)
|
||||||
{
|
{
|
||||||
UsbListenerLoop();
|
ConnectHidMixer();
|
||||||
mixerAutoConnectCheckbox.Checked = true;
|
mixerAutoConnectCheckbox.Checked = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnSliderValues(int[] values)
|
||||||
|
{
|
||||||
|
this.BeginInvoke(() =>
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 5; i++)
|
||||||
|
{
|
||||||
|
var gain = HidToGain(values[i]);
|
||||||
|
SetStripGain(_channels[i].CurrentStrip, gain);
|
||||||
|
_channels[i].TrackBar.Value = (int)gain;
|
||||||
|
_channels[i].IndicatorLabel.Text = $"{gain} dB";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleButtonPress(MixerButton button)
|
||||||
|
{
|
||||||
|
var buttonGroup = MixerButtonHelper.GetButtonGroup(button);
|
||||||
|
var channelButton = MixerButtonHelper.GetChannelButton(button, buttonGroup);
|
||||||
|
|
||||||
|
ChannelControlCollection channel;
|
||||||
|
switch (buttonGroup)
|
||||||
|
{
|
||||||
|
case ButtonGroups.Channel1:
|
||||||
|
channel = _channels[0];
|
||||||
|
break;
|
||||||
|
case ButtonGroups.Channel2:
|
||||||
|
channel = _channels[1];
|
||||||
|
break;
|
||||||
|
case ButtonGroups.Channel3:
|
||||||
|
channel = _channels[2];
|
||||||
|
break;
|
||||||
|
case ButtonGroups.Channel4:
|
||||||
|
channel = _channels[3];
|
||||||
|
break;
|
||||||
|
case ButtonGroups.Channel5:
|
||||||
|
channel = _channels[4];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception();
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (channelButton)
|
||||||
|
{
|
||||||
|
case ChannelButton.ChannelA1:
|
||||||
|
channel.BusA1Checkbox.Checked = !channel.BusA1Checkbox.Checked;
|
||||||
|
break;
|
||||||
|
case ChannelButton.ChannelA2:
|
||||||
|
channel.BusA2Checkbox.Checked = !channel.BusA2Checkbox.Checked;
|
||||||
|
break;
|
||||||
|
case ChannelButton.ChannelA3:
|
||||||
|
channel.BusA3Checkbox.Checked = !channel.BusA3Checkbox.Checked;
|
||||||
|
break;
|
||||||
|
case ChannelButton.ChannelA4:
|
||||||
|
channel.BusA4Checkbox.Checked = !channel.BusA4Checkbox.Checked;
|
||||||
|
break;
|
||||||
|
case ChannelButton.ChannelA5:
|
||||||
|
channel.BusA5Checkbox.Checked = !channel.BusA5Checkbox.Checked;
|
||||||
|
break;
|
||||||
|
case ChannelButton.ChannelB1:
|
||||||
|
channel.BusB1Checkbox.Checked = !channel.BusB1Checkbox.Checked;
|
||||||
|
break;
|
||||||
|
case ChannelButton.ChannelB2:
|
||||||
|
channel.BusB2Checkbox.Checked = !channel.BusB2Checkbox.Checked;
|
||||||
|
break;
|
||||||
|
case ChannelButton.ChannelB3:
|
||||||
|
channel.BusB3Checkbox.Checked = !channel.BusB3Checkbox.Checked;
|
||||||
|
break;
|
||||||
|
case ChannelButton.ChannelMute:
|
||||||
|
channel.MuteCheckBox.Checked = !channel.MuteCheckBox.Checked;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception();
|
||||||
|
}
|
||||||
|
listBox1.Items.Add($"{buttonGroup} {channelButton} pressed");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnButtons(List<MixerButton> buttons)
|
||||||
|
{
|
||||||
|
BeginInvoke(() =>
|
||||||
|
{
|
||||||
|
var newButtons = buttons.Except(_previousButtons).ToList();
|
||||||
|
_previousButtons = buttons;
|
||||||
|
|
||||||
|
newButtons.ForEach(HandleButtonPress);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnSliderComplete()
|
||||||
|
{
|
||||||
|
BeginInvoke(() =>
|
||||||
|
{
|
||||||
|
_mixerConnected = false;
|
||||||
|
button1.Enabled = true;
|
||||||
|
mixerLabel.Text = "Mixer disconnected";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ConnectHidMixer()
|
||||||
|
{
|
||||||
|
_mixerConnected = _hidInterface.ConnectDevice(0x0359, 0x6497);
|
||||||
|
if (_mixerConnected)
|
||||||
|
{
|
||||||
|
mixerLabel.Text = "Mixer connected";
|
||||||
|
button1.Enabled = false;
|
||||||
|
_hidInterface.SliderObservable.Subscribe(OnSliderValues, OnSliderComplete);
|
||||||
|
_hidInterface.ButtonsObservable.Subscribe(OnButtons);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async Task ConnectVoicemeeter()
|
private async Task ConnectVoicemeeter()
|
||||||
{
|
{
|
||||||
RunVoicemeeterParam version = RunVoicemeeterParam.None;
|
RunVoicemeeterParam version = RunVoicemeeterParam.None;
|
||||||
@@ -84,6 +198,7 @@ namespace HidSliders.Gui
|
|||||||
{
|
{
|
||||||
EnableVMControls(version);
|
EnableVMControls(version);
|
||||||
voicemeeterStatusLabel.Text = "Connected";
|
voicemeeterStatusLabel.Text = "Connected";
|
||||||
|
_syncTimer.Start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,6 +207,16 @@ namespace HidSliders.Gui
|
|||||||
await ConnectVoicemeeter();
|
await ConnectVoicemeeter();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void SyncVM(object? sender, EventArgs eventArgs)
|
||||||
|
{
|
||||||
|
if (_vmClient == null || Remote.IsParametersDirty() != 1) return;
|
||||||
|
|
||||||
|
foreach (var channelControlCollection in _channels)
|
||||||
|
{
|
||||||
|
SyncChannelControls(channelControlCollection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void EnableVMControls(RunVoicemeeterParam version)
|
private void EnableVMControls(RunVoicemeeterParam version)
|
||||||
{
|
{
|
||||||
foreach (var channel in _channels)
|
foreach (var channel in _channels)
|
||||||
@@ -106,6 +231,7 @@ namespace HidSliders.Gui
|
|||||||
|
|
||||||
private void SyncChannelControls(ChannelControlCollection channel)
|
private void SyncChannelControls(ChannelControlCollection channel)
|
||||||
{
|
{
|
||||||
|
_suppressCheckboxUpdate = true;
|
||||||
channel.BusA1Checkbox.Checked = GetBusEnabled(channel.CurrentStrip, VMBus.A1);
|
channel.BusA1Checkbox.Checked = GetBusEnabled(channel.CurrentStrip, VMBus.A1);
|
||||||
channel.BusB1Checkbox.Checked = GetBusEnabled(channel.CurrentStrip, VMBus.B1);
|
channel.BusB1Checkbox.Checked = GetBusEnabled(channel.CurrentStrip, VMBus.B1);
|
||||||
if (vmBananaRadio.Checked || vmPotatoRadio.Checked)
|
if (vmBananaRadio.Checked || vmPotatoRadio.Checked)
|
||||||
@@ -125,6 +251,7 @@ namespace HidSliders.Gui
|
|||||||
channel.TrackBar.Value = (int)GetStripGain(channel.CurrentStrip);
|
channel.TrackBar.Value = (int)GetStripGain(channel.CurrentStrip);
|
||||||
channel.SoloCheckBox.Checked = GetChannelSolo(channel.CurrentStrip);
|
channel.SoloCheckBox.Checked = GetChannelSolo(channel.CurrentStrip);
|
||||||
channel.MuteCheckBox.Checked = GetChannelMute(channel.CurrentStrip);
|
channel.MuteCheckBox.Checked = GetChannelMute(channel.CurrentStrip);
|
||||||
|
_suppressCheckboxUpdate = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
|
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
|
||||||
@@ -133,44 +260,9 @@ namespace HidSliders.Gui
|
|||||||
Properties.Settings.Default.Save();
|
Properties.Settings.Default.Save();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void UsbListenerLoop()
|
|
||||||
{
|
|
||||||
if (_hidDevice == null) return;
|
|
||||||
mixerLabel.Text = "Mixer online";
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
if (_hidDevice.IsConnected)
|
|
||||||
{
|
|
||||||
button1.Enabled = false;
|
|
||||||
//label1.Text = "waiting for report";
|
|
||||||
var progress = new Progress<string>();
|
|
||||||
progress.ProgressChanged += (o, s) => voicemeeterStatusLabel.Text = s;
|
|
||||||
var report = await Task.Run(() => _hidDevice.ReadReport());
|
|
||||||
if (report.ReadStatus == HidDeviceData.ReadStatus.Success)
|
|
||||||
{
|
|
||||||
var reportChunk = new byte[2];
|
|
||||||
for (int i = 0; i < 5; i++)
|
|
||||||
{
|
|
||||||
Array.Copy(report.Data, i * 2, reportChunk, 0, 2);
|
|
||||||
var sliderVal = BitConverter.ToInt16(reportChunk);
|
|
||||||
var gain = HidToGain(sliderVal);
|
|
||||||
SetStripGain(_channels[i].CurrentStrip, gain);
|
|
||||||
_channels[i].TrackBar.Value = (int)gain;
|
|
||||||
_channels[i].IndicatorLabel.Text = $"{gain} dB";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//button1.Enabled = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
button1.Enabled = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void button1_Click(object sender, EventArgs e)
|
private void button1_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
UsbListenerLoop();
|
ConnectHidMixer();
|
||||||
}
|
}
|
||||||
|
|
||||||
private float HidToGain(int hidValue)
|
private float HidToGain(int hidValue)
|
||||||
@@ -179,11 +271,43 @@ namespace HidSliders.Gui
|
|||||||
// Truncate to first decimal (move decimal, int truncate, move decimal)
|
// Truncate to first decimal (move decimal, int truncate, move decimal)
|
||||||
//var realResult = 5.8456f + 17.0486f * (float)Math.Log(Math.Max(hidValue / Resolution, 0.02));
|
//var realResult = 5.8456f + 17.0486f * (float)Math.Log(Math.Max(hidValue / Resolution, 0.02));
|
||||||
//return ((int)(realResult * 10)) / 10.0f;
|
//return ((int)(realResult * 10)) / 10.0f;
|
||||||
return hidValue - 60;
|
return (int)(CalculateGain(hidValue, ZeroPercent) * 10) / 10.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float CalculateGain(float slider, int zeroPct)
|
||||||
|
{
|
||||||
|
float minSlider;
|
||||||
|
float maxSlider;
|
||||||
|
float minGain;
|
||||||
|
float maxGain;
|
||||||
|
|
||||||
|
if (slider >= zeroPct)
|
||||||
|
{
|
||||||
|
minSlider = zeroPct;
|
||||||
|
maxSlider = 100;
|
||||||
|
minGain = 0;
|
||||||
|
maxGain = 12;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
minSlider = 0;
|
||||||
|
maxSlider = zeroPct;
|
||||||
|
minGain = -60;
|
||||||
|
maxGain = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate the percentage of slider position within the range
|
||||||
|
var percentage = (slider - minSlider) / (maxSlider - minSlider);
|
||||||
|
|
||||||
|
// Interpolate gain within the range based on the percentage
|
||||||
|
var calculatedGain = minGain + (percentage * (maxGain - minGain));
|
||||||
|
|
||||||
|
return calculatedGain;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void trackBar_Scroll(object sender, EventArgs e)
|
private void trackBar_Scroll(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
|
if (_suppressCheckboxUpdate) return;
|
||||||
if (sender is TrackBar trackBar && _vmClient != null)
|
if (sender is TrackBar trackBar && _vmClient != null)
|
||||||
{
|
{
|
||||||
var channel = _channels.First(c => c.OwnsControl(trackBar));
|
var channel = _channels.First(c => c.OwnsControl(trackBar));
|
||||||
@@ -193,6 +317,7 @@ namespace HidSliders.Gui
|
|||||||
|
|
||||||
private void busCheckbox_CheckedChanged(object sender, EventArgs e)
|
private void busCheckbox_CheckedChanged(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
|
if (_suppressCheckboxUpdate) return;
|
||||||
if (sender is CheckBox { Tag: VMBus bus } checkBox && _vmClient != null)
|
if (sender is CheckBox { Tag: VMBus bus } checkBox && _vmClient != null)
|
||||||
{
|
{
|
||||||
var channel = _channels.First(c => c.OwnsControl(checkBox));
|
var channel = _channels.First(c => c.OwnsControl(checkBox));
|
||||||
@@ -243,8 +368,6 @@ namespace HidSliders.Gui
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private void SetBusEnabled(int strip, VMBus bus, bool enabled)
|
private void SetBusEnabled(int strip, VMBus bus, bool enabled)
|
||||||
{
|
{
|
||||||
Remote.SetParameter($"Strip[{strip}].{bus}", enabled ? 1 : 0);
|
Remote.SetParameter($"Strip[{strip}].{bus}", enabled ? 1 : 0);
|
||||||
@@ -292,6 +415,7 @@ namespace HidSliders.Gui
|
|||||||
|
|
||||||
private void soloCheckBox_CheckedChanged(object sender, EventArgs e)
|
private void soloCheckBox_CheckedChanged(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
|
if (_suppressCheckboxUpdate) return;
|
||||||
if (sender is CheckBox checkBox && _vmClient != null)
|
if (sender is CheckBox checkBox && _vmClient != null)
|
||||||
{
|
{
|
||||||
var channel = _channels.First(c => c.OwnsControl(checkBox));
|
var channel = _channels.First(c => c.OwnsControl(checkBox));
|
||||||
@@ -301,6 +425,7 @@ namespace HidSliders.Gui
|
|||||||
|
|
||||||
private void muteCheckBox_CheckedChanged(object sender, EventArgs e)
|
private void muteCheckBox_CheckedChanged(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
|
if (_suppressCheckboxUpdate) return;
|
||||||
if (sender is CheckBox checkBox && _vmClient != null)
|
if (sender is CheckBox checkBox && _vmClient != null)
|
||||||
{
|
{
|
||||||
var channel = _channels.First(c => c.OwnsControl(checkBox));
|
var channel = _channels.First(c => c.OwnsControl(checkBox));
|
||||||
|
|||||||
@@ -9,10 +9,14 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="hidlibrary" Version="3.3.40" />
|
<PackageReference Include="hidlibrary" Version="3.2.49" />
|
||||||
<PackageReference Include="VoicemeeterRemote" Version="1.0.3" />
|
<PackageReference Include="VoicemeeterRemote" Version="1.0.3" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\HidSliders.Hid\HidSliders.Hid.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Update="Properties\Settings.Designer.cs">
|
<Compile Update="Properties\Settings.Designer.cs">
|
||||||
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
namespace HidSliders.Hid
|
|
||||||
{
|
|
||||||
public class Class1
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
87
HidSliders.Hid/HidInterface.cs
Normal file
87
HidSliders.Hid/HidInterface.cs
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
using System.Reactive.Subjects;
|
||||||
|
using HidLibrary;
|
||||||
|
|
||||||
|
namespace HidSliders.Hid
|
||||||
|
{
|
||||||
|
public class HidInterface
|
||||||
|
{
|
||||||
|
private IHidDevice? _device;
|
||||||
|
private Subject<int[]> _sliderUpdate = new();
|
||||||
|
private Subject<List<MixerButton>> _buttonsUpdate = new();
|
||||||
|
|
||||||
|
public IObservable<int[]> SliderObservable => _sliderUpdate;
|
||||||
|
public IObservable<List<MixerButton>> ButtonsObservable => _buttonsUpdate;
|
||||||
|
|
||||||
|
public bool ConnectDevice(int vendorId, int devId)
|
||||||
|
{
|
||||||
|
var enumerator = new HidEnumerator();
|
||||||
|
IEnumerable<IHidDevice> hidDevices = enumerator.Enumerate(vendorId, [devId]);
|
||||||
|
|
||||||
|
_device = hidDevices.FirstOrDefault();
|
||||||
|
|
||||||
|
if (_device is { IsConnected: true })
|
||||||
|
{
|
||||||
|
_device.OpenDevice();
|
||||||
|
_device.MonitorDeviceEvents = true;
|
||||||
|
|
||||||
|
_device.ReadReport(OnReport);
|
||||||
|
_device.Removed += DeviceOnRemoved;
|
||||||
|
_device.Inserted += DeviceOnInserted;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _device?.IsConnected ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DeviceOnInserted()
|
||||||
|
{
|
||||||
|
_sliderUpdate = new Subject<int[]>();
|
||||||
|
_buttonsUpdate = new Subject<List<MixerButton>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DeviceOnRemoved()
|
||||||
|
{
|
||||||
|
_sliderUpdate.OnCompleted();
|
||||||
|
_buttonsUpdate.OnCompleted();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ReadSliders(byte[] reportSliderBytes)
|
||||||
|
{
|
||||||
|
var reportChunk = new byte[4];
|
||||||
|
var sliderValues = new int[5];
|
||||||
|
for (int i = 0; i < 5; i++)
|
||||||
|
{
|
||||||
|
Array.Copy(reportSliderBytes, i * 2, reportChunk, 0, 2);
|
||||||
|
sliderValues[i] = BitConverter.ToInt32(reportChunk);
|
||||||
|
}
|
||||||
|
_sliderUpdate.OnNext(sliderValues);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ReadButtons(byte[] reportButtonBytes)
|
||||||
|
{
|
||||||
|
if (reportButtonBytes.Length != 8)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("incoming report data was not padded to 8 bytes");
|
||||||
|
}
|
||||||
|
var buttonLong = BitConverter.ToInt64(reportButtonBytes);
|
||||||
|
_buttonsUpdate.OnNext(MixerButtonHelper.GetSetFlags(buttonLong));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ReadReport(byte[] reportBytes)
|
||||||
|
{
|
||||||
|
var buttons = new byte[8];
|
||||||
|
var sliders = new byte[10];
|
||||||
|
Array.Copy(reportBytes, 0, buttons, 0, 6);
|
||||||
|
Array.Copy(reportBytes, 6, sliders, 0, 10);
|
||||||
|
ReadSliders(sliders);
|
||||||
|
ReadButtons(buttons);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnReport(HidReport report)
|
||||||
|
{
|
||||||
|
if (!_device!.IsConnected) return;
|
||||||
|
|
||||||
|
ReadReport(report.Data);
|
||||||
|
_device!.ReadReport(OnReport);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,7 +7,8 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="hidlibrary" Version="3.3.40" />
|
<PackageReference Include="hidlibrary" Version="3.2.49" />
|
||||||
|
<PackageReference Include="System.Reactive" Version="6.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
75
HidSliders.Hid/MixerButton.cs
Normal file
75
HidSliders.Hid/MixerButton.cs
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
namespace HidSliders.Hid;
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum MixerButton : long
|
||||||
|
{
|
||||||
|
Button1 = 1L << 0, // 1
|
||||||
|
Button2 = 1L << 1, // 2
|
||||||
|
Button3 = 1L << 2, // 4
|
||||||
|
Button4 = 1L << 3, // 8
|
||||||
|
Button5 = 1L << 4, // 16
|
||||||
|
Button6 = 1L << 5, // 32
|
||||||
|
Button7 = 1L << 6, // 64
|
||||||
|
Button8 = 1L << 7, // 128
|
||||||
|
Button9 = 1L << 8, // 256
|
||||||
|
Button10 = 1L << 9, // 512
|
||||||
|
Button11 = 1L << 10, // 1024
|
||||||
|
Button12 = 1L << 11, // 2048
|
||||||
|
Button13 = 1L << 12, // 4096
|
||||||
|
Button14 = 1L << 13, // 8192
|
||||||
|
Button15 = 1L << 14, // 16384
|
||||||
|
Button16 = 1L << 15, // 32768
|
||||||
|
Button17 = 1L << 16, // 65536
|
||||||
|
Button18 = 1L << 17, // 131072
|
||||||
|
Button19 = 1L << 18, // 262144
|
||||||
|
Button20 = 1L << 19, // 524288
|
||||||
|
Button21 = 1L << 20, // 1048576
|
||||||
|
Button22 = 1L << 21, // 2097152
|
||||||
|
Button23 = 1L << 22, // 4194304
|
||||||
|
Button24 = 1L << 23, // 8388608
|
||||||
|
Button25 = 1L << 24, // 16777216
|
||||||
|
Button26 = 1L << 25, // 33554432
|
||||||
|
Button27 = 1L << 26, // 67108864
|
||||||
|
Button28 = 1L << 27, // 134217728
|
||||||
|
Button29 = 1L << 28, // 268435456
|
||||||
|
Button30 = 1L << 29, // 536870912
|
||||||
|
Button31 = 1L << 30, // 1073741824
|
||||||
|
Button32 = 1L << 31, // 2147483648
|
||||||
|
Button33 = 1L << 32, // 4294967296
|
||||||
|
Button34 = 1L << 33, // 8589934592
|
||||||
|
Button35 = 1L << 34, // 17179869184
|
||||||
|
Button36 = 1L << 35, // 34359738368
|
||||||
|
Button37 = 1L << 36, // 68719476736
|
||||||
|
Button38 = 1L << 37, // 137438953472
|
||||||
|
Button39 = 1L << 38, // 274877906944
|
||||||
|
Button40 = 1L << 39, // 549755813888
|
||||||
|
Button41 = 1L << 40, // 1099511627776
|
||||||
|
Button42 = 1L << 41, // 2199023255552
|
||||||
|
Button43 = 1L << 42, // 4398046511104
|
||||||
|
Button44 = 1L << 43, // 8796093022208
|
||||||
|
Button45 = 1L << 44 // 17592186044416
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum ButtonGroups : long
|
||||||
|
{
|
||||||
|
Channel1 = 0b00001_00000000_00000000_00000000_00000000_11111111,
|
||||||
|
Channel2 = 0b00010_00000000_00000000_00000000_11111111_00000000,
|
||||||
|
Channel3 = 0b00100_00000000_00000000_11111111_00000000_00000000,
|
||||||
|
Channel4 = 0b01000_00000000_11111111_00000000_00000000_00000000,
|
||||||
|
Channel5 = 0b10000_11111111_00000000_00000000_00000000_00000000,
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum ChannelButton
|
||||||
|
{
|
||||||
|
ChannelA1 = 1 << 0,
|
||||||
|
ChannelA2 = 1 << 1,
|
||||||
|
ChannelA3 = 1 << 2,
|
||||||
|
ChannelA4 = 1 << 3,
|
||||||
|
ChannelA5 = 1 << 4,
|
||||||
|
ChannelB1 = 1 << 5,
|
||||||
|
ChannelB2 = 1 << 6,
|
||||||
|
ChannelB3 = 1 << 7,
|
||||||
|
ChannelMute = 1 << 8,
|
||||||
|
}
|
||||||
75
HidSliders.Hid/MixerButtonHelper.cs
Normal file
75
HidSliders.Hid/MixerButtonHelper.cs
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
namespace HidSliders.Hid;
|
||||||
|
|
||||||
|
public class MixerButtonHelper
|
||||||
|
{
|
||||||
|
public static List<MixerButton> GetSetFlags(long value)
|
||||||
|
{
|
||||||
|
var setFlags = new List<MixerButton>();
|
||||||
|
foreach (MixerButton flag in Enum.GetValues(typeof(MixerButton)))
|
||||||
|
{
|
||||||
|
if ((value & (long)flag) == (long)flag)
|
||||||
|
{
|
||||||
|
setFlags.Add(flag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return setFlags;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ButtonGroups GetButtonGroup(MixerButton button)
|
||||||
|
{
|
||||||
|
var buttonValue = (long)button;
|
||||||
|
|
||||||
|
if (((long)ButtonGroups.Channel1 & buttonValue) != 0) return ButtonGroups.Channel1;
|
||||||
|
if (((long)ButtonGroups.Channel2 & buttonValue) != 0) return ButtonGroups.Channel2;
|
||||||
|
if (((long)ButtonGroups.Channel3 & buttonValue) != 0) return ButtonGroups.Channel3;
|
||||||
|
if (((long)ButtonGroups.Channel4 & buttonValue) != 0) return ButtonGroups.Channel4;
|
||||||
|
if (((long)ButtonGroups.Channel5 & buttonValue) != 0) return ButtonGroups.Channel5;
|
||||||
|
|
||||||
|
throw new ArgumentException("The provided button does not match any button group.", nameof(button));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ChannelButton GetChannelButton(MixerButton button)
|
||||||
|
{
|
||||||
|
return GetChannelButton(button, GetButtonGroup(button));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ChannelButton GetChannelButton(MixerButton button, ButtonGroups buttonGroup)
|
||||||
|
{
|
||||||
|
var longButton = (long)button;
|
||||||
|
if (longButton >= 0x10000000000)
|
||||||
|
{
|
||||||
|
return ChannelButton.ChannelMute;
|
||||||
|
}
|
||||||
|
|
||||||
|
int intButton = 0;
|
||||||
|
switch (buttonGroup)
|
||||||
|
{
|
||||||
|
case ButtonGroups.Channel1:
|
||||||
|
intButton = (int)(longButton >> 0);
|
||||||
|
break;
|
||||||
|
case ButtonGroups.Channel2:
|
||||||
|
intButton = (int)(longButton >> 8);
|
||||||
|
break;
|
||||||
|
case ButtonGroups.Channel3:
|
||||||
|
intButton = (int)(longButton >> 16);
|
||||||
|
break;
|
||||||
|
case ButtonGroups.Channel4:
|
||||||
|
intButton = (int)(longButton >> 24);
|
||||||
|
break;
|
||||||
|
case ButtonGroups.Channel5:
|
||||||
|
intButton = (int)(longButton >> 32);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (((int)ChannelButton.ChannelA1 & intButton) != 0) return ChannelButton.ChannelA1;
|
||||||
|
if (((int)ChannelButton.ChannelA2 & intButton) != 0) return ChannelButton.ChannelA2;
|
||||||
|
if (((int)ChannelButton.ChannelA3 & intButton) != 0) return ChannelButton.ChannelA3;
|
||||||
|
if (((int)ChannelButton.ChannelA4 & intButton) != 0) return ChannelButton.ChannelA4;
|
||||||
|
if (((int)ChannelButton.ChannelA5 & intButton) != 0) return ChannelButton.ChannelA5;
|
||||||
|
if (((int)ChannelButton.ChannelB1 & intButton) != 0) return ChannelButton.ChannelB1;
|
||||||
|
if (((int)ChannelButton.ChannelB2 & intButton) != 0) return ChannelButton.ChannelB2;
|
||||||
|
if (((int)ChannelButton.ChannelB3 & intButton) != 0) return ChannelButton.ChannelB3;
|
||||||
|
|
||||||
|
throw new ArgumentException("The provided button does not match any channel button in the specified button group.", nameof(button));
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user