Example #1
0
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)
Example #2
0
 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)
Example #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 = 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
Example #4
0
    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
Example #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 = 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
Example #6
0
 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
Example #7
0
    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)
Example #8
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
Example #9
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