mute parameters

This commit is contained in:
nik gaffney 2024-09-19 13:15:26 +02:00
parent e05553b020
commit 00019ea7e7
15 changed files with 1643 additions and 0 deletions

48
CQ-20B.org Normal file
View file

@ -0,0 +1,48 @@
# -*- mode: org; coding: utf-8; -*-
#+LaTeX_CLASS: zzkt-article
#+LateX_Header: \setcounter{secnumdepth}{0}
#+OPTIONS: toc:2 num:nil html-style:nil
#+author:
#+title: Allen & Heath CQ-20B
based on MIDI Protocol V1.2 Issue 2
[[file:img/CQ-20B.png]]
The CQ uses MIDI Channel 1 for all control messaging.
* Available Controls
** Scene change
** Soft Keys
** Mutes
** Levels
** Panning/Balance
** Getting values
* Reference Tables
** Decimal, HEX, Note conversions
[[file:img/cq_ref_1.png]]
** Soft Key Note and Hex values
[[file:img/cq_ref_2.png]]
** Mutes Parameter Numbers
[[file:img/cq_ref_3.png]]
** Level Parameter Numbers — Inputs and FX to Outputs and FX
[[file:img/cq_ref_4.png]]
** Level Parameter Numbers — Outputs, FX unit input and DCAs
[[file:img/cq_ref_5.png]]
** Pan Balance Parameter Numbers — Inputs and FX to Main LR and Outputs
[[file:img/cq_ref_6.png]]
* Further
- CQ MIDI Protocol

14
README.org Normal file
View file

@ -0,0 +1,14 @@
# -*- mode: org; coding: utf-8; -*-
#+title: OSC bridge(s) for A&H Equipment
* XONE:K2
“Xone:K2 is a compact, slim line universal MIDI controller incorporating a 4 channel soundcard, for use with any DJ software.”
- MIDI controller
- output OSC
- https://www.allen-heath.com/hardware/xone-series/xonek2/
* CQ-20B
“Ultra-Compact 20-in / 8-out Digital Mixer with Wi-Fi”
- Digital mixer/stagebox
- config, control & monitoring via OSC
- https://www.allen-heath.com/hardware/cq/cq-20b/

260
XONE-K2.org Normal file
View file

