mik3y / pymidi

Python library for building RTP-MIDI / AppleMIDI clients and servers
MIT License
47 stars 11 forks source link

Exception for _last_command_byte #33

Open Brettles opened 1 year ago

Brettles commented 1 year ago

Under some circumstances (it seems when there are many packets in flight from a remote peer) there is an exception raised:

Traceback (most recent call last):
  File "/home/ubuntu/python/construct/lib/containers.py", line 93, in __getattr__
    return self[name]
KeyError: '_last_command_byte'

I can see in the code where this is being used but I don't have enough knowledge to figure out how to solve this.

Brettles commented 1 year ago

Sorry (about many things including the noise) - this is actually a reproducible issue that I thought I'd figured out.

Test rig is a MIDI keyboard attached to a MAC sending traffic to a Linux machine running pymidi. There the MIDI commands are sent to another RTP-connected host. The exception is raised during the creation of a new packet, so:

    try:
        packet = packets.MIDIPacket.create(
            header={
                'rtp_header': {
                    'flags': {
                        'v': 0x2,
                        'p': 0,
                        'x': 0,
                        'cc': 0,
                        'm': 0,
                        'pt': 0x61
                    },
                    'sequence_number': sequenceNumber
                },
                'timestamp': get_timestamp(),
                'ssrc': outputSocket.ssrc
            },
            command={
                'flags': {
                    'b': 0,
                    'j': 1 if journal else 0,
                    'z': 0,
                    'p': 0,
                    'len': 3+4*(len(commandList)-1),
                },
                'midi_list': commandList,
            },
            journal=journal
        )
    except Exception as e:
        print(f'Packet encode exception: {e}')

When there are a large number of MIDI commands being sent (for example when spinning the modulation wheel) sometimes this code throws an exception as above. I'm not familiar enough with Construct to figure out what is going on but in only happens sometimes.

I'm happy to do a packet capture and figure out what is being sent if that will help.

Brettles commented 1 year ago

Just in case it helps, here's the inbound packet that causes the exception. If I try to create another MIDI packet with this as the input I get the error as described:

Container:
    header = Container:
        rtp_header = Container:
            flags = Container:
                v = 2
                p = False
                x = False
                cc = 0
                m = False
                pt = 97
            sequence_number = 24218
        timestamp = 660835598
        ssrc = 2393251505
    command = Container:
        flags = Container:
            b = False
            j = True
            z = False
            p = False
            len = 6
        midi_list = ListContainer:
            Container:
                delta_time = None
                command_byte = 144
                command = (enum) note_on 144
                channel = 0
                params = Container:
                    key = (enum) B3 59
                    velocity = 25
            Container:
                delta_time = 37
                command_byte = 144
                command = (enum) note_on 144
                channel = 0
                params = Container:
                    key = (enum) G3 55
                    velocity = 127
    journal = Container:
        header = Container:
            s = False
            y = False
            a = True
            h = False
            totchan = 0
        checkpoint_seqnum = 24091
        system_journal = None
        channel_journal = Container:
            header = Container:
                s = False
                chan = 0
                h = False
                length = 12
                p = False
                c = False
                m = False
                w = True
                n = True
                e = False
                t = False
                a = False
            journal = b'\x80@\x81h9\x7f\xad\x1a\xc0' (total 9)