예제 #1
0
def musical_extract_midi(path: str):
    """Generates (BPM: float, duration since last: float, [pitch: int])"""
    f = MidiFile(path)
    assert f.type != 2, "asynchronous midi files are not supported yet"
    messages = []
    for track in f.tracks:
        messages.extend(_to_abstime(track))
    assert messages, "failed to find messages. Erroneous file?"
    messages.sort(key=attrgetter('time'))
    tempo = DEFAULT_TEMPO
    last = tick = 0
    output = set()
    for msg in messages:
        if msg.type == 'note_on' and msg.velocity > 0:
            if msg.time == tick:  # Current hit
                output.add(msg.note)
            elif output:  # New hit
                yield tempo2bpm(tempo), (tick - last) / f.ticks_per_beat, list(output)
                output = {msg.note}
                last, tick = tick, msg.time
            else:  # Non-0 Beginning
                last = tick = msg.time
                output.add(msg.note)
        elif msg.type == 'set_tempo':
            tempo = msg.tempo
    # Last hit
    if output:
        yield tempo2bpm(tempo), (tick - last) / f.ticks_per_beat, list(output)
예제 #2
0
def save_musical_file(path: str, out: str = None):
    if out is None:
        out = path
    f = MidiFile()
    ap = f.add_track('Main').append
    last_bpm = tempo2bpm(DEFAULT_TEMPO)
    ap(MetaMessage("set_tempo", tempo=DEFAULT_TEMPO))
    notes_on = []
    i = 0
    for bpm, duration, notes in musical_extract_midi(path):
        i += 1
        if notes_on:
            ap(Message(type='note_off', note=notes_on[0],
                       time=int(duration * f.ticks_per_beat * 0.95)))
            for n in notes_on[1:]:
                ap(Message(type='note_off', note=n, time=0))
        notes_on = notes
        ap(Message(type='note_on', note=notes_on[0],
                   time=int(duration * f.ticks_per_beat * 0.05)))
        for n in notes_on:
            ap(Message(type='note_on', note=n, time=0))
        if bpm != last_bpm:
            last_bpm = bpm
            ap(MetaMessage("set_tempo", tempo=bpm2tempo(bpm)))
    if notes_on:  # Last note; just make it 1 beat long
        ap(Message(type='note_off', note=notes_on[0], time=f.ticks_per_beat))
        for n in notes_on[1:]:
            ap(Message(type='note_off', note=n, time=0))
    f.save(out)
    print(f"{i} hits wrote to {out}")
예제 #3
0
def _get_tempo(msgs):
    """Search through msgs for a meta message with type 'set_tempo' and return
    the tempo of the last one found."""
    msgs = list(filter(lambda m: m.type == 'set_tempo', msgs))
    if msgs:
        return mido.tempo2bpm(msgs[-1].tempo)
    return 120  # by the standard, default to 120
예제 #4
0
파일: play.py 프로젝트: triad7th/piro
    def open(self, midi_filename=None, midi_portname=None):
        """ open midifile and(or) port """
        if midi_filename:
            clock = PrClock()
            clock.set_timer(1)
            # load midi file
            self.midi_file = mido.MidiFile(midi_filename)
            print("open midifile : ", clock.elapsed(1))
            # set iter_by_tick
            self.iter_by_tick = True
            # load iteration of it
            self.midi_iter = iter(self.midi_file)
            # set relative variables
            clock.set_timer(1)
            self.tempo = self.get_tempo()
            print('get tempo : ', clock.elapsed(1))
            self.bpm = mido.tempo2bpm(self.tempo)
            self.ppqn = self.get_ppqn()
            self.spt = self.get_spt()
            self.cur_evt_time = .0
            self.cur_evt_tick = .0
            self.next_evt_time = .0
            self.next_evt_tick = .0
            self.playing = False
            self.msg = None
            clock.set_timer(1)
            self.length = self.get_length(force=True)
            self.start_time = .0
            print('get length : ', clock.elapsed(1))

        if midi_portname:
            self.port = mido.open_output(midi_portname)
