// File: /workspace/github_c_makefile_star2_O1/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
xorl %ebp, %ebp
leaq 0x5722(%rip), %r15      # 0x93c0
leaq 0x26de(%rip), %r14      # 0x6383
xorl %ebx, %ebx
movl 0x804b(%rip), %eax      # 0xbcf8
cmpb $0x0, 0x5518(%rip)      # 0x91cc
movl $0x0, %ecx
cmovnel %eax, %ecx
movl $0x7fffffff, %r13d      # 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 0x3cf0
addq %r15, %rsi
movq 0x10(%rsi), %rsi
cmpq %r13, %rsi
cmovbl %ecx, %r12d
cmovbq %rsi, %r13
decl %edx
jne 0x3cc4
xorl %edi, %edi
cmpq 0x5493(%rip), %r13      # 0x9190
setae %dil
movq %r14, %rsi
callq 0x1b7b
movq %r13, %rax
subq 0x548d(%rip), %rax      # 0x91a0
imulq 0x7fe5(%rip), %rax      # 0xbd00
movq %r13, 0x546e(%rip)      # 0x9190
movl 0x53e4(%rip), %ecx      # 0x910c
xorl %edx, %edx
divq %rcx
addl 0x5465(%rip), %eax      # 0x9198
movl %eax, 0x545f(%rip)      # 0x9198
movq %r13, 0x5460(%rip)      # 0x91a0
cmpb $0x1, 0x547c(%rip)      # 0x91c3
jne 0x3d84
cmpq %rbx, %r13
je 0x3d84
movq 0x5483(%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 0x263c(%rip), %rsi      # 0x63ad
movl %r12d, %edx
movl %eax, %r8d
movq %r13, %r9
xorl %eax, %eax
callq 0x10b0
movq %r13, %rbx
movslq %r12d, %rax
leaq (%rax,%rax,2), %rax
shlq $0x4, %rax
addq %r15, %rax
cmpb $-0x2, 0x24(%rax)
jne 0x3de0
movq 0x18(%rax), %rax
cmpq %rax, 0x7f5d(%rip)      # 0xbd00
je 0x3db2
incl 0x5405(%rip)            # 0x91b0
movq %rax, 0x7f4e(%rip)      # 0xbd00
cmpb $0x1, 0x540a(%rip)      # 0x91c3
jne 0x3f83
movq 0x5412(%rip), %rdi      # 0x91d8
movq 0x7f33(%rip), %rdx      # 0xbd00
leaq 0x260e(%rip), %rsi      # 0x63e2
xorl %eax, %eax
callq 0x10b0
jmp 0x3f83
movzbl 0x25(%rax), %ecx
cmpb $0x1, 0x53dd(%rip)      # 0x91c8
movq %rbx, 0x8(%rsp)
jne 0x3dfd
cmpb $0x9, %cl
jne 0x3dfd
xorb $-0x80, 0x26(%rax)
jmp 0x3e17
movb 0x26(%rax), %dl
addb 0x5366(%rip), %dl       # 0x916c
movzbl %dl, %edx
cmpb $0x7f, %dl
movl $0x7f, %esi
cmovael %esi, %edx
movb %dl, 0x26(%rax)
imulq $0x194, %rcx, %rcx      # imm = 0x194
leaq 0x5a1b(%rip), %rdx      # 0x9840
leaq (%rdx,%rcx), %rbx
movzbl 0x24(%rax), %edx
cmpl $0x80, %edx
je 0x3ea1
cmpl $0x90, %edx
jne 0x3f1d
xorl %ecx, %ecx
cmpb $0x1, 0x4(%rbx,%rcx)
jne 0x3e58
incq %rcx
cmpq $0x10, %rcx
jne 0x3e43
movl $0x10, %ecx
cmpl $0x10, %ecx
jb 0x3f30
incl 0x52fd(%rip)            # 0x9164
cmpb $0x1, 0x5355(%rip)      # 0x91c3
jne 0x3e94
movq 0x5361(%rip), %rdi      # 0x91d8
movzbl 0x26(%rax), %ecx
movzbl 0x25(%rax), %r9d
leaq 0x25c4(%rip), %rsi      # 0x644b
movl %r12d, %edx
movl %ecx, %r8d
xorl %eax, %eax
callq 0x10b0
movl %r12d, %edi
callq 0x3be7
jmp 0x3f7e
leaq 0x5998(%rip), %rdx      # 0x9840
addq %rcx, %rdx
addq $0x20, %rdx
xorl %ecx, %ecx
cmpb $0x1, 0x4(%rbx,%rcx)
jne 0x3ec6
movzbl 0x26(%rax), %esi
cmpl %esi, (%rdx)
jne 0x3ec6
cmpl %r12d, -0x8(%rdx)
je 0x3ed8
incq %rcx
addq $0x18, %rdx
cmpq $0x10, %rcx
jne 0x3eb1
movl $0x10, %ecx
cmpl $0x10, %ecx
jb 0x3f90
incl 0x5281(%rip)            # 0x9168
cmpb $0x1, 0x52d5(%rip)      # 0x91c3
jne 0x4070
movq 0x52dd(%rip), %rdi      # 0x91d8
movzbl 0x26(%rax), %ecx
movzbl 0x25(%rax), %r9d
leaq 0x24f6(%rip), %rsi      # 0x6401
movl %r12d, %edx
movl %ecx, %r8d
xorl %eax, %eax
callq 0x10b0
jmp 0x4070
xorl %edi, %edi
leaq 0x2569(%rip), %rsi      # 0x648f
callq 0x1b7b
jmp 0x4078
movl %ecx, %ecx
movb $0x1, 0x4(%rbx,%rcx)
leaq (%rcx,%rcx,2), %rcx
leaq (%rbx,%rcx,8), %rsi
addq $0x14, %rsi
movl 0x524f(%rip), %ecx      # 0x9198
movl %ecx, (%rsi)
movl %r12d, 0x4(%rsi)
movzwl 0x25(%rax), %ecx
movd %ecx, %xmm0
pxor %xmm1, %xmm1
punpcklbw %xmm1, %xmm0    # xmm0 = xmm0[0],xmm1[0],xmm0[1],xmm1[1],xmm0[2],xmm1[2],xmm0[3],xmm1[3],xmm0[4],xmm1[4],xmm0[5],xmm1[5],xmm0[6],xmm1[6],xmm0[7],xmm1[7]
punpcklwd %xmm1, %xmm0    # xmm0 = xmm0[0],xmm1[0],xmm0[1],xmm1[1],xmm0[2],xmm1[2],xmm0[3],xmm1[3]
movq %xmm0, 0x8(%rsi)
movl (%rbx), %ecx
movl %ecx, 0x10(%rsi)
movzbl 0x27(%rax), %eax
movl %eax, 0x14(%rsi)
movl $0x90, %edi
callq 0x2e5f
movq 0x8(%rsp), %rbx
movl %r12d, %edi
callq 0x3336
jmp 0x407d
movl %ecx, %eax
movq %rax, 0x10(%rsp)
leaq (%rax,%rax,2), %rcx
movl 0x51f7(%rip), %edx      # 0x9198
movl 0x14(%rbx,%rcx,8), %eax
subl %eax, %edx
movq 0x514a(%rip), %rsi      # 0x90f8
movq %rdx, %r14
subq %rsi, %r14
jbe 0x3fc9
movq 0x51bb(%rip), %rdi      # 0x9178
addq %rdi, %rsi
cmpq %rdx, %rsi
cmovbeq %rdi, %r14
jmp 0x3fcc
xorl %r14d, %r14d
leaq (%rbx,%rcx,8), %r13
addq $0x14, %r13
movq 0x51a5(%rip), %rcx      # 0x9180
testq %rcx, %rcx
je 0x4045
cmpq %rdx, 0x5119(%rip)      # 0x9100
jbe 0x4045
subq %r14, %rdx
leaq 0x5161(%rip), %rsi      # 0x9154
cmpq %rcx, %rdx
jbe 0x4043
movl 0x510a(%rip), %edx      # 0x9108
imull 0x14(%r13), %edx
movslq %edx, %rdx
imulq $0x51eb851f, %rdx, %rsi # imm = 0x51EB851F
movq %rsi, %rdi
shrq $0x3f, %rdi
sarq $0x25, %rsi
addl %edi, %esi
cmpl $0x64, %edx
movl $0x1, %edx
cmovll %edx, %esi
movl %esi, 0x14(%r13)
addl %ecx, %eax
movl %eax, (%r13)
movl $0x90, %edi
movq %r13, %rsi
callq 0x2e5f
leaq 0x5115(%rip), %rsi      # 0x9158
incl (%rsi)
movl 0x514d(%rip), %eax      # 0x9198
subl %r14d, %eax
movl %eax, (%r13)
movl $0x80, %edi
movq %r13, %rsi
callq 0x2e5f
movq 0x10(%rsp), %rax
movb $0x0, 0x4(%rbx,%rax)
leaq 0x2313(%rip), %r14      # 0x6383
movl %r12d, %edi
callq 0x3336
movq 0x8(%rsp), %rbx
movl 0x50ad(%rip), %eax      # 0x9130
cmpl 0x7c6f(%rip), %eax      # 0xbcf8
jl 0x3ca7
jmp 0x4096
callq 0x286a
cmpl $0x0, 0x7147(%rip)      # 0xb1e4
jg 0x4091
cmpb $0x1, 0x511d(%rip)      # 0x91c3
jne 0x4104
movq 0x5129(%rip), %rdi      # 0x91d8
movl 0x50e3(%rip), %ecx      # 0x9198
imulq $0x10624dd3, %rcx, %rdx # imm = 0x10624DD3
shrq $0x26, %rdx
imull $0x3e8, %edx, %eax      # imm = 0x3E8
subl %eax, %ecx
leaq 0x23de(%rip), %rsi      # 0x64ad
xorl %eax, %eax
callq 0x10b0
movq 0x50fb(%rip), %rdi      # 0x91d8
movl 0x50c5(%rip), %ecx      # 0x91a8
imulq $0x10624dd3, %rcx, %rdx # imm = 0x10624DD3
shrq $0x26, %rdx
imull $0x3e8, %edx, %eax      # imm = 0x3E8
subl %eax, %ecx
leaq 0x23d0(%rip), %rsi      # 0x64cd
xorl %eax, %eax
callq 0x10b0
movl 0x508e(%rip), %eax      # 0x9198
xorl %edi, %edi
cmpl 0x5096(%rip), %eax      # 0x91a8
setae %dil
leaq 0x23d0(%rip), %rsi      # 0x64ed
callq 0x1b7b
movl 0x5070(%rip), %eax      # 0x9198
subl 0x507a(%rip), %eax      # 0x91a8
imulq $0x10624dd3, %rax, %rdi # imm = 0x10624DD3
shrq $0x26, %rdi
callq 0x2745
cmpb $0x1, 0x507b(%rip)      # 0x91c0
jne 0x4179
movzbl 0x507b(%rip), %edi      # 0x91c9
xorl $0x1, %edi
orl $0xe, %edi
shll $0x4, %edi
movq 0x5092(%rip), %rsi      # 0x91f0
callq 0x10a0
incq 0x501e(%rip)            # 0x9188
addq $0x18, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x5070(%rip), %rdi      # 0x91f0
movq 0x4f51(%rip), %rdx      # 0x90d8
movzbl 0x503b(%rip), %ecx      # 0x91c9
xorl $0x1, %ecx
orl $0xe, %ecx
shll $0x4, %ecx
leaq 0x1b14(%rip), %rsi      # 0x5cb2
xorl %eax, %eax
callq 0x10b0
incq 0x4fdc(%rip)            # 0x9188
cmpb $0x0, 0x5017(%rip)      # 0x91ca
jne 0x41d2
movq 0x5034(%rip), %rcx      # 0x91f0
leaq 0x2346(%rip), %rdi      # 0x6509
movl $0x2, %esi
movl $0x1, %edx
callq 0x1150
movq 0x5017(%rip), %rsi      # 0x91f0
movl $0xa, %edi
addq $0x18, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x1090