def generate(self, overlay=None, offset=0): """ Generates a midi stream. """ octaves = 1 if overlay is not None: stream = overlay # Use organ sound instrument = 23 # Find the last channel used in the file we're overlaying channel = max(ev.channel for ev in stream.trackpool) + 1 volume = 50 else: stream = EventStream() stream.resolution = self.resolution # Just use piano instrument = 0 channel = 0 volume = 127 stream.add_track() pc = ProgramChangeEvent() pc.value = instrument pc.tick = 0 pc.channel = channel stream.add_event(pc) # Length of each chord in midi ticks chord_length = int(self.resolution * self.chord_length) times = [i * chord_length + offset for i in range(len(self.labels))] pending_note_offs = [] for label, time in zip(self.labels, times): chord_root = label.root # Work out the notes for this chord triad_notes = [(chord_root + note) % (octaves*12) + 72 for \ note in self.chord_vocab[label.label]] # Add the root in the octave two below triad_notes.append(chord_root + 48) # Add note offs for notes already on for noff in pending_note_offs: noff.tick = time - 1 stream.add_event(noff) pending_note_offs = [] if self.text_events: # Add a text event to represent the chord label tevent = LyricsEvent() tevent.data = "%s\n" % label tevent.tick = time stream.add_event(tevent) # Add a note-on and off event for each note for note in triad_notes: non = NoteOnEvent() non.tick = time non.pitch = note non.channel = channel non.velocity = volume stream.add_event(non) # Hold the note until the next chord is played noff = NoteOffEvent() noff.pitch = note noff.channel = channel noff.velocity = volume pending_note_offs.append(noff) # Add the last remaining note offs for noff in pending_note_offs: noff.tick = time + chord_length stream.add_event(noff) return stream
def align(self, sequence, mid, lyrics=False): """ Aligns the sequence with the midi file and adds lyric events into the midi data to indicate where the chords occur. This ought to function like a karaoke midi file, showing the chords as the occur. Note that this modifies the midi sequence in place. @type lyrics: bool @param lyrics: use lyrics events the mark the chords. By default uses marker events, which are more appropriate but may not be supported by your player. @type sequence: L{ChordSequence<jazzparser.data.db_mirrors.ChordSequence>} @param sequence: the chord sequence to take chords from @type mid: L{midi.EventStream} @param sequence: input midi sequence @rtype: L{midi.EventStream} @return: the original midi sequence with text added in for the chords. """ if self.midi_beats_per_beat > 0: ticks_per_seq_beat = self.midi_beats_per_beat * mid.resolution elif self.midi_beats_per_beat < -1: ticks_per_seq_beat = mid.resolution / abs(self.midi_beats_per_beat) else: raise ValueError, "midi_beats_per_beat should be >0 or <-1: "\ "not %s" % self.midi_beats_per_beat # Look for the default start time for the chords noteon = first_note_on(mid) if noteon is None: # No note-on events found at all: we'll start at tick 0, # but the result's going to be nonsensical tick = 0 else: # Shift our start point by the requested number of ticks tick = noteon.tick + self.sequence_start cursor = 0 # Keep track of what repeats we've got to do and where they go repeats = {} for start,end,count in self.repeat_spans: if start >= end: raise MidiAlignmentError, "nonsensical repeat span "\ "ends before it starts: (%d,%d,%d)" % (start,end,count) repeats.setdefault(end, []).extend([start] * count) mid.curtrack = 0 sequence = list(sequence.iterator()) while cursor < len(sequence): # Get the chord for the current cursor from the sequence chord = sequence[cursor] # Add a text event to say what the chord is if lyrics: ev = LyricsEvent() ev.data = "%s " % chord else: ev = MarkerEvent() ev.data = "<%d> %s" % (cursor,chord) ev.tick = tick mid.add_event(ev) # Move the midi tick cursor on tick += chord.duration * ticks_per_seq_beat if cursor in repeats: # A repeat span ends at this chord: go back to the start new_cursor = repeats[cursor].pop(0) if len(repeats[cursor]) == 0: # No more spans with this end point del repeats[cursor] cursor = new_cursor else: # No repeats: just move to the next chord cursor += 1 mid.timesort() return mid
def generate(self, overlay=None, offset=0): """ Generates a midi stream. """ octaves = 1 if overlay is not None: stream = overlay # Use organ sound instrument = 23 # Find the last channel used in the file we're overlaying channel = max(ev.channel for ev in stream.trackpool) + 1 volume = 30 else: stream = EventStream() stream.resolution = self.resolution # Just use piano instrument = 0 channel = 0 volume = 127 stream.add_track() pc = ProgramChangeEvent() pc.value = instrument pc.tick = 0 pc.channel = channel stream.add_event(pc) # Length of each chord in midi ticks chord_length = int(self.resolution * self.chord_length) if self.times is None: times = [ i * chord_length + offset for i in range(len(self.labels)) ] else: times = [t + offset for t in self.times] formatter = getattr(self, 'formatter') pending_note_offs = [] for (tonic, mode, chord), time in zip(self.labels, times): scale_chord_root = constants.CHORD_NOTES[mode][chord][0] chord_root = (tonic + scale_chord_root) % 12 triad_type = constants.SCALE_TRIADS[mode][chord] # Work out the notes for this chord triad_notes = [(chord_root + note) % (octaves * 12) + 72 for note in constants.TRIAD_NOTES[triad_type]] # Add the root in the octave two below triad_notes.append(chord_root + 48) # Add note offs for notes already on for noff in pending_note_offs: noff.tick = time - 1 stream.add_event(noff) pending_note_offs = [] if self.text_events: # Add a text event to represent the chord label tevent = LyricsEvent() label = formatter((tonic, mode, chord)) tevent.data = "%s\n" % label tevent.tick = time stream.add_event(tevent) # Add a note-on and off event for each note for note in triad_notes: non = NoteOnEvent() non.tick = time non.pitch = note non.channel = channel non.velocity = volume stream.add_event(non) # Hold the note until the next chord is played noff = NoteOffEvent() noff.pitch = note noff.channel = channel noff.velocity = volume pending_note_offs.append(noff) # Add the last remaining note offs for noff in pending_note_offs: noff.tick = time + chord_length stream.add_event(noff) return stream
def generate(self, overlay=None, offset=0): """ Generates a midi stream. """ octaves = 1 if overlay is not None: stream = overlay # Use organ sound instrument = 23 # Find the last channel used in the file we're overlaying channel = max(ev.channel for ev in stream.trackpool) + 1 volume = 50 else: stream = EventStream() stream.resolution = self.resolution # Just use piano instrument = 0 channel = 0 volume = 127 stream.add_track() pc = ProgramChangeEvent() pc.value = instrument pc.tick = 0 pc.channel = channel stream.add_event(pc) # Length of each chord in midi ticks chord_length = int(self.resolution * self.chord_length) times = [i*chord_length + offset for i in range(len(self.labels))] pending_note_offs = [] for label,time in zip(self.labels, times): chord_root = label.root # Work out the notes for this chord triad_notes = [(chord_root + note) % (octaves*12) + 72 for \ note in self.chord_vocab[label.label]] # Add the root in the octave two below triad_notes.append(chord_root + 48) # Add note offs for notes already on for noff in pending_note_offs: noff.tick = time-1 stream.add_event(noff) pending_note_offs = [] if self.text_events: # Add a text event to represent the chord label tevent = LyricsEvent() tevent.data = "%s\n" % label tevent.tick = time stream.add_event(tevent) # Add a note-on and off event for each note for note in triad_notes: non = NoteOnEvent() non.tick = time non.pitch = note non.channel = channel non.velocity = volume stream.add_event(non) # Hold the note until the next chord is played noff = NoteOffEvent() noff.pitch = note noff.channel = channel noff.velocity = volume pending_note_offs.append(noff) # Add the last remaining note offs for noff in pending_note_offs: noff.tick = time+chord_length stream.add_event(noff) return stream
def generate(self, overlay=None, offset=0): """ Generates a midi stream. """ octaves = 1 if overlay is not None: stream = overlay # Use organ sound instrument = 23 # Find the last channel used in the file we're overlaying channel = max(ev.channel for ev in stream.trackpool) + 1 volume = 30 else: stream = EventStream() stream.resolution = self.resolution # Just use piano instrument = 0 channel = 0 volume = 127 stream.add_track() pc = ProgramChangeEvent() pc.value = instrument pc.tick = 0 pc.channel = channel stream.add_event(pc) # Length of each chord in midi ticks chord_length = int(self.resolution * self.chord_length) if self.times is None: times = [i*chord_length + offset for i in range(len(self.labels))] else: times = [t+offset for t in self.times] formatter = getattr(self, 'formatter') pending_note_offs = [] for (tonic,mode,chord),time in zip(self.labels, times): scale_chord_root = constants.CHORD_NOTES[mode][chord][0] chord_root = (tonic+scale_chord_root) % 12 triad_type = constants.SCALE_TRIADS[mode][chord] # Work out the notes for this chord triad_notes = [(chord_root + note) % (octaves*12) + 72 for note in constants.TRIAD_NOTES[triad_type]] # Add the root in the octave two below triad_notes.append(chord_root + 48) # Add note offs for notes already on for noff in pending_note_offs: noff.tick = time-1 stream.add_event(noff) pending_note_offs = [] if self.text_events: # Add a text event to represent the chord label tevent = LyricsEvent() label = formatter((tonic,mode,chord)) tevent.data = "%s\n" % label tevent.tick = time stream.add_event(tevent) # Add a note-on and off event for each note for note in triad_notes: non = NoteOnEvent() non.tick = time non.pitch = note non.channel = channel non.velocity = volume stream.add_event(non) # Hold the note until the next chord is played noff = NoteOffEvent() noff.pitch = note noff.channel = channel noff.velocity = volume pending_note_offs.append(noff) # Add the last remaining note offs for noff in pending_note_offs: noff.tick = time+chord_length stream.add_event(noff) return stream