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