babymix/encoding.py

78 lines
1.8 KiB
Python

import math
from typing import Optional, List
import mido
PREFIX = [0x00, 0x20, 0x0D, 0x10]
SUBID_IN_STATUS = 0
SUBID_IN_RMS = 1
SUBID_IN_PEAK = 2
SUBID_OPTIONS = 0
SUBID_MIXER = 1
SUBID_LOOPBACK = 2
SUBID_INPUT_OUTS = 3
SUBID_GAIN = 4
def decode_message(msg: mido.Message) -> tuple[Optional[int], Optional[List[int]]]:
msg_bytes = msg.bytes()
if msg_bytes[:5] != [0xF0] + PREFIX:
return None, None # noop
result_words = []
try:
chunks = zip(*[iter(msg_bytes[6:-1])] * 5, strict=True)
for packed in chunks:
value = packed[4] << 28 | packed[3] << 21 | packed[2] << 14 | packed[1] << 7 | packed[0]
result_words.append(value)
except ValueError:
pass # invalid message
return msg_bytes[5], result_words
def encode_message(subid: int, payload: List[int]) -> mido.Message:
data = [subid]
for word in payload:
data += [
word & 0x7F,
word >> 7 & 0x7F,
word >> 14 & 0x7F,
word >> 21 & 0x7F,
word >> 28 & 0x7F,
]
return mido.Message('sysex', data=PREFIX + data)
def hex_format(msg, width=2):
return ' '.join([("{x:0" + str(width) + "x}").format(x=x) for x in msg])
def bin_format(msg, width=32):
return ' '.join([("{x:0" + str(width) + "b}").format(x=x) for x in msg])
def get_bitfield(word, position, length):
return (word >> position) & ((1 << length) - 1)
def set_bitfield(word, val, position, length):
mask = ((1 << length) - 1)
val = (val & mask) << position
return (word & mask << position) | val
def level_to_db(val):
return 6 + (val - 0xFF) / 2
def fader_to_db(val):
return 6 + (abs(val) - 0xFF) / 2
def format_db(val, min_db=-120):
if math.isnan(val) or val <= min_db:
return ''
else:
return format(val, '.1f')