Exemple #1
0
    def __init__(self, midi_filename=None, midi_portname=None):
        """ init """
        # main members
        self.midi_file = None
        self.midi_iter = None
        self.port = None

        # play related
        self._scheduled_evt = False
        self.playing = False
        self.callback = None
        self.callback_timebar = None

        # midi file related
        self.totalticks = None
        self.length = None
        self.tempo = None
        self.bpm = None
        self.ppqn = None
        self.spt = None
        self.msg = None
        self.cur_evt_time = .0
        self.cur_evt_tick = .0
        self.next_evt_time = .0
        self.next_evt_tick = .0
        self.start_time = .0

        # clock and helper classes
        self.clock = PrClock()
        self.helper = PrHelper()

        # actual init
        self.open(midi_filename, midi_portname)
Exemple #2
0
        def build(self):
            # window size / position
            Window.size = (800, 600)
            Window.left, Window.top = 3100, 100

            # members
            self.layout = BoxLayout()
            self.layout.add_widget(view)

            # bind - keystrokes
            Window.bind(on_key_down=keydown)

            PrClock.schedule_once(trigger, 0)
            # return
            return self.layout
Exemple #3
0
        def build(self):
            # window size / position
            Window.size = (1280, 600)
            Window.left, Window.top = 3100, 30

            # members
            self.layout = BoxLayout()
            test = InstructionGroup()
            a = PrTracks()
            a.add(PrTrack('', True))

            self.layout.canvas.add(Rectangle(pos=(100, 100), size=(100, 100)))
            PrClock.schedule_once(trigger, 0)
            # return
            return self.layout
Exemple #4
0
    def trigger(self, msg=None, callback=None, callback_timebar=None):
        """ trigger midifile play """
        if not self.playing:
            self.midi_file.iter_by_tick = True
            # set flag
            self.playing = True
            PrHelper.msg('PrMidi', 'Played at',
                         '{0:10.4f} sec'.format(self.start_time))

            try:
                self.msg = msg = next(self.midi_iter)
            except StopIteration:
                pass
            else:
                # set the next event time
                time = mido.tick2second(msg.time,
                                        self.midi_file.ticks_per_beat,
                                        self.midi_file.tempo)
                self.cur_evt_time = self.next_evt_time
                self.cur_evt_tick = self.next_evt_tick
                self.next_evt_time += time
                self.next_evt_tick += msg.time

                # set the callback
                self.callback = callback
                self.callback_timebar = callback_timebar

                # trigger!
                self._scheduled_evt = PrClock.schedule_interval_free(
                    self.playback, self.spt)
Exemple #5
0
        def build(self):
            # window size / position
            Window.size = (1280, 600)
            Window.left, Window.top = 3100, 30

            # members
            self.layout = BoxLayout()
            self.view = ScrollView(size_hint=(1, 1),
                                   bar_width=25,
                                   scroll_type=['bars'],
                                   effect_cls=ScrollEffect)

            self.view.add_widget(roll)
            self.layout.add_widget(self.view)

            PrClock.schedule_once(trigger, 0)
            # return
            return self.layout
Exemple #6
0
        def build(self):
            # window size / position
            Window.size = (150, 1280)
            Window.left, Window.top = 30, 30

            # members
            self.layout = BoxLayout()
            self.view = ScrollView(size_hint=(None, 1),
                                   width=98,
                                   bar_width=5,
                                   scroll_type=['bars'])

            self.view.add_widget(pno)
            self.layout.add_widget(self.view)

            PrClock.schedule_once(trigger, 0)

            # return
            return self.layout
Exemple #7
0
    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)
