diff --git a/.gitignore b/.gitignore index 1c53385..bee8a64 100644 --- a/.gitignore +++ b/.gitignore @@ -1,14 +1 @@ -* - -!.gitignore -!/images -!/images/* -!/examples -!/examples/* -!/grid_instrument -!/grid_instrument/* -!play.py -!README.md -!MANIFEST.in -!LICENSE.txt -!setup.py +__pycache__ diff --git a/README.md b/README.md index 98929aa..c8fd26c 100644 --- a/README.md +++ b/README.md @@ -28,11 +28,13 @@ Before you try to do anything, make sure you have **Python 2** and **pip** insta Download the source code from github and install prerequisites: git clone https://github.com/dhilowitz/GridInstrument - cd GridInstrument; pip install launchpad_rtmidi_py + cd GridInstrument + pip install . -Run the app: +Run the examples: - python play.py + cd examples + ./midi_output.py If all goes well, you should see your grid light up. Next, go into another piece of software that can receive MIDI signals (sforzando is a good, free choice), and you should see a new MIDI device called "Grid Instrument (Virtual Port)" @@ -53,4 +55,4 @@ Install it: #### Option 2: Install it with Pip - pip install grid_instrument \ No newline at end of file + pip install grid_instrument diff --git a/examples/.gitignore b/examples/.gitignore deleted file mode 100644 index 2efe3d6..0000000 --- a/examples/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -* - -!.gitignore -!simple.py -!threading.py -!midi_output.py diff --git a/examples/threading.py b/examples/async.py old mode 100644 new mode 100755 similarity index 79% rename from examples/threading.py rename to examples/async.py index 49cc110..dbbb427 --- a/examples/threading.py +++ b/examples/async.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python # # Quick usage example of "grid_instrument" with threading. # Works with all Launchpads: Mk1, Mk2, S/Mini, Pro, XL and LaunchKey @@ -9,15 +9,16 @@ # import grid_instrument +from grid_instrument import grid_instrument import threading import time def note_callback(messageType, midiNote, velocity): - print "Note callback. messageType=", messageType, midiNote, velocity + print("Note callback. messageType=", messageType, midiNote, velocity) def button_callback(x, y, pressed): - print "Button Callback. x=", x, ", y=", y, ", pressed=", pressed + print("Button Callback. x=", x, ", y=", y, ", pressed=", pressed) instrument = grid_instrument.GridInstrument() @@ -37,4 +38,4 @@ def button_callback(x, y, pressed): while True: time.sleep(2) - pass \ No newline at end of file + pass diff --git a/examples/midi_output.py b/examples/midi_output.py old mode 100644 new mode 100755 index 1fe8abe..9d7af25 --- a/examples/midi_output.py +++ b/examples/midi_output.py @@ -1,29 +1,35 @@ -#!/usr/bin/python +#!/usr/bin/env python # # Quick usage example of "grid_instrument" with MIDI output port. # Works with all Launchpads: Mk1, Mk2, S/Mini, Pro, XL and LaunchKey # # -# David Hilowitz 9/24/17 +# David Hilowitz 1/15/19 # decided.ly / davehilowitz.com # import grid_instrument +from grid_instrument import grid_instrument import rtmidi import time def note_callback(messageType, midiNote, velocity): if messageType is "note_on": - midiout.send_message([0x90, midiNote, velocity]) + midiout.sendMessage(rtmidi.MidiMessage.noteOn(0x90, midiNote, velocity)) elif messageType is "note_off": - midiout.send_message([0x80, midiNote, velocity]) + midiout.sendMessage(rtmidi.MidiMessage.noteOff(0x80, midiNote)) # Create a MIDI output port -midiout = rtmidi.MidiOut() -midiout.open_virtual_port("Grid Instrument (Virtual Port)") +midiout = rtmidi.RtMidiOut() +midiout.openVirtualPort("Grid Instrument (Virtual Port)") # Set up GridInstrument instrument = grid_instrument.GridInstrument() instrument.intro_message = 'grid' instrument.note_callback = note_callback -instrument.start() \ No newline at end of file +instrument.launchpad_pro_velocity_multiplier = 2.5 +instrument.min_velocity = 100 +instrument.max_velocity = 100 +instrument.default_velocity = 100 + +instrument.start() diff --git a/examples/simple.py b/examples/simple.py old mode 100644 new mode 100755 index fab14ee..6d26c61 --- a/examples/simple.py +++ b/examples/simple.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python # # Quick usage example of "grid_instrument". # Works with all Launchpads: Mk1, Mk2, S/Mini, Pro, XL and LaunchKey @@ -9,14 +9,15 @@ # import grid_instrument +from grid_instrument import grid_instrument import threading def note_callback(messageType, midiNote, velocity): - print "Note callback. messageType=", messageType, midiNote, velocity + print("Note callback. messageType=", messageType, midiNote, velocity) def button_callback(x, y, pressed): - print "Button Callback. x=", x, ", y=", y, ", pressed=", pressed + print("Button Callback. x=", x, ", y=", y, ", pressed=", pressed) instrument = grid_instrument.GridInstrument() @@ -29,4 +30,4 @@ def button_callback(x, y, pressed): instrument.note_callback = note_callback # set the callback for function buttons instrument.func_button_callback = button_callback -instrument.start() \ No newline at end of file +instrument.start() diff --git a/grid_instrument/__init__.py b/grid_instrument/__init__.py index ac725ce..e69de29 100644 --- a/grid_instrument/__init__.py +++ b/grid_instrument/__init__.py @@ -1 +0,0 @@ -from grid_instrument import GridInstrument \ No newline at end of file diff --git a/grid_instrument/grid_instrument.py b/grid_instrument/grid_instrument.py index 9061cc8..f8e3f79 100644 --- a/grid_instrument/grid_instrument.py +++ b/grid_instrument/grid_instrument.py @@ -4,12 +4,12 @@ import collections try: - import launchpad_rtmidi_py as launchpad + import launchpad_py as launchpad except ImportError: try: - import launchpad_rtmidi_py + import launchpad_py except ImportError: - sys.exit("error loading launchpad_rtmidi.py") + sys.exit("error loading launchpad_py") class GridInstrument: @@ -50,10 +50,10 @@ class GridInstrument: NOTE_NAMES = ["C", "C#", "D", "Eb", "E", "F", "F#", "G", "G#", "A", "A#", "B"] - NOTE_COLORS = { - "Mk1": { - "pressed": [0, 63], - "root": [3, 0], + NOTE_COLORS = { + "Mk1": { + "pressed": [0, 63], + "root": [3, 0], "noteInScale": [1, 1], "noteOutOfScale": [0, 0], "settingsKeyOff": [0, 4], @@ -65,10 +65,10 @@ class GridInstrument: "settingsGridLayoutOff": [1, 0], "settingsGridLayoutOn": [3, 0], - }, - "Mk2": { - "pressed": [0, 50, 0], - "root": [0, 10, 30], + }, + "Mk2": { + "pressed": [0, 50, 0], + "root": [0, 10, 30], "noteInScale": [10, 10, 15], "noteOutOfScale": [0, 0, 0], "settingsKeyOff": [0, 4, 0], @@ -115,7 +115,7 @@ def discover_launchpad(self, keep_checking=False): # create an instance self.lp = launchpad.Launchpad() while self._launchpad_model is None: - # lp.ListAll() + self.lp.ListAll() # check what we have here and override lp if necessary if self.lp.Check( 0, "pro" ): self.lp = launchpad.LaunchpadPro() @@ -160,7 +160,7 @@ def _main_loop(self): if randomButtonModeEnabled: if randomButtonCounter > 30: if randomButton: - self._button_released(randomButton[0], randomButton[1]) + self._button_released(randomButton[0], randomButton[1]) randomButton = None # Make a new randomButton randomButton = [random.randint(1,8), random.randint(1,8)] @@ -207,10 +207,10 @@ def _main_loop(self): # Grid Key self._grid_key = self.WHITE_KEYS[x - 1] + (y == 7) self._color_buttons() - print "Key is ", self.NOTE_NAMES[self._grid_key] + print("Key is ", self.NOTE_NAMES[self._grid_key]) elif (1 <= x <= 8) and (1 <= y <= 4): self._grid_musical_mode_button_pressed(x, y) - if x in [1, 2] and y == 9 and pressed and (self.kid_mode is not True): + if x in [1, 2] and y == 9 and pressed and (self.kid_mode is not True) and self.func_button_callback: self.func_button_callback(x, y, pressed) elif x is 9 and y == 8: if pressed: @@ -375,8 +375,8 @@ def _get_buttons_for_midi_note(self, midiNote): def get_currently_playing_midi_notes(self): midiNotes = [] for buttonNumber in self._pressed_buttons: - x = int(math.floor(buttonNumber % 8)) + 1 - y = (buttonNumber / 8) + 1 + x = int(buttonNumber % 8) + 1 + y = math.floor(buttonNumber / 8) + 1 noteInfo = self._get_note_info(x, y) if noteInfo[0] not in midiNotes: midiNotes.append(noteInfo[0]) @@ -398,12 +398,12 @@ def _button_pressed(self, x, y, velocity): self._color_note_button(newButton[0], newButton[1], scaleNoteNumber, True) self._pressed_notes.append(midiNote) if self.debugging: - print "Button", buttonNumber, "pressed with MIDI note number", midiNote, "and velocity", velocity + print ("Button", buttonNumber, "pressed with MIDI note number", midiNote, "and velocity", velocity) pass # print "Pressed Notes", _pressed_notes return - # Todo, we should actually + # Todo, we should actually def _all_buttons_released(self): for midiNote in self._pressed_notes: self.note_callback('note_off', midiNote, 0) @@ -448,10 +448,11 @@ def _button_released(self, x, y): def _grid_musical_mode_button_pressed(self, x, y): index = (x - 1) + ((4 - y) * 8) - self._grid_musical_mode = self.MUSICAL_MODES.keys()[index] - if self.debugging: - print "Musical mode is", self._grid_musical_mode - pass + modes = list(self.MUSICAL_MODES.keys()) + if index < len(modes): + self._grid_musical_mode = modes[index] + if self.debugging: + print("Musical mode is", self._grid_musical_mode) self._all_buttons_released() self._color_buttons() diff --git a/play.py b/play.py deleted file mode 100755 index cd06cd7..0000000 --- a/play.py +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/python -# -# Quick usage example of "grid_instrument" with MIDI output port. -# Works with all Launchpads: Mk1, Mk2, S/Mini, Pro, XL and LaunchKey -# -# -# David Hilowitz 1/15/19 -# decided.ly / davehilowitz.com -# - -import grid_instrument -import rtmidi -import time - -def note_callback(messageType, midiNote, velocity): - if messageType is "note_on": - midiout.send_message([0x90, midiNote, velocity]) - elif messageType is "note_off": - midiout.send_message([0x80, midiNote, velocity]) - -# Create a MIDI output port -midiout = rtmidi.MidiOut() -midiout.open_virtual_port("Grid Instrument (Virtual Port)") - -# Set up GridInstrument -instrument = grid_instrument.GridInstrument() -instrument.intro_message = 'grid' -instrument.note_callback = note_callback -instrument.launchpad_pro_velocity_multiplier = 2.5 -instrument.min_velocity = 100 -instrument.max_velocity = 100 -instrument.default_velocity = 100 - -instrument.start() \ No newline at end of file diff --git a/setup.py b/setup.py index 0c9d138..ab5e3ce 100644 --- a/setup.py +++ b/setup.py @@ -1,19 +1,19 @@ from setuptools import setup import sys -if not sys.version_info[0] == 2: - sys.exit("Error: grid_instrument requires Python 2") +if not sys.version_info[0] == 3: + sys.exit("Error: grid_instrument requires Python 3") setup( name = "grid_instrument", - version = "0.6.2", + version = "0.7.0", description = "Turn your Novation Launchpad into a MIDI instrument.", - long_description = open('README.rst').read(), + long_description = open('README.md').read(), author = "Dave Hilowitz", author_email = "dhilowitz@gmail.com", license = "MIT License", keywords = "novation launchpad scales midi", url = "https://github.com/dhilowitz/GridInstrument", packages = ["grid_instrument"], - install_requires = ["launchpad_rtmidi_py", "python-rtmidi"] + install_requires = ["launchpad_py", "rtmidi"] )