Created
May 19, 2026 22:07
-
-
Save nicola-lunghi/696ae98e39a48430d4249e72a1fcda99 to your computer and use it in GitHub Desktop.
patch to icon scripts to enable track selection using the encoders
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| From c6d4bfc0bd06271878b7d4e3815b152d61d4bdc0 Mon Sep 17 00:00:00 2001 | |
| From: Nicola Lunghi <nick83ola@gmail.com> | |
| Date: Tue, 19 May 2026 17:43:07 +0200 | |
| Subject: [PATCH] mode: add vol_vpot and pan_vpot handlers | |
| This is the sum of two commits: | |
| Add vol_vpot handler so track_vol_mode encoders control volume | |
| Previously track_vol_mode had no vpot entry in manager_capabilities, | |
| so it fell back to standard_vpot (pan). Now vol_vpot is wired in for | |
| track_vol_mode, and track_pan_mode is explicitly mapped to standard_vpot. | |
| standard_mode encoder press selects track; pan_vpot handles track_pan_mode reset | |
| - standard_vpot press now selects the corresponding track | |
| - pan_vpot.py is a new handler for track_pan_mode with the original | |
| press-to-reset-pan behavior (and press-to-unity-gain in flip mode) | |
| --- | |
| .../v1_core/manager_capabilities.py | 15 ++- | |
| .../v1_handlers/pan_vpot.py | 91 +++++++++++++++++++ | |
| .../v1_handlers/standard_vpot.py | 21 +---- | |
| .../v1_handlers/vol_vpot.py | 66 ++++++++++++++ | |
| 4 files changed, 170 insertions(+), 23 deletions(-) | |
| create mode 100644 Icon_V_and_P_Series_Ableton/v1_handlers/pan_vpot.py | |
| create mode 100644 Icon_V_and_P_Series_Ableton/v1_handlers/vol_vpot.py | |
| diff --git a/Icon_V_and_P_Series_Ableton/v1_core/manager_capabilities.py b/Icon_V_and_P_Series_Ableton/v1_core/manager_capabilities.py | |
| index da68ba3..b138431 100644 | |
| --- a/Icon_V_and_P_Series_Ableton/v1_core/manager_capabilities.py | |
| +++ b/Icon_V_and_P_Series_Ableton/v1_core/manager_capabilities.py | |
| @@ -2,10 +2,13 @@ | |
| from ..v1_handlers import ( | |
| standard_bank, | |
| standard_vpot, | |
| + pan_vpot, | |
| + vol_vpot, | |
| plugin_vpot, | |
| plugin2_vpot, | |
| send_vpot, | |
| input_vpot, | |
| + vol_vpot, | |
| standard_fader, | |
| send_fader, | |
| standard_fader_m, | |
| @@ -64,11 +67,13 @@ bank_manager_capabilities = { | |
| # Vpot manager | |
| vpot_manager_capabilities = { | |
| - "standard_mode": standard_vpot, | |
| - "plugin_mode": plugin_vpot, | |
| - "plugin2_mode": plugin2_vpot, | |
| - "send_mode": send_vpot, | |
| - "input_mode": input_vpot, | |
| + "standard_mode": standard_vpot, | |
| + "track_pan_mode": pan_vpot, | |
| + "track_vol_mode": vol_vpot, | |
| + "plugin_mode": plugin_vpot, | |
| + "plugin2_mode": plugin2_vpot, | |
| + "send_mode": send_vpot, | |
| + "input_mode": input_vpot, | |
| } | |
| # Fader manager | |
| diff --git a/Icon_V_and_P_Series_Ableton/v1_handlers/pan_vpot.py b/Icon_V_and_P_Series_Ableton/v1_handlers/pan_vpot.py | |
| new file mode 100644 | |
| index 0000000..b0518b3 | |
| --- /dev/null | |
| +++ b/Icon_V_and_P_Series_Ableton/v1_handlers/pan_vpot.py | |
| @@ -0,0 +1,91 @@ | |
| +# === FLIP MODE SWITCH === | |
| +from ..v1_core.switch_manager import get as flip_state | |
| + | |
| +# === ADJUST: HARDWARE → DAW (Hardware CH 0–7) | |
| +def adjust(payload): | |
| + D1 = payload["data1"] | |
| + D2 = payload["data2"] | |
| + HT = payload["tracks"] | |
| + DM = payload["daw_map"] | |
| + AD = payload["addr"] | |
| + TT = payload["temp_text"] | |
| + | |
| + flip_mode = flip_state("flip") | |
| + | |
| + OS = D1 - AD.PAN1_OS | |
| + DT = DM.DAW_TRACK(HT[OS]) | |
| + POS1 = DM.PAN_GET(DT) if not flip_mode else DM.FADER_GET(DT) | |
| + DIR = -1.0 if (D2 & AD.PAN_DIR) else 1.0 | |
| + STEP = 0.05 | |
| + POS2 = float(POS1) + (DIR * STEP) | |
| + CLAMP = max(-1.0 if not flip_mode else 0.0, min(1.0, POS2)) | |
| + | |
| + if not flip_mode: | |
| + DM.PAN_SET(DT, CLAMP) | |
| + TT.SHOW_TEMP(OS, "Pan:", DM.TRACK_PAN(DT)) | |
| + else: | |
| + DM.FADER_SET(DT, CLAMP) | |
| + TT.SHOW_TEMP(OS, "Vol:", DM.TRACK_DB(DT)) | |
| + | |
| +# === PRESS: HARDWARE (Hardware CH 0–7) — center pan / unity gain | |
| +def press(payload): | |
| + DM = payload["daw_map"] | |
| + D1 = payload["data1"] | |
| + TT = payload["temp_text"] | |
| + AD = payload["addr"] | |
| + HT = payload["tracks"] | |
| + | |
| + flip_mode = flip_state("flip") | |
| + | |
| + OS = D1 - AD.PAN2_OS | |
| + DT = DM.DAW_TRACK(HT[OS]) | |
| + | |
| + if not flip_mode: | |
| + DM.PAN_SET(DT, 0.00) | |
| + TT.SHOW_TEMP(OS, "Pan:", DM.TRACK_PAN(DT)) | |
| + else: | |
| + DM.FADER_SET(DT, 0.85) | |
| + TT.SHOW_TEMP(OS, "Vol:", DM.TRACK_DB(DT)) | |
| + | |
| +# === REFRESH: DAW → HARDWARE (Hardware CH 0–7) | |
| +def refresh(payload): | |
| + HT = payload["tracks"] | |
| + DM = payload["daw_map"] | |
| + AD = payload["addr"] | |
| + | |
| + flip_mode = flip_state("flip") | |
| + | |
| + MODE = AD.MODE_PAN << 4 | |
| + FDPV = 16383.0 | |
| + PDPV = 10 | |
| + | |
| + for i in range(8): | |
| + CC = AD.VPOT_CC | |
| + | |
| + if not DM.HAS_AUDIO(payload, i): | |
| + if not flip_mode: | |
| + DM.SEND_DAW(payload, DM._3_BYTE_MSG(CC, AD.VPOT_OS + i, 0x00)) | |
| + else: | |
| + DM.SEND_DAW(payload, DM._3_BYTE_MSG(AD.PITCH_BEND_OS + i, 0, 0)) | |
| + else: | |
| + DT = DM.DAW_TRACK(HT[i]) | |
| + VALUE = DM.PAN_GET(DT) | |
| + CLAMP = max(-1.0, min(1.0, VALUE)) | |
| + NV = (CLAMP + 1.0) / 2 | |
| + POS = int(NV * PDPV) if not flip_mode else int(NV * FDPV + 0.5) | |
| + D1 = AD.VPOT_OS + i if not flip_mode else POS & 0x7F | |
| + D2 = MODE | (1 + POS) if not flip_mode else (POS >> 7) & 0x7F | |
| + | |
| + if not flip_mode: | |
| + DM.SEND_DAW(payload, DM._3_BYTE_MSG(CC, D1, D2)) | |
| + else: | |
| + DM.SEND_DAW(payload, DM._3_BYTE_MSG(AD.PITCH_BEND_OS + i, D1, D2)) | |
| + | |
| +# === RESET: DAW → HARDWARE (Hardware CH 0–7) | |
| +def reset(payload): | |
| + DM = payload["daw_map"] | |
| + AD = payload["addr"] | |
| + | |
| + CC = AD.VPOT_CC | |
| + for i in range(8): | |
| + DM.SEND_DAW(payload, DM._3_BYTE_MSG(CC, AD.VPOT_OS + i, 0x00)) | |
| diff --git a/Icon_V_and_P_Series_Ableton/v1_handlers/standard_vpot.py b/Icon_V_and_P_Series_Ableton/v1_handlers/standard_vpot.py | |
| index 40be4c9..2c147df 100644 | |
| --- a/Icon_V_and_P_Series_Ableton/v1_handlers/standard_vpot.py | |
| +++ b/Icon_V_and_P_Series_Ableton/v1_handlers/standard_vpot.py | |
| @@ -71,29 +71,14 @@ def refresh(payload): | |
| else: # FLIP ON | |
| DM.SEND_DAW(payload, DM._3_BYTE_MSG(AD.PITCH_BEND_OS + i, D1, D2)) | |
| -# === PRESS: HARDWARE (Hardware CH 0–7) — center pan | |
| +# === PRESS: HARDWARE (Hardware CH 0–7) — select track | |
| def press(payload): | |
| - # PAYLOAD IMPORTS | |
| DM = payload["daw_map"] | |
| D1 = payload["data1"] | |
| - TT = payload["temp_text"] | |
| AD = payload["addr"] | |
| - HT = payload["tracks"] | |
| - | |
| - # === FLIP MODE SWITCH === | |
| - flip_mode = flip_state("flip") | |
| - | |
| - # CALCULATIONS | |
| - OS = D1 - AD.PAN2_OS # Offset - Hardware Track | |
| - DT = DM.DAW_TRACK(HT[OS]) # Which Daw Track / Hardware Track Combination | |
| - # SEND: DAW → HARDWARE | |
| - if not flip_mode: # FLIP OFF | |
| - DM.PAN_SET(DT, 0.00) | |
| - TT.SHOW_TEMP(OS, "Pan:", DM.TRACK_PAN(DT)) # TEMP TEXT | |
| - else: # FLIP ON | |
| - DM.FADER_SET(DT, 0.85) | |
| - TT.SHOW_TEMP(OS, "Vol:", DM.TRACK_DB(DT)) # TEMP TEXT | |
| + OS = D1 - AD.PAN2_OS | |
| + DM.SELECT_SET(payload, OS) | |
| # === RESET: DAW → HARDWARE (Hardware CH 0–7) | |
| def reset(payload): | |
| diff --git a/Icon_V_and_P_Series_Ableton/v1_handlers/vol_vpot.py b/Icon_V_and_P_Series_Ableton/v1_handlers/vol_vpot.py | |
| new file mode 100644 | |
| index 0000000..60a07ad | |
| --- /dev/null | |
| +++ b/Icon_V_and_P_Series_Ableton/v1_handlers/vol_vpot.py | |
| @@ -0,0 +1,66 @@ | |
| +# === ADJUST: HARDWARE → DAW (Hardware CH 0–7) | |
| +def adjust(payload): | |
| + D1 = payload["data1"] | |
| + D2 = payload["data2"] | |
| + HT = payload["tracks"] | |
| + DM = payload["daw_map"] | |
| + AD = payload["addr"] | |
| + TT = payload["temp_text"] | |
| + | |
| + OS = D1 - AD.PAN1_OS | |
| + DT = DM.DAW_TRACK(HT[OS]) | |
| + POS1 = DM.FADER_GET(DT) | |
| + DIR = -1.0 if (D2 & AD.PAN_DIR) else 1.0 | |
| + STEP = 0.05 | |
| + POS2 = float(POS1) + (DIR * STEP) | |
| + CLAMP = max(0.0, min(1.0, POS2)) | |
| + | |
| + DM.FADER_SET(DT, CLAMP) | |
| + TT.SHOW_TEMP(OS, "Vol:", DM.TRACK_DB(DT)) | |
| + | |
| +# === PRESS: HARDWARE (Hardware CH 0–7) — reset to unity gain | |
| +def press(payload): | |
| + DM = payload["daw_map"] | |
| + D1 = payload["data1"] | |
| + TT = payload["temp_text"] | |
| + AD = payload["addr"] | |
| + HT = payload["tracks"] | |
| + | |
| + OS = D1 - AD.PAN2_OS | |
| + DT = DM.DAW_TRACK(HT[OS]) | |
| + | |
| + DM.FADER_SET(DT, 0.85) | |
| + TT.SHOW_TEMP(OS, "Vol:", DM.TRACK_DB(DT)) | |
| + | |
| +# === REFRESH: DAW → HARDWARE (Hardware CH 0–7) | |
| +def refresh(payload): | |
| + HT = payload["tracks"] | |
| + DM = payload["daw_map"] | |
| + AD = payload["addr"] | |
| + | |
| + MODE = AD.MODE_DOT << 4 # fill-from-left, suits a 0–1 fader range | |
| + PDPV = 10 # 11 discrete positions (0–10) | |
| + | |
| + for i in range(8): | |
| + CC = AD.VPOT_CC | |
| + | |
| + if not DM.HAS_AUDIO(payload, i): | |
| + DM.SEND_DAW(payload, DM._3_BYTE_MSG(CC, AD.VPOT_OS + i, 0x00)) | |
| + else: | |
| + DT = DM.DAW_TRACK(HT[i]) | |
| + VALUE = DM.FADER_GET(DT) | |
| + CLAMP = max(0.0, min(1.0, VALUE)) | |
| + POS = int(CLAMP * PDPV) | |
| + D1 = AD.VPOT_OS + i | |
| + D2 = MODE | (1 + POS) | |
| + | |
| + DM.SEND_DAW(payload, DM._3_BYTE_MSG(CC, D1, D2)) | |
| + | |
| +# === RESET: DAW → HARDWARE (Hardware CH 0–7) | |
| +def reset(payload): | |
| + DM = payload["daw_map"] | |
| + AD = payload["addr"] | |
| + | |
| + CC = AD.VPOT_CC | |
| + for i in range(8): | |
| + DM.SEND_DAW(payload, DM._3_BYTE_MSG(CC, AD.VPOT_OS + i, 0x00)) | |
| -- | |
| 2.54.0.windows.1 | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment