Input chord progressions by chord names e.g. C => F => G => Am and and play them help creating music.
Here, chord progression is a list of chord names as ["C", "F", "G", "Am"].
6th "C6", 7th "C7", 9th "C9", sus4 "Csus4" and on "ConE", "ConG" are OK. But for more complicated ones, need program update.
See a couple of functions in the program:
- chNtoPitches(ch): convert chord name to list of pitches (e.g. "C" => [60,64,67]
- addChord: add chord notes to MIDI file
Python examples are as below.
# blog 2
import mido
import time
from mido import Message, MidiFile, MidiTrack, MetaMessage
# port open
ports = mido.get_output_names()
port = mido.open_output(ports[0])
# input chord list
chord_list = ["C", "Em", "G", "CM7onE"]
# chord name converts to pitches e,g, "C" => [60, 64, 67]
toneDict = {"C":60, "Cs":61, "Df":61, "D":62, "Ds":63, "Ef":63, "E":64, "F":65, "Fs":66, "Gf":66, "G":67, "Gs":68, "Af":68, "A":69, "As":70, "Bf":70, "B":71}
def chNtoPitches(ch):
chord = []
adj = 0
ch1 = "major"
# "dim" to "m5f7f" "
if ch.find("dim7") > 0:
ch = ch.replace("dim7","m5f7f")
elif ch.find("dim") > 0:
ch = ch.replace("dim","m5f7f")
# f: flat, s:sharp
if len(ch) > 1 and (if ch[1] == "f" or ch[1] == "s"):
adj = 1
# chord bass pitch
bass = toneDict[ch[0:1+adj]]
chord.append(bass)
# major or minor
if len(ch) > 1+adj and ch[1+adj] == "m":
ch1 = "minor"
# 3rd
if ch.find("sus4") > 0:
chord.append(bass+5)
elif ch1 == "major":
chord.append(bass+4)
else:
chord.append(bass+3)
# 5th
if ch.find("5f") > 0:
chord.append(bass+6)
elif ch.find("5s") > 0 or ch.find("aug") > 0:
chord.append(bass+8)
else:
chord.append(bass+7)
# 6th (M6 only)
if ch.find("6") > 0:
chord.append(bass+9)
# 7th (M7 and 7, 7f for dim)
if ch.find("M7") > 0:
chord.append(bass+11)
elif ch.find("7f") > 0:
chord.append(bass+9)
elif ch.find("7") > 0:
chord.append(bass+10)
# 9th (M9 only)
if ch.find("9") > 0:
chord.append(bass+14)
# on (e.g. G) chord starting note to G.
if ch.find("on") > 0:
bass2 = toneDict[ch[ch.find("on")+2:len(ch)]]
# make bass2 as lowest chord tone
if bass2 in chord:
chord = [(tn + 12) if tn < bass2 else tn for tn in chord]
return chord
#------------------------------------------------------------------------------------------
# conver to list of pitch lists
pitch_lists = [chNtoPitches(ch) for ch in chord_list]
print(pitch_lists)
def addChord(track,pitch_list, duration, velocity):
for i in range(len(pitch_list)):
track.append(Message('note_on', channel = 0, note=pitch_list[i], velocity=velocity, time=0))
track.append(Message('note_off', channel = 0, note=pitch_list[0], velocity=0, time=beat_to_tick(duration)))
for i in range(1,len(pitch_list)):
track.append(Message('note_off', channel = 0, note=pitch_list[i], velocity=0, time=0))
# convert to beat to MIDI time scale (1 beat to 480 ticks)
def beat_to_tick(dur):
return int(dur * 480 +0.5)
# create new MIDI file
mid = MidiFile()
track0 = MidiTrack() # tempo
track1 = MidiTrack() # instrument 1
mid.tracks.append(track0)
mid.tracks.append(track1)
# set tempo
bpm = 120 # beat per minutes
track0.append(MetaMessage('set_tempo', tempo=int(1000000*60/bpm), time=0))
# add chords
for i in range(len(pitch_lists)):
addChord(track1, pitch_lists[i], 4, 70)
# play MIDI file
for msg in mid:
time.sleep(msg.time)
if not msg.is_meta:
port.send(msg)
Comments
Post a Comment