📄 munitrk.c
字号:
/* MikMod sound library (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for complete list. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *//*============================================================================== $Id: munitrk.c,v 1.27 1999/10/25 16:31:41 miod Exp $ All routines dealing with the manipulation of UNITRK streams==============================================================================*/#ifdef HAVE_CONFIG_H#include "config.h"#endif#include "unimod_priv.h"#include <string.h>/* Unibuffer chunk size */#define BUFPAGE 128UWORD unioperands[UNI_LAST] ={ 0, /* not used */ 1, /* UNI_NOTE */ 1, /* UNI_INSTRUMENT */ 1, /* UNI_PTEFFECT0 */ 1, /* UNI_PTEFFECT1 */ 1, /* UNI_PTEFFECT2 */ 1, /* UNI_PTEFFECT3 */ 1, /* UNI_PTEFFECT4 */ 1, /* UNI_PTEFFECT5 */ 1, /* UNI_PTEFFECT6 */ 1, /* UNI_PTEFFECT7 */ 1, /* UNI_PTEFFECT8 */ 1, /* UNI_PTEFFECT9 */ 1, /* UNI_PTEFFECTA */ 1, /* UNI_PTEFFECTB */ 1, /* UNI_PTEFFECTC */ 1, /* UNI_PTEFFECTD */ 1, /* UNI_PTEFFECTE */ 1, /* UNI_PTEFFECTF */ 1, /* UNI_S3MEFFECTA */ 1, /* UNI_S3MEFFECTD */ 1, /* UNI_S3MEFFECTE */ 1, /* UNI_S3MEFFECTF */ 1, /* UNI_S3MEFFECTI */ 1, /* UNI_S3MEFFECTQ */ 1, /* UNI_S3MEFFECTR */ 1, /* UNI_S3MEFFECTT */ 1, /* UNI_S3MEFFECTU */ 0, /* UNI_KEYOFF */ 1, /* UNI_KEYFADE */ 2, /* UNI_VOLEFFECTS */ 1, /* UNI_XMEFFECT4 */ 1, /* UNI_XMEFFECTA */ 1, /* UNI_XMEFFECTE1 */ 1, /* UNI_XMEFFECTE2 */ 1, /* UNI_XMEFFECTEA */ 1, /* UNI_XMEFFECTEB */ 1, /* UNI_XMEFFECTG */ 1, /* UNI_XMEFFECTH */ 1, /* UNI_XMEFFECTL */ 1, /* UNI_XMEFFECTP */ 1, /* UNI_XMEFFECTX1 */ 1, /* UNI_XMEFFECTX2 */ 1, /* UNI_ITEFFECTG */ 1, /* UNI_ITEFFECTH */ 1, /* UNI_ITEFFECTI */ 1, /* UNI_ITEFFECTM */ 1, /* UNI_ITEFFECTN */ 1, /* UNI_ITEFFECTP */ 1, /* UNI_ITEFFECTT */ 1, /* UNI_ITEFFECTU */ 1, /* UNI_ITEFFECTW */ 1, /* UNI_ITEFFECTY */ 2, /* UNI_ITEFFECTZ */ 1, /* UNI_ITEFFECTS0 */ 2, /* UNI_ULTEFFECT9 */ 2, /* UNI_MEDSPEED */ 0, /* UNI_MEDEFFECTF1 */ 0, /* UNI_MEDEFFECTF2 */ 0 /* UNI_MEDEFFECTF3 */};/* Sparse description of the internal module format ------------------------------------------------ A UNITRK stream is an array of bytes representing a single track of a pattern. It's made up of 'repeat/length' bytes, opcodes and operands (sort of a assembly language): rrrlllll [REP/LEN][OPCODE][OPERAND][OPCODE][OPERAND] [REP/LEN][OPCODE][OPERAND].. ^ ^ ^ |-------ROWS 0 - 0+REP of a track---------| |-------ROWS xx - xx+REP of a track... The rep/len byte contains the number of bytes in the current row, _including_ the length byte itself (So the LENGTH byte of row 0 in the previous example would have a value of 5). This makes it easy to search through a stream for a particular row. A track is concluded by a 0-value length byte. The upper 3 bits of the rep/len byte contain the number of times -1 this row is repeated for this track. (so a value of 7 means this row is repeated 8 times) Opcodes can range from 1 to 255 but currently only opcodes 1 to 52 are being used. Each opcode can have a different number of operands. You can find the number of operands to a particular opcode by using the opcode as an index into the 'unioperands' table. *//*========== Reading routines */static UBYTE *rowstart; /* startadress of a row */static UBYTE *rowend; /* endaddress of a row (exclusive) */static UBYTE *rowpc; /* current unimod(tm) programcounter */void UniSetRow (UBYTE * t){ rowstart = t; rowpc = rowstart; rowend = t ? rowstart + (*(rowpc++) & 0x1f) : t;}UBYTE UniGetByte (void){ return (rowpc < rowend) ? *(rowpc++) : 0;}UWORD UniGetWord (void){ return ((UWORD) UniGetByte () << 8) | UniGetByte ();}void UniSkipOpcode (UBYTE op){ if (op < UNI_LAST) { UWORD t = unioperands[op]; while (t--) UniGetByte (); }}/* Finds the address of row number 'row' in the UniMod(tm) stream 't' returns NULL if the row can't be found. */UBYTE *UniFindRow (UBYTE * t, UWORD row){ UBYTE c, l; if (t) while (1) { c = *t; /* get rep/len byte */ if (!c) return NULL; /* zero ? -> end of track.. */ l = (c >> 5) + 1; /* extract repeat value */ if (l > row) break; /* reached wanted row? -> return pointer */ row -= l; /* haven't reached row yet.. update row */ t += c & 0x1f; /* point t to the next row */ } return t;}/*========== Writing routines */static UBYTE *unibuf; /* pointer to the temporary unitrk buffer */static UWORD unimax; /* buffer size */static UWORD unipc; /* buffer cursor */static UWORD unitt; /* current row index */static UWORD lastp; /* previous row index *//* Resets index-pointers to create a new track. */void UniReset (void){ unitt = 0; /* reset index to rep/len byte */ unipc = 1; /* first opcode will be written to index 1 */ lastp = 0; /* no previous row yet */ unibuf[0] = 0; /* clear rep/len byte */}/* Expands the buffer */static BOOL UniExpand (int wanted){ if ((unipc + wanted) >= unimax) { UBYTE *newbuf; /* Expand the buffer by BUFPAGE bytes */ newbuf = (UBYTE *) realloc (unibuf, (unimax + BUFPAGE) * sizeof (UBYTE)); /* Check if realloc succeeded */ if (newbuf) { unibuf = newbuf; unimax += BUFPAGE; return 1; } else return 0; } return 1;}/* Appends one byte of data to the current row of a track. */void UniWriteByte (UBYTE data){ if (UniExpand (1)) /* write byte to current position and update */ unibuf[unipc++] = data;}void UniWriteWord (UWORD data){ if (UniExpand (2)) { unibuf[unipc++] = data >> 8; unibuf[unipc++] = data & 0xff; }}static BOOL MyCmp (UBYTE * a, UBYTE * b, UWORD l){ UWORD t; for (t = 0; t < l; t++) if (*(a++) != *(b++)) return 0; return 1;}/* Closes the current row of a unitrk stream (updates the rep/len byte) and sets pointers to start a new row. */void UniNewline (void){ UWORD n, l, len; n = (unibuf[lastp] >> 5) + 1; /* repeat of previous row */ l = (unibuf[lastp] & 0x1f); /* length of previous row */ len = unipc - unitt; /* length of current row */ /* Now, check if the previous and the current row are identical.. when they are, just increase the repeat field of the previous row */ if (n < 8 && len == l && MyCmp (&unibuf[lastp + 1], &unibuf[unitt + 1], len - 1)) { unibuf[lastp] += 0x20; unipc = unitt + 1; } else { if (UniExpand (unitt - unipc)) { /* current and previous row aren't equal... update the pointers */ unibuf[unitt] = len; lastp = unitt; unitt = unipc++; } }}/* Terminates the current unitrk stream and returns a pointer to a copy of the stream. */UBYTE *UniDup (void){ UBYTE *d; if (!UniExpand (unitt - unipc)) return NULL; unibuf[unitt] = 0; if (!(d = (UBYTE *) _mm_malloc (unipc))) return NULL; memcpy (d, unibuf, unipc); return d;}BOOL UniInit (void){ unimax = BUFPAGE; if (!(unibuf = (UBYTE *) _mm_malloc (unimax * sizeof (UBYTE)))) return 0; return 1;}void UniCleanup (void){ if (unibuf) free (unibuf); unibuf = NULL;}/* ex:set ts=4: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -