Exemple #1
0
 def __init__(self,
              peer_address,
              sport=0,
              rport=0,
              latency=20,
              jitter_buffer_size=10,
              safe_keyboard=0,
              recovery=1,
              follow_standard=0,
              verbose=0):
     #Init mother class
     RTPSession.__init__(self, peer_address, sport, rport, PAYLOAD,
                         jitter_buffer_size, TOOL_NAME)
     self.verbose = verbose
     if verbose:
         print("Your configuration:")
         print("  Latency:", latency, "ms")
         print("  Jitter Buffer Time:", jitter_buffer_size, "ms")
     #init midi
     if self.sport > 0:
         self.midi_in = MidiIn(self, verbose)
     #1 == Permisive mode (make this configurable)
     if self.rport > 0:
         self.midi_out = MidiOut(0, latency, safe_keyboard, verbose)
     #history of the feed
     self.packets_received_list = PacketCirc(HISTORY_SIZE)
     #Recovery utils
     self.recovery = 0
     self.recovery_journal_system = None
     if recovery:
         self.recovery = 1
         self.recovery_journal_system = RecoveryJournal(follow_standard)
         if verbose:
             print("  Recovery journal is running")
             if follow_standard:
                 print("  Recovery is following standard")
     self.init_timestamp = None
     #Flag
     self.sending_data = 0
     self.receiving_data = 0
     #Timestamp story
     self.last_midi_time_sent = pypm.Time()
     self.timeouterLoop = None
Exemple #2
0
 def __init__(self, peer_address, sport=0, rport=0, latency=20,
              jitter_buffer_size=10, safe_keyboard=0, recovery=1,
              follow_standard=0, verbose=0):
     #Init mother class
     RTPSession.__init__(self, peer_address, sport, rport, PAYLOAD,
                         jitter_buffer_size, TOOL_NAME)
     self.verbose = verbose
     if verbose:
         print "Your configuration:"
         print "  Latency:", latency, "ms"
         print "  Jitter Buffer Time:", jitter_buffer_size, "ms"
     #init midi
     if self.sport > 0:
         self.midi_in = MidiIn(self, verbose)
     #1 == Permisive mode (make this configurable)
     if self.rport > 0:
         self.midi_out = MidiOut(0, latency, safe_keyboard, verbose)
     #history of the feed
     self.packets_received_list = PacketCirc(HISTORY_SIZE)
     #Recovery utils
     self.recovery = 0
     self.recovery_journal_system = None
     if recovery:
         self.recovery = 1
         self.recovery_journal_system = RecoveryJournal(follow_standard)
         if verbose:
             print "  Recovery journal is running"
             if follow_standard:
                 print "  Recovery is following standard"
     self.init_timestamp = None
     #Flag
     self.sending_data = 0
     self.receiving_data = 0
     #Timestamp story
     self.last_midi_time_sent = pypm.Time()
     self.timeouterLoop = None
Exemple #3
0
class MidiSession(RTPSession):
    """
    Control RTP for MIDI payload.
    """
    def __init__(self,
                 peer_address,
                 sport=0,
                 rport=0,
                 latency=20,
                 jitter_buffer_size=10,
                 safe_keyboard=0,
                 recovery=1,
                 follow_standard=0,
                 verbose=0):
        #Init mother class
        RTPSession.__init__(self, peer_address, sport, rport, PAYLOAD,
                            jitter_buffer_size, TOOL_NAME)
        self.verbose = verbose
        if verbose:
            print("Your configuration:")
            print("  Latency:", latency, "ms")
            print("  Jitter Buffer Time:", jitter_buffer_size, "ms")
        #init midi
        if self.sport > 0:
            self.midi_in = MidiIn(self, verbose)
        #1 == Permisive mode (make this configurable)
        if self.rport > 0:
            self.midi_out = MidiOut(0, latency, safe_keyboard, verbose)
        #history of the feed
        self.packets_received_list = PacketCirc(HISTORY_SIZE)
        #Recovery utils
        self.recovery = 0
        self.recovery_journal_system = None
        if recovery:
            self.recovery = 1
            self.recovery_journal_system = RecoveryJournal(follow_standard)
            if verbose:
                print("  Recovery journal is running")
                if follow_standard:
                    print("  Recovery is following standard")
        self.init_timestamp = None
        #Flag
        self.sending_data = 0
        self.receiving_data = 0
        #Timestamp story
        self.last_midi_time_sent = pypm.Time()
        self.timeouterLoop = None

    def start(self):
        """
        Launch the MIDI session and the RTP session
        """
        if self.sport > 0:
            self.midi_in.start()
        if self.rport > 0:
            self.midi_out.start()
        self._keep_alive()

    def stop(self):
        """
        Stop midi session and the RTP session
        """
        if self.sport > 0:
            self.midi_in.stop()
        if self.rport > 0:
            self.midi_out.stop()
        if not self.timeouterLoop is None:
            if self.timeouterLoop.running:
                self.timeouterLoop.stop()

    def _keep_alive(self):
        #FIXME: document this
        def check_timeout():
            """
            Sends an empty packet if there is no activity.
            """
            if time.time() > self.last_send + MIDI_RTP_TIME_OUT:
                self.send_silence()
                #Deccomment following line if want to log keep aive packet
                #log.info("silent packet sent to keep alive the connection")
            self.timeouterLoop = task.LoopingCall(check_timeout, now=False)
            self.timeouterLoop.start(15)

    def incoming_rtp(self, cookie, timestamp, packet, read_recovery_journal=0):
        """
        Function called by RTPControl when incoming
        data comes out from jitter buffer.
        """
        #Parsing RTP MIDI Header
        marker_b, marker_j, marker_z, marker_p, length = \
            MidiCommand().parse_header(packet.data[0])
        if marker_p:
            #silent packet with recovery
            midi_list = []
        else:
            #normal packet
            #Extract Midi Note (length en nb notes)
            midi_list = packet.data[1:length * 7 + 1]
            #Decoding midi commands
            midi_list = MidiCommand().decode_midi_commands(midi_list, length)
        if DEBUG:
            print("receiving data", midi_list)
            #Saving feed history
            packet_to_save = OldPacket(self.seq, midi_list, 0)
            self.packets_received_list.to_list(packet_to_save)
        #Extract Midi Recovery Journal if is present in the packet and
        #the previous packet has been lost
        if self.recovery:
            if marker_j and read_recovery_journal:
                if DEBUG:
                    print("Read recovery journal")
                    print(packet.header.marker)
                journal = packet.data[length * 7 + 1:]
                if len(journal) > 0:
                    #Parse Recovery journal
                    r_journal = self.recovery_journal_system.parse(journal)
                else:
                    r_journal = []
                #compare it with history feed
                #Extract midi notes from checkpoint sent to actual seq
                midi_history = self.packets_received_list.get_packets(
                    self.last_checkpoint, self.seq)
                #Selecting only notes present in recovery
                #that are not in feed history
                midi_cmd_history = []
                for i in range(len(midi_history)):
                    cmd_tmp = midi_history[i].packet
                    for j in range(len(cmd_tmp)):
                        midi_cmd_history.append(cmd_tmp[j])
                if DEBUG:
                    rem = time()
                midi_from_history = compare_history_with_recovery(
                    r_journal, midi_cmd_history)
                if DEBUG:
                    print("tps for history compare:", str(time() - rem))
        #Initialize timestamp diff
        if self.init_timestamp is None:
            self.init_timestamp = timestamp
            #calculate delta midi
            self.midi_out.set_init_time()
        #adding recovery journal to the list
        if self.recovery:
            if marker_j and read_recovery_journal:
                midi_list.extend(midi_from_history)
        #profiter du parcours pour appliquer les timestamps
        for i in range(len(midi_list)):
            midi_list[i][1] = (timestamp - self.init_timestamp +
                               self.midi_out.init_time)
        #Adding the note to the playing buffer
        for i in range(len(midi_list)):
            self.midi_out.midi_cmd_list.put(midi_list[i])
        #switch off witness
        self.receiving_data = 0

    def send_silence(self):
        """
        Sends empty packet to signal a silent period
        """
        recovery_journal = ""
        marker_j = 0
        #Getting recovery
        if self.recovery:
            recovery_journal = self.recovery_journal_system.content
            if recovery_journal != "":
                #Recovery Journal 1 if present
                marker_j = 1
        #Creating empty midicommand filed
        header = MidiCommand().header(0, marker_j, 1, 1, 0)
        if recovery_journal != "":
            chunk = header + recovery_journal
        else:
            chunk = str(0)
        #sending silent packet with recovery journal
        RTPSession.send_empty_packet(self, chunk)
        #RTPControl().send_empty_packet(self.cookie, chunk)

    def send_midi_data(self, data, midi_time, recovery=1, timestamp=1):
        """
        Sends MIDI data through the RTP session.
        """
        if DEBUG:
            print("Sending data", data)
        #Witness
        self.sending_data = 1
        #midi Cmd List
        midi_list = data
        #Saving packet
        packet = OldPacket(self.seq, midi_list, 0)
        chunk = ""
        recovery_journal = ""
        if recovery:
            #Recovery Journal (can be empty)
            #TODO customize it for each member of the feed
            if self.recovery_journal_system is not None:
                recovery_journal = self.recovery_journal_system.content
                if recovery_journal == "":
                    recovery = 0
        #Packing All
        #Testing length of midi list ( in nb notes )
        if len(midi_list) < 1:
            return
        #Formating commands for network
        midi_list_formated, length = \
            MidiCommand().encode_midi_commands(midi_list)
        #Creating Header
        header = MidiCommand().header(0, recovery, 0, 0, length)
        #Building Chunk
        chunk = header + midi_list_formated + recovery_journal
        #Timestamp care (TS == temps midi ecouler depuis la creation de rtp)
        ts = midi_time - self.last_midi_time_sent
        self.last_midi_time_sent = midi_time
        #sending data to rtp session
        RTPSession.send_data(self, chunk, ts)
        self.sending_data = 0
        #Updating Recovery Journal
        if self.recovery:
            self.recovery_journal_system.update(packet)

    def update_checkpoint(self, new_checkpoint):
        """
        Function called by RTCP to reduce size of recovery journal.
        """
        if self.recovery:
            self.recovery_journal_system.trim(new_checkpoint)

        self.checkpoint = new_checkpoint

    def drop_connection(self, cookie=0):
        """
        Called by RTP when the connection has been dropped.
        """
        #Rename drop connection
        print("drop connexion for midi session")

    def get_devices(self):
        """
        Lists MIDI devices on this computer.
        @rtype: tuple
        @return: Tuple of list of device info. Input devices first, then output devices.
        """
        #FIXME: return a dict, not a tuple.
        if self.sport > 0:
            devices_in = self.midi_in.get_devices()
        else:
            devices_in = []
        if self.rport > 0:
            devices_out = self.midi_out.get_devices()
        else:
            devices_out = []
        return devices_in, devices_out

    def set_device_in(self, dev):
        """
        Selects the MIDI device to be polled.

        @param dev: The device number to choose.
        @type dev: int
        @rtype: bool
        @return: Success or not
        """
        return self.midi_in.set_device(dev)

    def set_device_out(self, dev):
        """
        Selects the MIDI output device to send data to.

        @param dev: The device number to choose.
        @type dev: int
        @rtype: bool
        @return: Success or not
        """
        return self.midi_out.set_device(dev)
Exemple #4
0
 def setUp(self):
     self.midi_out = MidiOut(1, 10)
Exemple #5
0
class TestMidiOut(unittest.TestCase):
    """Test on MidiOut class"""

    def setUp(self):
        self.midi_out = MidiOut(1, 10)

    def tearDown(self):
        del self.midi_out

    def test_get_devices(self):
        self.midi_out.get_devices()
        assert(len(self.midi_out.midi_device_list) > 0), \
            self.fail("Problem getting devices")

    def test_get_device_info(self):
        #setting device midi
        self.midi_out.get_devices()
        self.midi_out.set_device(self.midi_out.midi_device_list[0][0])

        #Getting device infos
        res = self.midi_out.get_device_info()
        print res

        #Testing device infos
        assert(res[1] == "Midi Through Port-0"), \
            self.fail("Problem getting right info from midi device")

    def test_set_device(self):
        #Getting list of midi device
        self.midi_out.get_devices()

        #Setting and testing midi device
        if len(self.midi_out.midi_device_list) > 0:
            dev_to_use = self.midi_out.midi_device_list
            res = self.midi_out.set_device(dev_to_use[0][0])
            assert( res == True ), self.fail("Problem setting midi device out")
        else:
            self.fail("Problem getting list of midi" \
                          + " devices or no midi device available.")

    def test_start(self):
        #Without device
        res = self.midi_out.start()
        assert(res == 0), \
            self.fail("Can start publy before setting a midi device")

        #With device
        self.midi_out.get_devices()

        dev = self.midi_out.set_device(self.midi_out.midi_device_list[0][0])

        if dev == 0:
            res = self.midi_out.start()
            assert(res == 1), \
                self.fail("Can't start publy with a midi device set")

    def test_send_note_off(self):
        self.midi_out.get_devices()
        self.midi_out.set_device(self.midi_out.midi_device_list[0][0])
        self.midi_out.send_note_off()
        #Nothin to test ??

    def test_play_midi_notes(self):
        pass

    def test_publish_midi_notes(self):
        pass
Exemple #6
0
class MidiSession(RTPSession):
    """
    Control RTP for MIDI payload.
    """
    def __init__(self, peer_address, sport=0, rport=0, latency=20,
                 jitter_buffer_size=10, safe_keyboard=0, recovery=1,
                 follow_standard=0, verbose=0):
        #Init mother class
        RTPSession.__init__(self, peer_address, sport, rport, PAYLOAD,
                            jitter_buffer_size, TOOL_NAME)
        self.verbose = verbose
        if verbose:
            print "Your configuration:"
            print "  Latency:", latency, "ms"
            print "  Jitter Buffer Time:", jitter_buffer_size, "ms"
        #init midi
        if self.sport > 0:
            self.midi_in = MidiIn(self, verbose)
        #1 == Permisive mode (make this configurable)
        if self.rport > 0:
            self.midi_out = MidiOut(0, latency, safe_keyboard, verbose)
        #history of the feed
        self.packets_received_list = PacketCirc(HISTORY_SIZE)
        #Recovery utils
        self.recovery = 0
        self.recovery_journal_system = None
        if recovery:
            self.recovery = 1
            self.recovery_journal_system = RecoveryJournal(follow_standard)
            if verbose:
                print "  Recovery journal is running"
                if follow_standard:
                    print "  Recovery is following standard"
        self.init_timestamp = None
        #Flag
        self.sending_data = 0
        self.receiving_data = 0
        #Timestamp story
        self.last_midi_time_sent = pypm.Time()
        self.timeouterLoop = None

    def start(self):
        """
        Launch the MIDI session and the RTP session
        """
        if self.sport > 0:
            self.midi_in.start()
        if self.rport > 0:
            self.midi_out.start()
        self._keep_alive()

    def stop(self):
        """
        Stop midi session and the RTP session
        """
        if self.sport > 0:
            self.midi_in.stop()
        if self.rport > 0:
            self.midi_out.stop()
        if not self.timeouterLoop is None:
            if self.timeouterLoop.running:
                self.timeouterLoop.stop()

    def _keep_alive(self):
        #FIXME: document this
        def check_timeout():
            """
            Sends an empty packet if there is no activity.
            """
            if time.time() > self.last_send + MIDI_RTP_TIME_OUT:
                self.send_silence()
                #Deccomment following line if want to log keep aive packet
                #log.info("silent packet sent to keep alive the connection")
            self.timeouterLoop = task.LoopingCall(check_timeout, now=False)
            self.timeouterLoop.start(15)

    def incoming_rtp(self, cookie, timestamp, packet, read_recovery_journal=0):
        """
        Function called by RTPControl when incoming
        data comes out from jitter buffer.
        """
        #Parsing RTP MIDI Header
        marker_b, marker_j, marker_z, marker_p, length = \
            MidiCommand().parse_header(packet.data[0])
        if marker_p :
            #silent packet with recovery
            midi_list = []
        else:
            #normal packet
            #Extract Midi Note (length en nb notes)
            midi_list = packet.data[1:length*7+1]
            #Decoding midi commands
            midi_list =  MidiCommand().decode_midi_commands(midi_list, length)
        if DEBUG:
            print "receiving data", midi_list
            #Saving feed history
            packet_to_save = OldPacket(self.seq, midi_list, 0)
            self.packets_received_list.to_list(packet_to_save)
        #Extract Midi Recovery Journal if is present in the packet and
        #the previous packet has been lost
        if self.recovery:
            if marker_j and read_recovery_journal:
                if DEBUG:
                    print "Read recovery journal"
                    print packet.header.marker
                journal = packet.data[length*7+1:]
                if len(journal)>0:
                    #Parse Recovery journal
                    r_journal = self.recovery_journal_system.parse(journal)
                else:
                    r_journal = []
                #compare it with history feed
                #Extract midi notes from checkpoint sent to actual seq
                midi_history = self.packets_received_list.get_packets(self.last_checkpoint,self.seq)
                #Selecting only notes present in recovery
                #that are not in feed history
                midi_cmd_history = []
                for i in range(len(midi_history)):
                    cmd_tmp = midi_history[i].packet
                    for j in range(len(cmd_tmp)):
                        midi_cmd_history.append(cmd_tmp[j])
                if DEBUG:
                    rem = time()
                midi_from_history = compare_history_with_recovery(r_journal, midi_cmd_history)
                if DEBUG:
                    print "tps for history compare:", str(time() - rem)
        #Initialize timestamp diff
        if self.init_timestamp is None:
            self.init_timestamp = timestamp
            #calculate delta midi
            self.midi_out.set_init_time()
        #adding recovery journal to the list
        if self.recovery:
            if marker_j and read_recovery_journal:
                midi_list.extend(midi_from_history)
        #profiter du parcours pour appliquer les timestamps
        for i in range(len(midi_list)):
            midi_list[i][1] = (timestamp - self.init_timestamp + self.midi_out.init_time)
        #Adding the note to the playing buffer
        for i in range(len(midi_list)):
            self.midi_out.midi_cmd_list.put(midi_list[i])
        #switch off witness
        self.receiving_data = 0

    def send_silence(self):
        """
        Sends empty packet to signal a silent period
        """
        recovery_journal = ""
        marker_j = 0
        #Getting recovery
        if self.recovery:
            recovery_journal = self.recovery_journal_system.content
            if recovery_journal != "":
                #Recovery Journal 1 if present
                marker_j = 1
        #Creating empty midicommand filed
        header = MidiCommand().header(0, marker_j, 1, 1, 0)
        if recovery_journal != "":
            chunk = header + recovery_journal
        else:
            chunk = str(0)
        #sending silent packet with recovery journal
        RTPSession.send_empty_packet(self, chunk)
        #RTPControl().send_empty_packet(self.cookie, chunk)

    def send_midi_data(self, data, midi_time, recovery=1, timestamp=1):
        """
        Sends MIDI data through the RTP session.
        """
        if DEBUG:
            print "Sending data", data
        #Witness
        self.sending_data = 1
        #midi Cmd List
        midi_list = data
        #Saving packet
        packet = OldPacket(self.seq, midi_list, 0)
        chunk = ""
        recovery_journal = ""
        if recovery:
            #Recovery Journal (can be empty)
            #TODO customize it for each member of the feed
            if self.recovery_journal_system is not None:
                recovery_journal = self.recovery_journal_system.content
                if recovery_journal == "":
                    recovery = 0
        #Packing All
        #Testing length of midi list ( in nb notes )
        if len(midi_list) < 1:
            return
        #Formating commands for network
        midi_list_formated, length = \
            MidiCommand().encode_midi_commands(midi_list)
        #Creating Header
        header = MidiCommand().header(0, recovery, 0, 0, length)
        #Building Chunk
        chunk = header + midi_list_formated + recovery_journal
        #Timestamp care (TS == temps midi ecouler depuis la creation de rtp)
        ts = midi_time - self.last_midi_time_sent
        self.last_midi_time_sent = midi_time
        #sending data to rtp session
        RTPSession.send_data(self, chunk, ts)
        self.sending_data = 0
        #Updating Recovery Journal
        if self.recovery:
            self.recovery_journal_system.update(packet)

    def update_checkpoint(self, new_checkpoint):
        """
        Function called by RTCP to reduce size of recovery journal.
        """
        if self.recovery:
            self.recovery_journal_system.trim(new_checkpoint)

        self.checkpoint = new_checkpoint

    def drop_connection(self, cookie=0):
        """
        Called by RTP when the connection has been dropped.
        """
        #Rename drop connection
        print "drop connexion for midi session"

    def get_devices(self):
        """
        Lists MIDI devices on this computer.
        @rtype: tuple
        @return: Tuple of list of device info. Input devices first, then output devices.
        """
        #FIXME: return a dict, not a tuple.
        if self.sport > 0:
            devices_in = self.midi_in.get_devices()
        else:
            devices_in = []
        if self.rport > 0:
            devices_out = self.midi_out.get_devices()
        else:
            devices_out = []
        return devices_in, devices_out

    def set_device_in(self, dev):
        """
        Selects the MIDI device to be polled.

        @param dev: The device number to choose.
        @type dev: int
        @rtype: bool
        @return: Success or not
        """
        return self.midi_in.set_device(dev)

    def set_device_out(self, dev):
        """
        Selects the MIDI output device to send data to.

        @param dev: The device number to choose.
        @type dev: int
        @rtype: bool
        @return: Success or not
        """
        return self.midi_out.set_device(dev)
Exemple #7
0
 def setUp(self):
     self.midi_out = MidiOut(1, 10)
Exemple #8
0
class TestMidiOut(unittest.TestCase):
    """Test on MidiOut class"""
    def setUp(self):
        self.midi_out = MidiOut(1, 10)

    def tearDown(self):
        del self.midi_out

    def test_get_devices(self):
        self.midi_out.get_devices()
        assert(len(self.midi_out.midi_device_list) > 0), \
            self.fail("Problem getting devices")

    def test_get_device_info(self):
        #setting device midi
        self.midi_out.get_devices()
        self.midi_out.set_device(self.midi_out.midi_device_list[0][0])

        #Getting device infos
        res = self.midi_out.get_device_info()
        print res

        #Testing device infos
        assert(res[1] == "Midi Through Port-0"), \
            self.fail("Problem getting right info from midi device")

    def test_set_device(self):
        #Getting list of midi device
        self.midi_out.get_devices()

        #Setting and testing midi device
        if len(self.midi_out.midi_device_list) > 0:
            dev_to_use = self.midi_out.midi_device_list
            res = self.midi_out.set_device(dev_to_use[0][0])
            assert (res == True), self.fail("Problem setting midi device out")
        else:
            self.fail("Problem getting list of midi" \
                          + " devices or no midi device available.")

    def test_start(self):
        #Without device
        res = self.midi_out.start()
        assert(res == 0), \
            self.fail("Can start publy before setting a midi device")

        #With device
        self.midi_out.get_devices()

        dev = self.midi_out.set_device(self.midi_out.midi_device_list[0][0])

        if dev == 0:
            res = self.midi_out.start()
            assert(res == 1), \
                self.fail("Can't start publy with a midi device set")

    def test_send_note_off(self):
        self.midi_out.get_devices()
        self.midi_out.set_device(self.midi_out.midi_device_list[0][0])
        self.midi_out.send_note_off()
        #Nothin to test ??

    def test_play_midi_notes(self):
        pass

    def test_publish_midi_notes(self):
        pass