예제 #5
0
 def feed(self, message):
     """
     Feed a mido message into the object, updating the internal state.
     Returns wrapped message
     """
     if (self.wrap_notes and
             message.type in ChannelState.NOTE_MESSAGE_TYPES):
         return self._channels[message.channel].feed(message)
     elif message.type == "control_change":
         if message.control == Control.LOCAL.value:
             # LOCAL message.
             value = SwitchBool.from_b(message.value)
             self.local(value)
             return WrappedMessage(
                 message, Control.LOCAL, value,
                 bonus_strings(('n', message.channel, 0x0, '1X')))
         else:
             return self._channels[message.channel].feed(message)
     elif message.type in ChannelState.CONTROL_MESSAGE_TYPES:
         return self._channels[message.channel].feed(message)
     # System Exclusive / Sequencer Specific
     elif message.type in {"sysex", "sequencer_specific"}:
         return self._handle_sysex_seqspec(message)
     # User Song Polytouch Special Handling
     elif self.user_song and message.type in ChannelState.US_MESSAGE_TYPES:
         return self._channels[message.channel].feed(message)
     # Meta Messages.
     elif message.type == "set_tempo":
         # We use the bpm instead of the midi-tempo as value.
         return WrappedMessage(
             message, MessageType.TEMPO, mido.tempo2bpm(message.tempo))
     return None
예제 #6
0
def change_midi_file_tempo(input_file, output_file, ratio=1.0):
    """
    Change the tempo in a midi file
    """
    infile = MidiFile(input_file)

    with MidiFile() as outfile:

        outfile.type = infile.type
        outfile.ticks_per_beat = infile.ticks_per_beat

        for msg_idx, track in enumerate(infile.tracks):

            out_track = MidiTrack()
            outfile.tracks.append(out_track)

            for message in track:
                if message.type == 'set_tempo':
                    bpm = tempo2bpm(message.tempo)
                    new_bpm = ratio * bpm
                    message.tempo = bpm2tempo(new_bpm)

                out_track.append(message)

    outfile.save(output_file)
예제 #7
0
파일: play.py 프로젝트: triad7th/piro
    def reload(self):
        """ reload midi file """
        # stop if it's needed
        self.stop()

        # reload
        if self.midi_file and self.port:
            # set iter_by_tick
            self.iter_by_tick = True
            # reset port
            self.port.reset()
            # reset iteration of midi file
            del self.midi_iter
            self.midi_iter = iter(self.midi_file)
            # set relative variables
            self.tempo = self.get_tempo()
            self.bpm = mido.tempo2bpm(self.tempo)
            self.ppqn = self.get_ppqn()
            self.spt = self.get_spt()
            self.cur_evt_time = .0
            self.cur_evt_tick = .0
            self.next_evt_time = .0
            self.next_evt_tick = .0
            self.playing = False
            self.msg = None
            self.length = self.get_length(force=True)
            self.clock.set_timer()
            self.start_time = .0
            # helper reset
            self.helper.reset()
예제 #8
0
def testFindTempo():
    tempo = findTempo(mid)
    print "how long 240 ticks",ticksToSeconds(240,mid)
    print "tempo (microseconds per beat?)",tempo
    print "bpm ",mido.tempo2bpm(tempo)
    print "ticks per beat", mid.ticks_per_beat
    print "total seconds",mid.length
