def test_smallsysex_between_notes(self): m = MIDI_mocked_both_loopback(3, 3) m.send([ NoteOn("C4", 0x7F), SystemExclusive([0x1F], [1, 2, 3, 4, 5, 6, 7, 8]), NoteOff(60, 0x28), ]) msg1 = m.receive() self.assertIsInstance(msg1, NoteOn) self.assertEqual(msg1.note, 60) self.assertEqual(msg1.velocity, 0x7F) self.assertEqual(msg1.channel, 3) msg2 = m.receive() self.assertIsInstance(msg2, SystemExclusive) self.assertEqual(msg2.manufacturer_id, bytes([0x1F])) self.assertEqual(msg2.data, bytes([1, 2, 3, 4, 5, 6, 7, 8])) self.assertEqual(msg2.channel, None) # SysEx does not have a channel msg3 = m.receive() self.assertIsInstance(msg3, NoteOff) self.assertEqual(msg3.note, 60) self.assertEqual(msg3.velocity, 0x28) self.assertEqual(msg3.channel, 3) msg4 = m.receive() self.assertIsNone(msg4)
def test_NoteOff_constructor_string(self): object1 = NoteOff("C4", 0x64) self.assertEqual(object1.note, 60) self.assertEqual(object1.velocity, 0x64) object2 = NoteOff("C3", 0x7F) self.assertEqual(object2.note, 48) self.assertEqual(object2.velocity, 0x7F) object3 = NoteOff("C#4", 0x00) self.assertEqual(object3.note, 61) self.assertEqual(object3.velocity, 0) object4 = NoteOff("C#4") # velocity defaults to 0 self.assertEqual(object4.note, 61) self.assertEqual(object4.velocity, 0)
def test_send_basic_single(self): # def printit(buffer, len): # print(buffer[0:len]) mockedPortOut = Mock() # mockedPortOut.write = printit m = adafruit_midi.MIDI(midi_out=mockedPortOut, out_channel=2) # Test sending some NoteOn and NoteOff to various channels nextcall = 0 m.send(NoteOn(0x60, 0x7F)) self.assertEqual(mockedPortOut.write.mock_calls[nextcall], call(b"\x92\x60\x7f", 3)) nextcall += 1 m.send(NoteOn(0x64, 0x3F)) self.assertEqual(mockedPortOut.write.mock_calls[nextcall], call(b"\x92\x64\x3f", 3)) nextcall += 1 m.send(NoteOn(0x67, 0x1F)) self.assertEqual(mockedPortOut.write.mock_calls[nextcall], call(b"\x92\x67\x1f", 3)) nextcall += 1 m.send(NoteOn(0x60, 0x00)) # Alternative to NoteOff self.assertEqual(mockedPortOut.write.mock_calls[nextcall], call(b"\x92\x60\x00", 3)) nextcall += 1 m.send(NoteOff(0x64, 0x01)) self.assertEqual(mockedPortOut.write.mock_calls[nextcall], call(b"\x82\x64\x01", 3)) nextcall += 1 m.send(NoteOff(0x67, 0x02)) self.assertEqual(mockedPortOut.write.mock_calls[nextcall], call(b"\x82\x67\x02", 3)) nextcall += 1 # Setting channel to non default m.send(NoteOn(0x6C, 0x7F), channel=9) self.assertEqual(mockedPortOut.write.mock_calls[nextcall], call(b"\x99\x6c\x7f", 3)) nextcall += 1 m.send(NoteOff(0x6C, 0x7F), channel=9) self.assertEqual(mockedPortOut.write.mock_calls[nextcall], call(b"\x89\x6c\x7f", 3)) nextcall += 1
def update_notes(lastStep, step): for _channel in range(16): for _note in range(16): if pattern[_channel][_note][step] == Note.ON: midi[_channel].send(NoteOn(36 + _note, 120)) elif pattern[_channel][_note][step] == Note.OFF: if pattern[_channel][_note][lastStep] != Note.OFF: midi[_channel].send(NoteOff(36 + _note, 120))
def step_select(key): if self.tracks[self.current_track].active: if not key.held: step = self.tracks[self.current_track].steps[key.index] step.toggle() if not step.active: current_note = step.note self.midi_channels[track.channel].send( NoteOff(current_note, 0)) step.note = DEFAULT_NOTE step.velocity = DEFAULT_VELOCITY else: self.steps_held.remove(key.index) self.note_down.led_off() self.note_up.led_off() self.velocity_down.led_off() self.velocity_up.led_off() self.update_track_select_keys(True)
def trigger(event): if config_mode is 1: config_check(event) elif config_mode is 0: # sampler mode actions if button_mode is 0: # trigger on when a rising edge is detected if event.edge == NeoTrellis.EDGE_RISING: trellis.pixels[event.number] = COLOR_A button = button_map[event.number] # use the reindexed button numbering note = note_map[button] # print("Pixel "+str(event.number)+" pressed.") # debug only of physical buttons print("Button "+str(button)+" pressed.") midi.send(NoteOn(note, 127)) print("Note On: "+str(note)) # trigger off when a rising edge is detected for pad mode elif event.edge == NeoTrellis.EDGE_FALLING: trellis.pixels[event.number] = COLOR_B button = button_map[event.number] note = note_map[button] # print("Button "+str(event.number)+" released") print("Button "+str(button)+" released.") midi.send(NoteOff(note, 0)) print("Note Off: "+str(note)) # sequencer mode actions elif button_mode is 1: # trigger on when a rising edge is detected if event.edge == NeoTrellis.EDGE_RISING: if button_state[event.number] is 0: trellis.pixels[event.number] = COLOR_A button_state[event.number] = 1 else: trellis.pixels[event.number] = COLOR_B button_state[event.number] = 0 button = button_map[event.number] # use the reindexed button numbering note = note_map[button] # print("Pixel "+str(event.number)+" pressed.") # debug only of physical buttons print("Button "+str(button)+" pressed.") midi.send(NoteOn(note, 127)) print("Note On: "+str(note))
def blink(xcoord, ycoord, edge): padNum = XY(xcoord, ycoord, 0) if edge == NeoTrellis.EDGE_RISING: print('key press! ', padNum) trellis.pressed_keys.add((xcoord,ycoord)) if keys[padNum][1]['type'] is 'momentary': #print('momentary ', padNum, ' on') #midi.send(NoteOn(keys[padNum][2], 120)) midi.send(NoteOn(padNum)) color = keys[padNum][1]['on'] trellis.color(xcoord, ycoord, color) elif keys[padNum][1]['type'] is 'latching': #midi.send(NoteOn(keys[padNum][2], 120)) midi.send(NoteOn(padNum)) if not keys[padNum][1]['state']: color = keys[padNum][1]['on'] #print('latching ', padNum, ' on ', keys[padNum]) elif keys[padNum][1]['state']: color = keys[padNum][1]['off'] #print('latching ', padNum, ' off ', keys[padNum]) trellis.color(xcoord, ycoord, color) keys[padNum][1]['state'] = not keys[padNum][1]['state'] elif edge == NeoTrellis.EDGE_FALLING: print('key release! ', padNum) if (xcoord,ycoord) in current_press: trellis.pressed_keys.remove((xcoord,ycoord)) if keys[padNum][1]['type'] is 'momentary': #print('momentary ', padNum, ' off') midi.send(NoteOff(padNum)) color = keys[padNum][1]['off'] trellis.color(xcoord, ycoord, color)
def stop_notes(step): for i in range(16): if pattern[i][step]: midi.send(NoteOff(36 + i, 120))
while ble.connected: # iterate through the touch inputs for i in range(3): inputs = pads[i] # if a touch input is detected... if inputs.value and triad_states[i] is False: # debounce state activated triad_states[i] = True # update triad active_triad = triads[i] print(active_triad) # after touch input... if not inputs.value and triad_states[i] is True: # reset debounce state triad_states[i] = False # send triad arpeggios out with half second delay midi.send(NoteOn(active_triad[z])) time.sleep(0.5) midi.send(NoteOff(active_triad[z])) time.sleep(0.5) # increase index by 1 z += 1 # reset index at end of triad if z > 2: z = 0 # BLE connection print("Disconnected") print() ble.start_advertising(advertisement)
board.GP22, ) touch_ins = [] touchs = [] for pin in touch_pins: touchin = touchio.TouchIn(pin) touchin.threshold += touch_threshold_adjust touch_ins.append(touchin) touchs.append(Debouncer(touchin)) print("\n----------") print("picotouch hello") while True: if debug: for i in range(len(touch_ins)): touchin = touch_ins[i] print(touchin.raw_value, ', ', end='') print() time.sleep(0.01) for i in range(len(touchs)): touch = touchs[i] touch.update() if touch.rose: print("press", i) midi.send(NoteOn(midi_base_note + i, midi_velocity)) if touch.fell: print("release", i) midi.send(NoteOff(midi_base_note + i, midi_velocity))
def release_handler(key): note = start_note + keymap[key.number] midi.send(NoteOff(note, 0)) key.set_led(*color_for_key(key))
key_pin.direction = digitalio.Direction.INPUT key_pin.pull = digitalio.Pull.UP keys.append(key_pin) # states for buttons key0_pressed = False key1_pressed = False key2_pressed = False key3_pressed = False # array for button states key_states = [key0_pressed, key1_pressed, key2_pressed, key3_pressed] while True: # iterate through 4 buttons for i in range(4): inputs = keys[i] # if button is pressed... if not inputs.value and key_states[i] is False: # update button state key_states[i] = True # send NoteOn for corresponding MIDI note midi.send(NoteOn(midi_notes[i], 120)) # if the button is released... if inputs.value and key_states[i] is True: # send NoteOff for corresponding MIDI note midi.send(NoteOff(midi_notes[i], 120)) key_states[i] = False
def reset_notes(): for _channel in range(16): for _note in range(16): midi[_channel].send(NoteOff(36 + _note, 120))
def wait(delay): global last_pressed s = time.monotonic() while time.monotonic() < s + delay: pressed = read_button_states(0, 16) for i in range(16): if pressed[i] and not last_pressed[i]: note1[i] = not note1[i] pixels[i] = rgb_armed if note1[i] else rgb_off last_pressed = pressed time.sleep(0.001) step = 0 rgb_off = (0, 0, 0) rgb_marker = (16, 16, 16) rgb_armed = (64, 64, 64) rgb_note = (255, 255, 255) note1 = [False] * 16 while True: pixels[step] = rgb_armed if note1[step] else rgb_off step = (step + 1) % 16 if note1[step]: pixels[step] = rgb_note midi.send(NoteOn("C2", 120)) else: pixels[step] = rgb_marker midi.send(NoteOff("C2", 120)) wait(0.125)
led.color = (0, 0, 0) time.sleep(0.3) ledw.value = False while True: for i in range(16): # MIDI input buttons = note_buttons[i] if not buttons.value and note_states[ i] is False: # if button is pressed... midi.send(NoteOn(midi_notes[i], 120, channel=5)) note_states[i] = True if buttons.value and note_states[ i] is True: # if the button is released... midi.send(NoteOff(midi_notes[i], 120, channel=5)) note_states[i] = False #read knob values cc_value = range_index(sAxis.value, 128, cc_value[0], cc_value[1]) cc_list.append(cc_value[0]) cc_list.pop(0) avgcc_val = round(sum(cc_list) / 30) if avgcc_val != last_cc_value[ 0]: # only send if it changed Form a MIDI CC message and send it: midi.send(ControlChange(1, avgcc_val)) last_cc_value = cc_value x_offset = filter_joystick_deadzone(xAxis.value) * -1 y_offset = filter_joystick_deadzone(yAxis.value) * -1 #Invert axis
g += 1 slither = time.monotonic() if g > 2: g = 1 # holds key index octave = keys[key_val2] # fifths mode if play_fifths: # tracks time divided by the beat division if (time.monotonic() - run) >= divide: # note index from mode, r counts index position f = fifths[r] # sends NoteOn midi.send(NoteOn(octave[f])) # turns previous note off midi.send(NoteOff(octave[last_f])) # print(octave[r]) run = time.monotonic() # go to next note r += 1 # updates previous value to hold current value if r > 0: last_r = r last_f = f hit = randint(2, 4) # resets note index position if r > 7: r = 0 last_r = r last_f = f hit = randint(2, 4)
) # check the encoder switch w debouncer if macropad.encoder_switch_debounced.pressed: print("Mod") push_text_area.text = "[.]" modifier = True macropad.pixels.brightness = DIM if macropad.encoder_switch_debounced.released: modifier = False push_text_area.text = "[o]" macropad.pixels.brightness = BRIGHT continue num = key_event.key_number if key_event.pressed and not modifier: midi.send(NoteOn(LIVE_NOTES[num], 127)) print("\nsent note", LIVE_NOTES[num], "\n") if key_event.pressed and modifier: midi.send(NoteOn(MODIFIER_NOTES[num], 127)) if key_event.released and not modifier: midi.send(NoteOff(LIVE_NOTES[num], 0)) if key_event.released and modifier: midi.send(NoteOff(MODIFIER_NOTES[num], 0)) macropad.pixels.show()
# create keypad keys = keypad.Keys(key_pins, value_when_pressed=False, pull=True) p = 0 # variable for tilegrid index while True: # get keypad inputs event = keys.events.get() if event: # if a key is pressed.. if event.pressed: # if a midi keyboard if midi_mode: # send note number midi.send(NoteOn(midi_notes[event.key_number], 120)) # if hid keyboard if keyboard_mode: # send hid keyboard shortcut keyboard.send(ctrl, shortcuts[event.key_number]) # advance parrot index p = (p + 1) % 10 # update parrot bitmap parrot0_grid[0] = p # if a key is released if event.released: # if a midi keyboard if midi_mode: # send note off message midi.send(NoteOff(midi_notes[event.key_number], 120))
# 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
def reset_notes(): for i in range(16): midi.send(NoteOff(36 + i, 120))
from analogio import AnalogOut, AnalogIn import adafruit_dotstar as dotstar import time #import neopixel import usb_midi import adafruit_midi from adafruit_midi.note_off import NoteOff from adafruit_midi.note_on import NoteOn from adafruit_debouncer import Debouncer # Your config! # Set this to be which pins you're using, and what to do button_config = [ # pin, midi press msg, midi release msg [board.D1, NoteOn(44,120), NoteOff(44,120) ], [board.D2, NoteOn(46,120), NoteOff(46,120) ], [board.D3, NoteOn(48,120), NoteOff(48,120) ], [board.D4, NoteOn(50,120), NoteOff(50,120) ], ] debouncers = [] midi = adafruit_midi.MIDI(midi_out=usb_midi.ports[1], out_channel=0) # One pixel connected internally! dot = dotstar.DotStar(board.APA102_SCK, board.APA102_MOSI, 1, brightness=0.2) # Built in red LED led = DigitalInOut(board.D13) led.direction = Direction.OUTPUT
def update(self): # Update the superclass (Keybow2040). super(Sequencer, self).update() if self.running: # Keep track of current time. current_time = time.monotonic() # If a step has elapsed... if current_time - self.last_step_time > self.step_time: for track in self.tracks: if track.active: # Turn last step off. last_step = track.steps[self.last_step_num] last_step.playing = False last_step.update() last_note = last_step.note # Helps prevent stuck notes. if last_step.note_changed: for note in last_step.last_notes: self.midi_channels[track.channel].send( NoteOff(note, 0)) last_step.note_changed = False last_step.last_notes = [] # If last step is active, send MIDI note off message. if last_step.active: self.midi_channels[track.channel].send( NoteOff(last_note, 0)) # Turn this step on. this_step = track.steps[self.this_step_num] this_step.playing = True this_step.update() this_note = this_step.note this_vel = this_step.velocity # Helps prevent stuck notes if this_step.note_changed: for note in this_step.last_notes: self.midi_channels[track.channel].send( NoteOff(note, 0)) this_step.note_changed = False this_step.last_notes = [] # If this step is active, send MIDI note on message. if this_step.active: self.midi_channels[track.channel].send( NoteOn(this_note, this_vel)) # If track is not active, send note off for last note and this note. else: last_note = track.steps[self.last_step_num].note this_note = track.steps[self.this_step_num].note self.midi_channels[track.channel].send( NoteOff(last_note, 0)) self.midi_channels[track.channel].send( NoteOff(this_note, 0)) # This step is now the last step! last_step = this_step self.last_step_num = self.this_step_num self.this_step_num += 1 # If we get to the end of the sequence, go back to the start. if self.this_step_num == self.num_steps: self.this_step_num = 0 # Keep track of last step time. self.last_step_time = current_time # Update the tracks. for track in self.tracks: track.update() # Update the step_time, in case the BPM has been changed. self.step_time = 60.0 / self.bpm / (self.num_steps / 2)
def note_off(self, key, keyboard, *args, **kwargs): self.send( NoteOff(key.meta.note, key.meta.velocity, channel=key.meta.channel))
# If any keys are pressed, go through shenanigans if keybow.any_pressed(): # Fetch a list of pressed keys pressed = keybow.get_pressed() # If the keys pressed have changed... if pressed != last_pressed: # Keys that were pressed, but are no longer missing = [k for k in last_pressed if k not in pressed] # Any keys that were pressed, but are no longer, turn LED off # and send MIDI note off for the respective note. for k in missing: note = start_note +k midi.send(NoteOff(note, 0)) keys[k].set_led(0, 0, 0) # Calculate MIDI note numbers notes = [start_note + k for k in pressed] last_pressed = pressed # If going forward (up or starting up-down), start at 0, # otherwise start at the end of the list of notes. if arp_style == 0 or arp_style == 2: this_note = 0 elif arp_style == 1: this_note = len(notes) - 1 # Send MIDI note on message for current note and turn LED on midi.send(NoteOn(notes[this_note], velocity))
while True: while True: msg_in = midi.receive() # non-blocking read # For a Note On or Note Off play a major chord # For any other known event just forward it if isinstance(msg_in, NoteOn) and msg_in.velocity != 0: print( "Playing major chord with root", msg_in.note, "from channel", msg_in.channel + 1, ) for offset in major_chord: new_note = msg_in.note + offset if 0 <= new_note <= 127: midi.send(NoteOn(new_note, msg_in.velocity)) elif (isinstance(msg_in, NoteOff) or isinstance(msg_in, NoteOn) and msg_in.velocity == 0): for offset in major_chord: new_note = msg_in.note + offset if 0 <= new_note <= 127: midi.send(NoteOff(new_note, 0x00)) elif isinstance(msg_in, MIDIUnknownEvent): # Message are only known if they are imported print("Unknown MIDI event status ", msg_in.status) elif msg_in is not None: midi.send(msg_in)
print(f"note {ix} started with modifier {modifier_value}") triggered_keys[ix] = modifier_value # Start all notes in the chord midi.send( [NoteOn(a, 60) for a in note_mapping[modifier_value][ix]]) for a in note_mapping[modifier_value][ix]: notes_playing.append(a) elif not pk and 0 <= tk: print(f"note {ix} stopped") triggered_keys[ix] = -1 # Check which notes/chords are currently playing after handling buttons notes_playing_updated = [] for ix, tk in enumerate(triggered_keys): if 0 <= tk: notes_playing_updated = notes_playing_updated + note_mapping[tk][ix] # Stop notes no longer playing notes_to_stop = set(notes_playing) - set(notes_playing_updated) midi.send([NoteOff(a, 0) for a in notes_to_stop]) # Move updated list to notes_playing for next cycle notes_playing = notes_playing_updated # Fade effect on LEDs for ix, led in enumerate(leds): led.duty_cycle = duty_cycles[ix] duty_cycles[ix] = max(duty_cycles[ix] - 900, 0) time.sleep(0.01)
def midi_panic(self): # Send note off messages for every note on this track's channel. for i in range(128): self.sequencer.midi_channels[self.channel].send(NoteOff(i, 0))
def sendKey(key): midi.send(NoteOn(key, 60)) time.sleep(0.25) midi.send([NoteOff(key, 127)]) time.sleep(0.2)
# simple_test import time import random import usb_midi import adafruit_midi from adafruit_midi.control_change import ControlChange from adafruit_midi.note_off import NoteOff from adafruit_midi.note_on import NoteOn from adafruit_midi.pitch_bend import PitchBend midi = adafruit_midi.MIDI(midi_out=usb_midi.ports[1], out_channel=0) print("Midi test") # Convert channel numbers at the presentation layer to the ones musicians use print("Default output channel:", midi.out_channel + 1) print("Listening on input channel:", midi.in_channel + 1 if midi.in_channel is not None else None) while True: midi.send(NoteOn(44, 120)) # G sharp 2nd octave time.sleep(0.25) a_pitch_bend = PitchBend(random.randint(0, 16383)) midi.send(a_pitch_bend) time.sleep(0.25) # note how a list of messages can be used midi.send([NoteOff("G#2", 120), ControlChange(3, 44)]) time.sleep(0.5)
def release_handler(key): note = start_note + key.number key.set_led(0, 0, 0) midi.send(NoteOff(note, 0))