@client.set_process_callback
def process(frames):
    """Main callback."""
    events = {}
    buf = memoryview(audioport.get_buffer()).cast('f')
    for offset, data in midiport.incoming_midi_events():
        if len(data) == 3:
            status, pitch, vel = bytes(data)
            # MIDI channel number is ignored!
            status >>= 4
            if status == NOTEON and vel > 0:
                events.setdefault(offset, []).append((pitch, vel))
            elif status in (NOTEON, NOTEOFF):
                # NoteOff velocity is ignored!
                events.setdefault(offset, []).append((pitch, 0))
            else:
                pass  # ignore
        else:
            pass  # ignore
    for i in range(len(buf)):
        buf[i] = 0
        try:
            eventlist = events[i]
        except KeyError:
            pass
        else:
            for pitch, vel in eventlist:
                if pitch not in voices:
                    if not vel:
                        break
                    voices[pitch] = Voice(pitch)
                voices[pitch].trigger(vel)
        for voice in voices.values():
            voice.update()
            if voice.weight > 0:
                buf[i] += voice.weight * math.sin(2 * math.pi * voice.time)
                voice.time += voice.time_increment
                if voice.time >= 1:
                    voice.time -= 1
    dead = [k for k, v in voices.items() if v.weight <= 0]
    for pitch in dead:
        del voices[pitch]
dataset/ETHPy150Open spatialaudio/jackclient-python/examples/midi_sine.py/process/original