home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / pc / ELYVER10.ZIP / MIKXMAS.ZIP / source / munitrk.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-12-12  |  7.7 KB  |  347 lines

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