A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 507 lines 13 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 15 instrument MOD loader 26 Also supports Ultimate Sound Tracker (old M15 format) 27 28==============================================================================*/ 29 30#ifdef HAVE_CONFIG_H 31#include "config.h" 32#endif 33 34#ifdef HAVE_UNISTD_H 35#include <unistd.h> 36#endif 37 38#include <ctype.h> 39#include <stdio.h> 40#ifdef HAVE_MEMORY_H 41#include <memory.h> 42#endif 43#include <string.h> 44 45#include "mikmod_internals.h" 46 47#ifdef SUNOS 48extern int fprintf(FILE *, const char *, ...); 49#endif 50 51/*========== Module Structure */ 52 53typedef struct MSAMPINFO { 54 CHAR samplename[23]; /* 22 in module, 23 in memory */ 55 UWORD length; 56 UBYTE finetune; 57 UBYTE volume; 58 UWORD reppos; 59 UWORD replen; 60} MSAMPINFO; 61 62typedef struct MODULEHEADER { 63 CHAR songname[21]; /* the songname.., 20 in module, 21 in memory */ 64 MSAMPINFO samples[15]; /* all sampleinfo */ 65 UBYTE songlength; /* number of patterns used */ 66 UBYTE magic1; /* should be 127 */ 67 UBYTE positions[128]; /* which pattern to play at pos */ 68} MODULEHEADER; 69 70typedef struct MODNOTE { 71 UBYTE a,b,c,d; 72} MODNOTE; 73 74/*========== Loader variables */ 75 76static MODULEHEADER *mh = NULL; 77static MODNOTE *patbuf = NULL; 78static int ust_loader = 0; /* if TRUE, load as an ust module. */ 79 80/* known file formats which can confuse the loader */ 81#define REJECT 2 82static const char *signatures[REJECT]={ 83 "CAKEWALK", /* cakewalk midi files */ 84 "SZDD" /* Microsoft compressed files */ 85}; 86static const int siglen[REJECT]={8,4}; 87 88/*========== Loader code */ 89 90static int LoadModuleHeader(MODULEHEADER *h) 91{ 92 int t,u; 93 94 _mm_read_string(h->songname,20,modreader); 95 96 /* sanity check : title should contain printable characters and a bunch 97 of null chars */ 98 for(t=0;t<20;t++) 99 if((h->songname[t])&&(h->songname[t]<32)) return 0; 100 for(t=0;(h->songname[t])&&(t<20);t++); 101 if(t<20) for(;t<20;t++) if(h->songname[t]) return 0; 102 103 for(t=0;t<15;t++) { 104 MSAMPINFO *s=&h->samples[t]; 105 106 _mm_read_string(s->samplename,22,modreader); 107 s->length =_mm_read_M_UWORD(modreader); 108 s->finetune =_mm_read_UBYTE(modreader); 109 s->volume =_mm_read_UBYTE(modreader); 110 s->reppos =_mm_read_M_UWORD(modreader); 111 s->replen =_mm_read_M_UWORD(modreader); 112 113 /* sanity check : sample title should contain printable characters and 114 a bunch of null chars */ 115 for(u=0;u<20;u++) 116 if((s->samplename[u])&&(s->samplename[u]</*32*/14)) return 0; 117 for(u=0;(s->samplename[u])&&(u<20);u++); 118 if(u<20) for(;u<20;u++) if(s->samplename[u]) return 0; 119 120 /* sanity check : finetune values */ 121 if(s->finetune>>4) return 0; 122 } 123 124 h->songlength =_mm_read_UBYTE(modreader); 125 h->magic1 =_mm_read_UBYTE(modreader); /* should be 127 */ 126 127 /* sanity check : no more than 128 positions, restart position in range */ 128 if((!h->songlength)||(h->songlength>128)) return 0; 129 /* values encountered so far are 0x6a and 0x78 */ 130 if(((h->magic1&0xf8)!=0x78)&&(h->magic1!=0x6a)&&(h->magic1>h->songlength)) return 0; 131 132 _mm_read_UBYTES(h->positions,128,modreader); 133 134 /* sanity check : pattern range is 0..63 */ 135 for(t=0;t<128;t++) 136 if(h->positions[t]>63) return 0; 137 138 return(!_mm_eof(modreader)); 139} 140 141/* Checks the patterns in the modfile for UST / 15-inst indications. 142 For example, if an effect 3xx is found, it is assumed that the song 143 is 15-inst. If a 1xx effect has dat greater than 0x20, it is UST. 144 145 Returns: 0 indecisive; 1 = UST; 2 = 15-inst */ 146static int CheckPatternType(int numpat) 147{ 148 unsigned int t; 149 UBYTE eff, dat; 150 151 for(t=0;t<numpat*(64U*4);t++) { 152 /* Load the pattern into the temp buffer and scan it */ 153 _mm_skip_BYTE(modreader);_mm_skip_BYTE(modreader); 154 eff = _mm_read_UBYTE(modreader); 155 dat = _mm_read_UBYTE(modreader); 156 157 switch(eff) { 158 case 1: 159 if(dat>0x1f) return 1; 160 if(dat<0x3) return 2; 161 break; 162 case 2: 163 if(dat>0x1f) return 1; 164 return 2; 165 case 3: 166 if (dat) return 2; 167 break; 168 default: 169 return 2; 170 } 171 } 172 return 0; 173} 174 175static int M15_Test(void) 176{ 177 int t, numpat; 178 MODULEHEADER h; 179 180 ust_loader = 0; 181 memset(&h, 0, sizeof(MODULEHEADER)); 182 if(!LoadModuleHeader(&h)) return 0; 183 184 /* reject other file types */ 185 for(t=0;t<REJECT;t++) 186 if(!memcmp(h.songname,signatures[t],siglen[t])) return 0; 187 188 if(h.magic1>127) return 0; 189 if((!h.songlength)||(h.songlength>h.magic1)) return 0; 190 191 for(t=0;t<15;t++) { 192 /* all finetunes should be zero */ 193 if(h.samples[t].finetune) return 0; 194 195 /* all volumes should be <= 64 */ 196 if(h.samples[t].volume>64) return 0; 197 198 /* all instrument names should begin with s, st-, or a number */ 199 if((h.samples[t].samplename[0]=='s')|| 200 (h.samples[t].samplename[0]=='S')) { 201 if((memcmp(h.samples[t].samplename,"st-",3)) && 202 (memcmp(h.samples[t].samplename,"ST-",3)) && 203 (*h.samples[t].samplename)) 204 ust_loader = 1; 205 } else 206 if(!isdigit((int)h.samples[t].samplename[0])) 207 ust_loader = 1; 208 209 if(h.samples[t].length>4999||h.samples[t].reppos>9999) { 210 ust_loader = 0; 211 if(h.samples[t].length>32768) return 0; 212 } 213 214 /* if loop information is incorrect as words, but correct as bytes, 215 this is likely to be an ust-style module */ 216 if((h.samples[t].reppos+h.samples[t].replen>h.samples[t].length)&& 217 (h.samples[t].reppos+h.samples[t].replen<(h.samples[t].length<<1))) { 218 ust_loader = 1; 219 return 1; 220 } 221 222 if(!ust_loader) return 1; 223 } 224 225 for(numpat=0,t=0;t<h.songlength;t++) 226 if(h.positions[t]>numpat) 227 numpat = h.positions[t]; 228 numpat++; 229 switch(CheckPatternType(numpat)) { 230 case 0: /* indecisive, so check more clues... */ 231 break; 232 case 1: 233 ust_loader = 1; 234 break; 235 case 2: 236 ust_loader = 0; 237 break; 238 } 239 return 1; 240} 241 242static int M15_Init(void) 243{ 244 if(!(mh=(MODULEHEADER*)MikMod_calloc(1,sizeof(MODULEHEADER)))) return 0; 245 return 1; 246} 247 248static void M15_Cleanup(void) 249{ 250 MikMod_free(mh); 251 MikMod_free(patbuf); 252 mh=NULL; 253 patbuf=NULL; 254} 255 256/* 257Old (amiga) noteinfo: 258 259 _____byte 1_____ byte2_ _____byte 3_____ byte4_ 260/ \ / \ / \ / \ 2610000 0000-00000000 0000 0000-00000000 262 263Upper four 12 bits for Lower four Effect command. 264bits of sam- note period. bits of sam- 265ple number. ple number. 266*/ 267 268static UBYTE M15_ConvertNote(MODNOTE* n, UBYTE lasteffect) 269{ 270 UBYTE instrument,effect,effdat,note; 271 UWORD period; 272 UBYTE lastnote=0; 273 274 /* decode the 4 bytes that make up a single note */ 275 instrument = n->c>>4; 276 period = (((UWORD)n->a&0xf)<<8)+n->b; 277 effect = n->c&0xf; 278 effdat = n->d; 279 280 /* Convert the period to a note number */ 281 note=0; 282 if(period) { 283 for(note=0;note<7*OCTAVE;note++) 284 if(period>=npertab[note]) break; 285 if(note==7*OCTAVE) note=0; 286 else note++; 287 } 288 289 if(instrument) { 290 /* if instrument does not exist, note cut */ 291 if((instrument>15)||(!mh->samples[instrument-1].length)) { 292 UniPTEffect(0xc,0); 293 if(effect==0xc) effect=effdat=0; 294 } else { 295 /* if we had a note, then change instrument... */ 296 if(note) 297 UniInstrument(instrument-1); 298 /* ...otherwise, only adjust volume... */ 299 else { 300 /* ...unless an effect was specified, which forces a new note 301 to be played */ 302 if(effect||effdat) { 303 UniInstrument(instrument-1); 304 note=lastnote; 305 } else 306 UniPTEffect(0xc,mh->samples[instrument-1].volume&0x7f); 307 } 308 } 309 } 310 if(note) { 311 UniNote(note+2*OCTAVE-1); 312 lastnote=note; 313 } 314 315 /* Convert pattern jump from Dec to Hex */ 316 if(effect == 0xd) 317 effdat=(((effdat&0xf0)>>4)*10)+(effdat&0xf); 318 319 /* Volume slide, up has priority */ 320 if((effect==0xa)&&(effdat&0xf)&&(effdat&0xf0)) 321 effdat&=0xf0; 322 323 /* Handle ``heavy'' volumes correctly */ 324 if ((effect == 0xc) && (effdat > 0x40)) 325 effdat = 0x40; 326 327 if(ust_loader) { 328 switch(effect) { 329 case 0: 330 case 3: 331 break; 332 case 1: 333 UniPTEffect(0,effdat); 334 break; 335 case 2: 336 if(effdat&0xf) UniPTEffect(1,effdat&0xf); 337 else if(effdat>>2) UniPTEffect(2,effdat>>2); 338 break; 339 default: 340 UniPTEffect(effect,effdat); 341 break; 342 } 343 } else { 344 /* An isolated 100, 200 or 300 effect should be ignored (no 345 "standalone" porta memory in mod files). However, a sequence 346 such as 1XX, 100, 100, 100 is fine. */ 347 if ((!effdat) && ((effect == 1)||(effect == 2)||(effect ==3)) && 348 (lasteffect < 0x10) && (effect != lasteffect)) 349 effect = 0; 350 351 UniPTEffect(effect,effdat); 352 } 353 if (effect == 8) 354 of.flags |= UF_PANNING; 355 356 return effect; 357} 358 359static UBYTE *M15_ConvertTrack(MODNOTE* n) 360{ 361 int t; 362 UBYTE lasteffect = 0x10; /* non existant effect */ 363 364 UniReset(); 365 for(t=0;t<64;t++) { 366 lasteffect = M15_ConvertNote(n,lasteffect); 367 UniNewline(); 368 n+=4; 369 } 370 return UniDup(); 371} 372 373/* Loads all patterns of a modfile and converts them into the 3 byte format. */ 374static int M15_LoadPatterns(void) 375{ 376 unsigned int t,s,tracks=0; 377 378 if(!AllocPatterns()) return 0; 379 if(!AllocTracks()) return 0; 380 381 /* Allocate temporary buffer for loading and converting the patterns */ 382 if(!(patbuf=(MODNOTE*)MikMod_calloc(64U*4,sizeof(MODNOTE)))) return 0; 383 384 for(t=0;t<of.numpat;t++) { 385 /* Load the pattern into the temp buffer and convert it */ 386 for(s=0;s<(64U*4);s++) { 387 patbuf[s].a=_mm_read_UBYTE(modreader); 388 patbuf[s].b=_mm_read_UBYTE(modreader); 389 patbuf[s].c=_mm_read_UBYTE(modreader); 390 patbuf[s].d=_mm_read_UBYTE(modreader); 391 } 392 393 for(s=0;s<4;s++) 394 if(!(of.tracks[tracks++]=M15_ConvertTrack(patbuf+s))) return 0; 395 } 396 return 1; 397} 398 399static int M15_Load(int curious) 400{ 401 unsigned int t,scan; 402 SAMPLE *q; 403 MSAMPINFO *s; 404 (void)curious; 405 406 /* try to read module header */ 407 if(!LoadModuleHeader(mh)) { 408 _mm_errno = MMERR_LOADING_HEADER; 409 return 0; 410 } 411 412 if(ust_loader) 413 of.modtype = MikMod_strdup("Ultimate Soundtracker"); 414 else 415 of.modtype = MikMod_strdup("Soundtracker"); 416 417 /* set module variables */ 418 of.initspeed = 6; 419 of.inittempo = 125; 420 of.numchn = 4; 421 of.songname = DupStr(mh->songname,21,1); 422 of.numpos = mh->songlength; 423 of.reppos = 0; 424 425 /* Count the number of patterns */ 426 of.numpat = 0; 427 for(t=0;t<of.numpos;t++) 428 if(mh->positions[t]>of.numpat) 429 of.numpat=mh->positions[t]; 430 /* since some old modules embed extra patterns, we have to check the 431 whole list to get the samples' file offsets right - however we can find 432 garbage here, so check carefully */ 433 scan=1; 434 for(t=of.numpos;t<128;t++) 435 if(mh->positions[t]>=0x80) scan=0; 436 if (scan) 437 for(t=of.numpos;t<128;t++) { 438 if(mh->positions[t]>of.numpat) 439 of.numpat=mh->positions[t]; 440 if((curious)&&(mh->positions[t])) of.numpos=t+1; 441 } 442 of.numpat++; 443 of.numtrk = of.numpat*of.numchn; 444 445 if(!AllocPositions(of.numpos)) return 0; 446 for(t=0;t<of.numpos;t++) 447 of.positions[t]=mh->positions[t]; 448 449 /* Finally, init the sampleinfo structures */ 450 of.numins=of.numsmp=15; 451 if(!AllocSamples()) return 0; 452 453 s = mh->samples; 454 q = of.samples; 455 456 for(t=0;t<of.numins;t++) { 457 /* convert the samplename */ 458 q->samplename = DupStr(s->samplename,23,1); 459 460 /* init the sampleinfo variables and convert the size pointers */ 461 q->speed = finetune[s->finetune&0xf]; 462 q->volume = s->volume; 463 if(ust_loader) 464 q->loopstart = s->reppos; 465 else 466 q->loopstart = s->reppos<<1; 467 q->loopend = q->loopstart+(s->replen<<1); 468 q->length = s->length<<1; 469 470 q->flags = SF_SIGNED; 471 if(ust_loader) q->flags |= SF_UST_LOOP; 472 if(s->replen>2) q->flags |= SF_LOOP; 473 474 s++; 475 q++; 476 } 477 478 if(!M15_LoadPatterns()) return 0; 479 ust_loader = 0; 480 481 return 1; 482} 483 484static CHAR *M15_LoadTitle(void) 485{ 486 CHAR s[21]; 487 488 _mm_fseek(modreader,0,SEEK_SET); 489 if(!_mm_read_UBYTES(s,20,modreader)) return NULL; 490 s[20]=0; /* just in case */ 491 return(DupStr(s,21,1)); 492} 493 494/*========== Loader information */ 495 496MIKMODAPI MLOADER load_m15={ 497 NULL, 498 "15-instrument module", 499 "MOD (15 instrument)", 500 M15_Init, 501 M15_Test, 502 M15_Load, 503 M15_Cleanup, 504 M15_LoadTitle 505}; 506 507/* ex:set ts=4: */