// File: /workspace/github_c_makefile_star2_O0/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:
subq $0x78, %rsp
movq $0x0, 0x70(%rsp)
movl 0x9235(%rip), %eax      # 0xde38
movl %eax, 0x64(%rsp)
movq $0x7fffffff, 0x58(%rsp) # imm = 0x7FFFFFFF
movl $0x0, 0x54(%rsp)
testb $0x1, 0x66ed(%rip)      # 0xb30c
je 0x4c2b
movl 0x9211(%rip), %eax      # 0xde38
movl %eax, 0x54(%rsp)
jmp 0x4c2d
movl 0x54(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x54(%rsp)
cmpl 0x91fa(%rip), %eax      # 0xde38
jl 0x4c48
movl $0x0, 0x54(%rsp)
movslq 0x54(%rsp), %rcx
leaq 0x68ac(%rip), %rax      # 0xb500
imulq $0x30, %rcx, %rcx
addq %rcx, %rax
movq %rax, 0x68(%rsp)
movq 0x68(%rsp), %rax
movzbl 0x24(%rax), %eax
cmpl $0xff, %eax
je 0x4c96
movq 0x68(%rsp), %rax
movq 0x10(%rax), %rax
cmpq 0x58(%rsp), %rax
jae 0x4c96
movq 0x68(%rsp), %rax
movq 0x10(%rax), %rax
movq %rax, 0x58(%rsp)
movl 0x54(%rsp), %eax
movl %eax, 0x50(%rsp)
jmp 0x4c98
movl 0x64(%rsp), %eax
addl $-0x1, %eax
movl %eax, 0x64(%rsp)
cmpl $0x0, %eax
jne 0x4c2d
movl 0x50(%rsp), %eax
movl %eax, 0x54(%rsp)
movslq 0x54(%rsp), %rcx
leaq 0x6844(%rip), %rax      # 0xb500
imulq $0x30, %rcx, %rcx
addq %rcx, %rax
movq %rax, 0x68(%rsp)
movq 0x58(%rsp), %rax
cmpq 0x65fc(%rip), %rax      # 0xb2d0
setae %al
movzbl %al, %edi
andl $0x1, %edi
leaq 0x386b(%rip), %rsi      # 0x854f
callq 0x1c70
movq 0x58(%rsp), %rax
movq %rax, 0x65db(%rip)      # 0xb2d0
movq 0x65d4(%rip), %rax      # 0xb2d0
subq 0x65dd(%rip), %rax      # 0xb2e0
imulq 0x9135(%rip), %rax      # 0xde40
movl 0x63eb(%rip), %ecx      # 0xb0fc
xorl %edx, %edx
divq %rcx
movq %rax, %rcx
movl 0x65b9(%rip), %eax      # 0xb2d8
addq %rcx, %rax
movl %eax, 0x65b0(%rip)      # 0xb2d8
movq 0x65a1(%rip), %rax      # 0xb2d0
movq %rax, 0x65aa(%rip)      # 0xb2e0
testb $0x1, 0x65c6(%rip)      # 0xb303
je 0x4da2
movq 0x58(%rsp), %rax
cmpq 0x70(%rsp), %rax
je 0x4da0
movq 0x65c6(%rip), %rdi      # 0xb318
movl 0x54(%rsp), %eax
movl %eax, 0x14(%rsp)
movl 0x6578(%rip), %eax      # 0xb2d8
movl $0x3e8, %ecx            # imm = 0x3E8
xorl %edx, %edx
divl %ecx
movl %eax, %ecx
movl 0x6567(%rip), %eax      # 0xb2d8
movl $0x3e8, %esi            # imm = 0x3E8
xorl %edx, %edx
divl %esi
movl %edx, %r8d
movl 0x14(%rsp), %edx
movq 0x6548(%rip), %r9       # 0xb2d0
leaq 0x37ea(%rip), %rsi      # 0x8579
movb $0x0, %al
callq 0x10a0
movq 0x58(%rsp), %rax
movq %rax, 0x70(%rsp)
jmp 0x4da2
movq 0x68(%rsp), %rax
movzbl 0x25(%rax), %eax
movl %eax, %ecx
leaq 0x6bcc(%rip), %rax      # 0xb980
imulq $0x194, %rcx, %rcx      # imm = 0x194
addq %rcx, %rax
movq %rax, 0x48(%rsp)
movq 0x68(%rsp), %rax
movzbl 0x24(%rax), %eax
cmpl $0xfe, %eax
jne 0x4e37
movq 0x9066(%rip), %rax      # 0xde40
movq 0x68(%rsp), %rcx
cmpq 0x18(%rcx), %rax
je 0x4e04
movl 0x6505(%rip), %eax      # 0xb2f0
addl $0x1, %eax
movl %eax, 0x64fc(%rip)      # 0xb2f0
movq 0x68(%rsp), %rax
movq 0x18(%rax), %rax
movq %rax, 0x903c(%rip)      # 0xde40
testb $0x1, 0x64f8(%rip)      # 0xb303
je 0x4e29
movq 0x6504(%rip), %rdi      # 0xb318
movq 0x9025(%rip), %rdx      # 0xde40
leaq 0x378c(%rip), %rsi      # 0x85ae
movb $0x0, %al
callq 0x10a0
movl 0x54(%rsp), %edi
callq 0x3f90
jmp 0x5247
testb $0x1, 0x64ca(%rip)      # 0xb308
je 0x4e62
movq 0x68(%rsp), %rax
movzbl 0x25(%rax), %eax
cmpl $0x9, %eax
jne 0x4e62
movq 0x68(%rsp), %rax
movzbl 0x26(%rax), %ecx
addl $0x80, %ecx
movb %cl, 0x26(%rax)
jmp 0x4ea6
movl 0x6444(%rip), %edx      # 0xb2ac
movq 0x68(%rsp), %rax
movzbl 0x26(%rax), %ecx
addl %edx, %ecx
movb %cl, 0x26(%rax)
movq 0x68(%rsp), %rax
movzbl 0x26(%rax), %eax
cmpl $0x0, %eax
jge 0x4e8d
movq 0x68(%rsp), %rax
movb $0x0, 0x26(%rax)
movq 0x68(%rsp), %rax
movzbl 0x26(%rax), %eax
cmpl $0x7f, %eax
jle 0x4ea4
movq 0x68(%rsp), %rax
movb $0x7f, 0x26(%rax)
jmp 0x4ea6
movq 0x68(%rsp), %rax
movzbl 0x24(%rax), %eax
cmpl $0x80, %eax
jne 0x50ef
movl $0x0, 0x44(%rsp)
cmpl $0x10, 0x44(%rsp)
jge 0x4f2e
movq 0x48(%rsp), %rax
movslq 0x44(%rsp), %rcx
testb $0x1, 0x4(%rax,%rcx)
je 0x4f1f
movq 0x48(%rsp), %rax
addq $0x14, %rax
movslq 0x44(%rsp), %rcx
imulq $0x18, %rcx, %rcx
addq %rcx, %rax
movl 0xc(%rax), %eax
movq 0x68(%rsp), %rcx
movzbl 0x26(%rcx), %ecx
cmpl %ecx, %eax
jne 0x4f1f
movq 0x48(%rsp), %rax
addq $0x14, %rax
movslq 0x44(%rsp), %rcx
imulq $0x18, %rcx, %rcx
addq %rcx, %rax
movl 0x4(%rax), %eax
cmpl 0x54(%rsp), %eax
jne 0x4f1f
jmp 0x4f2e
jmp 0x4f21
movl 0x44(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x44(%rsp)
jmp 0x4ec2
cmpl $0x10, 0x44(%rsp)
jl 0x4f88
movl 0x636d(%rip), %eax      # 0xb2a8
addl $0x1, %eax
movl %eax, 0x6364(%rip)      # 0xb2a8
testb $0x1, 0x63b8(%rip)      # 0xb303
je 0x4f83
movq 0x63c4(%rip), %rdi      # 0xb318
movl 0x54(%rsp), %edx
movq 0x68(%rsp), %rax
movzbl 0x26(%rax), %ecx
movq 0x68(%rsp), %rax
movzbl 0x26(%rax), %r8d
movq 0x68(%rsp), %rax
movzbl 0x25(%rax), %r9d
leaq 0x3651(%rip), %rsi      # 0x85cd
movb $0x0, %al
callq 0x10a0
jmp 0x50e1
movq 0x48(%rsp), %rax
addq $0x14, %rax
movslq 0x44(%rsp), %rcx
imulq $0x18, %rcx, %rcx
addq %rcx, %rax
movq %rax, 0x38(%rsp)
movl 0x6330(%rip), %eax      # 0xb2d8
movq 0x38(%rsp), %rcx
subl (%rcx), %eax
movl %eax, %eax
movq %rax, 0x30(%rsp)
movq 0x30(%rsp), %rax
cmpq 0x6126(%rip), %rax      # 0xb0e8
ja 0x4fcf
movq $0x0, 0x28(%rsp)
jmp 0x5008
movq 0x30(%rsp), %rax
movq 0x62dd(%rip), %rcx      # 0xb2b8
addq 0x6106(%rip), %rcx      # 0xb0e8
cmpq %rcx, %rax
jae 0x4ffa
movq 0x30(%rsp), %rax
subq 0x60f5(%rip), %rax      # 0xb0e8
movq %rax, 0x28(%rsp)
jmp 0x5006
movq 0x62b7(%rip), %rax      # 0xb2b8
movq %rax, 0x28(%rsp)
jmp 0x5008
cmpq $0x0, 0x62b0(%rip)      # 0xb2c0
jbe 0x50af
movq 0x30(%rsp), %rax
cmpq 0x60ce(%rip), %rax      # 0xb0f0
jae 0x50af
movq 0x30(%rsp), %rax
subq 0x28(%rsp), %rax
cmpq 0x6287(%rip), %rax      # 0xb2c0
jbe 0x509e
movq 0x38(%rsp), %rax
movl 0x14(%rax), %eax
imull 0x60ae(%rip), %eax      # 0xb0f8
movl $0x64, %ecx
cltd
idivl %ecx
movq 0x38(%rsp), %rcx
movl %eax, 0x14(%rcx)
cmpl $0x0, %eax
jg 0x506b
movq 0x38(%rsp), %rax
movl $0x1, 0x14(%rax)
movq 0x624e(%rip), %rdx      # 0xb2c0
movq 0x38(%rsp), %rax
movl (%rax), %ecx
addq %rdx, %rcx
movl %ecx, (%rax)
movq 0x38(%rsp), %rsi
movl $0x90, %edi
callq 0x38d0
movl 0x6205(%rip), %eax      # 0xb298
addl $0x1, %eax
movl %eax, 0x61fc(%rip)      # 0xb298
jmp 0x50ad
movl 0x61f0(%rip), %eax      # 0xb294
addl $0x1, %eax
movl %eax, 0x61e7(%rip)      # 0xb294
jmp 0x50af
movl 0x6223(%rip), %eax      # 0xb2d8
subq 0x28(%rsp), %rax
movl %eax, %ecx
movq 0x38(%rsp), %rax
movl %ecx, (%rax)
movq 0x38(%rsp), %rsi
movl $0x80, %edi
callq 0x38d0
movq 0x48(%rsp), %rax
movslq 0x44(%rsp), %rcx
movb $0x0, 0x4(%rax,%rcx)
movl 0x54(%rsp), %edi
callq 0x3f90
jmp 0x5245
movq 0x68(%rsp), %rax
movzbl 0x24(%rax), %eax
cmpl $0x90, %eax
jne 0x5235
movl $0x0, 0x24(%rsp)
cmpl $0x10, 0x24(%rsp)
jge 0x5134
movq 0x48(%rsp), %rax
movslq 0x24(%rsp), %rcx
testb $0x1, 0x4(%rax,%rcx)
jne 0x5125
jmp 0x5134
jmp 0x5127
movl 0x24(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x24(%rsp)
jmp 0x510b
cmpl $0x10, 0x24(%rsp)
jl 0x5197
movl 0x6163(%rip), %eax      # 0xb2a4
addl $0x1, %eax
movl %eax, 0x615a(%rip)      # 0xb2a4
testb $0x1, 0x61b2(%rip)      # 0xb303
je 0x5189
movq 0x61be(%rip), %rdi      # 0xb318
movl 0x54(%rsp), %edx
movq 0x68(%rsp), %rax
movzbl 0x26(%rax), %ecx
movq 0x68(%rsp), %rax
movzbl 0x26(%rax), %r8d
movq 0x68(%rsp), %rax
movzbl 0x25(%rax), %r9d
leaq 0x3495(%rip), %rsi      # 0x8617
movb $0x0, %al
callq 0x10a0
movl 0x54(%rsp), %edi
callq 0x4b10
jmp 0x522a
movq 0x48(%rsp), %rax
movslq 0x24(%rsp), %rcx
movb $0x1, 0x4(%rax,%rcx)
movq 0x48(%rsp), %rax
addq $0x14, %rax
movslq 0x24(%rsp), %rcx
imulq $0x18, %rcx, %rcx
addq %rcx, %rax
movq %rax, 0x18(%rsp)
movl 0x6112(%rip), %ecx      # 0xb2d8
movq 0x18(%rsp), %rax
movl %ecx, (%rax)
movl 0x54(%rsp), %ecx
movq 0x18(%rsp), %rax
movl %ecx, 0x4(%rax)
movq 0x68(%rsp), %rax
movzbl 0x25(%rax), %ecx
movq 0x18(%rsp), %rax
movl %ecx, 0x8(%rax)
movq 0x68(%rsp), %rax
movzbl 0x26(%rax), %ecx
movq 0x18(%rsp), %rax
movl %ecx, 0xc(%rax)
movq 0x48(%rsp), %rax
movl (%rax), %ecx
movq 0x18(%rsp), %rax
movl %ecx, 0x10(%rax)
movq 0x68(%rsp), %rax
movzbl 0x27(%rax), %ecx
movq 0x18(%rsp), %rax
movl %ecx, 0x14(%rax)
movq 0x18(%rsp), %rsi
movl $0x90, %edi
callq 0x38d0
movl 0x54(%rsp), %edi
callq 0x3f90
jmp 0x5243
xorl %edi, %edi
leaq 0x341d(%rip), %rsi      # 0x865b
callq 0x1c70
jmp 0x5245
jmp 0x5247
jmp 0x5249
movl 0x6021(%rip), %eax      # 0xb270
cmpl 0x8be3(%rip), %eax      # 0xde38
jl 0x4bfd
callq 0x33d0
testb $0x1, 0x609c(%rip)      # 0xb303
je 0x52e3
movq 0x60a8(%rip), %rdi      # 0xb318
movl 0x6062(%rip), %eax      # 0xb2d8
movl $0x3e8, %ecx            # imm = 0x3E8
xorl %edx, %edx
divl %ecx
movl %eax, 0xc(%rsp)
movl 0x604f(%rip), %eax      # 0xb2d8
movl $0x3e8, %ecx            # imm = 0x3E8
xorl %edx, %edx
divl %ecx
movl %edx, %ecx
movl 0xc(%rsp), %edx
leaq 0x33da(%rip), %rsi      # 0x8679
movb $0x0, %al
callq 0x10a0
movq 0x606b(%rip), %rdi      # 0xb318
movl 0x6035(%rip), %eax      # 0xb2e8
movl $0x3e8, %ecx            # imm = 0x3E8
xorl %edx, %edx
divl %ecx
movl %eax, 0x10(%rsp)
movl 0x6022(%rip), %eax      # 0xb2e8
movl $0x3e8, %ecx            # imm = 0x3E8
xorl %edx, %edx
divl %ecx
movl %edx, %ecx
movl 0x10(%rsp), %edx
leaq 0x33bd(%rip), %rsi      # 0x8699
movb $0x0, %al
callq 0x10a0
movl 0x5fef(%rip), %eax      # 0xb2d8
cmpl 0x5ff9(%rip), %eax      # 0xb2e8
setae %al
movzbl %al, %edi
andl $0x1, %edi
leaq 0x33ba(%rip), %rsi      # 0x86b9
callq 0x1c70
movl 0x5fce(%rip), %eax      # 0xb2d8
subl 0x5fd8(%rip), %eax      # 0xb2e8
movl $0x3e8, %ecx            # imm = 0x3E8
xorl %edx, %edx
divl %ecx
movl %eax, %eax
movl %eax, %edi
callq 0x2ed0
testb $0x1, 0x5fd7(%rip)      # 0xb300
je 0x5361
movb 0x5fd8(%rip), %cl       # 0xb309
movl $0xf0, %edi
movl $0xe0, %eax
testb $0x1, %cl
cmovnel %eax, %edi
movq 0x5fe8(%rip), %rsi      # 0xb330
callq 0x1090
movq 0x5f74(%rip), %rax      # 0xb2c8
addq $0x1, %rax
movq %rax, 0x5f69(%rip)      # 0xb2c8
jmp 0x53da
movq 0x5fc8(%rip), %rdi      # 0xb330
movq 0x5d59(%rip), %rdx      # 0xb0c8
movb 0x5f93(%rip), %sil      # 0xb309
movl $0xf0, %ecx
movl $0xe0, %eax
testb $0x1, %sil
cmovnel %eax, %ecx
leaq 0x2ad8(%rip), %rsi      # 0x7e66
movb $0x0, %al
callq 0x10a0
movq 0x5f2c(%rip), %rax      # 0xb2c8
addq $0x1, %rax
movq %rax, 0x5f21(%rip)      # 0xb2c8
testb $0x1, 0x5f5c(%rip)      # 0xb30a
jne 0x53c5
movq 0x5f79(%rip), %rdi      # 0xb330
leaq 0x3317(%rip), %rsi      # 0x86d5
movb $0x0, %al
callq 0x10a0
movq 0x5f64(%rip), %rdi      # 0xb330
leaq 0x3482(%rip), %rsi      # 0x8855
movb $0x0, %al
callq 0x10a0
addq $0x78, %rsp
retq
nop