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
15 changes: 1 addition & 14 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,14 +1 @@
*

!.gitignore
!/images
!/images/*
!/examples
!/examples/*
!/grid_instrument
!/grid_instrument/*
!play.py
!README.md
!MANIFEST.in
!LICENSE.txt
!setup.py
__pycache__
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)"

Expand All @@ -53,4 +55,4 @@ Install it:

#### Option 2: Install it with Pip

pip install grid_instrument
pip install grid_instrument
6 changes: 0 additions & 6 deletions examples/.gitignore

This file was deleted.

9 changes: 5 additions & 4 deletions examples/threading.py → examples/async.py
100644 → 100755
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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()

Expand All @@ -37,4 +38,4 @@ def button_callback(x, y, pressed):

while True:
time.sleep(2)
pass
pass
20 changes: 13 additions & 7 deletions examples/midi_output.py
100644 → 100755
Original file line number Diff line number Diff line change
@@ -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()
instrument.launchpad_pro_velocity_multiplier = 2.5
instrument.min_velocity = 100
instrument.max_velocity = 100
instrument.default_velocity = 100

instrument.start()
9 changes: 5 additions & 4 deletions examples/simple.py
100644 → 100755
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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()

Expand All @@ -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()
instrument.start()
1 change: 0 additions & 1 deletion grid_instrument/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@
from grid_instrument import GridInstrument
47 changes: 24 additions & 23 deletions grid_instrument/grid_instrument.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand Down Expand Up @@ -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],
Expand All @@ -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],
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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)]
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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])
Expand All @@ -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)
Expand Down Expand Up @@ -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()
Expand Down
34 changes: 0 additions & 34 deletions play.py

This file was deleted.

10 changes: 5 additions & 5 deletions setup.py
Original file line number Diff line number Diff line change
@@ -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"]
)