munitrk.c
上传用户:wstnjxml
上传日期:2014-04-03
资源大小:7248k
文件大小:8k
源码类别:

Windows CE

开发平台:

C/C++

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