// File: tobias93[P]piano/rtmidi_build/RtMidi.cpp
// Function: alsaMidiHandler(void*)
static void *alsaMidiHandler( void *ptr )
{
  MidiInApi::RtMidiInData *data = static_cast<MidiInApi::RtMidiInData *> (ptr);
  AlsaMidiData *apiData = static_cast<AlsaMidiData *> (data->apiData);

  long nBytes;
  unsigned long long time, lastTime;
  bool continueSysex = false;
  bool doDecode = false;
  MidiInApi::MidiMessage message;
  int poll_fd_count;
  struct pollfd *poll_fds;

  snd_seq_event_t *ev;
  int result;
  apiData->bufferSize = 32;
  result = snd_midi_event_new( 0, &apiData->coder );
  if ( result < 0 ) {
    data->doInput = false;
    std::cerr << "\nMidiInAlsa::alsaMidiHandler: error initializing MIDI event parser!\n\n";
    return 0;
  }
  unsigned char *buffer = (unsigned char *) malloc( apiData->bufferSize );
  if ( buffer == NULL ) {
    data->doInput = false;
    snd_midi_event_free( apiData->coder );
    apiData->coder = 0;
    std::cerr << "\nMidiInAlsa::alsaMidiHandler: error initializing buffer memory!\n\n";
    return 0;
  }
  snd_midi_event_init( apiData->coder );
  snd_midi_event_no_status( apiData->coder, 1 ); // suppress running status messages

  poll_fd_count = snd_seq_poll_descriptors_count( apiData->seq, POLLIN ) + 1;
  poll_fds = (struct pollfd*)alloca( poll_fd_count * sizeof( struct pollfd ));
  snd_seq_poll_descriptors( apiData->seq, poll_fds + 1, poll_fd_count - 1, POLLIN );
  poll_fds[0].fd = apiData->trigger_fds[0];
  poll_fds[0].events = POLLIN;

  while ( data->doInput ) {

    if ( snd_seq_event_input_pending( apiData->seq, 1 ) == 0 ) {
      // No data pending
      if ( poll( poll_fds, poll_fd_count, -1) >= 0 ) {
        if ( poll_fds[0].revents & POLLIN ) {
          bool dummy;
          int res = read( poll_fds[0].fd, &dummy, sizeof(dummy) );
          (void) res;
        }
      }
      continue;
    }

    // If here, there should be data.
    result = snd_seq_event_input( apiData->seq, &ev );
    if ( result == -ENOSPC ) {
      std::cerr << "\nMidiInAlsa::alsaMidiHandler: MIDI input buffer overrun!\n\n";
      continue;
    }
    else if ( result <= 0 ) {
      std::cerr << "\nMidiInAlsa::alsaMidiHandler: unknown MIDI input error!\n";
      perror("System reports");
      continue;
    }

    // This is a bit weird, but we now have to decode an ALSA MIDI
    // event (back) into MIDI bytes.  We'll ignore non-MIDI types.
    if ( !continueSysex ) message.bytes.clear();

    doDecode = false;
    switch ( ev->type ) {

    case SND_SEQ_EVENT_PORT_SUBSCRIBED:
#if defined(__RTMIDI_DEBUG__)
      std::cout << "MidiInAlsa::alsaMidiHandler: port connection made!\n";
#endif
      break;

    case SND_SEQ_EVENT_PORT_UNSUBSCRIBED:
#if defined(__RTMIDI_DEBUG__)
      std::cerr << "MidiInAlsa::alsaMidiHandler: port connection has closed!\n";
      std::cout << "sender = " << (int) ev->data.connect.sender.client << ":"
                << (int) ev->data.connect.sender.port
                << ", dest = " << (int) ev->data.connect.dest.client << ":"
                << (int) ev->data.connect.dest.port
                << std::endl;
#endif
      break;

    case SND_SEQ_EVENT_QFRAME: // MIDI time code
      if ( !( data->ignoreFlags & 0x02 ) ) doDecode = true;
      break;

    case SND_SEQ_EVENT_TICK: // 0xF9 ... MIDI timing tick
      if ( !( data->ignoreFlags & 0x02 ) ) doDecode = true;
      break;

    case SND_SEQ_EVENT_CLOCK: // 0xF8 ... MIDI timing (clock) tick
      if ( !( data->ignoreFlags & 0x02 ) ) doDecode = true;
      break;

    case SND_SEQ_EVENT_SENSING: // Active sensing
      if ( !( data->ignoreFlags & 0x04 ) ) doDecode = true;
      break;

		case SND_SEQ_EVENT_SYSEX:
      if ( (data->ignoreFlags & 0x01) ) break;
      if ( ev->data.ext.len > apiData->bufferSize ) {
        apiData->bufferSize = ev->data.ext.len;
        free( buffer );
        buffer = (unsigned char *) malloc( apiData->bufferSize );
        if ( buffer == NULL ) {
          data->doInput = false;
          std::cerr << "\nMidiInAlsa::alsaMidiHandler: error resizing buffer memory!\n\n";
          break;
        }
      }

    default:
      doDecode = true;
    }

    if ( doDecode ) {

      nBytes = snd_midi_event_decode( apiData->coder, buffer, apiData->bufferSize, ev );
      if ( nBytes > 0 ) {
        // The ALSA sequencer has a maximum buffer size for MIDI sysex
        // events of 256 bytes.  If a device sends sysex messages larger
        // than this, they are segmented into 256 byte chunks.  So,
        // we'll watch for this and concatenate sysex chunks into a
        // single sysex message if necessary.
        if ( !continueSysex )
          message.bytes.assign( buffer, &buffer[nBytes] );
        else
          message.bytes.insert( message.bytes.end(), buffer, &buffer[nBytes] );

        continueSysex = ( ( ev->type == SND_SEQ_EVENT_SYSEX ) && ( message.bytes.back() != 0xF7 ) );
        if ( !continueSysex ) {

          // Calculate the time stamp:
          message.timeStamp = 0.0;

          // Method 1: Use the system time.
          //(void)gettimeofday(&tv, (struct timezone *)NULL);
          //time = (tv.tv_sec * 1000000) + tv.tv_usec;

          // Method 2: Use the ALSA sequencer event time data.
          // (thanks to Pedro Lopez-Cabanillas!).
          time = ( ev->time.time.tv_sec * 1000000 ) + ( ev->time.time.tv_nsec/1000 );
          lastTime = time;
          time -= apiData->lastTime;
          apiData->lastTime = lastTime;
          if ( data->firstMessage == true )
            data->firstMessage = false;
          else
            message.timeStamp = time * 0.000001;
        }
        else {
#if defined(__RTMIDI_DEBUG__)
          std::cerr << "\nMidiInAlsa::alsaMidiHandler: event parsing error or not a MIDI event!\n\n";
#endif
        }
      }
    }

    snd_seq_free_event( ev );
    if ( message.bytes.size() == 0 || continueSysex ) continue;

    if ( data->usingCallback ) {
      RtMidiIn::RtMidiCallback callback = (RtMidiIn::RtMidiCallback) data->userCallback;
      callback( message.timeStamp, &message.bytes, data->userData );
    }
    else {
      // As long as we haven't reached our queue size limit, push the message.
      if ( data->queue.size < data->queue.ringSize ) {
        data->queue.ring[data->queue.back++] = message;
        if ( data->queue.back == data->queue.ringSize )
          data->queue.back = 0;
        data->queue.size++;
      }
      else
        std::cerr << "\nMidiInAlsa: message queue limit reached!!\n\n";
    }
  }

  if ( buffer ) free( buffer );
  snd_midi_event_free( apiData->coder );
  apiData->coder = 0;
  apiData->thread = apiData->dummy_thread_id;
  return 0;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x100, %rsp            # imm = 0x100
movq %rdi, -0x10(%rbp)
movq -0x10(%rbp), %rax
movq %rax, -0x18(%rbp)
movq -0x18(%rbp), %rax
movq 0x40(%rax), %rax
movq %rax, -0x20(%rbp)
movb $0x0, -0x39(%rbp)
movb $0x0, -0x3a(%rbp)
leaq -0x60(%rbp), %rdi
callq 0xd920
movq -0x20(%rbp), %rax
movl $0x20, 0x20(%rax)
movq -0x20(%rbp), %rsi
addq $0x18, %rsi
xorl %eax, %eax
movl %eax, %edi
callq 0xe050
movl %eax, -0xc4(%rbp)
jmp 0x10d08
movl -0xc4(%rbp), %eax
movl %eax, -0x7c(%rbp)
cmpl $0x0, -0x7c(%rbp)
jge 0x10d6b
movq -0x18(%rbp), %rax
movb $0x0, 0x39(%rax)
movq 0xe2ca(%rip), %rdi      # 0x1eff0
leaq 0x8af9(%rip), %rsi      # 0x19826
callq 0xda30
jmp 0x10d34
movq $0x0, -0x8(%rbp)
movl $0x1, -0x90(%rbp)
jmp 0x113ed
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x88(%rbp)
movl %eax, -0x8c(%rbp)
leaq -0x60(%rbp), %rdi
callq 0xde20
jmp 0x113ff
movq -0x20(%rbp), %rax
movl 0x20(%rax), %eax
movl %eax, %edi
callq 0xdf10
movq %rax, -0x98(%rbp)
cmpq $0x0, -0x98(%rbp)
jne 0x10dd9
movq -0x18(%rbp), %rax
movb $0x0, 0x39(%rax)
movq -0x20(%rbp), %rax
movq 0x18(%rax), %rdi
callq 0xe580
jmp 0x10da1
movq -0x20(%rbp), %rax
movq $0x0, 0x18(%rax)
movq 0xe23c(%rip), %rdi      # 0x1eff0
leaq 0x8ab1(%rip), %rsi      # 0x1986c
callq 0xda30
jmp 0x10dc2
movq $0x0, -0x8(%rbp)
movl $0x1, -0x90(%rbp)
jmp 0x113ed
movq -0x20(%rbp), %rax
movq 0x18(%rax), %rdi
callq 0xd470
jmp 0x10de8
movq -0x20(%rbp), %rax
movq 0x18(%rax), %rdi
movl $0x1, %esi
callq 0xdf20
jmp 0x10dfc
movq -0x20(%rbp), %rax
movq (%rax), %rdi
movl $0x1, %esi
callq 0xd750
movl %eax, -0xc8(%rbp)
jmp 0x10e15
movl -0xc8(%rbp), %eax
incl %eax
movl %eax, -0x64(%rbp)
movslq -0x64(%rbp), %rax
leaq 0xf(,%rax,8), %rcx
andq $-0x10, %rcx
movq %rsp, %rax
subq %rcx, %rax
movq %rax, %rsp
movq %rax, -0x70(%rbp)
movq -0x20(%rbp), %rax
movq (%rax), %rdi
movq -0x70(%rbp), %rsi
addq $0x8, %rsi
movl -0x64(%rbp), %edx
decl %edx
movl $0x1, %ecx
callq 0xd9c0
jmp 0x10e5d
movq -0x20(%rbp), %rax
movl 0x4c(%rax), %ecx
movq -0x70(%rbp), %rax
movl %ecx, (%rax)
movq -0x70(%rbp), %rax
movw $0x1, 0x4(%rax)
movq -0x18(%rbp), %rax
testb $0x1, 0x39(%rax)
je 0x1139a
movq -0x20(%rbp), %rax
movq (%rax), %rdi
movl $0x1, %esi
callq 0xd250
movl %eax, -0xcc(%rbp)
jmp 0x10e9b
movl -0xcc(%rbp), %eax
cmpl $0x0, %eax
jne 0x10f0f
movq -0x70(%rbp), %rdi
movslq -0x64(%rbp), %rsi
movl $0xffffffff, %edx       # imm = 0xFFFFFFFF
callq 0xe1b0
movl %eax, -0xd0(%rbp)
jmp 0x10ec0
movl -0xd0(%rbp), %eax
cmpl $0x0, %eax
jl 0x10f0a
movq -0x70(%rbp), %rax
movswl 0x6(%rax), %eax
andl $0x1, %eax
cmpl $0x0, %eax
je 0x10f08
movq -0x70(%rbp), %rax
movl (%rax), %edi
leaq -0x99(%rbp), %rsi
movl $0x1, %edx
callq 0xe0f0
movq %rax, -0xd8(%rbp)
jmp 0x10efb
movq -0xd8(%rbp), %rax
movl %eax, -0xa0(%rbp)
jmp 0x10f0a
jmp 0x10e74
movq -0x20(%rbp), %rax
movq (%rax), %rdi
leaq -0x78(%rbp), %rsi
callq 0xe330
movl %eax, -0xdc(%rbp)
jmp 0x10f27
movl -0xdc(%rbp), %eax
movl %eax, -0x7c(%rbp)
cmpl $-0x1c, -0x7c(%rbp)
jne 0x10f50
movq 0xe0b3(%rip), %rdi      # 0x1eff0
leaq 0x896a(%rip), %rsi      # 0x198ae
callq 0xda30
jmp 0x10f4b
jmp 0x10e74
cmpl $0x0, -0x7c(%rbp)
jg 0x10f7e
movq 0xe093(%rip), %rdi      # 0x1eff0
leaq 0x8985(%rip), %rsi      # 0x198e9
callq 0xda30
jmp 0x10f6b
leaq 0x89b0(%rip), %rdi      # 0x19922
callq 0xd840
jmp 0x10f79
jmp 0x10e74
jmp 0x10f80
testb $0x1, -0x39(%rbp)
jne 0x10f8f
leaq -0x60(%rbp), %rdi
callq 0xe3b0
movb $0x0, -0x3a(%rbp)
movq -0x78(%rbp), %rax
movzbl (%rax), %eax
movl %eax, -0xe0(%rbp)
subl $0x16, %eax
je 0x1100c
jmp 0x10fa7
movl -0xe0(%rbp), %eax
subl $0x24, %eax
je 0x1103e
jmp 0x10fb8
movl -0xe0(%rbp), %eax
subl $0x25, %eax
je 0x11025
jmp 0x10fc5
movl -0xe0(%rbp), %eax
subl $0x2a, %eax
je 0x11057
jmp 0x10fd6
movl -0xe0(%rbp), %eax
subl $0x42, %eax
je 0x11002
jmp 0x10fe3
movl -0xe0(%rbp), %eax
subl $0x43, %eax
je 0x11007
jmp 0x10ff0
movl -0xe0(%rbp), %eax
subl $0x82, %eax
je 0x11070
jmp 0x110ee
jmp 0x110f2
jmp 0x110f2
movq -0x18(%rbp), %rax
movzbl 0x38(%rax), %eax
andl $0x2, %eax
cmpl $0x0, %eax
jne 0x11020
movb $0x1, -0x3a(%rbp)
jmp 0x110f2
movq -0x18(%rbp), %rax
movzbl 0x38(%rax), %eax
andl $0x2, %eax
cmpl $0x0, %eax
jne 0x11039
movb $0x1, -0x3a(%rbp)
jmp 0x110f2
movq -0x18(%rbp), %rax
movzbl 0x38(%rax), %eax
andl $0x2, %eax
cmpl $0x0, %eax
jne 0x11052
movb $0x1, -0x3a(%rbp)
jmp 0x110f2
movq -0x18(%rbp), %rax
movzbl 0x38(%rax), %eax
andl $0x4, %eax
cmpl $0x0, %eax
jne 0x1106b
movb $0x1, -0x3a(%rbp)
jmp 0x110f2
movq -0x18(%rbp), %rax
movzbl 0x38(%rax), %eax
andl $0x1, %eax
cmpl $0x0, %eax
je 0x11082
jmp 0x110f2
movq -0x78(%rbp), %rax
movl 0x10(%rax), %eax
movq -0x20(%rbp), %rcx
cmpl 0x20(%rcx), %eax
jbe 0x110ec
movq -0x78(%rbp), %rax
movl 0x10(%rax), %ecx
movq -0x20(%rbp), %rax
movl %ecx, 0x20(%rax)
movq -0x98(%rbp), %rdi
callq 0xdd40
movq -0x20(%rbp), %rax
movl 0x20(%rax), %eax
movl %eax, %edi
callq 0xdf10
movq %rax, -0x98(%rbp)
cmpq $0x0, -0x98(%rbp)
jne 0x110ea
movq -0x18(%rbp), %rax
movb $0x0, 0x39(%rax)
movq 0xdf16(%rip), %rdi      # 0x1eff0
leaq 0x8850(%rip), %rsi      # 0x19931
callq 0xda30
jmp 0x110e8
jmp 0x110f2
jmp 0x110ec
jmp 0x110ee
movb $0x1, -0x3a(%rbp)
testb $0x1, -0x3a(%rbp)
je 0x112c2
movq -0x20(%rbp), %rax
movq 0x18(%rax), %rdi
movq -0x98(%rbp), %rsi
movl 0x20(%rax), %eax
movl %eax, %edx
movq -0x78(%rbp), %rcx
callq 0xdcc0
movq %rax, -0xe8(%rbp)
jmp 0x11122
movq -0xe8(%rbp), %rax
movq %rax, -0x28(%rbp)
cmpq $0x0, -0x28(%rbp)
jle 0x112c0
testb $0x1, -0x39(%rbp)
jne 0x1115c
movq -0x98(%rbp), %rsi
movq -0x28(%rbp), %rax
movq %rsi, %rdx
addq %rax, %rdx
leaq -0x60(%rbp), %rdi
callq 0xe290
jmp 0x1115a
jmp 0x111c1
leaq -0x60(%rbp), %rdi
movq %rdi, -0xf8(%rbp)
callq 0xe5f0
movq %rax, -0xb0(%rbp)
leaq -0xa8(%rbp), %rdi
leaq -0xb0(%rbp), %rsi
callq 0xdde0
movq -0xf8(%rbp), %rdi
movq -0x98(%rbp), %rdx
movq -0x28(%rbp), %rax
movq %rdx, %rcx
addq %rax, %rcx
movq -0xa8(%rbp), %rsi
callq 0xdb30
movq %rax, -0xf0(%rbp)
jmp 0x111b3
movq -0xf0(%rbp), %rax
movq %rax, -0xb8(%rbp)
movq -0x78(%rbp), %rax
movzbl (%rax), %ecx
xorl %eax, %eax
cmpl $0x82, %ecx
movb %al, -0xf9(%rbp)
jne 0x111f2
leaq -0x60(%rbp), %rdi
callq 0xd220
movzbl (%rax), %eax
cmpl $0xf7, %eax
setne %al
movb %al, -0xf9(%rbp)
movb -0xf9(%rbp), %al
andb $0x1, %al
movb %al, -0x39(%rbp)
testb $0x1, -0x39(%rbp)
jne 0x112bc
xorps %xmm0, %xmm0
movsd %xmm0, -0x48(%rbp)
movq -0x78(%rbp), %rax
imull $0xf4240, 0x4(%rax), %eax # imm = 0xF4240
movl %eax, -0x100(%rbp)
movq -0x78(%rbp), %rax
movl 0x8(%rax), %eax
movl $0x3e8, %ecx            # imm = 0x3E8
xorl %edx, %edx
divl %ecx
movl %eax, %ecx
movl -0x100(%rbp), %eax
addl %ecx, %eax
movl %eax, %eax
movq %rax, -0x30(%rbp)
movq -0x30(%rbp), %rax
movq %rax, -0x38(%rbp)
movq -0x20(%rbp), %rax
movq 0x40(%rax), %rcx
movq -0x30(%rbp), %rax
subq %rcx, %rax
movq %rax, -0x30(%rbp)
movq -0x38(%rbp), %rcx
movq -0x20(%rbp), %rax
movq %rcx, 0x40(%rax)
movq -0x18(%rbp), %rax
movb 0x3a(%rax), %al
andb $0x1, %al
movzbl %al, %eax
cmpl $0x1, %eax
jne 0x11282
movq -0x18(%rbp), %rax
movb $0x0, 0x3a(%rax)
jmp 0x112ba
movaps 0x7d87(%rip), %xmm1     # 0x19010
movq -0x30(%rbp), %xmm0
punpckldq %xmm1, %xmm0    # xmm0 = xmm0[0],xmm1[0],xmm0[1],xmm1[1]
movapd 0x7d86(%rip), %xmm1     # 0x19020
subpd %xmm1, %xmm0
movaps %xmm0, %xmm1
unpckhpd %xmm0, %xmm0            # xmm0 = xmm0[1,1]
addsd %xmm1, %xmm0
movsd 0x7d4f(%rip), %xmm1     # 0x19000
mulsd %xmm1, %xmm0
movsd %xmm0, -0x48(%rbp)
jmp 0x112be
jmp 0x112be
jmp 0x112c0
jmp 0x112c2
movq -0x78(%rbp), %rdi
callq 0xddb0
jmp 0x112cd
leaq -0x60(%rbp), %rdi
callq 0xe2c0
cmpq $0x0, %rax
je 0x112e2
testb $0x1, -0x39(%rbp)
je 0x112e7
jmp 0x10e74
movq -0x18(%rbp), %rax
testb $0x1, 0x48(%rax)
je 0x1131e
movq -0x18(%rbp), %rax
movq 0x50(%rax), %rax
movq %rax, -0xc0(%rbp)
movq -0xc0(%rbp), %rax
movsd -0x48(%rbp), %xmm0
movq -0x18(%rbp), %rcx
movq 0x58(%rcx), %rsi
leaq -0x60(%rbp), %rdi
callq *%rax
jmp 0x1131c
jmp 0x11395
movq -0x18(%rbp), %rax
movl 0x8(%rax), %eax
movq -0x18(%rbp), %rcx
cmpl 0xc(%rcx), %eax
jae 0x1137c
movq -0x18(%rbp), %rcx
movq 0x10(%rcx), %rdi
movl 0x4(%rcx), %eax
movl %eax, %edx
incl %edx
movl %edx, 0x4(%rcx)
shlq $0x5, %rax
addq %rax, %rdi
leaq -0x60(%rbp), %rsi
callq 0xd620
jmp 0x11352
movq -0x18(%rbp), %rax
movl 0x4(%rax), %eax
movq -0x18(%rbp), %rcx
cmpl 0xc(%rcx), %eax
jne 0x1136d
movq -0x18(%rbp), %rax
movl $0x0, 0x4(%rax)
movq -0x18(%rbp), %rax
movl 0x8(%rax), %ecx
addl $0x1, %ecx
movl %ecx, 0x8(%rax)
jmp 0x11393
movq 0xdc6d(%rip), %rdi      # 0x1eff0
leaq 0x85e5(%rip), %rsi      # 0x1996f
callq 0xda30
jmp 0x11391
jmp 0x11393
jmp 0x11395
jmp 0x10e74
cmpq $0x0, -0x98(%rbp)
je 0x113b0
movq -0x98(%rbp), %rdi
callq 0xdd40
movq -0x20(%rbp), %rax
movq 0x18(%rax), %rdi
callq 0xe580
jmp 0x113bf
movq -0x20(%rbp), %rax
movq $0x0, 0x18(%rax)
movq -0x20(%rbp), %rax
movq 0x38(%rax), %rcx
movq -0x20(%rbp), %rax
movq %rcx, 0x30(%rax)
movq $0x0, -0x8(%rbp)
movl $0x1, -0x90(%rbp)
leaq -0x60(%rbp), %rdi
callq 0xde20
movq -0x8(%rbp), %rax
movq %rbp, %rsp
popq %rbp
retq
movq -0x88(%rbp), %rdi
callq 0xe590
nopl (%rax,%rax)