home *** CD-ROM | disk | FTP | other *** search
/ PC Online 1999 February / PCO_0299.ISO / filesbbs / linux / mikmod-3.000 / mikmod-3 / mikmod-3.1.2 / playercode / munitrk.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-12-07  |  7.1 KB  |  277 lines

  1. /*    MikMod sound library
  2.     (c) 1998 Miodrag Vallat and others - see file AUTHORS for complete list
  3.  
  4.     This library is free software; you can redistribute it and/or modify
  5.     it under the terms of the GNU Library General Public License as
  6.     published by the Free Software Foundation; either version 2 of
  7.     the License, or (at your option) any later version.
  8.  
  9.     This program is distributed in the hope that it will be useful,
  10.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.     GNU Library General Public License for more details.
  13.  
  14.     You should have received a copy of the GNU Library General Public
  15.     License along with this library; if not, write to the Free Software
  16.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. */
  18.  
  19. /*==============================================================================
  20.  
  21.   $Id: munitrk.c,v 1.16 1998/12/07 06:00:47 miod Exp $
  22.  
  23.   All routines dealing with the manipulation of UNITRK streams
  24.  
  25. ==============================================================================*/
  26.  
  27. #ifdef HAVE_CONFIG_H
  28. #include "config.h"
  29. #endif
  30.  
  31. #include <mikmod_internals.h>
  32.  
  33. #include <string.h>
  34.  
  35. /* Unibuffer chunk size */
  36. #define BUFPAGE  128
  37.  
  38. static    UWORD unioperands[UNI_LAST]={
  39.     0, /* not used */
  40.     1, /* UNI_NOTE */
  41.     1, /* UNI_INSTRUMENT */
  42.     1, /* UNI_PTEFFECT0 */
  43.     1, /* UNI_PTEFFECT1 */
  44.     1, /* UNI_PTEFFECT2 */
  45.     1, /* UNI_PTEFFECT3 */
  46.     1, /* UNI_PTEFFECT4 */
  47.     1, /* UNI_PTEFFECT5 */
  48.     1, /* UNI_PTEFFECT6 */
  49.     1, /* UNI_PTEFFECT7 */
  50.     1, /* UNI_PTEFFECT8 */
  51.     1, /* UNI_PTEFFECT9 */
  52.     1, /* UNI_PTEFFECTA */
  53.     1, /* UNI_PTEFFECTB */
  54.     1, /* UNI_PTEFFECTC */
  55.     1, /* UNI_PTEFFECTD */
  56.     1, /* UNI_PTEFFECTE */
  57.     1, /* UNI_PTEFFECTF */
  58.     1, /* UNI_S3MEFFECTA */
  59.     1, /* UNI_S3MEFFECTD */
  60.     1, /* UNI_S3MEFFECTE */
  61.     1, /* UNI_S3MEFFECTF */
  62.     1, /* UNI_S3MEFFECTI */
  63.     1, /* UNI_S3MEFFECTQ */
  64.     1, /* UNI_S3MEFFECTR */
  65.     1, /* UNI_S3MEFFECTT */
  66.     1, /* UNI_S3MEFFECTU */
  67.     0, /* UNI_KEYOFF */
  68.     1, /* UNI_KEYFADE */
  69.     2, /* UNI_VOLEFFECTS */
  70.     1, /* UNI_XMEFFECT4 */
  71.     1, /* UNI_XMEFFECTA */
  72.     1, /* UNI_XMEFFECTE1 */
  73.     1, /* UNI_XMEFFECTE2 */
  74.     1, /* UNI_XMEFFECTEA */
  75.     1, /* UNI_XMEFFECTEB */
  76.     1, /* UNI_XMEFFECTG */
  77.     1, /* UNI_XMEFFECTH */
  78.     1, /* UNI_XMEFFECTL */
  79.     1, /* UNI_XMEFFECTP */
  80.     1, /* UNI_XMEFFECTX1 */
  81.     1, /* UNI_XMEFFECTX2 */
  82.     1, /* UNI_ITEFFECTG */
  83.     1, /* UNI_ITEFFECTH */
  84.     1, /* UNI_ITEFFECTI */
  85.     1, /* UNI_ITEFFECTM */
  86.     1, /* UNI_ITEFFECTN */
  87.     1, /* UNI_ITEFFECTP */
  88.     1, /* UNI_ITEFFECTU */
  89.     1, /* UNI_ITEFFECTW */
  90.     1, /* UNI_ITEFFECTY */
  91.     2, /* UNI_ITEFFECTZ */
  92.     1, /* UNI_ITEFFECTS0 */
  93.     2, /* UNI_ULTEFFECT9 */
  94. };
  95.  
  96. /* Sparse description of the internal module format
  97.    ------------------------------------------------
  98.  
  99.   A UNITRK stream is an array of bytes representing a single track of a pattern.
  100. It's made up of 'repeat/length' bytes, opcodes and operands (sort of a assembly
  101. language):
  102.  
  103. rrrlllll
  104. [REP/LEN][OPCODE][OPERAND][OPCODE][OPERAND] [REP/LEN][OPCODE][OPERAND]..
  105. ^                                         ^ ^
  106. |-------ROWS 0 - 0+REP of a track---------| |-------ROWS xx - xx+REP of a track...
  107.  
  108.   The rep/len byte contains the number of bytes in the current row, _including_
  109. the length byte itself (So the LENGTH byte of row 0 in the previous example
  110. would have a value of 5). This makes it easy to search through a stream for a
  111. particular row. A track is concluded by a 0-value length byte.
  112.  
  113.   The upper 3 bits of the rep/len byte contain the number of times -1 this row
  114. is repeated for this track. (so a value of 7 means this row is repeated 8 times)
  115.  
  116.   Opcodes can range from 1 to 255 but currently only opcodes 1 to 52 are being
  117. used. Each opcode can have a different number of operands. You can find the
  118. number of operands to a particular opcode by using the opcode as an index into
  119. the 'unioperands' table.
  120.  
  121. */
  122.  
  123. /*========== Reading routines */
  124.  
  125. static    UBYTE *rowstart; /* startadress of a row */
  126. static    UBYTE *rowend;   /* endaddress of a row (exclusive) */
  127. static    UBYTE *rowpc;    /* current unimod(tm) programcounter */
  128.  
  129.  
  130. void UniSetRow(UBYTE* t)
  131. {
  132.     rowstart = t;
  133.     rowpc    = rowstart;
  134.     rowend   = rowstart+(*(rowpc++)&0x1f);
  135. }
  136.  
  137. UBYTE UniGetByte(void)
  138. {
  139.     return (rowpc<rowend)?*(rowpc++):0;
  140. }
  141.  
  142. void UniSkipOpcode(UBYTE op)
  143. {
  144.     if(op<UNI_LAST) {
  145.         UWORD t=unioperands[op];
  146.  
  147.         while(t--) UniGetByte();
  148.     }
  149. }
  150.  
  151. /* Finds the address of row number 'row' in the UniMod(tm) stream 't' returns
  152.    NULL if the row can't be found. */
  153. UBYTE *UniFindRow(UBYTE* t,UWORD row)
  154. {
  155.     UBYTE c,l;
  156.  
  157.     while(1) {
  158.         c = *t;             /* get rep/len byte */
  159.         if(!c) return NULL; /* zero ? -> end of track.. */
  160.         l = (c>>5)+1;       /* extract repeat value */
  161.         if(l>row) break;    /* reached wanted row? -> return pointer */
  162.         row -= l;           /* haven't reached row yet.. update row */
  163.         t += c&0x1f;        /* point t to the next row */
  164.     }
  165.     return t;
  166. }
  167.  
  168. /*========== Writing routines */
  169.  
  170. static    UBYTE *unibuf; /* pointer to the temporary unitrk buffer */
  171. static    UWORD unimax;  /* buffer size */
  172.  
  173. static    UWORD unipc;   /* buffer cursor */
  174. static    UWORD unitt;   /* current row index */
  175. static    UWORD lastp;   /* previous row index */
  176.  
  177. /* Resets index-pointers to create a new track. */
  178. void UniReset(void)
  179. {
  180.     unitt     = 0;   /* reset index to rep/len byte */
  181.     unipc     = 1;   /* first opcode will be written to index 1 */
  182.     lastp     = 0;   /* no previous row yet */
  183.     unibuf[0] = 0;   /* clear rep/len byte */
  184. }
  185.  
  186. /* Expands the buffer */
  187. static BOOL UniExpand(int wanted)
  188. {
  189.     if ((unipc+wanted)>=unimax) {
  190.         UBYTE *newbuf;
  191.  
  192.         /* Expand the buffer by BUFPAGE bytes */
  193.         newbuf=(UBYTE*)realloc(unibuf,(unimax+BUFPAGE)*sizeof(UBYTE));
  194.  
  195.         /* Check if realloc succeeded */
  196.         if(newbuf) {
  197.             unibuf = newbuf;
  198.             unimax+=BUFPAGE;
  199.             return 1;
  200.         } else 
  201.             return 0;
  202.     }
  203.     return 1;
  204. }
  205.  
  206. /* Appends one byte of data to the current row of a track. */
  207. void UniWrite(UBYTE data)
  208. {
  209.     if (UniExpand(1))
  210.         /* write byte to current position and update */
  211.         unibuf[unipc++] = data;
  212. }
  213.  
  214. static BOOL MyCmp(UBYTE* a,UBYTE* b,UWORD l)
  215. {
  216.     UWORD t;
  217.  
  218.     for(t=0;t<l;t++)
  219.         if(*(a++)!=*(b++)) return 0;
  220.     return 1;
  221. }
  222.  
  223. /* Closes the current row of a unitrk stream (updates the rep/len byte) and sets
  224.    pointers to start a new row. */
  225. void UniNewline(void)
  226. {
  227.     UWORD n,l,len;
  228.  
  229.     n = (unibuf[lastp]>>5)+1;     /* repeat of previous row */
  230.     l = (unibuf[lastp]&0x1f);     /* length of previous row */
  231.  
  232.     len = unipc-unitt;            /* length of current row */
  233.  
  234.     /* Now, check if the previous and the current row are identical.. when they
  235.        are, just increase the repeat field of the previous row */
  236.     if(n<8 && len==l && MyCmp(&unibuf[lastp+1],&unibuf[unitt+1],len-1)) {
  237.         unibuf[lastp]+=0x20;
  238.         unipc = unitt+1;
  239.     } else {
  240.         if (UniExpand(unitt-unipc)) {
  241.             /* current and previous row aren't equal... update the pointers */
  242.             unibuf[unitt] = len;
  243.             lastp = unitt;
  244.             unitt = unipc++;
  245.         }
  246.     }
  247. }
  248.  
  249. /* Terminates the current unitrk stream and returns a pointer to a copy of the
  250.    stream. */
  251. UBYTE* UniDup(void)
  252. {
  253.     UBYTE *d;
  254.  
  255.     if (!UniExpand(unitt-unipc)) return NULL;
  256.     unibuf[unitt] = 0;
  257.  
  258.     if(!(d=(UBYTE *)_mm_malloc(unipc))) return NULL;
  259.     memcpy(d,unibuf,unipc);
  260.  
  261.     return d;
  262. }
  263.  
  264. BOOL UniInit(void)
  265. {
  266.     unimax = BUFPAGE;
  267.  
  268.     if(!(unibuf=(UBYTE*)_mm_malloc(unimax*sizeof(UBYTE)))) return 0;
  269.     return 1;
  270. }
  271.  
  272. void UniCleanup(void)
  273. {
  274.     if(unibuf) free(unibuf);
  275.     unibuf = NULL;
  276. }
  277.