Beispiel #1
0
    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
Beispiel #2
0
	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
Beispiel #3
0
    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
Beispiel #4
0
 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
Beispiel #5
0
 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