Python program to sequence MIDI music using a CSV spreadsheet
#!/usr/bin/env python3 | |
import time | |
import csv | |
import mido | |
############################################################################## | |
def get_out_port(dev_name): | |
out_port = None | |
outputNames = mido.get_output_names() | |
for outputName in outputNames: | |
if dev_name in outputName.lower(): | |
print('Connecting to %s' % outputName) | |
out_port = mido.open_output(outputName) | |
break | |
return out_port | |
bass_station = get_out_port("bass station") | |
drumbrute = get_out_port("drumbrute") | |
############################################################################## | |
MIDDLE_C = 60 | |
# Semitone intervals for different scales | |
SCALE_INTERVS = { | |
'major': [2, 2, 1, 2, 2, 2], | |
'natural minor': [2, 1, 2, 2, 1, 2], | |
'major pentatonic': [2, 2, 3, 2], | |
'minor pentatonic': [3, 2, 2, 3], | |
'blues': [3, 2, 1, 1, 3], | |
'chromatic': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1], | |
} | |
def gen_scale(root_note, scale, num_octaves=1): | |
""" | |
Generate the notes of a scale based on a root note | |
""" | |
# Get the intervals for this type of chord | |
intervs = SCALE_INTERVS[scale] | |
# List of generated notes | |
notes = [] | |
# For each octave | |
for oct_no in range(0, num_octaves): | |
oct_root = root_note + 12 * oct_no | |
# Add the root note to the scale | |
notes.append(oct_root) | |
# Add the scale notes | |
for i in range(0, len(intervs)): | |
prevNote = notes[-1] | |
interv = intervs[i] | |
notes.append(prevNote + interv) | |
# Add the note closing the last octave | |
notes.append(root_note + 12 * num_octaves) | |
return notes | |
############################################################################## | |
scale = gen_scale(MIDDLE_C, 'natural minor') | |
print('scale:', scale) | |
def play_music(): | |
with open('music.csv', 'rt') as csvfile: | |
reader = csv.reader(csvfile, delimiter=',', quotechar='"') | |
rows = list(reader) | |
for step_idx, row in enumerate(rows): | |
if "kick" in row: | |
drumbrute.send(mido.Message('note_on', note=36, velocity=127, channel=1)) | |
if "snare" in row: | |
drumbrute.send(mido.Message('note_on', note=38, velocity=127, channel=1)) | |
if "clap" in row: | |
drumbrute.send(mido.Message('note_on', note=39, velocity=127, channel=1)) | |
if "hat" in row: | |
drumbrute.send(mido.Message('note_on', note=42, velocity=127, channel=1)) | |
note_no = None | |
if "X" in row: | |
degree = row.index("X") | |
note_no = scale[degree] | |
if note_no: | |
note_no = scale[degree] | |
bass_station.send(mido.Message('note_on', velocity=127, note=note_no)) | |
time.sleep(0.07) | |
if note_no: | |
bass_station.send(mido.Message('note_off', velocity=127, note=note_no)) | |
time.sleep(0.05) | |
try: | |
while True: | |
play_music() | |
except KeyboardInterrupt: | |
# Send all-notes-off message | |
bass_station.reset() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment