def copy_event(event): if type(event) is SetTempoEvent: new_event = SetTempoEvent() new_event.tick = event.tick new_event.data[0] = event.data[0] new_event.data[1] = event.data[1] new_event.data[2] = event.data[2] return new_event elif type(event) is NoteOnEvent: new_event = NoteOnEvent() new_event.tick = event.tick new_event.channel = event.channel new_event.data[0] = event.data[0] new_event.data[1] = event.data[1] return new_event elif type(event) is NoteOffEvent: new_event = NoteOffEvent() new_event.tick = event.tick new_event.channel = event.channel new_event.data[0] = event.data[0] new_event.data[1] = event.data[1] return new_event elif type(event) is ProgramChangeEvent: new_event = ProgramChangeEvent new_event.tick = event.tick new_event.channel = event.channel new_event.data[0] = event.data[0] return new_event else: raise ('Not Supported')
def add_note_on_abs(track, pitch, start, loudness, channel, resolution=default_resolution): on = NoteOnEvent(tick=int(resolution * start), channel=channel, velocity=loudness, pitch=pitch) track.append(on) return track
def to_midi(self): """ Constructs a L{MIDI EventStream<midi.EventStream>} from the data in this stream. This can then be output to a file to be played. Note that TPCNotes will be output as normal MIDI notes. We can't do anything of the clever tuning stuff that we can do with tonal space coordinates, since we'd need to do a further step of analysis to work out the fully specified TS point from the pitch class. """ tempo = 120 from midi import EventStream, NoteOffEvent, NoteOnEvent, SetTempoEvent mid = EventStream() mid.add_track() # Set the tempo first at the beginning temp = SetTempoEvent() temp.tempo = tempo temp.tick = 0 mid.add_event(temp) # Work out how many ticks there are in a millisecond ticks_per_ms = float(mid.resolution) * tempo / 60000 # Create midi events for every event in our stream for ev in self.events: if isinstance(ev, TPCNoteEvent): # Create note-on and note-off events note = ev.note noteon = NoteOnEvent() noteon.pitch = note noteon.tick = int(ev.start * ticks_per_ms) noteon.velocity = 100 mid.add_event(noteon) noteoff = NoteOffEvent() noteoff.pitch = note noteoff.tick = int(ev.end * ticks_per_ms) noteoff.velocity = 100 mid.add_event(noteoff) elif isinstance(ev, (ChordEvent, BeatEvent)): # These events don't affect the midi data continue else: raise TypeError, "event type %s not recognised by "\ "MIDI converter." % type(ev).__name__ return mid
def tonal_space_note_events(coord, start, duration, origin_note=60, velocity=100): """ Creates the MIDI events needed to play the given tonal space coordinate. These will be a single-note tuning event (to retune the appropriate note), a note-on event and a note-off event. @type coord: tuple @param coord: 3D tonal space coordinate @type start: int @param start: start time of note in ticks @type duration: int @param duration: length of the note in ticks @type origin_note: int @param origin_note: midi note number to assume the origin of the tonal space is equal to in pitch (default 60, middle C) @rtype: tuple @return: (tuning event, note on event, note off event) """ # Work out what note to retune for the root and how change = tonal_space_tuning(coord) note = change[0] # Create the tuning event tuning = single_note_tuning_event([change]) tuning.tick = start # Play the note note_on = NoteOnEvent() note_on.pitch = note note_on.velocity = velocity note_on.tick = start # Stop the note note_off = NoteOffEvent() note_off.pitch = note note_off.tick = start + duration note_off.velocity = velocity return (tuning, note_on, note_off)
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