def create_window(left, bottom, right, top, device_id, tuner=False, **kwargs): sequencer = RealtimeSequencer(device_id) instr = kwargs.pop('instrument', None) if instr is not None: pc = ProgramChangeEvent() pc.value = instr sequencer.send_event(pc) if tuner: from .tstuner import TonalSpaceRetunerWindow cls = TonalSpaceRetunerWindow else: cls = TonalSpaceWindow return cls(left, bottom, right, top, sequencer, **kwargs)
def from_data(data, directives): # Build the tone matrix straight up state = { 'equal_temperament' : False, 'double_root' : False, 'envelope' : None, 'origin' : 440, 'time' : 0.0, } tone_matrix = ToneMatrix() #### Prepare a midi stream mid = EventStream() mid.add_track() # Add a tempo event tempo = SetTempoEvent() tempo.tempo = directives['tempo'] tempo.tick = 0 mid.add_event(tempo) # Each line represents a single chord or some kind of directive for line in data: first_word = line.split()[0].lower() if "=" in line: # This is an assignment key, __, value = line.partition("=") key = key.strip() value = value.strip() # Check it's valid if key == "equal_temperament": if value not in ['off','on']: raise HarmonicalInputFileReadError, \ "equal_temperament must be 'off' or 'on', "\ "not '%s'" % value value = (value == 'on') elif key == "origin": try: value = int(value) except ValueError: # Try interpreting as a coordinate try: coord = _read_coord(value) except HarmonicalInputFileReadError: raise HarmonicalInputFileReadError, "origin "\ "value must be an integer or a coordinate." value = _get_pitch(coord) elif key == "double_root": if value not in ['off','on']: raise HarmonicalInputFileReadError, \ "double_root must be 'off' or 'on', "\ "not '%s'" % value value = (value == 'on') elif key == "envelope": if value not in ENVELOPES: raise HarmonicalInputFileReadError, "unknown "\ "envelope '%s'. Must be one of: %s" % \ (value, ", ".join(ENVELOPES.keys())) value = ENVELOPES[value]() elif key == "program": # Midi program change try: value = int(value) if value > 127 or value < 0: raise ValueError except ValueError: raise HarmonicalInputFileReadError, "invalid program "\ "change: %s. Should be an integer 0-127" % value pchange = ProgramChangeEvent() pchange.value = value pchange.tick = int(state['time'] * mid.resolution) mid.add_event(pchange) else: raise HarmonicalInputFileReadError, "invalid "\ "assignment key: '%s'" % key # Make this assignment when we get to it in the score state[key] = value elif first_word == "rest": tokens = line.split() duration = _get_duration(tokens) # Just move the time counter on without doing anything state['time'] += duration elif first_word == "chord": tokens = line.lstrip("chord").split() duration = _get_duration(tokens) root = _get_root(tokens) volume = _get_volume(tokens) sec_duration = _qn_to_seconds(duration) # Must be just a chord type left if len(tokens) > 1: raise HarmonicalInputFileReadError, "chord must "\ "include just a chord type" if len(tokens) == 0: ctype = '' else: ctype = tokens[0] # Add the chord to the tone matrix tone_matrix.add_tone( _qn_to_seconds(state['time']), SineChordEvent( _get_pitch(root), ctype, duration=sec_duration, amplitude=volume, equal_temperament=state['equal_temperament'], double_root=state['double_root'], envelope=state['envelope'] ) ) # Add the same chord to the midi file tick_time = int(mid.resolution * state['time']) tick_duration = int(duration * mid.resolution) # TODO: currently this will always treat C as the origin # even if you change it with directives events = events_for_chord(root, ctype, tick_time, tick_duration, velocity = int(volume*127), equal_temperament=state['equal_temperament'], double_root=state['double_root']) for ev in events: mid.add_event(ev) # Move the timer on ready for the next chord state['time'] += duration elif first_word in ["tones", "t"]: # Must be a chord made up of coordinates tokens = line.lstrip("tones").split() duration = _get_duration(tokens) root = _get_root(tokens) volume = _get_volume(tokens) sec_duration = _qn_to_seconds(duration) # The rest should be the list of coordinates coordinates = [_read_coord(token) for token in tokens] # Add the chord to the tone matrix tone_matrix.add_tone( _qn_to_seconds(state['time']), SineClusterEvent( _get_pitch(root), coordinates, duration=sec_duration, amplitude=volume, equal_temperament=state['equal_temperament'], double_root=state['double_root'], envelope=state['envelope'] ) ) # Add the same chord to the midi file tick_time = int(mid.resolution * state['time']) tick_duration = int(duration * mid.resolution) for note in coordinates: # TODO: currently this will always treat C as the origin # even if you change it with directives events = tonal_space_note_events(note, tick_time, tick_duration, velocity = int(volume*127)) if state['equal_temperament']: # Omit tuning event (the first one) events = events[1:] for ev in events: mid.add_event(ev) # Move the timer on ready for the next chord state['time'] += duration else: raise HarmonicalInputFileReadError, "could not make sense "\ "of the line: %s" % line return ChordInputFile(tone_matrix, midi_file=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 = 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 render(self): """ Creates MIDI data from the path and chord types. @rtype: midi.EventStream @return: an event stream containing all the midi events """ mid = EventStream() mid.add_track() # Set the tempo at the beginning tempo = SetTempoEvent() tempo.tempo = self.tempo mid.add_event(tempo) # Set the instrument at the beginning instr = ProgramChangeEvent() instr.value = self.instrument mid.add_event(instr) beat_length = mid.resolution # Work out when each root change occurs time = Fraction(0) root_times = [] for root, length in self.path: root_times.append((root, time)) time += length def _root_at_time(time): current_root = root_times[0][0] for root, rtime in root_times[1:]: # Move through root until we get the first one that # occurs after the previous time if rtime > time: return current_root current_root = root # If we're beyond the time of the last root, use that one return current_root # Add each chord time = Fraction(0) bass_events = [] bass = self.bass_root is not None for chord_type, length in self.chord_types: tick_length = length * beat_length - 10 tick_time = time * beat_length # Find out what root we're on at this time root = _root_at_time(time) # Add all the necessary events for this chord chord_events = events_for_chord( root, chord_type, int(tick_time), int(tick_length), equal_temperament=self.equal_temperament, root_octave=self.root_octave, double_root=(self.double_root or bass)) if bass: # Add the bass note to the bass track bass_events.extend([copy.copy(ev) for ev in chord_events[-1]]) if bass and not self.double_root: # Remove the doubled root that we got for the bass line chord_events = sum(chord_events[:-1], []) # Add the main chord notes to the midi track for ev in chord_events: mid.add_event(ev) time += length if bass: bass_channel = 1 # Add another track to the midi file for the bass notes mid.add_track() # Select a bass instrument - picked bass instr = ProgramChangeEvent() instr.value = 33 instr.channel = bass_channel mid.add_event(instr) # Add all the bass notes for ev in bass_events: ev.channel = bass_channel mid.add_event(ev) 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 = 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 render(self): """ Creates MIDI data from the path and chord types. @rtype: midi.EventStream @return: an event stream containing all the midi events """ mid = EventStream() mid.add_track() # Set the tempo at the beginning tempo = SetTempoEvent() tempo.tempo = self.tempo mid.add_event(tempo) # Set the instrument at the beginning instr = ProgramChangeEvent() instr.value = self.instrument mid.add_event(instr) beat_length = mid.resolution # Work out when each root change occurs time = Fraction(0) root_times = [] for root,length in self.path: root_times.append((root,time)) time += length def _root_at_time(time): current_root = root_times[0][0] for root,rtime in root_times[1:]: # Move through root until we get the first one that # occurs after the previous time if rtime > time: return current_root current_root = root # If we're beyond the time of the last root, use that one return current_root # Add each chord time = Fraction(0) bass_events = [] bass = self.bass_root is not None for chord_type,length in self.chord_types: tick_length = length * beat_length - 10 tick_time = time * beat_length # Find out what root we're on at this time root = _root_at_time(time) # Add all the necessary events for this chord chord_events = events_for_chord(root, chord_type, int(tick_time), int(tick_length), equal_temperament=self.equal_temperament, root_octave=self.root_octave, double_root=(self.double_root or bass)) if bass: # Add the bass note to the bass track bass_events.extend([copy.copy(ev) for ev in chord_events[-1]]) if bass and not self.double_root: # Remove the doubled root that we got for the bass line chord_events = sum(chord_events[:-1], []) # Add the main chord notes to the midi track for ev in chord_events: mid.add_event(ev) time += length if bass: bass_channel = 1 # Add another track to the midi file for the bass notes mid.add_track() # Select a bass instrument - picked bass instr = ProgramChangeEvent() instr.value = 33 instr.channel = bass_channel mid.add_event(instr) # Add all the bass notes for ev in bass_events: ev.channel = bass_channel mid.add_event(ev) return mid
def write_patterns(path, patterns, unit, tonalities, instruments): if len(patterns) == 0: return keys = patterns.keys() keys.sort() resolution = patterns[keys[0]].resolution pattern = Pattern(resolution=resolution) last_index = -1 key_signature_map = [0, -5, 2, -3, 4, -1, -6, 1, -4, 3, -2, 5] for excerpt_index in keys: excerpt = patterns[excerpt_index] # if there is no note event, then ignore that bar has_note_event = False for track in excerpt: for event in track: if type(event) is NoteOnEvent or type( event) is NoteOffEvent: has_note_event = True break if has_note_event == True: break if has_note_event == False: continue for track_index in range(len(excerpt)): if track_index >= 3: break if len(pattern) <= track_index: new_track = Track(tick_relative=False) pattern.append(new_track) time_signature = TimeSignatureEvent() denominator = 4 numerator = unit while abs(round(numerator) - numerator) >= 1.0 / 24.0 and numerator <= 16: denominator *= 2 numerator *= 2 time_signature.set_denominator(denominator) time_signature.set_numerator(int(round(numerator))) time_signature.tick = 0 new_track.append(time_signature) if last_index == -1 or \ tonalities[excerpt_index]['mode'] != tonalities[last_index]['mode'] or \ tonalities[excerpt_index]['key'] != tonalities[last_index]['key']: key_signature = KeySignatureEvent() if tonalities[excerpt_index]['mode'] == 'Major': value = key_signature_map[tonalities[excerpt_index] ['key']] minor = 0 else: value = key_signature_map[ (tonalities[excerpt_index]['key'] + 3) % 12] minor = 1 key_signature.set_alternatives(value) key_signature.set_minor(minor) key_signature.tick = int(excerpt_index * unit * resolution) pattern[track_index].append(key_signature) num_instruments = min(3, len(instruments[excerpt_index])) current_instrument_id = instruments[excerpt_index][min( track_index, num_instruments - 1)]['ID'] if last_index != -1: last_instrument_id = instruments[last_index][min( track_index, num_instruments - 1)]['ID'] if last_index == -1 or current_instrument_id != last_instrument_id: program_change = ProgramChangeEvent() program_change.set_value(current_instrument_id) program_change.tick = int(excerpt_index * unit * resolution) program_change.channel = track_index pattern[track_index].append(program_change) track = excerpt[track_index] track.make_ticks_abs() for event in track: new_event = MIDI.copy_event(event) new_event.tick = int(event.tick) + int( excerpt_index * unit * resolution) pattern[track_index].append(new_event) track.make_ticks_rel() last_index = excerpt_index for track in pattern: track.sort() track.make_ticks_rel() track.append(EndOfTrackEvent(tick=resolution)) MIDI.write_pattern(path, pattern)
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 = 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