Hello fellow Ardourers,
I recently bought the Akai APC key 25 Mk2. I turns out the knobs are relative encoders, rather than positional controllers (i.e. the enc2
option in Ardour). Sadly, Ardour doesn’t support MIDI learn for relative encoders, which is something I might find myself using.
I wanted to find a JACK/ALSA plugin, which handles the conversion between relative encoders and positional controllers before MIDI reaches Ardour and Ardour sees only positional controller values. This plugin’s job would be simple:

keep a 0127 value representing the controller’s current state

on each MIDI encoder event, increase/decrease the current state according to the event, and

send the newly updated state as output
After some playing around with mididings, here is my script that does exactly this:
from mididings import *
from mididings.extra import *
from mididings.extra.inotify import AutoRestart
from mididings.event import CtrlEvent
from collections import defaultdict
import numpy as np
config(
backend='alsa',
# backend='jack',
)
BIT7_MIN = 0
BIT7_MID = 64
BIT7_MAX = 127
BIT7_MODULO = 128
class CtrlsState:
def __init__(self):
self.states = defaultdict(lambda: np.int(BIT7_MID))
ctrls_state = CtrlsState()
def twos_complement_to_signed_7bit(num):
return ((num + BIT7_MID) % BIT7_MODULO)  BIT7_MID
def process_ctrl(ev):
if ev.type == CTRL:
ctrl_key = (ev.port, ev.channel, ev.ctrl)
ctrl_value = ctrls_state.states[ctrl_key]
delta_2s = ev.value
delta = twos_complement_to_signed_7bit(delta_2s)
ctrl_value += delta
ctrl_value = np.clip(ctrl_value, BIT7_MIN, BIT7_MAX)
ctrls_state.states[ctrl_key] = ctrl_value
return CtrlEvent(ev.port, ev.channel, ev.ctrl, int(ctrl_value))
else:
return ev
run(Process(process_ctrl))
I hope that someone else might find that useful as well!