// File: /workspace/github_c_makefile_star2_O3/LenShustek[P]miditones/miditones.c
// Function: process_track_data
void process_track_data(void) {
   unsigned long last_earliest_time = 0;

   do { // while there are still track notes to process

      /* Find the track with the earliest event time, and process it's event.

      A potential improvement: If there are multiple tracks with the same time,
      first do the ones with STOPNOTE as the next command, if any.  That would
      help avoid running out of tone generators.  In practice, though, most MIDI
      files do all the STOPNOTEs first anyway, so it won't have much effect.

      Usually we start with the track after the one we did last time (tracknum),
      so that if we run out of tone generators, we have been fair to all the tracks.
      The alternate "strategy1" says we always start with track 0, which means
      that we favor early tracks over later ones when there aren't enough tone generators. */

      struct track_status *trk;
      int count_tracks = num_tracks;
      unsigned long earliest_time = 0x7fffffff; // in ticks, of course
      int tracknum = 0;
      int earliest_tracknum;
      if (strategy1)
         tracknum = num_tracks;      /* beyond the end, so we start with track 0 */
      do {
         if (++tracknum >= num_tracks) tracknum = 0;
         trk = &track[tracknum];
         if (trk->cmd != CMD_TRACKDONE && trk->time < earliest_time) {
            earliest_time = trk->time;
            earliest_tracknum = tracknum; } }
      while (--count_tracks);
      tracknum = earliest_tracknum;  /* the track we picked */
      trk = &track[tracknum];
      assert(earliest_time >= timenow_ticks, "time went backwards in process_track_data");
      timenow_ticks = earliest_time; // we make it the global time
      timenow_usec += (uint64_t)(timenow_ticks - timenow_usec_updated) * tempo / ticks_per_beat;
      timenow_usec_updated = timenow_ticks;  // usec version is updated based on the current tempo
      if (loggen) {
         if (earliest_time != last_earliest_time) {
            fprintf(logfile, "->process trk %d at time %lu.%03lu msec (%lu ticks)\n",
                    tracknum, timenow_usec / 1000, timenow_usec % 1000, timenow_ticks);
            last_earliest_time = earliest_time; } }
      struct channel_status *cp = &channel[trk->chan];  // the channel info, if play or stop

      if (trk->cmd == CMD_TEMPO) { // change the global tempo, which affects future usec computations
         if (tempo != trk->tempo) {
            ++tempo_changes;
            tempo = trk->tempo; }
         if (loggen) fprintf(logfile, "  tempo set to %ld usec/qnote\n", tempo);
         find_next_note(tracknum); }

      else { // should be PLAYNOTE or STOPNOTE
         if (percussion_translate && trk->chan == PERCUSSION_TRACK)
            trk->note += 128;  // maybe move percussion notes up to 128..255
         else {  // shift notes as requested
            trk->note += keyshift;
            if (trk->note < 0) trk->note = 0;
            if (trk->note > 127) trk->note = 127; }

         if (trk->cmd == CMD_STOPNOTE) {
            int ndx;  // find the noteinfo for this note -- which better be playing -- in the channel status
            for (ndx = 0; ndx < MAX_CHANNELNOTES; ++ndx) {
               if (cp->note_playing[ndx]
                     && cp->notes_playing[ndx].note == trk->note
                     && cp->notes_playing[ndx].track == tracknum)
                  break; }
            if (ndx >= MAX_CHANNELNOTES) {
               ++noteinfo_notfound; // presumably the array overflowed on input
               if (loggen) fprintf(logfile, "  *** noteinfo slot not found to stop track %d note %d (%02X) channel %d\n",
                                      tracknum, trk->note, trk->note, trk->chan); }
            else { // found the playing note for this stopnote
               // Analyze the sustain and release parameters. We might generate another "note on"
               // command with reduced volume, and/or move the stopnote command earlier than now.
               struct noteinfo *np = &cp->notes_playing[ndx];
               unsigned long duration_usec = timenow_usec - np->time_usec; // it has the start time in it
               unsigned long truncation;
               if (duration_usec <= notemin_usec) truncation = 0;
               else if (duration_usec < releasetime_usec + notemin_usec) truncation = duration_usec - notemin_usec;
               else truncation = releasetime_usec;
               if (attacktime_usec > 0 && duration_usec < attacknotemax_usec) {
                  if (duration_usec - truncation > attacktime_usec) { // do a sustain phase
                     if ((np->volume = np->volume * sustainlevel_pct / 100) <= 0) np->volume = 1;
                     np->time_usec += attacktime_usec; // adjust time to be when sustain phase starts
                     queue_cmd(CMD_PLAYNOTE, np);
                     ++sustainphases_done; }
                  else ++sustainphases_skipped; }
               np->time_usec = timenow_usec - truncation; // adjust time to be when the note stops
               queue_cmd(CMD_STOPNOTE, np);
               cp->note_playing[ndx] = false; }
            find_next_note(tracknum); }

         else if (trk->cmd == CMD_PLAYNOTE) { // Process only one "start note", so other tracks get a chance at tone generators
            int ndx;  // find an unused noteinfo slot to use
            for (ndx = 0; ndx < MAX_CHANNELNOTES; ++ndx) {
               if (!cp->note_playing[ndx]) break; }
            if (ndx >= MAX_CHANNELNOTES) {
               ++noteinfo_overflow; // too many simultaneous notes
               if (loggen) fprintf(logfile, "  *** no noteinfo slot to queue track %d note %d (%02X) channel %d\n",
                                      tracknum, trk->note, trk->note, trk->chan);
               show_noteinfo_slots(tracknum); }
            else {
               cp->note_playing[ndx] = true;  // assign it to us
               struct noteinfo *pn = &cp->notes_playing[ndx];
               pn->time_usec = timenow_usec; // fill it in
               pn->track = tracknum;
               pn->channel = trk->chan;
               pn->note = trk->note;
               pn->instrument = cp->instrument;
               pn->volume = trk->volume;
               queue_cmd(CMD_PLAYNOTE, pn); }
            find_next_note(tracknum); }   // use up the note

         else assert(false, "bad cmd in process_track_data"); } }

   while (tracks_done < num_tracks);

   // empty the output queue and generate the end-of-score command
   flush_queue();
   if (loggen) {
      fprintf(logfile, "ending timenow_usec: %lu.%03lu\n", timenow_usec / 1000, timenow_usec % 1000);
      fprintf(logfile, "ending output_usec:  %lu.%03lu\n", output_usec / 1000, output_usec % 1000); }
   assert(timenow_usec >= output_usec, "time deficit at end of song");
   generate_delay((timenow_usec - output_usec) / 1000);
   if (binaryoutput) {
      putc(gen_restart ? CMD_RESTART : CMD_STOP, outfile);
      outfile_bytecount +=1; }
   else {
      fprintf(outfile, "%s%02X", hex, gen_restart ? CMD_RESTART : CMD_STOP);
      ++outfile_bytecount;
      if (!asm_output) fprintf(outfile, "};");
      fprintf(outfile, "\n"); } }

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x18, %rsp
movl 0x810c(%rip), %eax      # 0xbcf8
xorl %ebp, %ebp
leaq 0x57cb(%rip), %r15      # 0x93c0
leaq 0x2787(%rip), %rbx      # 0x6383
xorl %r14d, %r14d
cmpb $0x0, 0x55c6(%rip)      # 0x91cc
movl $0x0, %ecx
cmovnel %eax, %ecx
movl $0x7fffffff, %r12d      # imm = 0x7FFFFFFF
movl %eax, %edx
incl %ecx
cmpl %eax, %ecx
cmovgel %ebp, %ecx
movslq %ecx, %rsi
leaq (%rsi,%rsi,2), %rsi
shlq $0x4, %rsi
cmpb $-0x1, 0x24(%rsi,%r15)
je 0x3c42
addq %r15, %rsi
movq 0x10(%rsi), %rsi
cmpq %r12, %rsi
cmovbl %ecx, %r13d
cmovbq %rsi, %r12
decl %edx
jne 0x3c16
xorl %edi, %edi
cmpq 0x5541(%rip), %r12      # 0x9190
setae %dil
movq %rbx, %rsi
callq 0x1af6
movq %r12, %rax
subq 0x553b(%rip), %rax      # 0x91a0
imulq 0x8093(%rip), %rax      # 0xbd00
movq %r12, 0x551c(%rip)      # 0x9190
movl 0x5492(%rip), %ecx      # 0x910c
xorl %edx, %edx
divq %rcx
addl 0x5513(%rip), %eax      # 0x9198
movl %eax, 0x550d(%rip)      # 0x9198
movq %r12, 0x550e(%rip)      # 0x91a0
cmpb $0x1, 0x552a(%rip)      # 0x91c3
jne 0x3cd6
cmpq %r14, %r12
je 0x3cd6
movq 0x5531(%rip), %rdi      # 0x91d8
movl %eax, %ecx
imulq $0x10624dd3, %rcx, %rcx # imm = 0x10624DD3
shrq $0x26, %rcx
imull $0x3e8, %ecx, %edx      # imm = 0x3E8
subl %edx, %eax
leaq 0x26ea(%rip), %rsi      # 0x63ad
movl %r13d, %edx
movl %eax, %r8d
movq %r12, %r9
xorl %eax, %eax
callq 0x10b0
movq %r12, %r14
movslq %r13d, %rax
leaq (%rax,%rax,2), %rax
shlq $0x4, %rax
addq %r15, %rax
movzbl 0x24(%rax), %edx
cmpl $0xfe, %edx
jne 0x3d37
movq 0x8009(%rip), %rdx      # 0xbd00
movq 0x18(%rax), %rax
cmpq %rax, %rdx
je 0x3d10
incl 0x54aa(%rip)            # 0x91b0
movq %rax, 0x7ff3(%rip)      # 0xbd00
movq %rax, %rdx
cmpb $0x1, 0x54ac(%rip)      # 0x91c3
jne 0x3ea7
movq 0x54b4(%rip), %rdi      # 0x91d8
leaq 0x26b7(%rip), %rsi      # 0x63e2
xorl %eax, %eax
callq 0x10b0
jmp 0x3ea7
movzbl 0x25(%rax), %r9d
cmpb $0x1, 0x5485(%rip)      # 0x91c8
jne 0x3d53
cmpb $0x9, %r9b
jne 0x3d53
movb 0x26(%rax), %cl
addb $-0x80, %cl
jmp 0x3d6a
movb 0x26(%rax), %cl
addb 0x5410(%rip), %cl       # 0x916c
movzbl %cl, %ecx
cmpb $0x7f, %cl
movl $0x7f, %esi
cmovael %esi, %ecx
movb %cl, 0x26(%rax)
imulq $0x194, %r9, %rsi       # imm = 0x194
leaq 0x5ac5(%rip), %rdi      # 0x9840
leaq (%rdi,%rsi), %rbx
cmpl $0x80, %edx
je 0x3df7
cmpl $0x90, %edx
jne 0x3e5d
leaq 0x5aa6(%rip), %rdx      # 0x9840
addq %rdx, %rsi
addq $0x14, %rsi
movl $0x4, %edx
cmpb $0x1, (%rbx,%rdx)
jne 0x3e70
addq $0x18, %rsi
incq %rdx
cmpq $0x14, %rdx
jne 0x3da6
incl 0x53a1(%rip)            # 0x9164
cmpb $0x1, 0x53f9(%rip)      # 0x91c3
jne 0x3dea
movq 0x5405(%rip), %rdi      # 0x91d8
movzbl %cl, %ecx
leaq 0x266e(%rip), %rsi      # 0x644b
movl %r13d, %edx
movl %ecx, %r8d
xorl %eax, %eax
callq 0x10b0
movl %r13d, %edi
callq 0x3b38
jmp 0x3ea0
movzbl %cl, %ecx
movl $0x4, %r12d
movl $0x14, %eax
cmpb $0x1, (%rbx,%r12)
jne 0x3e1d
cmpl %ecx, 0xc(%rbx,%rax)
jne 0x3e1d
cmpl %r13d, 0x4(%rbx,%rax)
je 0x3eb4
incq %r12
addq $0x18, %rax
cmpq $0x14, %r12
jne 0x3e05
incl 0x5338(%rip)            # 0x9168
cmpb $0x1, 0x538c(%rip)      # 0x91c3
jne 0x3f85
movq 0x5394(%rip), %rdi      # 0x91d8
leaq 0x25b6(%rip), %rsi      # 0x6401
movl %r13d, %edx
movl %ecx, %r8d
xorl %eax, %eax
callq 0x10b0
jmp 0x3f85
xorl %edi, %edi
leaq 0x2629(%rip), %rsi      # 0x648f
callq 0x1af6
jmp 0x3f8d
movb $0x1, (%rbx,%rdx)
movl 0x531e(%rip), %edx      # 0x9198
movl %edx, (%rsi)
movl %r13d, 0x4(%rsi)
movl %r9d, 0x8(%rsi)
movzbl %cl, %ecx
movl %ecx, 0xc(%rsi)
movl (%rbx), %ecx
movl %ecx, 0x10(%rsi)
movzbl 0x27(%rax), %eax
movl %eax, 0x14(%rsi)
movl $0x90, %edi
callq 0x2d87
leaq 0x24dc(%rip), %rbx      # 0x6383
movl %r13d, %edi
callq 0x328d
jmp 0x3f94
movl 0x52de(%rip), %edx      # 0x9198
movl (%rbx,%rax), %ecx
movl %edx, %edi
subl %ecx, %edi
movq 0x5230(%rip), %rsi      # 0x90f8
movq %rdi, %r9
subq %rsi, %r9
jbe 0x3ee3
movq 0x52a1(%rip), %r8       # 0x9178
addq %r8, %rsi
cmpq %rdi, %rsi
cmovbeq %r8, %r9
jmp 0x3ee6
xorl %r9d, %r9d
leaq (%rbx,%rax), %rsi
movq 0x528f(%rip), %r10      # 0x9180
testq %r10, %r10
je 0x3f71
cmpq %rdi, 0x5203(%rip)      # 0x9100
jbe 0x3f71
subq %r9, %rdi
cmpq %r10, %rdi
jbe 0x3f6b
movl 0x51fb(%rip), %edx      # 0x9108
imull 0x14(%rbx,%rax), %edx
movslq %edx, %rdx
imulq $0x51eb851f, %rdx, %rdi # imm = 0x51EB851F
movq %rdi, %r8
shrq $0x3f, %r8
sarq $0x25, %rdi
addl %r8d, %edi
cmpl $0x64, %edx
movl $0x1, %edx
cmovll %edx, %edi
movl %edi, 0x14(%rbx,%rax)
addl %r10d, %ecx
movl %ecx, (%rbx,%rax)
movl $0x90, %edi
movq %r9, 0x10(%rsp)
movq %rsi, 0x8(%rsp)
callq 0x2d87
movq 0x8(%rsp), %rsi
movq 0x10(%rsp), %r9
incl 0x51f5(%rip)            # 0x9158
movl 0x522f(%rip), %edx      # 0x9198
jmp 0x3f71
incl 0x51e3(%rip)            # 0x9154
subl %r9d, %edx
movl %edx, (%rsi)
movl $0x80, %edi
callq 0x2d87
movb $0x0, (%rbx,%r12)
movl %r13d, %edi
callq 0x328d
leaq 0x23ef(%rip), %rbx      # 0x6383
movl 0x7d5e(%rip), %eax      # 0xbcf8
cmpl %eax, 0x5190(%rip)      # 0x9130
jl 0x3bff
jmp 0x3fad
callq 0x279b
cmpl $0x0, 0x7230(%rip)      # 0xb1e4
jg 0x3fa8
cmpb $0x1, 0x5206(%rip)      # 0x91c3
jne 0x401b
movq 0x5212(%rip), %rdi      # 0x91d8
movl 0x51cc(%rip), %ecx      # 0x9198
imulq $0x10624dd3, %rcx, %rdx # imm = 0x10624DD3
shrq $0x26, %rdx
imull $0x3e8, %edx, %eax      # imm = 0x3E8
subl %eax, %ecx
leaq 0x24c7(%rip), %rsi      # 0x64ad
xorl %eax, %eax
callq 0x10b0
movq 0x51e4(%rip), %rdi      # 0x91d8
movl 0x51ae(%rip), %ecx      # 0x91a8
imulq $0x10624dd3, %rcx, %rdx # imm = 0x10624DD3
shrq $0x26, %rdx
imull $0x3e8, %edx, %eax      # imm = 0x3E8
subl %eax, %ecx
leaq 0x24b9(%rip), %rsi      # 0x64cd
xorl %eax, %eax
callq 0x10b0
movl 0x5177(%rip), %eax      # 0x9198
xorl %edi, %edi
cmpl 0x517f(%rip), %eax      # 0x91a8
setae %dil
leaq 0x24b9(%rip), %rsi      # 0x64ed
callq 0x1af6
movl 0x5159(%rip), %eax      # 0x9198
subl 0x5163(%rip), %eax      # 0x91a8
imulq $0x10624dd3, %rax, %rdi # imm = 0x10624DD3
shrq $0x26, %rdi
callq 0x2676
cmpb $0x1, 0x5164(%rip)      # 0x91c0
jne 0x4090
movzbl 0x5164(%rip), %edi      # 0x91c9
xorl $0x1, %edi
orl $0xe, %edi
shll $0x4, %edi
movq 0x517b(%rip), %rsi      # 0x91f0
callq 0x10a0
incq 0x5107(%rip)            # 0x9188
addq $0x18, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x5159(%rip), %rdi      # 0x91f0
movq 0x503a(%rip), %rdx      # 0x90d8
movzbl 0x5124(%rip), %ecx      # 0x91c9
xorl $0x1, %ecx
orl $0xe, %ecx
shll $0x4, %ecx
leaq 0x1bfd(%rip), %rsi      # 0x5cb2
xorl %eax, %eax
callq 0x10b0
incq 0x50c5(%rip)            # 0x9188
cmpb $0x0, 0x5100(%rip)      # 0x91ca
jne 0x40e9
movq 0x511d(%rip), %rcx      # 0x91f0
leaq 0x242f(%rip), %rdi      # 0x6509
movl $0x2, %esi
movl $0x1, %edx
callq 0x1150
movq 0x5100(%rip), %rsi      # 0x91f0
movl $0xa, %edi
addq $0x18, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x1090