home *** CD-ROM | disk | FTP | other *** search
/ The Games Machine 25 / GNOME_DEMO.iso / amiga / music / mikmod.lzx / mikmod / munitrk.c < prev    next >
C/C++ Source or Header  |  1999-01-06  |  7KB  |  345 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_XMEFFECTP */
  90. };
  91.  
  92.  
  93. /***************************************************************************
  94. >>>>>>>>>>> Next are the routines for reading a UNITRK stream: <<<<<<<<<<<<<
  95. ***************************************************************************/
  96.  
  97.  
  98. static UBYTE *rowstart;        /* startadress of a row */
  99. static UBYTE *rowend;          /* endaddress of a row (exclusive) */
  100. static UBYTE *rowpc;           /* current unimod(tm) programcounter */
  101.  
  102.  
  103. void UniSetRow(UBYTE *t)
  104. {
  105.     rowstart=t;
  106.     rowpc=rowstart;
  107.     rowend=rowstart+(*(rowpc++)&0x1f);
  108. }
  109.  
  110.  
  111. UBYTE UniGetByte(void)
  112. {
  113.     return (rowpc<rowend) ? *(rowpc++) : 0;
  114. }
  115.  
  116.  
  117. void UniSkipOpcode(UBYTE op)
  118. {
  119.     UWORD t=unioperands[op];
  120.     while(t--) UniGetByte();
  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. /***************************************************************************
  153. >>>>>>>>>>> Next are the routines for CREATING UNITRK streams: <<<<<<<<<<<<<
  154. ***************************************************************************/
  155.  
  156.  
  157. static UBYTE *unibuf;        /* pointer to the temporary unitrk buffer */
  158. static UWORD unimax;        /* maximum number of bytes to be written to this buffer */
  159.  
  160. static UWORD unipc;            /* index in the buffer where next opcode will be written */
  161. static UWORD unitt;            /* holds index of the rep/len byte of a row */
  162. static UWORD lastp;            /* holds index to the previous row (needed for compressing) */
  163.  
  164.  
  165. void UniReset(void)
  166. /*
  167.     Resets index-pointers to create a new track.
  168. */
  169. {
  170.     unitt=0;        /* reset index to rep/len byte */
  171.     unipc=1;        /* first opcode will be written to index 1 */
  172.     lastp=0;        /* no previous row yet */
  173.     unibuf[0]=0;    /* clear rep/len byte */
  174. }
  175.  
  176.  
  177. void UniWrite(UBYTE data)
  178. /*
  179.     Appends one byte of data to the current row of a track.
  180. */
  181. {
  182.     /* write byte to current position and update */
  183.  
  184.     unibuf[unipc++]=data;
  185.  
  186.     /* Check if we've reached the end of the buffer */
  187.  
  188.     if(unipc>(unimax-TRESHOLD)){
  189.  
  190.         UBYTE *newbuf;
  191.  
  192.         /* We've reached the end of the buffer, so expand
  193.            the buffer by BUFPAGE bytes */
  194.  
  195.         newbuf=realloc(unibuf,unimax+BUFPAGE);
  196.  
  197.         /* Check if realloc succeeded */
  198.  
  199.         if(newbuf!=NULL){
  200.             unibuf=newbuf;
  201.             unimax+=BUFPAGE;
  202.         }
  203.         else{
  204.             /* realloc failed, so decrease unipc so we won't write beyond
  205.                the end of the buffer.. I don't report the out-of-memory
  206.                here; the UniDup() will fail anyway so that's where the
  207.                loader sees that something went wrong */
  208.  
  209.             unipc--;
  210.         }
  211.     }
  212. }
  213.  
  214.  
  215. void UniInstrument(UBYTE ins)
  216. /*
  217.     Appends UNI_INSTRUMENT opcode to the unitrk stream.
  218. */
  219. {
  220.     UniWrite(UNI_INSTRUMENT);
  221.     UniWrite(ins);
  222. }
  223.  
  224.  
  225. void UniNote(UBYTE note)
  226. /*
  227.     Appends UNI_NOTE opcode to the unitrk stream.
  228. */
  229. {
  230.     UniWrite(UNI_NOTE);
  231.     UniWrite(note);
  232. }
  233.  
  234.  
  235. void UniPTEffect(UBYTE eff,UBYTE dat)
  236. /*
  237.     Appends UNI_PTEFFECTX opcode to the unitrk stream.
  238. */
  239. {
  240.     if(eff!=0 || dat!=0){                /* don't write empty effect */
  241.         UniWrite(UNI_PTEFFECT0+eff);
  242.         UniWrite(dat);
  243.     }
  244. }
  245.  
  246.  
  247. BOOL MyCmp(UBYTE *a,UBYTE *b,UWORD l)
  248. {
  249.     UWORD t;
  250.  
  251.     for(t=0;t<l;t++){
  252.         if(*(a++)!=*(b++)) return 0;
  253.     }
  254.     return 1;
  255. }
  256.  
  257.  
  258. void UniNewline(void)
  259. /*
  260.     Closes the current row of a unitrk stream (updates the rep/len byte)
  261.     and sets pointers to start a new row.
  262. */
  263. {
  264.     UWORD n,l,len;
  265.  
  266.     n=(unibuf[lastp]>>5)+1;        /* repeat of previous row */
  267.     l=(unibuf[lastp]&0x1f);        /* length of previous row */
  268.  
  269.     len=unipc-unitt;            /* length of current row */
  270.  
  271.     /* Now, check if the previous and the current row are identical..
  272.        when they are, just increase the repeat field of the previous row */
  273.  
  274.     if(n<8 && len==l && MyCmp(&unibuf[lastp+1],&unibuf[unitt+1],len-1)){
  275.         unibuf[lastp]+=0x20;
  276.         unipc=unitt+1;
  277.     }
  278.     else{
  279.         /* current and previous row aren't equal.. so just update the pointers */
  280.  
  281.         unibuf[unitt]=len;
  282.         lastp=unitt;
  283.         unitt=unipc;
  284.         unipc++;
  285.     }
  286. }
  287.  
  288.  
  289. UBYTE *UniDup(void)
  290. /*
  291.     Terminates the current unitrk stream and returns a pointer
  292.     to a copy of the stream.
  293. */
  294. {
  295.     UBYTE *d;
  296.  
  297.     unibuf[unitt]=0;
  298.  
  299.     if((d=malloc(unipc))==NULL){
  300.         myerr=ERROR_ALLOC_STRUCT;
  301.         return NULL;
  302.     }
  303.     memcpy(d,unibuf,unipc);
  304.  
  305.     return d;
  306. }
  307.  
  308.  
  309. UWORD TrkLen(UBYTE *t)
  310. /*
  311.     Determines the length (in rows) of a unitrk stream 't'
  312. */
  313. {
  314.     UWORD len=0;
  315.     UBYTE c;
  316.  
  317.     while(c=*t&0x1f){
  318.         len+=c;
  319.         t+=c;
  320.     }
  321.     len++;
  322.  
  323.     return len;
  324. }
  325.  
  326.  
  327. BOOL UniInit(void)
  328. {
  329.     unimax=BUFPAGE;
  330.  
  331.     if(!(unibuf=malloc(unimax))){
  332.         myerr=ERROR_ALLOC_STRUCT;
  333.         return 0;
  334.     }
  335.     return 1;
  336. }
  337.  
  338.  
  339. void UniCleanup(void)
  340. {
  341.     if(unibuf!=NULL) free(unibuf);
  342.     unibuf=NULL;
  343. }
  344.  
  345.