Skip to content

Commit

Permalink
Allow the user to specify the channel. Useful to use channel 10 for p…
Browse files Browse the repository at this point in the history
…ercussion.
  • Loading branch information
kroger committed Oct 4, 2015
1 parent aaafe96 commit 1aa15ce
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 11 deletions.
19 changes: 17 additions & 2 deletions demo_tracks.py
@@ -1,7 +1,7 @@
from pyknon.genmidi import Midi
from pyknon.music import NoteSeq

# Notes on two tracks
# Notes on two tracks using the defaults

notes1 = NoteSeq("C4.'' B8' A4 D")
notes2 = NoteSeq("E4 F G4. A8")
Expand All @@ -11,7 +11,7 @@
m.seq_notes(notes2, track=1)
m.write("tracks.mid")

# Chords on two tracks
# Chords on two tracks using the defaults

chords1 = [NoteSeq("C2 E G"), NoteSeq("G2 B D")]
chords2 = [NoteSeq("C,4 E"), NoteSeq("E, G"), NoteSeq("G, B"), NoteSeq("B, D'")]
Expand All @@ -20,3 +20,18 @@
midi.seq_chords(chords1, track=0)
midi.seq_chords(chords2, track=1)
midi.write("chords.mid")

# Notes on two tracks using percussion

# In the MIDI library, the tracks and channels are numbered from 0,
# While the MIDI Standard is numbered from 1,
# So to use percussion you must use channel 9 in the library

n1 = NoteSeq("C4 D E F")
n2 = NoteSeq("C8 C G, G C' C G, G")

m2 = Midi(2, tempo=123, channel=[0, 9], instrument=[20, 40])
m2.seq_notes(n1, track=0, channel=0)
m2.seq_notes(n2, track=1, channel=9)
m2.write("percussion.mid")

26 changes: 17 additions & 9 deletions pyknon/genmidi.py
Expand Up @@ -7,47 +7,55 @@ class MidiError(Exception):


class Midi(object):
def __init__(self, number_tracks=1, tempo=60, instrument=0):
def __init__(self, number_tracks=1, tempo=60, instrument=0, channel=None):
"""
instrument: can be an integer or a list
channel: can be an integer or a list
"""

self.number_tracks = number_tracks
self.midi_data = MIDIFile(number_tracks)

for track in range(number_tracks):
channel = track
self.midi_data.addTrackName(track, 0, "Track {0}".format(track))
self.midi_data.addTempo(track, 0, tempo)
instr = instrument[track] if isinstance(instrument, list) else instrument
self.midi_data.addProgramChange(track, channel, 0, instr)
if channel is None:
_channel = track
elif isinstance(channel, list):
_channel = channel[track]
else:
_channel = channel
self.midi_data.addProgramChange(track, _channel, 0, instr)

def seq_chords(self, seqlist, track=0, time=0):
def seq_chords(self, seqlist, track=0, time=0, channel=None):
if track + 1 > self.number_tracks:
raise MidiError("You are trying to use more tracks than we have.")

channel = track
_channel = channel if channel is not None else track

for item in seqlist:
if isinstance(item, NoteSeq):
volume = item[0].volume
dur = item[0].midi_dur
for note in item:
self.midi_data.addNote(track, channel, note.midi_number, time, dur, volume)
self.midi_data.addNote(track, _channel, note.midi_number, time, dur, volume)
time += dur
elif isinstance(item, Rest):
time += item.midi_dur
else:
raise MidiError("The input should be a list of NoteSeq but yours is a {0}: {1}".format(type(seqlist), seqlist))
return time

def seq_notes(self, noteseq, track=0, time=0):
def seq_notes(self, noteseq, track=0, time=0, channel=None):
if track + 1 > self.number_tracks:
raise MidiError("You are trying to use more tracks than we have.")

channel = track
_channel = channel if channel is not None else track

for note in noteseq:
if isinstance(note, Note):
self.midi_data.addNote(track, channel, note.midi_number, time, note.midi_dur, note.volume)
self.midi_data.addNote(track, _channel, note.midi_number, time, note.midi_dur, note.volume)
else:
# we ignore the rests
pass
Expand Down

0 comments on commit 1aa15ce

Please sign in to comment.