// File: /workspace/github_c_makefile_star2_O2/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 0x84ad(%rip), %eax      # 0xbcf8
xorl %ebp, %ebp
leaq 0x5b6c(%rip), %r15      # 0x93c0
leaq 0x2b28(%rip), %rbx      # 0x6383
xorl %r14d, %r14d
cmpb $0x0, 0x5967(%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
imulq $0x30, %rsi, %rsi
cmpb $-0x1, 0x24(%rsi,%r15)
je 0x389d
addq %r15, %rsi
movq 0x10(%rsi), %rsi
cmpq %r12, %rsi
cmovbl %ecx, %r13d
cmovbq %rsi, %r12
decl %edx
jne 0x3875
xorl %edi, %edi
cmpq 0x58e6(%rip), %r12      # 0x9190
setae %dil
movq %rbx, %rsi
callq 0x19f1
movq %r12, %rax
subq 0x58e0(%rip), %rax      # 0x91a0
imulq 0x8438(%rip), %rax      # 0xbd00
movq %r12, 0x58c1(%rip)      # 0x9190
movl 0x5837(%rip), %ecx      # 0x910c
xorl %edx, %edx
divq %rcx
addl 0x58b8(%rip), %eax      # 0x9198
movl %eax, 0x58b2(%rip)      # 0x9198
movq %r12, 0x58b3(%rip)      # 0x91a0
cmpb $0x1, 0x58cf(%rip)      # 0x91c3
jne 0x3927
cmpq %r14, %r12
je 0x3927
movq 0x58d6(%rip), %rdi      # 0x91d8
xorl %edx, %edx
movl $0x3e8, %ecx            # imm = 0x3E8
divl %ecx
movl %edx, %r8d
leaq 0x2a98(%rip), %rsi      # 0x63ad
movl %r13d, %edx
movl %eax, %ecx
movq %r12, %r9
xorl %eax, %eax
callq 0x10b0
movq %r12, %r14
movslq %r13d, %rax
imulq $0x30, %rax, %rax
addq %r15, %rax
movzbl 0x24(%rax), %edx
cmpl $0xfe, %edx
jne 0x3984
movq 0x83bc(%rip), %rdx      # 0xbd00
movq 0x18(%rax), %rax
cmpq %rax, %rdx
je 0x395d
incl 0x585d(%rip)            # 0x91b0
movq %rax, 0x83a6(%rip)      # 0xbd00
movq %rax, %rdx
cmpb $0x1, 0x585f(%rip)      # 0x91c3
jne 0x3ae9
movq 0x5867(%rip), %rdi      # 0x91d8
leaq 0x2a6a(%rip), %rsi      # 0x63e2
xorl %eax, %eax
callq 0x10b0
jmp 0x3ae9
movzbl 0x25(%rax), %r9d
cmpb $0x1, 0x5838(%rip)      # 0x91c8
jne 0x39a0
cmpb $0x9, %r9b
jne 0x39a0
movb 0x26(%rax), %cl
addb $-0x80, %cl
jmp 0x39b5
movb 0x26(%rax), %cl
addb 0x57c3(%rip), %cl       # 0x916c
movzbl %cl, %ecx
cmpb $0x7f, %cl
pushq $0x7f
popq %rsi
cmovael %esi, %ecx
movb %cl, 0x26(%rax)
imulq $0x194, %r9, %rsi       # imm = 0x194
leaq 0x5e7a(%rip), %rdi      # 0x9840
leaq (%rdi,%rsi), %rbx
movzbl %cl, %ecx
cmpl $0x80, %edx
je 0x3a0b
cmpl $0x90, %edx
jne 0x3a3b
leaq 0x5e5c(%rip), %rdx      # 0x9840
addq %rdx, %rsi
addq $0x14, %rsi
pushq $0x4
popq %rdx
cmpq $0x14, %rdx
je 0x3a81
cmpb $0x1, (%rbx,%rdx)
jne 0x3ab5
addq $0x18, %rsi
incq %rdx
jmp 0x39ee
pushq $0x14
popq %r10
pushq $0x4
popq %r12
cmpq $0x14, %r12
je 0x3a4e
cmpb $0x1, (%rbx,%r12)
jne 0x3a32
cmpl %ecx, 0xc(%rbx,%r10)
jne 0x3a32
cmpl %r13d, 0x4(%rbx,%r10)
je 0x3af6
incq %r12
addq $0x18, %r10
jmp 0x3a13
xorl %edi, %edi
leaq 0x2a4b(%rip), %rsi      # 0x648f
callq 0x19f1
jmp 0x3bc3
incl 0x5714(%rip)            # 0x9168
cmpb $0x1, 0x5768(%rip)      # 0x91c3
jne 0x3bbb
movq 0x5770(%rip), %rdi      # 0x91d8
leaq 0x2992(%rip), %rsi      # 0x6401
movl %r13d, %edx
movl %ecx, %r8d
xorl %eax, %eax
callq 0x10b0
jmp 0x3bbb
incl 0x56dd(%rip)            # 0x9164
cmpb $0x1, 0x5735(%rip)      # 0x91c3
jne 0x3aab
movq 0x5741(%rip), %rdi      # 0x91d8
leaq 0x29ad(%rip), %rsi      # 0x644b
movl %r13d, %edx
movl %ecx, %r8d
xorl %eax, %eax
callq 0x10b0
movl %r13d, %edi
callq 0x3795
jmp 0x3ae2
movb $0x1, (%rbx,%rdx)
movl 0x56d9(%rip), %edx      # 0x9198
movl %edx, (%rsi)
movl %r13d, 0x4(%rsi)
movl %r9d, 0x8(%rsi)
movl %ecx, 0xc(%rsi)
movl (%rbx), %ecx
movl %ecx, 0x10(%rsi)
movzbl 0x27(%rax), %eax
movl %eax, 0x14(%rsi)
movl $0x90, %edi
callq 0x2b78
leaq 0x289a(%rip), %rbx      # 0x6383
movl %r13d, %edi
callq 0x2fc2
jmp 0x3bca
movl 0x569c(%rip), %eax      # 0x9198
movl (%rbx,%r10), %edi
movl %eax, %ecx
subl %edi, %ecx
movq 0x55ed(%rip), %rdx      # 0x90f8
movq %rcx, %r9
subq %rdx, %r9
jbe 0x3b26
movq 0x565e(%rip), %r8       # 0x9178
addq %r8, %rdx
cmpq %rcx, %rdx
cmovbeq %r8, %r9
jmp 0x3b29
xorl %r9d, %r9d
leaq (%rbx,%r10), %rsi
movq 0x564c(%rip), %r8       # 0x9180
testq %r8, %r8
je 0x3ba7
cmpq %rcx, 0x55c0(%rip)      # 0x9100
jbe 0x3ba7
subq %r9, %rcx
cmpq %r8, %rcx
jbe 0x3ba1
movl 0x55b8(%rip), %ecx      # 0x9108
imull 0x14(%rbx,%r10), %ecx
movl %ecx, %eax
cltd
movq %r9, 0x10(%rsp)
pushq $0x64
popq %r9
idivl %r9d
cmpl $0x64, %ecx
pushq $0x1
popq %rcx
cmovll %ecx, %eax
movl %eax, 0x14(%rbx,%r10)
addl %r8d, %edi
movl %edi, (%rbx,%r10)
movl $0x90, %edi
movq %rsi, 0x8(%rsp)
callq 0x2b78
movq 0x8(%rsp), %rsi
movq 0x10(%rsp), %r9
incl 0x55bf(%rip)            # 0x9158
movl 0x55f9(%rip), %eax      # 0x9198
jmp 0x3ba7
incl 0x55ad(%rip)            # 0x9154
subl %r9d, %eax
movl %eax, (%rsi)
movl $0x80, %edi
callq 0x2b78
movb $0x0, (%rbx,%r12)
movl %r13d, %edi
callq 0x2fc2
leaq 0x27b9(%rip), %rbx      # 0x6383
movl 0x8128(%rip), %eax      # 0xbcf8
cmpl %eax, 0x555a(%rip)      # 0x9130
jl 0x385e
callq 0x28a4
cmpb $0x1, 0x55db(%rip)      # 0x91c3
jne 0x3c35
movq 0x55e7(%rip), %rdi      # 0x91d8
movl 0x55a1(%rip), %eax      # 0x9198
movl $0x3e8, %ebx            # imm = 0x3E8
xorl %edx, %edx
divl %ebx
movl %edx, %ecx
leaq 0x28a4(%rip), %rsi      # 0x64ad
movl %eax, %edx
xorl %eax, %eax
callq 0x10b0
movq 0x55bf(%rip), %rdi      # 0x91d8
movl 0x5589(%rip), %eax      # 0x91a8
xorl %edx, %edx
divl %ebx
movl %edx, %ecx
leaq 0x28a1(%rip), %rsi      # 0x64cd
movl %eax, %edx
xorl %eax, %eax
callq 0x10b0
movl 0x555d(%rip), %eax      # 0x9198
xorl %edi, %edi
cmpl 0x5565(%rip), %eax      # 0x91a8
setae %dil
leaq 0x289f(%rip), %rsi      # 0x64ed
callq 0x19f1
movl 0x553f(%rip), %eax      # 0x9198
subl 0x5549(%rip), %eax      # 0x91a8
movl $0x3e8, %ecx            # imm = 0x3E8
xorl %edx, %edx
divl %ecx
movq %rax, %rdi
callq 0x2501
cmpb $0x1, 0x5549(%rip)      # 0x91c0
jne 0x3cab
movzbl 0x5549(%rip), %edi      # 0x91c9
xorl $0x1, %edi
orl $0xe, %edi
shll $0x4, %edi
movq 0x5560(%rip), %rsi      # 0x91f0
callq 0x10a0
incq 0x54ec(%rip)            # 0x9188
addq $0x18, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x553e(%rip), %rdi      # 0x91f0
movq 0x541f(%rip), %rdx      # 0x90d8
movzbl 0x5509(%rip), %ecx      # 0x91c9
xorl $0x1, %ecx
orl $0xe, %ecx
shll $0x4, %ecx
leaq 0x1fe2(%rip), %rsi      # 0x5cb2
xorl %eax, %eax
callq 0x10b0
incq 0x54aa(%rip)            # 0x9188
cmpb $0x0, 0x54e5(%rip)      # 0x91ca
jne 0x3d00
movq 0x5502(%rip), %rcx      # 0x91f0
leaq 0x2814(%rip), %rdi      # 0x6509
pushq $0x2
popq %rsi
pushq $0x1
popq %rdx
callq 0x1150
movq 0x54e9(%rip), %rsi      # 0x91f0
pushq $0xa
popq %rdi
addq $0x18, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x1090