Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions modalapi/modhandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,9 @@ def set_current_pedalboard(self, pedalboard):
cfg = yaml.load(ymlfile, Loader=yaml.SafeLoader)
self.hardware.reinit(cfg)

# Sync current state of analog controls (expression pedals, etc.)
self.hardware.sync_analog_controls()

# Initialize the data and draw on LCD
self.bind_current_pedalboard()
self.load_current_presets()
Expand Down
29 changes: 24 additions & 5 deletions pistomp/analogmidicontrol.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,12 @@
import logging


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


class AnalogMidiControl(analogcontrol.AnalogControl):
def __init__(self, spi, adc_channel, tolerance, midi_CC, midi_channel, midiout, type, id=None, cfg={}):
super(AnalogMidiControl, self).__init__(spi, adc_channel, tolerance)
self.midi_CC = midi_CC
Expand All @@ -37,7 +41,7 @@ def __init__(self, spi, adc_channel, tolerance, midi_CC, midi_channel, midiout,
# Parent member overrides
self.type = type
self.id = id
self.last_read = 0 # this keeps track of the last potentiometer value
self.last_read = 0 # this keeps track of the last potentiometer value
self.value = None
self.cfg = cfg

Expand All @@ -47,18 +51,33 @@ def set_midi_channel(self, midi_channel):
def set_value(self, value):
self.value = value

def send_current_value(self):
"""
Force-send the current analog control value via MIDI.
Used for syncing external devices during pedalboard load.
"""
# read the analog pin
value = self.readChannel()
set_volume = as_midi_value(value)

cc = [self.midi_channel | CONTROL_CHANGE, self.midi_CC, set_volume]
logging.debug("AnalogControl force-sending CC event %s" % cc)
self.midiout.send_message(cc)

# save the reading to prevent duplicate sends on next poll
self.last_read = value

# Override of base class method
def refresh(self):
# read the analog pin
value = self.readChannel()

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

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

cc = [self.midi_channel | CONTROL_CHANGE, self.midi_CC, set_volume]
logging.debug("AnalogControl Sending CC event %s" % cc)
Expand Down
12 changes: 12 additions & 0 deletions pistomp/hardware.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,18 @@ def poll_controls(self):
if s:
s.check_longpress_events()

def sync_analog_controls(self):
"""
Send current values of all analog controls via MIDI.
Used for syncing external devices during pedalboard load.
"""
for control in self.analog_controls:
if hasattr(control, 'send_current_value'):
try:
control.send_current_value()
except Exception as e:
logging.warning(f"Failed to sync analog control {control.midi_CC}: {e}")

def poll_indicators(self):
for i in self.indicators:
i.refresh()
Expand Down