# SPDX-FileCopyrightText: 2020 Liz Clark for Adafruit Industries # # SPDX-License-Identifier: MIT import time import board import simpleio import busio import adafruit_lis3dh import digitalio from digitalio import DigitalInOut, Direction, Pull from analogio import AnalogIn import usb_midi import adafruit_midi from adafruit_midi.note_on import NoteOn from adafruit_midi.note_off import NoteOff from adafruit_midi.control_change import ControlChange from adafruit_midi.pitch_bend import PitchBend # imports MIDI midi = adafruit_midi.MIDI(midi_out=usb_midi.ports[1], out_channel=0) # setup for LIS3DH accelerometer i2c = busio.I2C(board.SCL, board.SDA) lis3dh = adafruit_lis3dh.LIS3DH_I2C(i2c) lis3dh.range = adafruit_lis3dh.RANGE_2_G # setup for 3 potentiometers pitchbend_pot = AnalogIn(board.A1) mod_pot = AnalogIn(board.A2) velocity_pot = AnalogIn(board.A3) # setup for two switches that will switch modes mod_select = DigitalInOut(board.D52) mod_select.direction = Direction.INPUT mod_select.pull = Pull.UP strum_select = DigitalInOut(board.D53) strum_select.direction = Direction.INPUT strum_select.pull = Pull.UP # setup for strummer switches strumUP = DigitalInOut(board.D22) strumUP.direction = Direction.INPUT strumUP.pull = Pull.UP strumDOWN = DigitalInOut(board.D23) strumDOWN.direction = Direction.INPUT strumDOWN.pull = Pull.UP # setup for cherry mx switches on neck note_pins = [board.D14, board.D2, board.D3, board.D4, board.D5, board.D6, board.D7, board.D8, board.D9, board.D10, board.D11, board.D12] note_buttons = [] for pin in note_pins: note_pin = digitalio.DigitalInOut(pin) note_pin.direction = digitalio.Direction.INPUT note_pin.pull = digitalio.Pull.UP note_buttons.append(note_pin) # setup for rotary switch oct_sel_pins = [board.D24, board.D25, board.D26, board.D27, board.D28, board.D29, board.D30, board.D31] octave_selector = [] for pin in oct_sel_pins: sel_pin = digitalio.DigitalInOut(pin) sel_pin.direction = digitalio.Direction.INPUT sel_pin.pull = digitalio.Pull.UP octave_selector.append(sel_pin) # cherry mx switch states note_e_pressed = None note_f_pressed = None note_fsharp_pressed = None note_g_pressed = None note_gsharp_pressed = None note_a_pressed = None note_asharp_pressed = None note_b_pressed = None note_c_pressed = None note_csharp_pressed = None note_d_pressed = None note_dsharp_pressed = None # state machines strummed = None pick = None up_pick = None down_pick = None # states for analog inputs pitchbend_val2 = 0 mod_val2 = 0 velocity_val2 = 0 acc_pos_val2 = 0 acc_neg_val2 = 0 # array for cherry mx switch states note_states = [note_e_pressed, note_f_pressed, note_fsharp_pressed, note_g_pressed, note_gsharp_pressed, note_a_pressed, note_asharp_pressed, note_b_pressed, note_c_pressed, note_csharp_pressed, note_d_pressed, note_dsharp_pressed] # array of MIDI note numbers note_numbers = [21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 120, 123, 124, 125, 126, 127] # list of note name variables that are assigned to the note_numbers array # this allows you to use the note names rather than numbers when assigning # them to the cherry mx switches (A0, Bb0, B0, C1, Db1, D1, Eb1, E1, F1, Gb1, G1, Ab1, A1, Bb1, B1, C2, Db2, D2, Eb2, E2, F2, Gb2, G2, Ab2, A2, Bb2, B2, C3, Db3, D3, Eb3, E3, F3, Gb3, G3, Ab3, A3, Bb3, B3, C4, Db4, D4, Eb4, E4, F4, Gb4, G4, Ab4, A4, Bb4, B4, C5, Db5, D5, Eb5, E5, F5, Gb5, G5, Ab5, A5, Bb5, B5, C6, Db6, D6, Eb6, E6, F6, Gb6, G6, Ab6, A6, Bb6, B6, C7, Db7, D7, Eb7, E7, F7, Gb7, G7, Ab7, A7, Bb7, B7, C8, Db8, D8, Eb8, E8, F8, Gb8, G8, Ab8, A8, Bb8, B8, C9, Db9, D9, Eb9, E9, F9, Gb9, G9) = note_numbers # arrays for note inputs that are tied to the rotary switch octave_8_cc = [E8, F8, Gb8, G8, Ab8, A8, Bb8, B8, C9, Db9, D9, Eb9] octave_7_cc = [E7, F7, Gb7, G7, Ab7, A7, Bb7, B7, C8, Db8, D8, Eb8] octave_6_cc = [E6, F6, Gb6, G6, Ab6, A6, Bb6, B6, C7, Db7, D7, Eb7] octave_5_cc = [E5, F5, Gb5, G5, Ab5, A5, Bb5, B5, C6, Db6, D6, Eb6] octave_4_cc = [E4, F4, Gb4, G4, Ab4, A4, Bb4, B4, C5, Db5, D5, Eb5] octave_3_cc = [E3, F3, Gb3, G3, Ab3, A3, Bb3, B3, C4, Db4, D4, Eb4] octave_2_cc = [E2, F2, Gb2, G2, Ab2, A2, Bb2, B2, C3, Db3, D3, Eb3] octave_1_cc = [E1, F1, Gb1, G1, Ab1, A1, Bb1, B1, C2, Db2, D2, Eb2] octave_select = [octave_1_cc, octave_2_cc, octave_3_cc, octave_4_cc, octave_5_cc, octave_6_cc, octave_7_cc, octave_8_cc] # function for reading analog inputs def val(voltage): return voltage.value # beginning script REPL printout print("MX MIDI Guitar") print("Default output MIDI channel:", midi.out_channel + 1) # loop while True: # values for LIS3DH x, y, z = [value / adafruit_lis3dh.STANDARD_GRAVITY for value in lis3dh.acceleration] # mapping analog values to MIDI value ranges # PitchBend MIDI has a range of 0 to 16383 # all others used here are 0 to 127 pitchbend_val1 = round(simpleio.map_range(val(pitchbend_pot), 0, 65535, 0, 16383)) mod_val1 = round(simpleio.map_range(val(mod_pot), 0, 65535, 0, 127)) velocity_val1 = round(simpleio.map_range(val(velocity_pot), 0, 65535, 0, 127)) acc_pos_val1 = round(simpleio.map_range(x, 0, 0.650, 127, 0)) acc_neg_val1 = round(simpleio.map_range(y, -0.925, 0, 127, 0)) # checks if modulation switch is engaged if not mod_select.value: # if it is, then get modulation MIDI data from LIS3DH # positive and negative values for LIS3DH depending on # orientation of the guitar neck # when the guitar is held "normally" aka horizontal # then the modulation value is neutral aka 0 # compares previous LIS3DH value to current value if abs(acc_pos_val1 - acc_pos_val2) < 50: # updates previous value to hold current value acc_pos_val2 = acc_pos_val1 # MIDI data has to be sent as an integer # this converts the LIS3DH data into an int accelerator_pos = int(acc_pos_val2) # int is stored as a CC message accWheel_pos = ControlChange(1, accelerator_pos) # CC message is sent midi.send(accWheel_pos) # delay to settle MIDI data time.sleep(0.001) # same code but for negative values elif abs(acc_neg_val1 - acc_neg_val2) < 50: acc_neg_val2 = acc_neg_val1 accelerator_neg = int(acc_neg_val2) accWheel_neg = ControlChange(1, accelerator_neg) midi.send(accWheel_neg) time.sleep(0.001) # if it isn't then get modulation MIDI data from pot else: # compares previous mod_pot value to current value if abs(mod_val1 - mod_val2) > 2: # updates previous value to hold current value mod_val2 = mod_val1 # MIDI data has to be sent as an integer # this converts the pot data into an int modulation = int(mod_val2) # int is stored as a CC message modWheel = ControlChange(1, modulation) # CC message is sent midi.send(modWheel) # delay to settle MIDI data time.sleep(0.001) # reads analog input to send MIDI data for Velocity # compares previous velocity pot value to current value if abs(velocity_val1 - velocity_val2) > 2: # updates previous value to hold current value velocity_val2 = velocity_val1 # MIDI data has to be sent as an integer # this converts the pot data into an int # velocity data is sent with NoteOn message # NoteOn is sent in the loop velocity = int(velocity_val2) # delay to settle MIDI data time.sleep(0.001) # reads analog input to send MIDI data for PitchBend # compares previous picthbend pot value to current value if abs(pitchbend_val1 - pitchbend_val2) > 75: # updates previous value to hold current value pitchbend_val2 = pitchbend_val1 # MIDI data has to be sent as an integer # this converts the pot data into an int # int is stored as a PitchBend message a_pitch_bend = PitchBend(int(pitchbend_val2)) # PitchBend message is sent midi.send(a_pitch_bend) # delay to settle MIDI data time.sleep(0.001) # checks position of the rotary switch # determines which notes are mapped to the cherry mx switches for s in octave_selector: if not s.value: o = octave_selector.index(s) octave = octave_select[o] # checks if strum select switch is engaged if not strum_select.value: # if it is, then: # setup states for both strummer switches if strumUP.value and up_pick is None: up_pick = "strummed" pick = time.monotonic() if strumDOWN.value and down_pick is None: down_pick = "strummed" pick = time.monotonic() # bug fix using time.monotonic(): if you hit the strummer, but don't hit a note # the state of the strummer switch is reset if (not pick) or ((time.monotonic() - pick) > 0.5 and (down_pick or up_pick == "strummed")): up_pick = None down_pick = None # if either strummer switch is hit if (not strumUP.value and up_pick == "strummed") or (not strumDOWN.value and down_pick == "strummed"): # indexes the cherry mx switch array for i in range(12): buttons = note_buttons[i] # if any of the mx cherry switches are pressed # and they weren't previously pressed (checking note_states[i]) # where i is the matching index from the note_buttons array if not buttons.value and not note_states[i]: # send the NoteOn message that matches with the octave[i] array # along with the velocity value midi.send(NoteOn(octave[i], velocity)) # note number is printed to REPL print(octave[i]) # note state is updated note_states[i] = True # updates strummer switch states up_pick = None down_pick = None # delay to settle MIDI data time.sleep(0.001) # the next if statement allows for you to strum notes multiple times without # having to release the note # if either strummer switch is hit if (not strumUP.value and up_pick == "strummed") or (not strumDOWN.value and down_pick == "strummed"): # indexes the cherry mx switch array for i in range(12): buttons = note_buttons[i] # if any of the cherry mx switches are pressed # and they *were* previously pressed (checking note_states[i]) # where i is the matching index from the note_buttons array if not buttons.value and note_states[i]: # send the NoteOn message that matches with the octave[i] array # along with the velocity value midi.send(NoteOn(octave[i], velocity)) # note number is printed to REPL print(octave[i]) # note state is updated note_states[i] = True # updates strummer switch states up_pick = None down_pick = None # sends a NoteOff message to prevent notes from # staying on forever aka preventing glitches midi.send(NoteOff(octave[i], velocity)) # delay to settle MIDI data time.sleep(0.001) # the next for statement sends NoteOff when the cherry mx switches # are released # indexes the cherry mx switch array for i in range(12): buttons = note_buttons[i] # if any of the cherry mx switches are released # and they *were* previously pressed (checking note_states[i]) # where i is the matching index from the note_buttons array if buttons.value and note_states[i]: # send the NoteOff message that matches with the octave[i] array # along with the velocity value midi.send(NoteOff(octave[i], velocity)) # note state is updated note_states[i] = False # updates strummer switch states down_pick = None up_pick = None # delay to settle MIDI data time.sleep(0.001) # if strum select switch is not engaged else: # indexes the cherry mx switch array for i in range(12): buttons = note_buttons[i] # if any of the mx cherry switches are pressed # and they weren't previously pressed (checking note_states[i]) # where i is the matching index from the note_buttons array if not buttons.value and not note_states[i]: # send the NoteOn message that matches with the octave[i] array # along with the velocity value midi.send(NoteOn(octave[i], velocity)) # note number is printed to REPL print(octave[i]) # note state is updated note_states[i] = True # delay to settle MIDI data time.sleep(0.001) # if any of the cherry mx switches are released # and they *were* previously pressed (checking note_states[i]) # where i is the matching index from the note_buttons array if (buttons.value and note_states[i]): # send the NoteOff message that matches with the octave[i] array # along with the velocity value midi.send(NoteOff(octave[i], velocity)) # note state is updated note_states[i] = False # delay to settle MIDI data time.sleep(0.001) # delay to settle MIDI data time.sleep(0.005)
Write, Run & Share Python code online using OneCompiler's Python online compiler for free. It's one of the robust, feature-rich online compilers for python language, supporting both the versions which are Python 3 and Python 2.7. Getting started with the OneCompiler's Python editor is easy and fast. The editor shows sample boilerplate code when you choose language as Python or Python2 and start coding.
OneCompiler's python online editor supports stdin and users can give inputs to programs using the STDIN textbox under the I/O tab. Following is a sample python program which takes name as input and print your name with hello.
import sys
name = sys.stdin.readline()
print("Hello "+ name)
Python is a very popular general-purpose programming language which was created by Guido van Rossum, and released in 1991. It is very popular for web development and you can build almost anything like mobile apps, web apps, tools, data analytics, machine learning etc. It is designed to be simple and easy like english language. It's is highly productive and efficient making it a very popular language.
When ever you want to perform a set of operations based on a condition IF-ELSE is used.
if conditional-expression
#code
elif conditional-expression
#code
else:
#code
Indentation is very important in Python, make sure the indentation is followed correctly
For loop is used to iterate over arrays(list, tuple, set, dictionary) or strings.
mylist=("Iphone","Pixel","Samsung")
for i in mylist:
print(i)
While is also used to iterate a set of statements based on a condition. Usually while is preferred when number of iterations are not known in advance.
while condition
#code
There are four types of collections in Python.
List is a collection which is ordered and can be changed. Lists are specified in square brackets.
mylist=["iPhone","Pixel","Samsung"]
print(mylist)
Tuple is a collection which is ordered and can not be changed. Tuples are specified in round brackets.
myTuple=("iPhone","Pixel","Samsung")
print(myTuple)
Below throws an error if you assign another value to tuple again.
myTuple=("iPhone","Pixel","Samsung")
print(myTuple)
myTuple[1]="onePlus"
print(myTuple)
Set is a collection which is unordered and unindexed. Sets are specified in curly brackets.
myset = {"iPhone","Pixel","Samsung"}
print(myset)
Dictionary is a collection of key value pairs which is unordered, can be changed, and indexed. They are written in curly brackets with key - value pairs.
mydict = {
"brand" :"iPhone",
"model": "iPhone 11"
}
print(mydict)
Following are the libraries supported by OneCompiler's Python compiler
Name | Description |
---|---|
NumPy | NumPy python library helps users to work on arrays with ease |
SciPy | SciPy is a scientific computation library which depends on NumPy for convenient and fast N-dimensional array manipulation |
SKLearn/Scikit-learn | Scikit-learn or Scikit-learn is the most useful library for machine learning in Python |
Pandas | Pandas is the most efficient Python library for data manipulation and analysis |
DOcplex | DOcplex is IBM Decision Optimization CPLEX Modeling for Python, is a library composed of Mathematical Programming Modeling and Constraint Programming Modeling |