#include #include #include #include "h.h" note * ol[30000]; // time sorted notes for a track. void Write(char * fn, note * N, BP * bp){ char * oc, // Running cursor in buffer for collecting output * oe, // End of buffer * bb; // Beginning of buffer // Routine ex is just an easy way out. // Deposit character in buff if there is room. void pc(char x){if(oc==oe) ex(1); *(oc++) = x;} // Deposit string. void ps(char * s){while(*s) pc(*(s++));} // Deposit binary number v in c bytes. void pn(int c, ui v){if(c) {pn(c-1, v>>8); pc(v&255);}} // Next two routines for depositing variable length binary numbers. void pvlr(ui n){if(n > 127) pvlr(n>>7); pc(0x80 | n&127);} char * suspense; // Remember where to fill in track length. FILE * out = fopen(*fn?fn:"out.midi", "w"); // Get a buffer for output. {int sp = 1000000; bb=oc = (char*)malloc(sp); if(!oc) ex(2); oe = oc+sp;} ps("MThd"); pn(4, 6); // MIDI file header and length of next three fields. pn(2, bp->type); // Format of file pn(2, bp->trks); // Track count printf("%d tracks out\n", bp->trks); pn(2, bp->den); // Ticks per quarter note. {int tc = bp->trks; while(tc--){int cst = -1; // Running Status int Time = 0; // Ideal time void pvl(ui n){if(n > 127) pvlr(n>>7); pc(n&127);} void dt(ui n){Time += n; pvl(n);} // Introduce the music track and remember where to put its length. ps("MTrk"); suspense = oc; pn(4, 0); // The music: {int tn = bp->trks - tc; int nx = sizeof(ol)/sizeof(ol[0]), ne=nx; void rdx(note ** b, note ** e, ui bit){ // Radix Exchange Sort if(bstart & bit)) if(Bstart & bit) if(Bstart & bit) --B; else ++E;} else {--B; ++E;} break;}} f: rdx(b, B, bit>>1); rdx(E, e, bit>>1);}} note * sch = N; while(sch) {if (sch->trk == tn) ol[--nx] = sch; if(!nx) ex(100); sch = sch->next;} if(1){ //This block is a strong test of the sort. long summ(){long s=0; int n=ne; while(n-- > nx) s += (long)ol[n]; return s;} {long sum = summ(); rdx(&ol[nx], &ol[ne-1], 1<<31); // Sort by play time. if (sum != summ()) ex(101);} {int n=ne-1; while(n-- >nx) if(ol[n+1]->start < ol[n]->start) {if(1) printf("order nx=%d, n = %d, ne=%d ol[n+1]->start=0x%x, " "ol[n]->start=0x%x\n", nx, n, ne, ol[n+1]->start, ol[n]->start); ex(103);}} printf("%d events sorted\n", ne-nx);} else rdx(&ol[nx], &ol[ne-1], 1<<31); // Sort by play time. {int j; note * playing[40]; // Array of note pointers sorted by end times. int xe = sizeof(playing)/sizeof(playing[0]), nxe = 0; int etj(int j) {return playing[j]->start + playing[j]->dur;} void finish(ui z){ // Turn off all the notes that must finish before the new note. int q=0; while(qchan-1)); cst = 9;} pc(playing[q]->o.n.freq); pc(0); ++q;} {int n; for(n=q; n>7);} else if(n.dur == OpaqueStuff){ pc(0xff); pc(n.o.opaque.subtype); pvl(n.o.opaque.cc); {int j; for(j=0; j=m; --k) playing[k+1] = playing[k];} break;} playing[m] = ol[j]; ++nxe;}} ckply(3); // After we have commenced new note } //Now we must finish the playing notes. finish(-1); }} // The "end of track" meta-event. dt(0); pc(0xFF); pc(47); dt(0); // Fill in the now known track length. {char*t = oc; oc = suspense; pn(4, t-(oc+4)); oc = t;} {char * c; for(c = bb; c < oc; ++c) putc(*c, out);} oc=bb; // Reuse buffer for next track. } // end of per track loop fclose(out); // release buffer. free(bb);}}