Skip to content

Instantly share code, notes, and snippets.

@AlexNisnevich
Last active April 19, 2019 00:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AlexNisnevich/00f451118550035b780995caa2733f92 to your computer and use it in GitHub Desktop.
Save AlexNisnevich/00f451118550035b780995caa2733f92 to your computer and use it in GitHub Desktop.
# sudo apt-get install i2c-tools jack libportmidi python-dev python-gpiozero python-smbus
# pip install mido
# pip install adafruit-mcp3008
# Enable I2C in raspi-config.
# Install Adafruit_LED_Backpack from Github.
from Adafruit_LED_Backpack.AlphaNum4 import AlphaNum4
from gpiozero import Button, LED, MCP3008
from gpiozero.tools import smoothed, zip_values
import mido
def cc(control, value):
return mido.Message('control_change', control=control, value=value)
MODES = [
{
# Filter / Resonance
'display': 'FiRe',
'knobs': [
{
'name': 'Filter',
'value': lambda x: x / 8,
'msgs': lambda val: [cc(74, val)]
},
{
'name': 'Resonance',
'value': lambda x: x / 8,
'msgs': lambda val: [cc(71, val)]
}
]
},
{
# Attack / Release
'display': ' A R',
'knobs': [
{
'name': 'Attack',
'value': lambda x: x / 8,
'msgs': lambda val: [cc(73, val)]
},
{
'name': 'Release',
'value': lambda x: x / 8,
'msgs': lambda val: [cc(72, val)]
}
]
},
{
# Decay / Sustain
'display': ' D S',
'knobs': [
{
'name': 'Decay/Hold',
'value': lambda x: x / 8,
'msgs': lambda val: [cc(75, val)]
},
{
'name': 'Variation/Sustain',
'value': lambda x: x / 8,
'msgs': lambda val: [cc(70, val)]
}
]
},
{
# Pitch wheel / Portamento
'display': 'PiPo',
'knobs': [
{
'name': 'Pitchwheel',
'value': lambda x: (x - 512) * 16,
'formatted_value': lambda val: '%+04d' % (round(val / 4096.0, 2) * 100),
'msgs': lambda val: [mido.Message('pitchwheel', pitch=val)]
},
{
'name': 'Portamento',
'value': lambda x: x / 8,
'formatted_value': lambda val: str(val) if val > 10 else 'off',
'msgs': lambda val: [cc(5, val), cc(65, 127 if val > 10 else 0)]
}
]
}
]
TOLERANCE = 24
class MidiController:
def __init__(self):
port_name = [n for n in mido.get_output_names()
if n.startswith('SV1')][0]
self.port = mido.open_output(port_name)
self.blue_button = Button(21)
self.led = LED(26)
self.display = AlphaNum4()
self.display_timeout = None
knob1 = MCP3008(channel=1, clock_pin=18, mosi_pin=24,
miso_pin=23, select_pin=25)
knob2 = MCP3008(channel=0, clock_pin=18, mosi_pin=24,
miso_pin=23, select_pin=25)
self.knobs = [smoothed(knob1, 20), smoothed(knob2, 20)]
self.values = self.get_knob_values()
self.mode_num = 0
self.mode = MODES[self.mode_num]
def teardown(self):
self.led.off()
self.print_to_display('')
def get_knob_values(self):
return [int(next(knob) * 1024) for knob in self.knobs]
def next_mode(self):
self.mode_num = (self.mode_num + 1) % len(MODES)
self.mode = MODES[self.mode_num]
self.print_to_display(self.mode['display'])
def print_to_display(self, msg):
self.display_msg = msg
self.display.clear()
self.display.print_str(msg)
self.display.write_display()
def print_temp_to_display(self, msg, timeout):
self.display_timeout = timeout
self.display.clear()
self.display.print_str(msg)
self.display.write_display()
def send_cc(self, knob_idx, raw_value):
knob_opts = self.mode['knobs'][knob_idx]
true_value = knob_opts['value'](raw_value)
formatted_value = knob_opts['formatted_value'](true_value) if 'formatted_value' in knob_opts else str(true_value)
print('Setting {} to {} ...'.format(knob_opts['name'], formatted_value))
self.print_temp_to_display(formatted_value, 10)
for msg in knob_opts['msgs'](true_value):
self.port.send(msg)
def run(self):
self.led.on()
self.display.begin()
self.print_to_display(self.mode['display'])
try:
self.blue_button.when_pressed = self.next_mode
while True:
next_values = self.get_knob_values()
for i in range(len(self.knobs)):
if abs(next_values[i] - self.values[i]) > TOLERANCE or (next_values[i] == 0 and self.values[i] > 0):
self.values[i] = next_values[i]
self.send_cc(i, next_values[i])
if self.display_timeout:
self.display_timeout -= 1
if self.display_timeout <= 0:
self.display_timeout = None
self.print_to_display(self.display_msg)
except KeyboardInterrupt:
pass
finally:
self.teardown()
def main():
mido.set_backend('mido.backends.portmidi')
MidiController().run()
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment