Package jazzparser :: Package misc :: Package chordlabel :: Module realize
[hide private]
[frames] | no frames]

Source Code for Module jazzparser.misc.chordlabel.realize

  1  from __future__ import absolute_import 
  2  """Chord sequence realizer for the output of a chord labeler. 
  3   
  4  """ 
  5  """ 
  6  ============================== License ======================================== 
  7   Copyright (C) 2008, 2010-12 University of Edinburgh, Mark Granroth-Wilding 
  8    
  9   This file is part of The Jazz Parser. 
 10    
 11   The Jazz Parser is free software: you can redistribute it and/or modify 
 12   it under the terms of the GNU General Public License as published by 
 13   the Free Software Foundation, either version 3 of the License, or 
 14   (at your option) any later version. 
 15    
 16   The Jazz Parser is distributed in the hope that it will be useful, 
 17   but WITHOUT ANY WARRANTY; without even the implied warranty of 
 18   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 19   GNU General Public License for more details. 
 20    
 21   You should have received a copy of the GNU General Public License 
 22   along with The Jazz Parser.  If not, see <http://www.gnu.org/licenses/>. 
 23   
 24  ============================ End license ====================================== 
 25   
 26  """ 
 27  __author__ = "Mark Granroth-Wilding <mark.granroth-wilding@ed.ac.uk>"  
 28   
 29  from midi import EventStream, NoteOnEvent, read_midifile, NoteOffEvent, \ 
 30                      ProgramChangeEvent, LyricsEvent 
 31   
32 -class ChordSequenceRealizer(object):
33 """ 34 Factory to take the output from the labeler and realize the chord sequence 35 as a midi file. 36 37 Very basic - not going to sound great, but it's easier than playing it 38 myself. 39 40 """
41 - def __init__(self, labels, chord_vocab, resolution=120, chord_length=2, \ 42 text_events=False):
43 """ 44 @type labels: list of L{jazzparser.misc.chordlabel.data.ChordLabel}s 45 @param labels: chord labels output by the model 46 @type chord_vocab: dict 47 @param chord_vocab: mapping from the chord labels that may appear in 48 C{labels} to the notes of the chord 49 @type resolution: int 50 @param resolution: midi resolution to give the result (midi ticks per beat) 51 @type chord_length: int 52 @param chord_length: length of each chord as a number of beats 53 @type text_events: bool 54 @param text_events: include chord labels in the midi as text events 55 56 """ 57 self.labels = labels 58 self.chord_vocab = chord_vocab 59 self.resolution = resolution 60 self.chord_length = chord_length 61 self.text_events = text_events
62
63 - def generate(self, overlay=None, offset=0):
64 """ 65 Generates a midi stream. 66 67 """ 68 octaves = 1 69 70 if overlay is not None: 71 stream = overlay 72 # Use organ sound 73 instrument = 23 74 # Find the last channel used in the file we're overlaying 75 channel = max(ev.channel for ev in stream.trackpool) + 1 76 volume = 50 77 else: 78 stream = EventStream() 79 stream.resolution = self.resolution 80 # Just use piano 81 instrument = 0 82 channel = 0 83 volume = 127 84 85 stream.add_track() 86 pc = ProgramChangeEvent() 87 pc.value = instrument 88 pc.tick = 0 89 pc.channel = channel 90 stream.add_event(pc) 91 92 # Length of each chord in midi ticks 93 chord_length = int(self.resolution * self.chord_length) 94 95 times = [i*chord_length + offset for i in range(len(self.labels))] 96 97 pending_note_offs = [] 98 for label,time in zip(self.labels, times): 99 chord_root = label.root 100 # Work out the notes for this chord 101 triad_notes = [(chord_root + note) % (octaves*12) + 72 for \ 102 note in self.chord_vocab[label.label]] 103 # Add the root in the octave two below 104 triad_notes.append(chord_root + 48) 105 106 # Add note offs for notes already on 107 for noff in pending_note_offs: 108 noff.tick = time-1 109 stream.add_event(noff) 110 pending_note_offs = [] 111 112 if self.text_events: 113 # Add a text event to represent the chord label 114 tevent = LyricsEvent() 115 tevent.data = "%s\n" % label 116 tevent.tick = time 117 stream.add_event(tevent) 118 119 # Add a note-on and off event for each note 120 for note in triad_notes: 121 non = NoteOnEvent() 122 non.tick = time 123 non.pitch = note 124 non.channel = channel 125 non.velocity = volume 126 stream.add_event(non) 127 128 # Hold the note until the next chord is played 129 noff = NoteOffEvent() 130 noff.pitch = note 131 noff.channel = channel 132 noff.velocity = volume 133 pending_note_offs.append(noff) 134 135 # Add the last remaining note offs 136 for noff in pending_note_offs: 137 noff.tick = time+chord_length 138 stream.add_event(noff) 139 return stream
140