A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 372 lines 8.6 kB view raw
1/* MikMod sound library 2 (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file 3 AUTHORS 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 DSIK internal format (DSM) module loader 26 27==============================================================================*/ 28 29#ifdef HAVE_CONFIG_H 30#include "config.h" 31#endif 32 33#ifdef HAVE_UNISTD_H 34#include <unistd.h> 35#endif 36 37#include <stdio.h> 38#ifdef HAVE_MEMORY_H 39#include <memory.h> 40#endif 41#include <string.h> 42 43#include "mikmod_internals.h" 44 45#ifdef SUNOS 46extern int fprintf(FILE *, const char *, ...); 47#endif 48 49/*========== Module structure */ 50 51#define DSM_MAXCHAN (16) 52#define DSM_MAXORDERS (128) 53 54typedef struct DSMSONG { 55 CHAR songname[28]; 56 UWORD version; 57 UWORD flags; 58 ULONG reserved2; 59 UWORD numord; 60 UWORD numsmp; 61 UWORD numpat; 62 UWORD numtrk; 63 UBYTE globalvol; 64 UBYTE mastervol; 65 UBYTE speed; 66 UBYTE bpm; 67 UBYTE panpos[DSM_MAXCHAN]; 68 UBYTE orders[DSM_MAXORDERS]; 69} DSMSONG; 70 71typedef struct DSMINST { 72 CHAR filename[13]; 73 UWORD flags; 74 UBYTE volume; 75 ULONG length; 76 ULONG loopstart; 77 ULONG loopend; 78 ULONG reserved1; 79 UWORD c2spd; 80 UWORD period; 81 CHAR samplename[28]; 82} DSMINST; 83 84typedef struct DSMNOTE { 85 UBYTE note,ins,vol,cmd,inf; 86} DSMNOTE; 87 88#define DSM_SURROUND (0xa4) 89 90/*========== Loader variables */ 91 92static const CHAR* SONGID="SONG"; 93static const CHAR* INSTID="INST"; 94static const CHAR* PATTID="PATT"; 95 96static UBYTE blockid[4]; 97static ULONG blockln; 98static ULONG blocklp; 99static DSMSONG* mh=NULL; 100static DSMNOTE* dsmbuf=NULL; 101 102static CHAR DSM_Version[]="DSIK DSM-format"; 103 104static const unsigned char DSMSIG[4+4]={'R','I','F','F','D','S','M','F'}; 105 106/*========== Loader code */ 107 108static int DSM_Test(void) 109{ 110 UBYTE id[12]; 111 112 if(!_mm_read_UBYTES(id,12,modreader)) return 0; 113 if(!memcmp(id,DSMSIG,4) && !memcmp(id+8,DSMSIG+4,4)) return 1; 114 115 return 0; 116} 117 118static int DSM_Init(void) 119{ 120 if(!(dsmbuf=(DSMNOTE *)MikMod_malloc(DSM_MAXCHAN*64*sizeof(DSMNOTE)))) return 0; 121 if(!(mh=(DSMSONG *)MikMod_calloc(1,sizeof(DSMSONG)))) return 0; 122 return 1; 123} 124 125static void DSM_Cleanup(void) 126{ 127 MikMod_free(dsmbuf); 128 MikMod_free(mh); 129 dsmbuf = NULL; 130 mh = NULL; 131} 132 133static int GetBlockHeader(void) 134{ 135 /* make sure we're at the right position for reading the 136 next riff block, no matter how many bytes read */ 137 _mm_fseek(modreader, blocklp+blockln, SEEK_SET); 138 139 while(1) { 140 _mm_read_UBYTES(blockid,4,modreader); 141 blockln=_mm_read_I_ULONG(modreader); 142 if(_mm_eof(modreader)) { 143 _mm_errno = MMERR_LOADING_HEADER; 144 return 0; 145 } 146 147 if(memcmp(blockid,SONGID,4) && memcmp(blockid,INSTID,4) && 148 memcmp(blockid,PATTID,4)) { 149#ifdef MIKMOD_DEBUG 150 fprintf(stderr,"\rDSM: Skipping unknown block type %4.4s\n",blockid); 151#endif 152 _mm_fseek(modreader, blockln, SEEK_CUR); 153 } else 154 break; 155 } 156 157 blocklp = _mm_ftell(modreader); 158 159 return 1; 160} 161 162static int DSM_ReadPattern(void) 163{ 164 int flag,row=0; 165 SWORD length; 166 DSMNOTE *n; 167 168 /* clear pattern data */ 169 memset(dsmbuf,255,DSM_MAXCHAN*64*sizeof(DSMNOTE)); 170 length=_mm_read_I_SWORD(modreader); 171 172 while(row<64) { 173 flag=_mm_read_UBYTE(modreader); 174 if((_mm_eof(modreader))||(--length<0)) { 175 _mm_errno = MMERR_LOADING_PATTERN; 176 return 0; 177 } 178 179 if(flag) { 180 n=&dsmbuf[((flag&0xf)*64)+row]; 181 if(flag&0x80) n->note=_mm_read_UBYTE(modreader); 182 if(flag&0x40) n->ins=_mm_read_UBYTE(modreader); 183 if(flag&0x20) n->vol=_mm_read_UBYTE(modreader); 184 if(flag&0x10) { 185 n->cmd=_mm_read_UBYTE(modreader); 186 n->inf=_mm_read_UBYTE(modreader); 187 } 188 } else 189 row++; 190 } 191 192 return 1; 193} 194 195static UBYTE *DSM_ConvertTrack(DSMNOTE *tr) 196{ 197 int t; 198 UBYTE note,ins,vol,cmd,inf; 199 200 UniReset(); 201 for(t=0;t<64;t++) { 202 note=tr[t].note; 203 ins=tr[t].ins; 204 vol=tr[t].vol; 205 cmd=tr[t].cmd; 206 inf=tr[t].inf; 207 208 if(ins!=0 && ins!=255) UniInstrument(ins-1); 209 if(note!=255) UniNote(note-1); /* normal note */ 210 if(vol<65) UniPTEffect(0xc,vol); 211 212 if(cmd!=255) { 213 if(cmd==0x8) { 214 if(inf==DSM_SURROUND) 215 UniEffect(UNI_ITEFFECTS0,0x91); 216 else 217 if(inf<=0x80) { 218 inf=(inf<0x80)?inf<<1:255; 219 UniPTEffect(cmd,inf); 220 } 221 } else 222 if(cmd==0xb) { 223 if(inf<=0x7f) UniPTEffect(cmd,inf); 224 } else { 225 /* Convert pattern jump from Dec to Hex */ 226 if(cmd == 0xd) 227 inf = (((inf&0xf0)>>4)*10)+(inf&0xf); 228 UniPTEffect(cmd,inf); 229 } 230 } 231 UniNewline(); 232 } 233 return UniDup(); 234} 235 236static int DSM_Load(int curious) 237{ 238 int t; 239 DSMINST s; 240 SAMPLE *q; 241 int cursmp=0,curpat=0,track=0; 242 (void)curious; 243 244 blocklp=0; 245 blockln=12; 246 247 if(!GetBlockHeader()) return 0; 248 if(memcmp(blockid,SONGID,4)) { 249 _mm_errno = MMERR_LOADING_HEADER; 250 return 0; 251 } 252 253 _mm_read_UBYTES(mh->songname,28,modreader); 254 mh->version=_mm_read_I_UWORD(modreader); 255 mh->flags=_mm_read_I_UWORD(modreader); 256 mh->reserved2=_mm_read_I_ULONG(modreader); 257 mh->numord=_mm_read_I_UWORD(modreader); 258 mh->numsmp=_mm_read_I_UWORD(modreader); 259 mh->numpat=_mm_read_I_UWORD(modreader); 260 mh->numtrk=_mm_read_I_UWORD(modreader); 261 mh->globalvol=_mm_read_UBYTE(modreader); 262 mh->mastervol=_mm_read_UBYTE(modreader); 263 mh->speed=_mm_read_UBYTE(modreader); 264 mh->bpm=_mm_read_UBYTE(modreader); 265 _mm_read_UBYTES(mh->panpos,DSM_MAXCHAN,modreader); 266 _mm_read_UBYTES(mh->orders,DSM_MAXORDERS,modreader); 267 268 /* set module variables */ 269 of.initspeed=mh->speed; 270 of.inittempo=mh->bpm; 271 of.modtype=MikMod_strdup(DSM_Version); 272 of.numchn=mh->numtrk; 273 of.numpat=mh->numpat; 274 of.numtrk=of.numchn*of.numpat; 275 of.songname=DupStr(mh->songname,28,1); /* make a cstr of songname */ 276 of.reppos=0; 277 of.flags |= UF_PANNING; 278 /* XXX whenever possible, we should try to determine the original format. 279 Here we assume it was S3M-style wrt bpmlimit... */ 280 of.bpmlimit = 32; 281 282 for(t=0;t<DSM_MAXCHAN;t++) 283 of.panning[t]=mh->panpos[t]==DSM_SURROUND?PAN_SURROUND: 284 mh->panpos[t]<0x80?(mh->panpos[t]<<1):255; 285 286 if(!AllocPositions(mh->numord)) return 0; 287 of.numpos=0; 288 for(t=0;t<mh->numord;t++) { 289 int order=mh->orders[t]; 290 if(order==255) order=LAST_PATTERN; 291 else if (of.positions[t]>of.numpat) { /* SANITIY CHECK */ 292 /* fprintf(stderr,"positions[%d]=%d > numpat=%d\n",t,of.positions[t],of.numpat);*/ 293 _mm_errno = MMERR_LOADING_HEADER; 294 return 0; 295 } 296 of.positions[of.numpos]=order; 297 if(mh->orders[t]<254) of.numpos++; 298 } 299 300 of.numins=of.numsmp=mh->numsmp; 301 302 if(!AllocSamples()) return 0; 303 if(!AllocTracks()) return 0; 304 if(!AllocPatterns()) return 0; 305 306 while(cursmp<of.numins||curpat<of.numpat) { 307 if(!GetBlockHeader()) return 0; 308 if(!memcmp(blockid,INSTID,4) && cursmp<of.numins) { 309 q=&of.samples[cursmp]; 310 311 /* try to read sample info */ 312 _mm_read_UBYTES(s.filename,13,modreader); 313 s.flags=_mm_read_I_UWORD(modreader); 314 s.volume=_mm_read_UBYTE(modreader); 315 s.length=_mm_read_I_ULONG(modreader); 316 s.loopstart=_mm_read_I_ULONG(modreader); 317 s.loopend=_mm_read_I_ULONG(modreader); 318 s.reserved1=_mm_read_I_ULONG(modreader); 319 s.c2spd=_mm_read_I_UWORD(modreader); 320 s.period=_mm_read_I_UWORD(modreader); 321 _mm_read_UBYTES(s.samplename,28,modreader); 322 323 q->samplename=DupStr(s.samplename,28,1); 324 q->seekpos=_mm_ftell(modreader); 325 q->speed=s.c2spd; 326 q->length=s.length; 327 q->loopstart=s.loopstart; 328 q->loopend=s.loopend; 329 q->volume=s.volume; 330 331 if(s.flags&1) q->flags|=SF_LOOP; 332 if(s.flags&2) q->flags|=SF_SIGNED; 333 /* (s.flags&4) means packed sample, 334 but did they really exist in dsm ?*/ 335 cursmp++; 336 } else 337 if(!memcmp(blockid,PATTID,4) && curpat<of.numpat) { 338 DSM_ReadPattern(); 339 for(t=0;t<of.numchn;t++) 340 if(!(of.tracks[track++]=DSM_ConvertTrack(&dsmbuf[t*64]))) return 0; 341 curpat++; 342 } 343 } 344 345 return 1; 346} 347 348static CHAR *DSM_LoadTitle(void) 349{ 350 CHAR s[28]; 351 352 _mm_fseek(modreader,12,SEEK_SET); 353 if(!_mm_read_UBYTES(s,28,modreader)) return NULL; 354 355 return(DupStr(s,28,1)); 356} 357 358/*========== Loader information */ 359 360MIKMODAPI MLOADER load_dsm={ 361 NULL, 362 "DSM", 363 "DSM (DSIK internal format)", 364 DSM_Init, 365 DSM_Test, 366 DSM_Load, 367 DSM_Cleanup, 368 DSM_LoadTitle 369}; 370 371 372/* ex:set ts=4: */