Exemple #8
0
class PrMidi():
    """ play midi file(s) with callback support """

    # init
    def __init__(self, midi_filename=None, midi_portname=None):
        """ init """
        # main members
        self.midi_file = None
        self.midi_iter = None
        self.port = None

        # play related
        self._scheduled_evt = False
        self.playing = False
        self.callback = None
        self.callback_timebar = None

        # midi file related
        self.totalticks = None
        self.length = None
        self.tempo = None
        self.bpm = None
        self.ppqn = None
        self.spt = None
        self.msg = None
        self.cur_evt_time = .0
        self.cur_evt_tick = .0
        self.next_evt_time = .0
        self.next_evt_tick = .0
        self.start_time = .0

        # clock and helper classes
        self.clock = PrClock()
        self.helper = PrHelper()

        # actual init
        self.open(midi_filename, midi_portname)

    # midifile open/reload
    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)

    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()

    # get props
    def get_tempo(self):
        """ get tempo """
        if self.midi_file:
            tempotrack = self.midi_file.tracks[0]
            for msg in tempotrack:
                if msg.is_meta and msg.type == 'set_tempo':
                    return msg.tempo
        return None

    def get_ppqn(self):
        """ get ppqn(pulses per quarter note) """
        if self.midi_file:
            return self.midi_file.ticks_per_beat
        return None

    def get_spt(self):
        """ get second per tick """
        if self.ppqn:
            return mido.tick2second(1, self.ppqn, self.tempo)
        return None

    def get_totalticks(self, force=False):
        """ get total ticks of the song """
        if force or not self.totalticks:
            self.get_length(force=True)
        return self.totalticks

    def get_length(self, force=False, ticks=False):
        """ get total length of the song """
        if force or not self.length:
            """ reset the legnth """
            tempo = 600000
            ppqn = self.ppqn
            spt = tempo / ppqn / 1000000

            totalticks = 0

            # tempo track related
            tempoticks = 0
            tempolen = .0
            lasttempo = 0

            tempotrack = self.midi_file.tracks[0]

            # find the total tick / length of the tempo track
            for msg in tempotrack:
                tempoticks += msg.time
                tempolen += spt * msg.time
                if msg.is_meta and msg.type == 'set_tempo':
                    if tempo != msg.tempo:
                        tempo = msg.tempo
                        spt = tempo / ppqn / 1000000
                        lasttempo = msg.tempo

            # find the largest ticks in the tracks
            for track in self.midi_file.tracks:
                ticks = 0
                for msg in track:
                    ticks += msg.time
                if ticks > totalticks:
                    totalticks = ticks

            # calculate and set the length
            self.length = tempolen + mido.tick2second(totalticks - tempoticks,
                                                      ppqn, lasttempo)
            self.totalticks = totalticks
        if ticks:
            return self.totalticks
        else:
            return self.length

    # midifile trigger/play/stop
    def trigger(self, msg=None, callback=None, callback_timebar=None):
        """ trigger midifile play """
        if not self.playing:
            self.midi_file.iter_by_tick = True
            # set flag
            self.playing = True
            PrHelper.msg('PrMidi', 'Played at',
                         '{0:10.4f} sec'.format(self.start_time))

            try:
                self.msg = msg = next(self.midi_iter)
            except StopIteration:
                pass
            else:
                # set the next event time
                time = mido.tick2second(msg.time,
                                        self.midi_file.ticks_per_beat,
                                        self.midi_file.tempo)
                self.cur_evt_time = self.next_evt_time
                self.cur_evt_tick = self.next_evt_tick
                self.next_evt_time += time
                self.next_evt_tick += msg.time

                # set the callback
                self.callback = callback
                self.callback_timebar = callback_timebar

                # trigger!
                self._scheduled_evt = PrClock.schedule_interval_free(
                    self.playback, self.spt)

    def playback(self, now=0):
        """ callback for midifile play """
        if self.playing:
            # get now
            now = self.clock.elapsed(begin_with_this=True) + self.start_time
            # timbar callback
            if self.callback_timebar:
                self.callback_timebar(self, now)
            # if it's passed the next event time
            if now >= self.next_evt_time:
                # play current message
                self.play(self.msg, now)
                # run callback
                if self.callback:
                    self.callback(self, self.msg, now)
                # fetch next event message
                try:
                    self.msg = next(self.midi_iter)
                except StopIteration:
                    self.stop()
                else:
                    time = mido.tick2second(self.msg.time,
                                            self.midi_file.ticks_per_beat,
                                            self.midi_file.tempo)
                    self.cur_evt_time = self.next_evt_time
                    self.cur_evt_tick = self.next_evt_tick
                    self.next_evt_time += time
                    self.next_evt_tick += self.msg.time

    def stop(self):
        """ stop the current playback """
        if self.playing:
            # write the start time for next trigger
            self.start_time += self.clock.elapsed(begin_with_this=True)
            PrHelper.msg('PrMidi', 'Stopped at',
                         '{0:10.4f} sec'.format(self.start_time))
            # clear flag
            self.playing = False
            # reset port
            self.port.reset()
            # unschedule the callback
            self._scheduled_evt.cancel()
            # clock reset
            self.clock.set_timer()

    def rewind(self):
        """ rewind to zero """
        # backup playing status
        playing = self.playing

        # stop playing temporarily
        self.playing = False

        # clock reset
        self.port.reset()
        self.clock.set_timer()
        self.start_time = .0
        self.cur_evt_time = .0
        self.cur_evt_tick = .0
        self.next_evt_time = .0
        self.next_evt_tick = .0
        del self.midi_iter
        self.midi_iter = iter(self.midi_file)

        # recover playing status
        self.playing = playing

    def play(self, msg, now=0):
        """ send one event message """
        if msg.is_meta:
            pass
            #self.helper.log(now, msg)
        else:
            self.port.send(msg)
            #self.helper.log(now, msg)

    def second2tick(self, sec):
        return mido.second2tick(sec, self.midi_file.ticks_per_beat,
                                self.midi_file.tempo)
Exemple #9
0
        return mido.second2tick(sec, self.midi_file.ticks_per_beat,
                                self.midi_file.tempo)


if __name__ == '__main__':
    """
    from kivy.uix.widget import Widget
    from kivy.app import App
    class PlayApp(App):
        def build(self):
            self.prMidi = prMidi = PrMidi(
                midi_filename='.\\midi\\midifiles\\waldstein_1.mid',
                midi_portname='Microsoft GS Wavetable Synth 0')
    
            prMidi.test()            
            Clock.schedule_once(prMidi.trigger,0.5)

            return Widget()
    PlayApp().run()
    """
    prMidi = PrMidi(midi_filename='.\\midi\\midifiles\\waldstein_1.mid',
                    midi_portname='Microsoft GS Wavetable Synth 0')

    clock = PrClock()

    clock.set_timer(1)
    print("length from calculation : ", prMidi.get_length(), "(",
          clock.elapsed(1), ")")
    clock.set_timer(1)
    print("length from mido : ", prMidi.midi_file.length, "(",
          clock.elapsed(1), ")")