Skip to content

Commit d18690e

Browse files
committed
Sync state of analog controls (e.g. expression pedal) on pedalboard load
1 parent ca436dd commit d18690e

4 files changed

Lines changed: 43 additions & 5 deletions

File tree

modalapi/mod.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -558,6 +558,9 @@ def set_current_pedalboard(self, pedalboard):
558558
except Exception as e:
559559
logging.warning(f"Failed to send external MIDI messages: {e}")
560560

561+
# Sync current state of analog controls (expression pedals, etc.)
562+
self.hardware.sync_analog_controls()
563+
561564
# Selection info
562565
self.selectable_items.clear()
563566
self.selectable_items.append((SelectedType.PEDALBOARD, None))

modalapi/modhandler.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,9 @@ def set_current_pedalboard(self, pedalboard):
364364
cfg = yaml.load(ymlfile, Loader=yaml.SafeLoader)
365365
self.hardware.reinit(cfg)
366366

367+
# Sync current state of analog controls (expression pedals, etc.)
368+
self.hardware.sync_analog_controls()
369+
367370
# Initialize the data and draw on LCD
368371
self.bind_current_pedalboard()
369372
self.load_current_presets()
@@ -378,6 +381,7 @@ def set_current_pedalboard(self, pedalboard):
378381
except Exception as e:
379382
logging.warning(f"Failed to send external MIDI messages: {e}")
380383

384+
381385
def bind_current_pedalboard(self):
382386
# "current" being the pedalboard mod-host says is current
383387
# The pedalboard data has already been loaded, but this will overlay

pistomp/analogmidicontrol.py

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,12 @@
2626
import logging
2727

2828

29-
class AnalogMidiControl(analogcontrol.AnalogControl):
29+
def as_midi_value(adc_value: int):
30+
"""Convert a 10-bit ADC value (0-1023) to a MIDI value (0-127)."""
31+
return util.renormalize(adc_value, 0, 1023, 0, 127)
32+
3033

34+
class AnalogMidiControl(analogcontrol.AnalogControl):
3135
def __init__(self, spi, adc_channel, tolerance, midi_CC, midi_channel, midiout, type, id=None, cfg={}):
3236
super(AnalogMidiControl, self).__init__(spi, adc_channel, tolerance)
3337
self.midi_CC = midi_CC
@@ -37,7 +41,7 @@ def __init__(self, spi, adc_channel, tolerance, midi_CC, midi_channel, midiout,
3741
# Parent member overrides
3842
self.type = type
3943
self.id = id
40-
self.last_read = 0 # this keeps track of the last potentiometer value
44+
self.last_read = 0 # this keeps track of the last potentiometer value
4145
self.value = None
4246
self.cfg = cfg
4347

@@ -47,18 +51,33 @@ def set_midi_channel(self, midi_channel):
4751
def set_value(self, value):
4852
self.value = value
4953

54+
def send_current_value(self):
55+
"""
56+
Force-send the current analog control value via MIDI.
57+
Used for syncing external devices during pedalboard load.
58+
"""
59+
# read the analog pin
60+
value = self.readChannel()
61+
set_volume = as_midi_value(value)
62+
63+
cc = [self.midi_channel | CONTROL_CHANGE, self.midi_CC, set_volume]
64+
logging.debug("AnalogControl force-sending CC event %s" % cc)
65+
self.midiout.send_message(cc)
66+
67+
# save the reading to prevent duplicate sends on next poll
68+
self.last_read = value
69+
5070
# Override of base class method
5171
def refresh(self):
5272
# read the analog pin
5373
value = self.readChannel()
5474

5575
# how much has it changed since the last read?
5676
pot_adjust = abs(value - self.last_read)
57-
value_changed = (pot_adjust > self.tolerance)
77+
value_changed = pot_adjust > self.tolerance
5878

5979
if value_changed:
60-
# convert 16bit adc0 (0-65535) trim pot read into 0-100 volume level
61-
set_volume = util.renormalize(value, 0, 1023, 0, 127)
80+
set_volume = as_midi_value(value)
6281

6382
cc = [self.midi_channel | CONTROL_CHANGE, self.midi_CC, set_volume]
6483
logging.debug("AnalogControl Sending CC event %s" % cc)

pistomp/hardware.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,18 @@ def poll_controls(self):
8888
if s:
8989
s.check_longpress_events()
9090

91+
def sync_analog_controls(self):
92+
"""
93+
Send current values of all analog controls via MIDI.
94+
Used for syncing external devices during pedalboard load.
95+
"""
96+
for control in self.analog_controls:
97+
if hasattr(control, 'send_current_value'):
98+
try:
99+
control.send_current_value()
100+
except Exception as e:
101+
logging.warning(f"Failed to sync analog control {control.midi_CC}: {e}")
102+
91103
def poll_indicators(self):
92104
for i in self.indicators:
93105
i.refresh()

0 commit comments

Comments
 (0)