// File: /workspace/github_cpp_makefile_star2_O1/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 0x9ba0
movl 0x20(%rbx), %edi
callq 0x75e0
testq %rax, %rax
je 0x9bbf
movq %rax, -0x38(%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 0x9b78
incq %r12
movl $0x0, -0x2c(%rbp)
movq %r15, -0x70(%rbp)
movq (%rbx), %rdi
movl $0x1, %esi
callq 0x70a0
testl %eax, %eax
je 0x98c8
movq (%rbx), %rdi
leaq -0x68(%rbp), %rsi
callq 0x7780
cmpl $-0x1c, %eax
jne 0x98f7
movl $0x3a, %edx
movq 0x7736(%rip), %rdi      # 0x10ff0
leaq 0x3fe5(%rip), %rsi      # 0xd8a6
callq 0x74a0
jmp 0x991f
movq %r13, %rdi
movq %r12, %rsi
movl $0xffffffff, %edx       # imm = 0xFFFFFFFF
callq 0x76b0
testl %eax, %eax
js 0x991f
testb $0x1, 0x6(%r13)
je 0x991f
movl (%r13), %edi
movl $0x1, %edx
leaq -0x39(%rbp), %rsi
callq 0x7690
jmp 0x991f
testl %eax, %eax
jg 0x992f
movl $0x38, %edx
movq 0x76e9(%rip), %rdi      # 0x10ff0
leaq 0x3fd3(%rip), %rsi      # 0xd8e1
callq 0x74a0
leaq 0x4000(%rip), %rdi      # 0xd91a
callq 0x7300
cmpb $0x0, 0x39(%r14)
jne 0x988c
jmp 0x9b78
testb $0x1, -0x2c(%rbp)
jne 0x9943
movq -0x60(%rbp), %rax
cmpq %rax, -0x58(%rbp)
je 0x9943
movq %rax, -0x58(%rbp)
movq -0x68(%rbp), %rcx
movzbl (%rcx), %eax
cmpl $0x29, %eax
jg 0x996d
cmpl $0x16, %eax
je 0x9962
cmpl $0x24, %eax
je 0x9962
cmpl $0x25, %eax
jne 0x99e3
testb $0x2, 0x38(%r14)
sete %r15b
jmp 0x99e6
leal -0x42(%rax), %edx
cmpl $0x2, %edx
jb 0x99de
cmpl $0x2a, %eax
je 0x9a92
cmpl $0x82, %eax
jne 0x99e3
testb $0x1, 0x38(%r14)
jne 0x99de
movl 0x10(%rcx), %eax
movb $0x1, %r15b
cmpl 0x20(%rbx), %eax
jbe 0x99e6
movl %eax, 0x20(%rbx)
movq -0x38(%rbp), %rdi
callq 0x7500
movl 0x20(%rbx), %edi
callq 0x75e0
movq %rax, -0x38(%rbp)
testq %rax, %rax
jne 0x99e6
movb $0x0, 0x39(%r14)
movl $0x3d, %edx
movq 0x762b(%rip), %rdi      # 0x10ff0
leaq 0x3f5d(%rip), %rsi      # 0xd929
callq 0x74a0
xorl %r15d, %r15d
movq $0x0, -0x38(%rbp)
jmp 0x99e6
xorl %r15d, %r15d
jmp 0x99e6
movb $0x1, %r15b
testb %r15b, %r15b
je 0x9acd
movq 0x18(%rbx), %rdi
movl 0x20(%rbx), %edx
movq -0x68(%rbp), %rcx
movq -0x38(%rbp), %rsi
callq 0x74d0
testq %rax, %rax
jle 0x9acd
testb $0x1, -0x2c(%rbp)
je 0x9a2b
movq -0x58(%rbp), %rsi
movq -0x38(%rbp), %rdx
addq %rdx, %rax
leaq -0x60(%rbp), %rdi
movq %rax, %rcx
callq 0x7460
jmp 0x9a3e
movq -0x38(%rbp), %rsi
addq %rsi, %rax
leaq -0x60(%rbp), %rdi
movq %rax, %rdx
callq 0x7480
movq -0x68(%rbp), %rax
cmpb $-0x7e, (%rax)
jne 0x9a54
movq -0x58(%rbp), %rcx
cmpb $-0x9, -0x1(%rcx)
setne %cl
jmp 0x9a56
xorl %ecx, %ecx
movl %ecx, -0x2c(%rbp)
testb %cl, %cl
jne 0x9acd
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 0x9a9c
movb $0x0, 0x3a(%r14)
jmp 0x9acd
testb $0x4, 0x38(%r14)
jmp 0x9967
subq %rcx, %rax
movq %rax, %xmm0
punpckldq 0x3554(%rip), %xmm0 # xmm0 = xmm0[0],mem[0],xmm0[1],mem[1]
subpd 0x355c(%rip), %xmm0     # 0xd010
movapd %xmm0, %xmm1
unpckhpd %xmm0, %xmm1            # xmm1 = xmm1[1],xmm0[1]
addsd %xmm0, %xmm1
mulsd 0x3558(%rip), %xmm1     # 0xd020
movsd %xmm1, -0x48(%rbp)
movq -0x68(%rbp), %rdi
callq 0x7550
movq -0x58(%rbp), %rax
cmpq -0x60(%rbp), %rax
je 0x9b69
testb $0x1, -0x2c(%rbp)
jne 0x9b69
cmpb $0x1, 0x48(%r14)
jne 0x9b04
movsd -0x48(%rbp), %xmm0
movq 0x58(%r14), %rsi
leaq -0x60(%rbp), %rdi
callq *0x50(%r14)
jmp 0x9b69
movl 0x8(%r14), %eax
cmpl 0xc(%r14), %eax
jae 0x9b51
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 0x9b4b
movl $0x0, 0x4(%r14)
incl 0x8(%r14)
jmp 0x9b69
movl $0x2c, %edx
movq 0x7493(%rip), %rdi      # 0x10ff0
leaq 0x3e03(%rip), %rsi      # 0xd967
callq 0x74a0
cmpb $0x0, 0x39(%r14)
movq -0x70(%rbp), %r15
jne 0x988c
movq -0x38(%rbp), %rdi
testq %rdi, %rdi
je 0x9b86
callq 0x7500
movq (%r15), %rdi
callq 0x78a0
movq $0x0, 0x18(%rbx)
movq 0x38(%rbx), %rax
movq %rax, 0x30(%rbx)
jmp 0x9beb
movb $0x0, 0x39(%r14)
movq 0x7444(%rip), %rdi      # 0x10ff0
leaq 0x3c6b(%rip), %rsi      # 0xd81e
movl $0x45, %edx
callq 0x74a0
jmp 0x9beb
movb $0x0, 0x39(%r14)
movq (%r15), %rdi
callq 0x78a0
movq $0x0, (%r15)
movq 0x7416(%rip), %rdi      # 0x10ff0
leaq 0x3c83(%rip), %rsi      # 0xd864
movl $0x41, %edx
callq 0x74a0
movq -0x60(%rbp), %rdi
testq %rdi, %rdi
je 0x9c00
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 0x9c1d
jmp 0x9c1d
jmp 0x9c1d
jmp 0x9c1d
jmp 0x9c1d
jmp 0x9c1d
movq %rax, %rbx
movq -0x60(%rbp), %rdi
testq %rdi, %rdi
je 0x9c35
movq -0x50(%rbp), %rsi
subq %rdi, %rsi
callq 0x7420
movq %rbx, %rdi
callq 0x78b0
nop