예제 #9
0
def getTempoString(tempos, ticksPerBeat):
    string = ''
    for msg in tempos:
        string += '\t{} = B {}000\n'.format(
            int(msg.time * Track.RESOLUTION // ticksPerBeat),
            mido.tempo2bpm(msg.tempo))
    return string
예제 #10
0
def play_file(filename, print_messages):
    midi_file = MidiFile(filename)

    print('Playing {}.'.format(midi_file.filename))
    length = midi_file.length
    print('Song length: {} minutes, {} seconds.'.format(
        int(length / 60), int(length % 60)))
    print('Tracks:')
    for i, track in enumerate(midi_file.tracks):
        print('  {:2d}: {!r}'.format(i, track.name.strip()))

    for message in midi_file.play(meta_messages=True):
        if print_messages:
            sys.stdout.write(repr(message) + '\n')
            sys.stdout.flush()

        if isinstance(message, Message):
            sys.stdout.write("")
            sys.stdout.flush()
            #output.send(message)
        elif message.type == 'set_tempo':
            print('Tempo changed to {:.1f} BPM.'.format(
                tempo2bpm(message.tempo)))

    print()
예제 #11
0
def midi2pianoroll(mid):
    midd = mido.MidiFile(mid)
    midp = pretty_midi.PrettyMIDI(mid)
    # basic information
    tempo = get_tempo(midd)
    bpm = mido.tempo2bpm(tempo)
    sixteen_t = (1 / (bpm / 60)) / 4
    midi_length = int(np.ceil(midd.length / sixteen_t))

    #
    notes = np.zeros((midi_length, 13))
    for instrument in midp.instruments:
        print(instrument)
        if instrument.is_drum == False:
            pr = instrument.get_piano_roll(1 / sixteen_t)
            cnt = 0
            for i, ppr in enumerate(pr):
                # i: notes
                # j: time stamp
                for j, nt in enumerate(ppr):
                    if nt > 0:
                        notes[j][i % 12 + 1] += 1
    for i, note in enumerate(notes):
        if np.count_nonzero(note) == 0:
            notes[i][0] = 1
    return notes, sixteen_t
def midi2score(song, subdivision):
    mid = mido.MidiFile(song)

    tempo = 0
    sec_per_tick = 0
    length = mid.length

    time = 0

    # set initial score len
    for msg in mid:
        if (msg.is_meta):
            if (msg.type == 'set_tempo'):
                tempo = msg.tempo
        else:
            if (msg.type == "note_on"):
                bpm = mido.tempo2bpm(tempo)
                sec_per_tick = 60 / bpm / subdivision
                break

    score = np.zeros((int(length / sec_per_tick) + 1, 90))

    for msg in mid:
        time += msg.time
        pos = int(np.round(time / sec_per_tick))
        if (pos + 1 > score.shape[0]):
            score = np.append(score,
                              np.zeros((pos - score.shape[0] + 1, 90)),
                              axis=0)
        if (msg.is_meta):
            if (msg.type == 'set_tempo'):
                tempo = mido.tempo2bpm(msg.tempo)
                sec_per_tick = 60 / tempo / subdivision

        elif (msg.type == 'note_on'):
            if (msg.velocity == 0):
                p = msg.note - 21
                score[pos:, p] = 0
            else:
                p = msg.note - 21
                score[pos:, p] = 1

        elif (msg.type == 'note_off'):
            p = msg.note - 21
            score[pos:, p] = 0

    return score
예제 #13
0
def getBpmSet(path: str) -> Set[float]:
    bpm = set()
    f = MidiFile(path)
    for track in f.tracks:
        for msg in track:
            if msg.type == 'set_tempo':
                bpm.add(tempo2bpm(msg.tempo))
    return bpm
예제 #14
0
def secNum(path):
    midd = MidiFile(path)
    midp = pretty_midi.PrettyMIDI(path)
    tempo = get_tempo(midd)
    bpm = tempo2bpm(tempo)
    measure_t = (1 / (bpm / 60)) * 4
    midi_sec = int(np.ceil(midd.length / measure_t))

    return midi_sec
예제 #15
0
def get_bpm_from_track(track):
    for msg in track:
        if msg.type == 'set_tempo':
            try:
                return mido.tempo2bpm(msg.tempo)
            except:
                print(traceback.format_exc())
                continue
    return None
예제 #16
0
 def check_if_pattern_is_ok(self, pattern, tempo):
     """ Check if a pattern has right tempo and no change in tempo during time """
     for track in pattern.tracks:
         for evt in track:
             if evt.type == 'set_tempo':
                 if mido.tempo2bpm(evt.tempo) != tempo:
                     return False
             elif evt.type == 'note_on':
                 if not self.lowerbound < evt.note < self.upperbound:
                     return False
     return True
예제 #17
0
    def wait_for_messages(self):
        while 1:
            socket_list = [self.sock]

            # Get the list sockets which are readable
            read_sockets, write_sockets, error_sockets = select.select(
                socket_list, [], [], 0)
            for sock in read_sockets:
                # incoming message from remote server
                if sock == self.sock:
                    data = sock.recv(4096)
                    if not data:
                        print('\nDisconnected from chat server')
                        sys.exit()
                    else:
                        # print data
                        #sys.stdout.write(">" +  str(binascii.unhexlify(data.decode())) + "<")
                        #print("Received1: " + data.decode())
                        messages = str(data.decode()).split("m")
                        if len(messages) >= 2:
                            messages.pop(0)
                            for message in messages:
                                message_header = message[:1]
                                message_body = message[2:]
                                print(message)
                                if message_header == "n":
                                    notes_hex = message_body
                                    notes_bin = bytearray.fromhex(notes_hex)
                                    notes_mido = mido.parse_all(notes_bin)
                                    print(notes_mido)
                                    if self.midi_ports != None:
                                        for note in notes_mido:
                                            if isinstance(note, Message):
                                                self.midi_ports_out.send(note)
                                            elif note.type == 'set_tempo':
                                                print(
                                                    'Tempo changed to {:.1f} BPM.'
                                                    .format(
                                                        tempo2bpm(note.tempo)))

            if self.midi_ports != None:
                msg = ''
                bytes = bytearray()
                for message in mido.ports.multi_receive(self.midi_ports,
                                                        block=False):
                    print('Sending: {}'.format(message))
                    bytes = bytes + message.bin()
                if bytes != b'':
                    message = "mn=" + bytes.hex()
                    #hex = "mn=803c00"
                    #hex = "mn=803c00mn=903740"
                    print("Sent: " + message)
                    self.sock.send(message.encode())
예제 #18
0
    def __init__(self, composer, path):
        self.path = path
        self.notes = IntervalSet()
        self.tempos = IntervalSet()
        self.time_sigs = IntervalSet()
        self.keys = IntervalSet()
        self.composer = Composers.getIndex(composer)
        self.qnls = 0

        # Default values for metadata
        self.tempos.addPosEdge('tp', 0, 120)
        self.time_sigs.addPosEdge('ts', 0, TimeSignatures.getIndex((4, 4)))
        self.keys.addPosEdge('key', 0, KeySignatures.getIndex('unknown'))

        mid = mido.MidiFile(path)
        for track in mid.tracks:
            time = 0 # In qnls
            for msg in track:
                time += float(msg.time) / mid.ticks_per_beat
                if msg.type == 'note_on':
                    self.notes.addPosEdge(msg.note, time, msg.note)
                elif msg.type == 'note_off':
                    self.notes.addNegEdge(msg.note, time)
                elif msg.type == 'set_tempo':
                    self.tempos.addNegEdge('tp', time)
                    self.tempos.addPosEdge('tp', time, mido.tempo2bpm(msg.tempo))
                elif msg.type == 'time_signature':
                    self.time_sigs.addNegEdge('ts', time)
                    self.time_sigs.addPosEdge('ts', time, 
                        TimeSignatures.getIndex((msg.numerator, msg.denominator)))
                elif msg.type == 'key_signature':
                    self.keys.addNegEdge('key', time)
                    self.keys.addPosEdge('key', time, KeySignatures.getIndex(msg.key))

            self.qnls = max(self.qnls, time)

        self.notes.finalize(self.qnls)
        self.tempos.finalize(self.qnls)
        self.time_sigs.finalize(self.qnls)
        self.keys.finalize(self.qnls)

        self.normalize_notes()

        self.examples = self.getTrainingExamples()

        print 'Processed %s (%d notes, %d keys, %d times, %d tempos, %d examples)' % (
            self.path, 
            len(self.notes.intervals),
            len(self.keys.intervals),
            len(self.time_sigs.intervals),
            len(self.tempos.intervals),
            len(self.examples)
        )
예제 #19
0
def findTempo(file):
    # returns tempo of song
    count = 0
    for (i, msg) in enumerate(file):
        if isTempo(msg):
            tempo = msg.tempo
            count += 1
            break
    if not count == 0:
        return int(mido.tempo2bpm(tempo))
    else:
        return 120
예제 #20
0
    def __init__(self, filename, track=0, resolution=4, bpm=None):
        self.filename = filename
        self.file = mido.MidiFile(filename)
        self.track = self.file.tracks[track]
        print(self.track.name)
        self.res = resolution

        self.bpm = bpm
        self.tpb = self.file.ticks_per_beat
        self.total_ticks = 0
        for msg in self.track:
            if msg.type == 'set_tempo':
                self.bpm = mido.tempo2bpm(msg.tempo)

            if msg.type == 'note_on' or msg.type == 'note_off':
                self.total_ticks += msg.time

        # For now we only work with note_on and note_off messages
        total_notes = 127
        self.min_note = total_notes
        self.max_note = 0

        for msg in self.track:
            if msg.type == 'note_on' or msg.type == 'note_off':
                if msg.note < self.min_note:
                    self.min_note = msg.note
                if msg.note > self.max_note:
                    self.max_note = msg.note

        self.note_range = (self.max_note - self.min_note) + 1
        self.roll = [[0 for j in range(self.note_range)]
                     for i in range(self.total_ticks)]
        self.beat_roll = [[
            0 for j in range(self.note_range)
        ] for i in range(ceil(self.total_ticks * self.res / self.tpb))]

        current_tick = 0
        last_tick_on = [0 for i in range(self.note_range)]

        for msg in self.track:
            if msg.type == 'note_on' and msg.velocity != 0:
                current_tick += msg.time
                last_tick_on[msg.note - self.min_note] = current_tick
            elif msg.type == 'note_off' or (msg.type == 'note_on'
                                            and msg.velocity == 0):
                current_tick += msg.time
                for tick in range(last_tick_on[msg.note - self.min_note],
                                  current_tick):
                    self.roll[tick][msg.note - self.min_note] = 1
                    self.beat_roll[floor(tick * self.res /
                                         self.tpb)][msg.note -
                                                    self.min_note] = 1
예제 #21
0
파일: structure.py 프로젝트: GaryQian/Viano
def formImg(tempo, tpb, notes):
    ar = np.zeros((6, 4, 1))
    y = None
    temp = None
    for i, n in enumerate(notes):
        if i < 6 and n is not None:
            temp = [[n.note * 100], [tempo / tpb * n.length],
                    [n.velocity * 10], [mido.tempo2bpm(tempo) * 10]]
            ar[i, :, :] = temp
        else:
            y = n
    #print ar
    return [ar, y]
예제 #22
0
def get_piece_info(mfile):
    whole_note = mfile.ticks_per_beat * 4
    time_sign = None
    tempo = None
    for msg in mfile.tracks[0]:
        if msg.is_meta:
            if msg.type == 'time_signature':
                time_sign = (msg.numerator, msg.denominator)
            elif msg.type == 'set_tempo':
                tempo = round(mido.tempo2bpm(msg.tempo))
    if time_sign == None: time_sign=(4, 4)
    if tempo == None: tempo = 500000
    return time_sign, tempo, whole_note
예제 #23
0
def scan_rock_midi_files():
    midi_table = get_midi_table()
    genre = 'rock'
    dir = 'E:/free_midi_library/raw_midi/'
    for midi in midi_table.find({'Genre': genre}):
        path = dir + genre + '/' + midi['md5'] + '.mid'
        mido_object = mido.MidiFile(path)

        for i, track in enumerate(mido_object.tracks):
            for msg in track:
                if msg.is_meta and msg.type == 'set_tempo':
                    print(mido.tempo2bpm(msg.tempo))
        print('\n')
예제 #24
0
  def _parse_midi_messages(self):

    elapsed_ticks=0
    for mdt in range(len(self.midifile.tracks)):
      for m,message in enumerate(self.midifile.tracks[mdt]):
        
        message_type=message.type
        elapsed_ticks+=message.time
        #print(message, elapsed_ticks)
        #print(f'message {m} , time= {message.time} elapsed_ticks={elapsed_ticks}')

        if message_type=="set_tempo":
          self.tempo=message.tempo
          self.bpm=round(mido.tempo2bpm(self.tempo))

        elif message_type=="time_signature":
          self.rythm_numerator=message.numerator
          self.rythm_denominator=message.denominator
          self.clocks_per_click=message.clocks_per_click
          self.notated_32nd_notes_per_beat=message.notated_32nd_notes_per_beat
        
        elif message_type=="key_signature":
          self.key=message.key
      
        elif message_type=="end_of_track":
          self.ending_tick=message.time
          self.total_ticks=elapsed_ticks

        elif message_type=="note_on":
          channel=message.channel 
          pitch=message.note
          velocity=message.velocity
          time=message.time
          #duration=self.midifile.tracks[0][m+1].time
          #print(f'duration={self.midifile.tracks[0][m+1].time}')
          timestamp=elapsed_ticks
          timestamp_sec=self.convert_tic2sec(timestamp)
          #print(pitch, timestamp_sec)
          if velocity!=0:

            temp_counter=1
            duration=0
            for msg in self.midifile.tracks[mdt][m+1:]:
              duration+=msg.time
              if msg.type=="note_on" and msg.note==pitch and msg.velocity==0:
                new_note=Note(channel,pitch,velocity,timestamp,timestamp_sec,duration,self.convert_tic2sec(duration))
                self.notes.append(new_note)
                break
        else:
          #print(f"Unknown message {message}")
          pass
예제 #25
0
def read(filename):
    song = Song()
    song.segs.append(Seg())
    mid = None
    if '.mid' not in filename:
        mid = MidiFile(filename + '.mid')
    else:
        mid = MidiFile(filename)
    song.tpb = mid.ticks_per_beat
    for i, track in enumerate(mid.tracks):
        if i != 1:
            for m in mid:
                #print m
                if m.type == 'set_tempo':
                    song.tempo = m.tempo
        else:
            activeNotes = list()
            activeNotesData = dict()
            time = 0
            tempNote = None
            for m in mid:
                #print m
                if m.type == 'set_tempo':
                    song.tempo = m.tempo
                    song.segs[0].notes.append(Note(999, 0, m.tempo, time))
                    #print m.tempo
                #print mid.length
                time = time + m.time * song.tpb * mido.tempo2bpm(
                    song.tempo) / 60
                #print time
                if m.type == 'note_on':
                    if m.note in activeNotes and activeNotesData[
                            m.note] != None:
                        tempNote = activeNotesData[m.note]
                        song.segs[0].notes.append(
                            Note(m.note, time - tempNote[1],
                                 tempNote[0].velocity, tempNote[1]))
                    activeNotes.append(m.note)
                    activeNotesData[m.note] = (m, time)
                elif m.type == 'note_off':
                    if m.note in activeNotes and activeNotesData[
                            m.note] != None:
                        tempNote = activeNotesData[m.note]
                        song.segs[0].notes.append(
                            Note(m.note, time - tempNote[1],
                                 tempNote[0].velocity, tempNote[1]))
                        #print time - tempNote[1]
                        activeNotes.remove(m.note)
                        activeNotesData[m.note] = None
    #song.tempo = int(song.tempo * 1)
    return song
    def _load_tempo_changes(self, midi_data, track_idx=0):
        tempo_changes = [TempoChange(DEFAUL_BPM, 0)]

        for event in midi_data.tracks[track_idx]:
            if event.type == 'set_tempo':
                bpm = mido.tempo2bpm(event.tempo)
                tick = event.time
                if tick == 0:
                    tempo_changes = [TempoChange(bpm, 0)]
                else:
                    last_bpm = tempo_changes[-1].tempo
                    if bpm != last_bpm:
                        tempo_changes.append(TempoChange(bpm, tick))
        return tempo_changes
예제 #27
0
    def get_tempo(cls, path):
        if not path:
            return None

        midi_file = urllib.urlopen(path)
        tempo = 40
        meta_message = MyMetaMessage(midi_file.read())
        midi_file.close()
        for message in meta_message.get_all_meta_message():
            if message.type == 'set_tempo':
                tempo = int(tempo2bpm(message.tempo))
                break

        return tempo
예제 #28
0
    def _parse_notes(midi_file: mido.MidiFile) -> List[_MidiNote]:
        ticks_per_beat: int = midi_file.ticks_per_beat
        tempo_bpm: float = MidiParser._DEFAULT_TEMPO_BPM
        held_notes: List[_MidiNote] = []
        completed_notes: List[_MidiNote] = []
        current_tick: int = 0
        current_time: float = 0.0
        current_bar: float = 1.0
        current_bar_factor: int = 1

        for msg, track in MidiParser.__merge_tracks(midi_file.tracks):
            current_tick += msg.time
            current_time += mido.tick2second(msg.time, ticks_per_beat,
                                             mido.bpm2tempo(tempo_bpm))
            current_bar += msg.time / ticks_per_beat * current_bar_factor
            track_name: str = track.name if track else ""
            if msg.type == 'set_tempo':
                tempo_bpm = mido.tempo2bpm(msg.tempo)
            elif msg.type == 'time_signature':
                current_bar_factor = msg.denominator / (4 * msg.numerator)
            elif msg.type == 'note_on' or msg.type == 'note_off':
                # if the note is already held, complete the note regardless of whether the input is a note_on or
                # note_off message. This is to avoid duplicate notes in a slice if re-triggered before its note_off
                # See test case "keithjarrett_kolnconcert_Right.mid" bars 311 to 330 for an example of this.
                completed: List[_MidiNote] = [
                    note for note in held_notes
                    if note.matches(msg.note, msg.channel, track_name)
                ]
                for note in completed:
                    note.end_tick = current_tick
                    note.end_time = current_time
                completed_notes.extend(completed)
                held_notes = [
                    note for note in held_notes
                    if not note.matches(msg.note, msg.channel, track_name)
                ]
                if msg.type == 'note_on' and msg.velocity > 0:
                    held_notes.append(
                        _MidiNote(msg.note, msg.velocity, msg.channel,
                                  current_tick, current_time, tempo_bpm,
                                  current_bar, track_name))
                # elif msg.type == 'note_off' or (msg.type == 'note_on' and msg.velocity == 0):

        for note in held_notes:
            # If note ons still exist at end of midi file, generate note offs for all of them
            note.end_tick = current_tick
            note.end_time = current_time
            completed_notes.append(note)

        return completed_notes
예제 #29
0
def build_tempo_map_from_midi(druid):

    midi_filepath = Path(f"midi/{druid}.mid")
    midi = MidiFile(midi_filepath)

    tempo_map = []
    current_tick = 0

    for event in midi.tracks[0]:
        current_tick += event.time
        if event.type == "set_tempo":
            tempo_map.append((current_tick, tempo2bpm(event.tempo)))

    return tempo_map
예제 #30
0
    def _load_track0(self, midi_data):
        self.key_signatures = []
        self.time_signatures = []
        self.tempo_changes = []

        for msg in midi_data.tracks[0]:
            if msg.type == 'key_signature':
                self.key_signatures.append(KeySignature(msg.key, msg.time))
            elif msg.type == 'time_signature':
                self.time_signatures.append(
                    TimeSignature(msg.numerator, msg.denominator, msg.time))
            elif msg.type == 'set_tempo':
                self.tempo_changes.append(
                    TempoChange(tempo2bpm(msg.tempo), msg.time))
예제 #31
0
def musical_extract_midi_with_inst(path: str, offset=True):
    """Generates (BPM: float, duration since last: float,
    [(pitch: int, instrument_index: int)])"""
    if offset:
        offset = 1
    else:
        offset = 0
    f = MidiFile(path)
    assert f.type != 2, "asynchronous midi files are not supported yet"
    messages = []
    for track in f.tracks:
        messages.extend(_to_abstime(track))
    assert messages, "failed to find messages. Erroneous file?"
    messages.sort(key=attrgetter('time'))
    tempo = DEFAULT_TEMPO
    last = tick = 0
    output = set()
    insts = dict()
    for msg in messages:
        if msg.type == 'note_on' and msg.velocity > 0:
            if msg.time == tick:  # Current hit
                output.add((msg.note, insts.get(msg.channel, offset)))
            elif output:  # New hit
                yield (tempo2bpm(tempo),
                       (tick - last) / f.ticks_per_beat, list(output))
                output = {(msg.note, insts.get(msg.channel, offset))}
                last, tick = tick, msg.time
            else:  # Non-0 Beginning
                last = tick = msg.time
                output.add((msg.note, insts.get(msg.channel, offset)))
        elif msg.type == 'set_tempo':
            tempo = msg.tempo
        elif msg.type == 'program_change':
            insts[msg.channel] = msg.program + offset
    # Last hit
    if output:
        yield tempo2bpm(tempo), (tick - last) / f.ticks_per_beat, list(output)