// File: /workspace/github_cpp_makefile_star2_O3/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
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x48, %rsp
movq %rdi, %r14
movq 0x40(%rdi), %rbx
xorpd %xmm0, %xmm0
movapd %xmm0, -0x50(%rbp)
movapd %xmm0, -0x60(%rbp)
movl $0x20, 0x20(%rbx)
leaq 0x18(%rbx), %r15
xorl %edi, %edi
movq %r15, %rsi
callq 0x7660
testl %eax, %eax
js 0x9afd
movl 0x20(%rbx), %edi
callq 0x75e0
testq %rax, %rax
je 0x9b1c
movq %rax, -0x30(%rbp)
movq (%r15), %rdi
callq 0x7180
movq (%r15), %rdi
movl $0x1, %esi
callq 0x75f0
movq (%rbx), %rdi
movl $0x1, %esi
callq 0x72a0
movslq %eax, %r12
movq %rsp, %rcx
leaq 0x17(,%r12,8), %rdx
andq $-0x10, %rdx
movq %rcx, %r13
subq %rdx, %r13
movq %r13, %rsp
movq (%rbx), %rdi
negq %rdx
leaq (%rcx,%rdx), %rsi
addq $0x8, %rsi
movl %eax, %edx
movl $0x1, %ecx
callq 0x73c0
movl 0x4c(%rbx), %eax
movl %eax, (%r13)
movw $0x1, 0x4(%r13)
cmpb $0x1, 0x39(%r14)
jne 0x9b4a
incq %r12
movq $0x0, -0x40(%rbp)
movq %r15, -0x70(%rbp)
movq (%rbx), %rdi
movl $0x1, %esi
callq 0x70a0
testl %eax, %eax
je 0x9846
movq (%rbx), %rdi
leaq -0x68(%rbp), %rsi
callq 0x7780
cmpl $-0x1c, %eax
jne 0x9875
movl $0x3a, %edx
movq 0x77b8(%rip), %rdi      # 0x10ff0
leaq 0x4067(%rip), %rsi      # 0xd8a6
callq 0x74a0
jmp 0x989d
movq %r13, %rdi
movq %r12, %rsi
movl $0xffffffff, %edx       # imm = 0xFFFFFFFF
callq 0x76b0
testl %eax, %eax
js 0x989d
testb $0x1, 0x6(%r13)
je 0x989d
movl (%r13), %edi
movl $0x1, %edx
leaq -0x31(%rbp), %rsi
callq 0x7690
jmp 0x989d
testl %eax, %eax
jg 0x98ad
movl $0x38, %edx
movq 0x776b(%rip), %rdi      # 0x10ff0
leaq 0x4055(%rip), %rsi      # 0xd8e1
callq 0x74a0
leaq 0x4082(%rip), %rdi      # 0xd91a
callq 0x7300
cmpb $0x0, 0x39(%r14)
jne 0x980a
jmp 0x9b50
testb $0x1, -0x40(%rbp)
jne 0x98c1
movq -0x60(%rbp), %rax
cmpq %rax, -0x58(%rbp)
je 0x98c1
movq %rax, -0x58(%rbp)
movq -0x68(%rbp), %rcx
movzbl (%rcx), %eax
cmpl $0x29, %eax
jg 0x991f
cmpl $0x16, %eax
je 0x98dc
cmpl $0x24, %eax
je 0x98dc
cmpl $0x25, %eax
jne 0x98e7
testb $0x2, 0x38(%r14)
jne 0x9a12
movq 0x18(%rbx), %rdi
movl 0x20(%rbx), %edx
movq -0x30(%rbp), %rsi
callq 0x74d0
testq %rax, %rax
jle 0x9a12
testb $0x1, -0x40(%rbp)
je 0x9978
movq -0x58(%rbp), %rsi
movq -0x30(%rbp), %rdx
addq %rdx, %rax
leaq -0x60(%rbp), %rdi
movq %rax, %rcx
callq 0x7460
jmp 0x998b
leal -0x42(%rax), %edx
cmpl $0x2, %edx
jb 0x9a12
cmpl $0x2a, %eax
je 0x9a9a
cmpl $0x82, %eax
jne 0x98e7
testb $0x1, 0x38(%r14)
jne 0x9a12
movl 0x10(%rcx), %eax
cmpl 0x20(%rbx), %eax
jbe 0x98e7
movl %eax, 0x20(%rbx)
movq -0x30(%rbp), %rdi
callq 0x7500
movl 0x20(%rbx), %edi
callq 0x75e0
testq %rax, %rax
je 0x9ad3
movq %rax, -0x30(%rbp)
movq -0x68(%rbp), %rcx
jmp 0x98e7
movq -0x30(%rbp), %rsi
addq %rsi, %rax
leaq -0x60(%rbp), %rdi
movq %rax, %rdx
callq 0x7480
movq -0x68(%rbp), %rax
cmpb $-0x7e, (%rax)
jne 0x99a4
movq -0x58(%rbp), %rcx
movb $0x1, %dl
movq %rdx, -0x40(%rbp)
cmpb $-0x9, -0x1(%rcx)
jne 0x9a12
movq $0x0, -0x48(%rbp)
imull $0xf4240, 0x4(%rax), %ecx # imm = 0xF4240
movl 0x8(%rax), %eax
imulq $0x10624dd3, %rax, %rax # imm = 0x10624DD3
shrq $0x26, %rax
addl %ecx, %eax
movq 0x40(%rbx), %rcx
movq %rax, 0x40(%rbx)
cmpb $0x1, 0x3a(%r14)
jne 0x99d9
movb $0x0, 0x3a(%r14)
jmp 0x9a0a
subq %rcx, %rax
movq %rax, %xmm0
punpckldq 0x3617(%rip), %xmm0 # xmm0 = xmm0[0],mem[0],xmm0[1],mem[1]
subpd 0x361f(%rip), %xmm0     # 0xd010
movapd %xmm0, %xmm1
unpckhpd %xmm0, %xmm1            # xmm1 = xmm1[1],xmm0[1]
addsd %xmm0, %xmm1
mulsd 0x361b(%rip), %xmm1     # 0xd020
movsd %xmm1, -0x48(%rbp)
movq $0x0, -0x40(%rbp)
movq -0x68(%rbp), %rdi
callq 0x7550
movq -0x58(%rbp), %rax
cmpq -0x60(%rbp), %rax
je 0x9ac2
testb $0x1, -0x40(%rbp)
jne 0x9ac2
cmpb $0x1, 0x48(%r14)
jne 0x9a4d
movsd -0x48(%rbp), %xmm0
movq 0x58(%r14), %rsi
leaq -0x60(%rbp), %rdi
callq *0x50(%r14)
jmp 0x9ac2
movl 0x8(%r14), %eax
cmpl 0xc(%r14), %eax
jae 0x9aaa
movl 0x4(%r14), %r15d
leal 0x1(%r15), %eax
movl %eax, 0x4(%r14)
shlq $0x5, %r15
addq 0x10(%r14), %r15
movq %r15, %rdi
leaq -0x60(%rbp), %rsi
callq 0x7040
movsd -0x48(%rbp), %xmm0
movsd %xmm0, 0x18(%r15)
movl 0x4(%r14), %eax
cmpl 0xc(%r14), %eax
jne 0x9a94
movl $0x0, 0x4(%r14)
incl 0x8(%r14)
jmp 0x9ac2
testb $0x4, 0x38(%r14)
je 0x98e7
jmp 0x9a12
movl $0x2c, %edx
movq 0x753a(%rip), %rdi      # 0x10ff0
leaq 0x3eaa(%rip), %rsi      # 0xd967
callq 0x74a0
cmpb $0x0, 0x39(%r14)
movq -0x70(%rbp), %r15
jne 0x980a
jmp 0x9b50
movb $0x0, 0x39(%r14)
movl $0x3d, %edx
movq 0x750c(%rip), %rdi      # 0x10ff0
leaq 0x3e3e(%rip), %rsi      # 0xd929
callq 0x74a0
movq $0x0, -0x30(%rbp)
jmp 0x9a12
movb $0x0, 0x39(%r14)
movq 0x74e7(%rip), %rdi      # 0x10ff0
leaq 0x3d0e(%rip), %rsi      # 0xd81e
movl $0x45, %edx
callq 0x74a0
jmp 0x9b76
movb $0x0, 0x39(%r14)
movq (%r15), %rdi
callq 0x78a0
movq $0x0, (%r15)
movq 0x74b9(%rip), %rdi      # 0x10ff0
leaq 0x3d26(%rip), %rsi      # 0xd864
movl $0x41, %edx
callq 0x74a0
jmp 0x9b76
movq -0x30(%rbp), %rdi
jmp 0x9b59
movq -0x30(%rbp), %rdi
testq %rdi, %rdi
je 0x9b5e
callq 0x7500
movq (%r15), %rdi
callq 0x78a0
movq $0x0, 0x18(%rbx)
movq 0x38(%rbx), %rax
movq %rax, 0x30(%rbx)
movq -0x60(%rbp), %rdi
testq %rdi, %rdi
je 0x9b8b
movq -0x50(%rbp), %rsi
subq %rdi, %rsi
callq 0x7420
xorl %eax, %eax
leaq -0x28(%rbp), %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x9ba8
jmp 0x9ba8
jmp 0x9ba8
jmp 0x9ba8
jmp 0x9ba8
jmp 0x9ba8
movq %rax, %rbx
movq -0x60(%rbp), %rdi
testq %rdi, %rdi
je 0x9bc0
movq -0x50(%rbp), %rsi
subq %rdi, %rsi
callq 0x7420
movq %rbx, %rdi
callq 0x78b0