// File: /workspace/github_cpp_makefile_star2_O2/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
leaq -0x68(%rbp), %rdi
callq 0x73f0
movl $0x20, 0x20(%rbx)
leaq 0x18(%rbx), %r15
xorl %edi, %edi
movq %r15, %rsi
callq 0x7750
testl %eax, %eax
js 0x94a8
movl 0x20(%rbx), %edi
callq 0x76a0
movq %rax, -0x30(%rbp)
testq %rax, %rax
je 0x94c2
movq (%r15), %rdi
callq 0x71b0
movq (%r15), %rdi
pushq $0x1
popq %rsi
callq 0x76b0
movq (%rbx), %rdi
pushq $0x1
popq %rsi
callq 0x72f0
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
pushq $0x1
popq %rcx
movl %eax, %edx
callq 0x7430
movq %r15, -0x70(%rbp)
incq %r12
movl 0x4c(%rbx), %eax
movl %eax, (%r13)
movw $0x1, 0x4(%r13)
movq $0x0, -0x40(%rbp)
pushq $0x1
popq %r15
cmpb $0x1, 0x39(%r14)
jne 0x9484
movq (%rbx), %rdi
movl %r15d, %esi
callq 0x70d0
testl %eax, %eax
je 0x9219
movq (%rbx), %rdi
leaq -0x48(%rbp), %rsi
callq 0x78b0
cmpl $-0x1c, %eax
jne 0x9244
movq 0x7de5(%rip), %rdi      # 0x10ff0
leaq 0x36a4(%rip), %rsi      # 0xc8b6
callq 0x7470
jmp 0x91d9
movq %r13, %rdi
movq %r12, %rsi
pushq $-0x1
popq %rdx
callq 0x77d0
testl %eax, %eax
js 0x91d9
testb $0x1, 0x6(%r13)
je 0x91d9
movl (%r13), %edi
leaq -0x31(%rbp), %rsi
pushq $0x1
popq %rdx
callq 0x77a0
jmp 0x91d9
testl %eax, %eax
jg 0x926c
movq 0x7da1(%rip), %rdi      # 0x10ff0
leaq 0x369b(%rip), %rsi      # 0xc8f1
callq 0x7470
leaq 0x36c8(%rip), %rdi      # 0xc92a
callq 0x7360
jmp 0x91d9
testb $0x1, -0x40(%rbp)
jne 0x9280
movq -0x68(%rbp), %rax
cmpq %rax, -0x60(%rbp)
je 0x9280
movq %rax, -0x60(%rbp)
movq -0x48(%rbp), %rcx
movzbl (%rcx), %eax
leal -0x42(%rax), %edx
cmpl $0x2, %edx
jb 0x93cb
cmpl $0x82, %eax
je 0x92c6
cmpl $0x24, %eax
je 0x92ae
cmpl $0x25, %eax
je 0x92ae
cmpl $0x2a, %eax
je 0x92ba
cmpl $0x16, %eax
jne 0x92fe
testb $0x2, 0x38(%r14)
je 0x92fe
jmp 0x93cb
testb $0x4, 0x38(%r14)
je 0x92fe
jmp 0x93cb
testb $0x1, 0x38(%r14)
jne 0x93cb
movl 0x10(%rcx), %eax
cmpl 0x20(%rbx), %eax
jbe 0x92fe
movl %eax, 0x20(%rbx)
movq -0x30(%rbp), %rdi
callq 0x75a0
movl 0x20(%rbx), %edi
callq 0x76a0
movq %rax, -0x30(%rbp)
testq %rax, %rax
je 0x945f
movq -0x48(%rbp), %rcx
movq 0x18(%rbx), %rdi
movl 0x20(%rbx), %edx
movq -0x30(%rbp), %rsi
callq 0x7550
testq %rax, %rax
jle 0x93cb
testb $0x1, -0x40(%rbp)
je 0x9336
movq -0x60(%rbp), %rsi
movq -0x30(%rbp), %rdx
addq %rdx, %rax
leaq -0x68(%rbp), %rdi
movq %rax, %rcx
callq 0x74c0
jmp 0x9349
movq -0x30(%rbp), %rsi
addq %rsi, %rax
leaq -0x68(%rbp), %rdi
movq %rax, %rdx
callq 0x7510
movq -0x48(%rbp), %rax
cmpb $-0x7e, (%rax)
jne 0x9362
movq -0x60(%rbp), %rcx
movb $0x1, %dl
movq %rdx, -0x40(%rbp)
cmpb $-0x9, -0x1(%rcx)
jne 0x93cb
andq $0x0, -0x50(%rbp)
imull $0xf4240, 0x4(%rax), %ecx # imm = 0xF4240
movl 0x8(%rax), %eax
xorl %edx, %edx
movl $0x3e8, %esi            # imm = 0x3E8
divl %esi
addl %ecx, %eax
movq 0x40(%rbx), %rcx
movq %rax, 0x40(%rbx)
cmpb $0x1, 0x3a(%r14)
jne 0x9392
movb $0x0, 0x3a(%r14)
jmp 0x93c3
subq %rcx, %rax
movq %rax, %xmm0
punpckldq 0x2c6e(%rip), %xmm0 # xmm0 = xmm0[0],mem[0],xmm0[1],mem[1]
subpd 0x2c76(%rip), %xmm0     # 0xc020
movapd %xmm0, %xmm1
unpckhpd %xmm0, %xmm1            # xmm1 = xmm1[1],xmm0[1]
addsd %xmm0, %xmm1
mulsd 0x2c72(%rip), %xmm1     # 0xc030
movsd %xmm1, -0x50(%rbp)
movq $0x0, -0x40(%rbp)
movq -0x48(%rbp), %rdi
callq 0x75f0
movq -0x60(%rbp), %rax
cmpq -0x68(%rbp), %rax
je 0x91d9
testb $0x1, -0x40(%rbp)
jne 0x91d9
cmpb $0x1, 0x48(%r14)
jne 0x9409
movsd -0x50(%rbp), %xmm0
movq 0x58(%r14), %rsi
leaq -0x68(%rbp), %rdi
callq *0x50(%r14)
jmp 0x91d9
movl 0x8(%r14), %eax
cmpl 0xc(%r14), %eax
jae 0x9447
movl 0x4(%r14), %edi
leal 0x1(%rdi), %eax
movl %eax, 0x4(%r14)
shlq $0x5, %rdi
addq 0x10(%r14), %rdi
leaq -0x68(%rbp), %rsi
callq 0x7260
movl 0x4(%r14), %eax
cmpl 0xc(%r14), %eax
jne 0x943e
andl $0x0, 0x4(%r14)
incl 0x8(%r14)
jmp 0x91d9
movq 0x7ba2(%rip), %rdi      # 0x10ff0
leaq 0x3522(%rip), %rsi      # 0xc977
callq 0x7470
jmp 0x91d9
movb $0x0, 0x39(%r14)
movq 0x7b85(%rip), %rdi      # 0x10ff0
leaq 0x34c7(%rip), %rsi      # 0xc939
callq 0x7470
movq $0x0, -0x30(%rbp)
jmp 0x93cb
movq -0x30(%rbp), %rdi
callq 0x75a0
movq -0x70(%rbp), %rax
movq (%rax), %rdi
callq 0x7a00
andq $0x0, 0x18(%rbx)
movq 0x38(%rbx), %rax
movq %rax, 0x30(%rbx)
jmp 0x94e6
movb $0x0, 0x39(%r14)
movq 0x7b3c(%rip), %rdi      # 0x10ff0
leaq 0x3373(%rip), %rsi      # 0xc82e
callq 0x7470
jmp 0x94e6
movb $0x0, 0x39(%r14)
movq (%r15), %rdi
callq 0x7a00
andq $0x0, (%r15)
movq 0x7b16(%rip), %rdi      # 0x10ff0
leaq 0x3393(%rip), %rsi      # 0xc874
callq 0x7470
leaq -0x68(%rbp), %rdi
callq 0x7850
xorl %eax, %eax
leaq -0x28(%rbp), %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x950c
jmp 0x950c
jmp 0x950c
jmp 0x950c
jmp 0x950c
jmp 0x950c
movq %rax, %rbx
leaq -0x68(%rbp), %rdi
callq 0x7850
movq %rbx, %rdi
callq 0x7a10