@ -0,0 +1,260 @@
# -*- mode: org; coding: utf-8; -*-
#+LaTeX_CLASS: zzkt-article
#+LateX_Header: \setcounter{secnumdepth}{0}
#+OPTIONS: toc:2 num:nil html-style:nil
#+title: XONE:K2
file:img/XONE-K2-squared.jpg
* install & setup
requirements
#+BEGIN_SRC shell :dir :wrap SRC text :results raw
python -m pip install oscpy mido python-rtmidi argparse
#+END_SRC
make it go
#+BEGIN_SRC shell :dir :wrap SRC text :results raw
python k2-misc.py
#+END_SRC
usage
#+BEGIN_SRC text
usage: k2-misc [-h] [--host OSC-host] [--port OSC-port] [--midi MIDI-port]
[-v verbose] [-q quiet]
MIDI->OSC bridge for Allen & Heath XONE:K2 controller
options:
-h, --help show this help message and exit
--host OSC-host hostname or address of OSC destination
--port OSC-port port for OSC messages
--midi MIDI-port port name of MIDI device
-v verbose
-q quiet
#+END_SRC
defaults
#+BEGIN_SRC shell :dir :wrap SRC text :results raw
python k2-misc.py --host "127.0.0.1" --port 5111 --midi 'XONE:K2'
#+END_SRC
* Overview
* Physical layout
XONE:K2 Publication AP8509
** Rotary Encoders
Turning an encoder produces MIDI CC (continuous controller) messages with a unique controller number in twos compliment binary encoding These encoders feature a built in momentary push switch. Pressing down on the encoder knob activates the switch and sends a “Note On” MIDI message, releasing the switch sends a corresponding “Note Off” message. The window below the top row of encoders can be used to display the state of the encoder switch in the same manner as the other switches.
** Rotary Potentiometers
These controls are standard potentiometers with end stops. Turning a pot from left to right will send MIDI messages with a unique CC number and a control value from 0 to 127.
** Pot Switches
Each rotary potentiometer has a switch with tri-colour illumination below it.
** Linear Faders
Moving a linear fader will send a MIDI message with a unique CC number and a control value from 0 (bottom) to 127 (top).
** Switch Matrix
The switch matrix consists of 16 back-lit tri-colour switches.
** Layer Button
The Layer button is completely user assignable but can also function as an embedded layer button.
* OSC layout & mapping
Physical controls are numbered L->R and top->down
[[file:img/K2-layout.png]]
** Rotary potentiometers
Rotary potentiometers are numbered 1-12 (soft sync/pickup?) and send value 0-127 when turned, and =pressed= / =released= messages are sent when knobs are pressed (and released).
#+BEGIN_SRC text
/xone/k2/rp/<n> <int>
/xone/k2/rp/<n>/pressed
/xone/k2/rp/<n>/released
#+END_SRC
** Rotary encoders
Rotary encoders on the top row are numbered 1-4 and the bottom row are numbered 5 and 6. Encoders send =inc= messages when turned right (clockwise) or =dec= when lurned left (widdershins). While turned & pressed, the encoder sends =inc-fine= and =dec-fine= messages.
#+BEGIN_SRC text
/xone/k2/re/<n>/inc
/xone/k2/re/<n>/dec
/xone/k2/re/<n>/inc-fine
/xone/k2/re/<n>/dec-fine
#+END_SRC
** Linear faders
Linear faders are numbered 1-4 and send values from 0 (fully down) up to 127 (fully up).
#+BEGIN_SRC text
/xone/k2/fader/<n>/value <int>
#+END_SRC
** Buttons
The upper block of buttons (above the faders) are numbered from 1-12 and the lower block (grid below the faders) are named =A-P=, =LAYER=, and =SHIFT= as labled)
#+BEGIN_SRC text
/xone/k2/button/<name>/pressed
/xone/k2/button/<name>/released
#+END_SRC
set button colour (not yet implemented)
#+BEGIN_SRC text
/xone/k2/button/<name>/set <colour>
<colour> = red, orange, green, off (string)
#+END_SRC
* MIDI layout (MIDI IMPLEMENTATION SEND / RETURN)
By default the MIDI Channel number is set to 15 (14) to prevent control interaction with Xone DB series mixers which default to channel 16 (15).
[[file:img/XONE-K2-layers.jpg]]
* MIDI NOTE IMPLEMENTATION TABLE
| DEC | HEX | NOTE |
| 0 | 00 | C-1 |
| 1 | 01 | C#-1 |
| 2 | 02 | D-1 |
| 3 | 03 | D#-1 |
| 4 | 04 | E-1 |
| 5 | 05 | F-1 |
| 6 | 06 | F#-1 |
| 7 | 07 | G-1 |
| 8 | 08 | G#-1 |
| 9 | 09 | A-1 |
| 10 | 0A | A#-1 |
| 11 | 0B | B-1 |
| 12 | 0C | C0 |
| 13 | 0D | C#0 |
| 14 | 0E | D0 |
| 15 | 0F | D#0 |
| 16 | 10 | E0 |
| 17 | 11 | F0 |
| 18 | 12 | F#0 |
| 19 | 13 | G0 |
| 20 | 14 | G#0 |
| 21 | 15 | A0 |
| 22 | 16 | A#0 |
| 23 | 17 | B0 |
| 24 | 18 | C1 |
| 25 | 19 | C#1 |
| 26 | 1A | D1 |
| 27 | 1B | D#1 |
| 28 | 1C | E1 |
| 29 | 1D | F1 |
| 30 | 1E | F#1 |
| 31 | 1F | G1 |
| 32 | 20 | G#1 |
| 33 | 21 | A1 |
| 34 | 22 | A#1 |
| 35 | 23 | B1 |
| 36 | 24 | C2 |
| 37 | 25 | C#2 |
| 38 | 26 | D2 |
| 39 | 27 | D#2 |
| 40 | 28 | E2 |
| 41 | 29 | F2 |
| 42 | 2A | F#2 |
| 43 | 2B | G2 |
| 44 | 2C | G#2 |
| 45 | 2D | A2 |
| 46 | 2E | A#2 |
| 47 | 2F | B2 |
| 48 | 30 | C3 |
| 49 | 31 | C#3 |
| 50 | 32 | D3 |
| 51 | 33 | D#3 |
| 52 | 34 | E3 |
| 53 | 35 | F3 |
| 54 | 36 | F#3 |
| 55 | 37 | G3 |
| 56 | 38 | G#3 |
| 57 | 39 | A3 |
| 58 | 3A | A#3 |
| 59 | 3B | B3 |
| 60 | 3C | C4 |
| 61 | 3D | C#4 |
| 62 | 3E | D4 |
| 63 | 3F | D#4 |
| 64 | 40 | E4 |
| 65 | 41 | F4 |
| 66 | 42 | F#4 |
| 67 | 43 | G4 |
| 68 | 44 | G#4 |
| 69 | 45 | A4 |
| 70 | 46 | A#4 |
| 71 | 47 | B4 |
| 72 | 48 | C5 |
| 73 | 49 | C#5 |
| 74 | 4A | D5 |
| 75 | 4B | D#5 |
| 76 | 4C | E5 |
| 77 | 4D | F5 |
| 78 | 4E | F#5 |
| 79 | 4F | G5 |
| 80 | 50 | G#5 |
| 81 | 51 | A5 |
| 82 | 52 | A#5 |
| 83 | 53 | B5 |
| 84 | 54 | C6 |
| 85 | 55 | C#6 |
| 86 | 56 | D6 |
| 87 | 57 | D#6 |
| 88 | 58 | E6 |
| 89 | 59 | F6 |
| 90 | 5A | F#6 |
| 91 | 5B | G6 |
| 92 | 5C | G#6 |
| 93 | 5D | A6 |
| 94 | 5E | A#6 |
| 95 | 5F | B6 |
| 96 | 60 | C7 |
| 97 | 61 | C#7 |
| 98 | 62 | D7 |
| 99 | 63 | D#7 |
| 100 | 64 | E7 |
| 101 | 65 | F7 |
| 102 | 66 | F#7 |
| 103 | 67 | G7 |
| 104 | 68 | G#7 |
| 105 | 69 | A7 |
| 106 | 6A | A#7 |
| 107 | 6B | B7 |
| 108 | 6C | C8 |
| 109 | 6D | C#8 |
| 110 | 6E | D8 |
| 111 | 6F | D#8 |
| 112 | 70 | E8 |
| 113 | 71 | F8 |
| 114 | 72 | F#8 |
| 115 | 73 | G8 |
| 116 | 74 | G#8 |
| 117 | 75 | A8 |
| 118 | 76 | A#8 |
| 119 | 77 | B8 |
| 120 | 78 | C9 |
| 121 | 79 | C#9 |
| 122 | 7A | D9 |
| 123 | 7B | D#9 |
| 124 | 7C | E9 |
| 125 | 7D | F9 |
| 126 | 7E | F#9 |
| 127 | 7F | G9 |
* various
- Allen & Heath [[https://www.allen-heath.com/hardware/xone-series/xonek2/][hardware notes]] & MIDI docs
- see also https://github.com/taw10/x1k2-midi-osc-alsa

BIN
img/CQ-20B.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 481 KiB

BIN
img/K2-layout.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

1155
img/K2-layout.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 104 KiB

BIN
img/XONE-K2-layers.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 447 KiB

BIN
img/XONE-K2-squared.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

BIN
img/cq_ref_1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 417 KiB

BIN
img/cq_ref_2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 301 KiB

BIN
img/cq_ref_3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 KiB

BIN
img/cq_ref_4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 328 KiB

BIN
img/cq_ref_5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

BIN
img/cq_ref_6.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 KiB

166
k2-misc.py Normal file
View file

@ -0,0 +1,166 @@
#!/usr/bin/env python
# File name: K2-misc.py
# Description: MIDI->OSC bridge for Allen & Heath XONE:K2 controller
# Author: nik gaffney <nik@fo.am>
# Created: 2024-09-10
# SPDX-License-Identifier: GPL-3.0-or-later
import argparse
import mido
import mido.backends.rtmidi
from oscpy.client import OSCClient
def parse_arguments():
parser = argparse.ArgumentParser(
prog='k2osc',
description='MIDI->OSC bridge for Allen & Heath XONE:K2 controller')
parser.add_argument("--host", metavar='OSC-host', required=False,
help='hostname or address of OSC destination',
dest='osc_host', default='127.0.0.1')
parser.add_argument("--port", metavar='OSC-port', required=False,
help='port for OSC messages',
dest='osc_port', default=5111)
parser.add_argument("--midi", metavar='MIDI-port',
required=False, help='port name of MIDI device',
dest='midi_port', default='XONE:K2')
parser.add_argument("-v", metavar='verbose',
required=False, dest='verbose')
parser.add_argument("-q", metavar='quiet',
required=False, dest='quiet')
args = parser.parse_args()
return args
# XONE:K2 controller mapping
# valid types of controllers
# rp - rotary pots from 0-127
# re - rotary encoders (inc/dec)
# fader - linear faders 0-127
# button - pressed/released (MIDI notes)
CONTROLLERS = ["rp", "re", "fader", "button"]
# controller types and corresponding MIDI control_id
rotary_encoder_channels = [0, 1, 2, 3, 20, 21]
rotary_potentiometer_channels = [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
fader_channels = [16, 17, 18, 19]
# map MIDI control_id to controller number
def normalise_control_id(id):
id_map = [1, 2, 3, 4, 1,
2, 3, 4, 5, 6,
7, 8, 9, 10, 11,
12, 1, 2, 3, 4,
5, 6, 0, 0, 0,]
return id_map[id]
# map MIDI note to button number (NOTE: no latching layers or LEDs yet)
def normalise_button_id(id):
id_map = {
# upper block
48: 1, 49: 2, 50: 3, 51: 4,
44: 5, 45: 6, 46: 7, 47: 8,
40: 9, 41: 10, 42: 11, 43: 12,
# lower block
36: "A", 37: "B", 38: "C", 39: "D",
32: "E", 33: "F", 34: "G", 35: "H",
28: "I", 29: "J", 30: "K", 31: "L",
24: "M", 25: "N", 26: "O", 27: "P",
# square buttons
12: "LAYER", 15: "EXIT"}
return id_map[id]
# predicates for mapped controllers
def is_rp(id):
return id in rotary_potentiometer_channels
def is_re(id):
return id in rotary_encoder_channels
def is_fader(id):
return id in fader_channels
def is_button(note):
return True
# MIDI in OSC out
def parse_midi_message(msg):
msg_type = msg.type
print(f"\nrecv message of type '{msg_type}': {msg}")
if msg_type == 'control_change':
control_id, value = msg.control, msg.value
id = normalise_control_id(control_id)
if is_rp(control_id):
mutaliate("rp", id, value)
elif is_re(control_id):
mutaliate("re", id, "inc" if (value == 1) else "dec")
elif is_fader(control_id):
mutaliate("fader", id, value)
if msg_type in ['note_on', 'note_off']:
note = msg.note
if is_button(note):
id = normalise_button_id(note)
mutaliate("button", id,
"pressed" if (msg_type == 'note_on') else "released")
elif is_re(note):
print("increase resolution of encoder when pressed...")
# print(f"note: {note}")
print(f"unrecognised: {msg}")
# OSC interslonk
# see also -> https://github.com/kivy/oscpy
def osc_setup(address="127.0.0.1", port=5111):
osc = OSCClient(address, port)
print(f"OSC client active. Sending to {address} on port {port}")
return osc
# send some OSC messages etc+
def mutaliate(control, control_id, value=""):
global osc
# print(f"mutaliate: {control}, {control_id}, {arg}, {value}")
if control in CONTROLLERS:
path = f"/xone/k2/{control}/{control_id}"
print(f"osc: {path} {value}")
osc.send_message(path, value)
return True
def looper():
loop = 0
while True:
loop += 1
return True
# setup MIDI ports
# send_port = mido.open_output('send-to-K2')
def midi_setup(label):
mido.open_input(label, callback=parse_midi_message)
port = mido.open_output(label)
return port
def main():
global osc, k2_send_port
args = parse_arguments()
osc = osc_setup(args.osc_host, args.osc_port)
# midi = midi_setup('XONE:K2')
# event loop
looper()
if __name__ == '__main__':
main()