home *** CD-ROM | disk | FTP | other *** search
/ PC Loisirs 18 / cd.iso / sharewar / mikm202 / source / munitrk.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-09-18  |  6.9 KB  |  342 lines

  1. /*
  2.  
  3.     UNITRK.C
  4.  
  5.     All routines dealing with the manipulation of UNITRK(tm) streams
  6.  
  7. */
  8.  
  9. #include <malloc.h>
  10. #include <string.h>
  11. #include "munitrk.h"
  12.  
  13.  
  14. #define BUFPAGE  128            // smallest unibuffer size
  15. #define TRESHOLD 16
  16.  
  17. /* unibuffer is increased by BUFPAGE
  18.   bytes when unipc reaches unimax-TRESHOLD */
  19.  
  20.  
  21.  
  22. /*
  23.     Ok.. I'll try to explain the new internal module format.. so here it goes:
  24.  
  25.  
  26.     The UNITRK(tm) Format:
  27.     ======================
  28.  
  29.     A UNITRK stream is an array of bytes representing a single track
  30.     of a pattern. It's made up of 'repeat/length' bytes, opcodes and
  31.     operands (sort of a assembly language):
  32.  
  33.     rrrlllll
  34.     [REP/LEN][OPCODE][OPERAND][OPCODE][OPERAND] [REP/LEN][OPCODE][OPERAND]..
  35.     ^                                         ^ ^
  36.     |-------ROWS 0 - 0+REP of a track---------| |-------ROWS xx - xx+REP of a track...
  37.  
  38.  
  39.     The rep/len byte contains the number of bytes in the current row,
  40.     _including_ the length byte itself (So the LENGTH byte of row 0 in the
  41.     previous example would have a value of 5). This makes it easy to search
  42.     through a stream for a particular row. A track is concluded by a 0-value
  43.     length byte.
  44.  
  45.     The upper 3 bits of the rep/len byte contain the number of times -1 this
  46.     row is repeated for this track. (so a value of 7 means this row is repeated
  47.     8 times)
  48.  
  49.     Opcodes can range from 1 to 255 but currently only opcodes 1 to 19 are
  50.     being used. Each opcode can have a different number of operands. You can
  51.     find the number of operands to a particular opcode by using the opcode
  52.     as an index into the 'unioperands' table.
  53.  
  54. */
  55.  
  56.  
  57.  
  58. UWORD unioperands[256]={
  59.     0,              // not used
  60.     1,              // UNI_NOTE
  61.     1,              // UNI_INSTRUMENT
  62.     1,              // UNI_PTEFFECT0
  63.     1,              // UNI_PTEFFECT1
  64.     1,              // UNI_PTEFFECT2
  65.     1,              // UNI_PTEFFECT3
  66.     1,              // UNI_PTEFFECT4
  67.     1,              // UNI_PTEFFECT5
  68.     1,              // UNI_PTEFFECT6
  69.     1,              // UNI_PTEFFECT7
  70.     1,              // UNI_PTEFFECT8
  71.     1,              // UNI_PTEFFECT9
  72.     1,              // UNI_PTEFFECTA
  73.     1,              // UNI_PTEFFECTB
  74.     1,              // UNI_PTEFFECTC
  75.     1,              // UNI_PTEFFECTD
  76.     1,              // UNI_PTEFFECTE
  77.     1,              // UNI_PTEFFECTF
  78.     1,                // UNI_S3MEFFECTA
  79.     1,              // UNI_S3MEFFECTD
  80.     1,              // UNI_S3MEFFECTE
  81.     1,              // UNI_S3MEFFECTF
  82.     1,              // UNI_S3MEFFECTI
  83.     1,              // UNI_S3MEFFECTQ
  84.     1,                // UNI_S3MEFFECTT
  85.     1,                // UNI_XMEFFECTA
  86.     1                // UNI_XMEFFECTP
  87. };
  88.  
  89.  
  90. UBYTE *unibuf;        // pointer to the temporary unitrk buffer
  91. UWORD unimax;        // maximum number of bytes to be written to this buffer
  92.  
  93. UWORD unipc;        // index in the buffer where next opcode will be written
  94. UWORD unitt;        // holds index of the rep/len byte of a row
  95. UWORD lastp;        // holds index to the previous row (needed for compressing)
  96.  
  97. UBYTE *rowstart;    // startadress of a row
  98. UBYTE *rowend;      // endaddress of a row (exclusive)
  99. UBYTE *rowpc;       // current unimod(tm) programcounter
  100.  
  101.  
  102. void UniSetRow(UBYTE *t)
  103. {
  104.     rowstart=t;
  105.     rowpc=rowstart;
  106.     rowend=rowstart+(*(rowpc++)&0x1f);
  107. }
  108.  
  109.  
  110. UBYTE UniGetByte(void)
  111. {
  112.     return (rowpc<rowend) ? *(rowpc++) : 0;
  113. }
  114.  
  115.  
  116. void UniSkipOpcode(UBYTE op)
  117. {
  118.     UWORD t=unioperands[op];
  119.     while(t--) UniGetByte();
  120. }
  121.  
  122.  
  123.  
  124. UBYTE *UniFindRow(UBYTE *t,UWORD row)
  125. /*
  126.     Finds the address of row number 'row' in the UniMod(tm) stream 't'
  127.  
  128.     returns NULL if the row can't be found.
  129. */
  130. {
  131.     UBYTE c,l;
  132.  
  133.     while(1){
  134.  
  135.         c=*t;                    // get rep/len byte
  136.  
  137.         if(!c) return NULL;        // zero ? -> end of track..
  138.  
  139.         l=(c>>5)+1;                // extract repeat value
  140.  
  141.         if(l>row) break;        // reached wanted row? -> return pointer
  142.  
  143.         row-=l;                    // havn't reached row yet.. update row
  144.         t+=c&0x1f;                // point t to the next row
  145.     }
  146.  
  147.     return t;
  148. }
  149.  
  150.  
  151.  
  152. void UniReset(void)
  153. /*
  154.     Resets index-pointers to create a new track.
  155. */
  156. {
  157.     unitt=0;        // reset index to rep/len byte
  158.     unipc=1;        // first opcode will be written to index 1
  159.     lastp=0;        // no previous row yet
  160.     unibuf[0]=0;    // clear rep/len byte
  161. }
  162.  
  163.  
  164.  
  165. void UniWrite(UBYTE data)
  166. /*
  167.     Appends one byte of data to the current row of a track.
  168. */
  169. {
  170.     // write byte to current position and update
  171.  
  172.     unibuf[unipc++]=data;
  173.  
  174.     // Check if we've reached the end of the buffer
  175.  
  176.     if(unipc>(unimax-TRESHOLD)){
  177.  
  178.         UBYTE *newbuf;
  179.  
  180.         /* We've reached the end of the buffer, so expand
  181.            the buffer by BUFPAGE bytes */
  182.  
  183.         newbuf=realloc(unibuf,unimax+BUFPAGE);
  184.  
  185.         // Check if realloc succeeded
  186.  
  187.         if(newbuf!=NULL){
  188.             unibuf=newbuf;
  189.             unimax+=BUFPAGE;
  190.         }
  191.         else{
  192.             /* realloc failed, so decrease unipc so we won't write beyond
  193.                the end of the buffer.. I don't report the out-of-memory
  194.                here; the UniDup() will fail anyway so that's where the
  195.                loader sees that something went wrong */
  196.  
  197.             unipc--;
  198.         }
  199.     }
  200. }
  201.  
  202.  
  203.  
  204. void UniInstrument(UBYTE ins)
  205. /*
  206.     Appends UNI_INSTRUMENT opcode to the unitrk stream.
  207. */
  208. {
  209.     UniWrite(UNI_INSTRUMENT);
  210.     UniWrite(ins);
  211. }
  212.  
  213.  
  214.  
  215. void UniNote(UBYTE note)
  216. /*
  217.     Appends UNI_NOTE opcode to the unitrk stream.
  218. */
  219. {
  220.     UniWrite(UNI_NOTE);
  221.     UniWrite(note);
  222. }
  223.  
  224.  
  225. void UniPTEffect(UBYTE eff,UBYTE dat)
  226. /*
  227.     Appends UNI_PTEFFECTX opcode to the unitrk stream.
  228. */
  229. {
  230.     if(eff!=0 || dat!=0){                // don't write empty effect
  231.         UniWrite(UNI_PTEFFECT0+eff);
  232.         UniWrite(dat);
  233.     }
  234. }
  235.  
  236.  
  237.  
  238. BOOL MyCmp(UBYTE *a,UBYTE *b,UWORD l)
  239. {
  240.     UWORD t;
  241.  
  242.     for(t=0;t<l;t++){
  243.         if(*(a++)!=*(b++)) return 0;
  244.     }
  245.     return 1;
  246. }
  247.  
  248.  
  249.  
  250. void UniNewline(void)
  251. /*
  252.     Closes the current row of a unitrk stream (updates the rep/len byte)
  253.     and sets pointers to start a new row.
  254. */
  255. {
  256.     UWORD n,l,len;
  257.  
  258.     n=(unibuf[lastp]>>5)+1;        // repeat of previous row
  259.     l=(unibuf[lastp]&0x1f);        // length of previous row
  260.  
  261.     len=unipc-unitt;            // length of current row
  262.  
  263.     /* Now, check if the previous and the current row are identical..
  264.        when they are, just increase the repeat field of the previous row */
  265.  
  266.     if(n<8 && len==l && MyCmp(&unibuf[lastp+1],&unibuf[unitt+1],len-1)){
  267.         unibuf[lastp]+=0x20;
  268.         unipc=unitt+1;
  269.     }
  270.     else{
  271.         // current and previous row aren't equal.. so just update the pointers
  272.  
  273.         unibuf[unitt]=len;
  274.         lastp=unitt;
  275.         unitt=unipc;
  276.         unipc++;
  277.     }
  278. }
  279.  
  280.  
  281.  
  282.  
  283. UBYTE *UniDup(void)
  284. /*
  285.     Terminates the current unitrk stream and returns a pointer
  286.     to a copy of the stream.
  287. */
  288. {
  289.     UBYTE *d;
  290.  
  291.     unibuf[unitt]=0;
  292.  
  293.     if((d=malloc(unipc))==NULL){
  294.         myerr=ERROR_ALLOC_STRUCT;
  295.         return NULL;
  296.     }
  297.     memcpy(d,unibuf,unipc);
  298.  
  299.     return d;
  300. }
  301.  
  302.  
  303.  
  304. UWORD TrkLen(UBYTE *t)
  305. /*
  306.     Determines the length (in rows) of a unitrk stream 't'
  307. */
  308. {
  309.     UWORD len=0;
  310.     UBYTE c;
  311.  
  312.     while(c=*t&0x1f){
  313.         len+=c;
  314.         t+=c;
  315.     }
  316.     len++;
  317.  
  318.     return len;
  319. }
  320.  
  321.  
  322.  
  323. BOOL UniInit(void)
  324. {
  325.     unimax=BUFPAGE;
  326.  
  327.     if(!(unibuf=malloc(unimax))){
  328.         myerr=ERROR_ALLOC_STRUCT;
  329.         return 0;
  330.     }
  331.     return 1;
  332. }
  333.  
  334.  
  335.  
  336. void UniCleanup(void)
  337. {
  338.     if(unibuf!=NULL) free(unibuf);
  339.     unibuf=NULL;
  340. }
  341.  
  342.