A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 562 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 General DigiMusic (GDM) module loader 26 27==============================================================================*/ 28 29/* 30 31 Written by Kev Vance<kvance@zeux.org> 32 based on the file format description written by 'MenTaLguY' 33 <mental@kludge.org> 34 35*/ 36 37#ifdef HAVE_CONFIG_H 38#include "config.h" 39#endif 40 41#ifdef HAVE_UNISTD_H 42#include <unistd.h> 43#endif 44 45#include <stdio.h> 46#ifdef HAVE_MEMORY_H 47#include <memory.h> 48#endif 49#include <string.h> 50 51#include "mikmod_internals.h" 52 53#ifdef SUNOS 54extern int fprintf(FILE *, const char *, ...); 55#endif 56 57typedef struct GDMNOTE { 58 UBYTE note; 59 UBYTE samp; 60 struct { 61 UBYTE effect; 62 UBYTE param; 63 } effect[4]; 64} GDMNOTE; 65 66typedef GDMNOTE GDMTRACK[64]; 67 68typedef struct GDMHEADER { 69 CHAR id1[4]; 70 CHAR songname[32]; 71 CHAR author[32]; 72 CHAR eofmarker[3]; 73 CHAR id2[4]; 74 75 UBYTE majorver; 76 UBYTE minorver; 77 UWORD trackerid; 78 UBYTE t_majorver; 79 UBYTE t_minorver; 80 UBYTE pantable[32]; 81 UBYTE mastervol; 82 UBYTE mastertempo; 83 UBYTE masterbpm; 84 UWORD flags; 85 86 ULONG orderloc; 87 UBYTE ordernum; 88 ULONG patternloc; 89 UBYTE patternnum; 90 ULONG samhead; 91 ULONG samdata; 92 UBYTE samnum; 93 ULONG messageloc; 94 ULONG messagelen; 95 ULONG scrollyloc; 96 UWORD scrollylen; 97 ULONG graphicloc; 98 UWORD graphiclen; 99} GDMHEADER; 100 101typedef struct GDMSAMPLE { 102 CHAR sampname[32]; 103 CHAR filename[13]; 104 UBYTE ems; 105 ULONG length; 106 ULONG loopbeg; 107 ULONG loopend; 108 UBYTE flags; 109 UWORD c4spd; 110 UBYTE vol; 111 UBYTE pan; 112} GDMSAMPLE; 113 114static GDMHEADER *mh=NULL; /* pointer to GDM header */ 115static GDMNOTE *gdmbuf=NULL; /* pointer to a complete GDM pattern */ 116 117static CHAR GDM_Version[]="General DigiMusic 1.xx"; 118 119static int GDM_Test(void) 120{ 121 /* test for gdm magic numbers */ 122 UBYTE id[4]; 123 124 _mm_fseek(modreader,0x00,SEEK_SET); 125 if (!_mm_read_UBYTES(id,4,modreader)) 126 return 0; 127 if (!memcmp(id,"GDM\xfe",4)) { 128 _mm_fseek(modreader,71,SEEK_SET); 129 if (!_mm_read_UBYTES(id,4,modreader)) 130 return 0; 131 if (!memcmp(id,"GMFS",4)) 132 return 1; 133 } 134 return 0; 135} 136 137static int GDM_Init(void) 138{ 139 if (!(gdmbuf=(GDMNOTE*)MikMod_malloc(32*64*sizeof(GDMNOTE)))) return 0; 140 if (!(mh=(GDMHEADER*)MikMod_malloc(sizeof(GDMHEADER)))) return 0; 141 142 return 1; 143} 144 145static void GDM_Cleanup(void) 146{ 147 MikMod_free(mh); 148 MikMod_free(gdmbuf); 149 mh=NULL; 150 gdmbuf=NULL; 151} 152 153static int GDM_ReadPattern(void) 154{ 155 int pos,flag,ch,i; 156 GDMNOTE n; 157 SLONG length,x=0; 158 159 /* get pattern length */ 160 length=(SLONG)_mm_read_I_UWORD(modreader); 161 length-=2; 162 163 /* clear pattern data */ 164 memset(gdmbuf,255,32*64*sizeof(GDMNOTE)); 165 pos=0; 166 167 while (x<length) { 168 memset(&n,255,sizeof(GDMNOTE)); 169 flag=_mm_read_UBYTE(modreader); 170 x++; 171 172 if (_mm_eof(modreader)) 173 return 0; 174 175 ch=flag&31; 176 if (ch > of.numchn) 177 return 0; 178 179 if (!flag) { 180 pos++; 181 if (x==length) { 182 if (pos > 64) 183 return 0; 184 } else { 185 if (pos >= 64) 186 return 0; 187 } 188 continue; 189 } 190 if (flag&0x60) { 191 if (flag&0x20) { 192 /* new note */ 193 n.note=_mm_read_UBYTE(modreader)&127; 194 n.samp=_mm_read_UBYTE(modreader); 195 x +=2; 196 } 197 if (flag&0x40) { 198 do { 199 /* effect channel set */ 200 i=_mm_read_UBYTE(modreader); 201 n.effect[i>>6].effect=i&31; 202 n.effect[i>>6].param=_mm_read_UBYTE(modreader); 203 x +=2; 204 } while (i&32); 205 } 206 memcpy(gdmbuf+(64U*ch)+pos,&n,sizeof(GDMNOTE)); 207 } 208 } 209 return 1; 210} 211 212static UBYTE *GDM_ConvertTrack(GDMNOTE*tr) 213{ 214 int t,i=0; 215 UBYTE note,ins,inf; 216 217 UniReset(); 218 for (t=0;t<64;t++) { 219 note=tr[t].note; 220 ins=tr[t].samp; 221 222 if ((ins)&&(ins!=255)) 223 UniInstrument(ins-1); 224 if (note && note!=255) { 225 UniNote(((note>>4)*OCTAVE)+(note&0xf)-1); 226 } 227 for (i=0;i<4;i++) { 228 inf = tr[t].effect[i].param; 229 switch (tr[t].effect[i].effect) { 230 case 1: /* toneslide up */ 231 UniEffect(UNI_S3MEFFECTF,inf); 232 break; 233 case 2: /* toneslide down */ 234 UniEffect(UNI_S3MEFFECTE,inf); 235 break; 236 case 3: /* glissando to note */ 237 UniEffect(UNI_ITEFFECTG,inf); 238 break; 239 case 4: /* vibrato */ 240 UniEffect(UNI_GDMEFFECT4,inf); 241 break; 242 case 5: /* portamento+volslide */ 243 UniEffect(UNI_ITEFFECTG,0); 244 UniEffect(UNI_S3MEFFECTD,inf); 245 break; 246 case 6: /* vibrato+volslide */ 247 UniEffect(UNI_GDMEFFECT4,0); 248 UniEffect(UNI_S3MEFFECTD,inf); 249 break; 250 case 7: /* tremolo */ 251 UniEffect(UNI_GDMEFFECT7,inf); 252 break; 253 case 8: /* tremor */ 254 UniEffect(UNI_S3MEFFECTI,inf); 255 break; 256 case 9: /* offset */ 257 UniPTEffect(0x09,inf); 258 break; 259 case 0x0a: /* volslide */ 260 UniEffect(UNI_S3MEFFECTD,inf); 261 break; 262 case 0x0b: /* jump to order */ 263 UniPTEffect(0x0b,inf); 264 break; 265 case 0x0c: /* volume set */ 266 UniPTEffect(0x0c,inf); 267 break; 268 case 0x0d: /* pattern break */ 269 UniPTEffect(0x0d,inf); 270 break; 271 case 0x0e: /* extended */ 272 switch (inf&0xf0) { 273 case 0x10: /* fine portamento up */ 274 UniEffect(UNI_S3MEFFECTF, 0xf0|(inf&0x0f)); 275 break; 276 case 0x20: /* fine portamento down */ 277 UniEffect(UNI_S3MEFFECTE, 0xf0|(inf&0x0f)); 278 break; 279 case 0x30: /* glissando control */ 280 case 0x40: /* vibrato waveform */ 281 case 0x50: /* set c4spd */ 282 case 0x60: /* loop fun */ 283 case 0x70: /* tremolo waveform */ 284 UniPTEffect(0xe, inf); 285 break; 286 case 0x80: /* extra fine porta up */ 287 UniEffect(UNI_S3MEFFECTF, 0xe0|(inf&0x0f)); 288 break; 289 case 0x90: /* extra fine porta down */ 290 UniEffect(UNI_S3MEFFECTE, 0xe0|(inf&0x0f)); 291 break; 292 case 0xa0: /* fine volslide up */ 293 UniEffect(UNI_S3MEFFECTD, 0x0f|((inf&0x0f)<<4)); 294 break; 295 case 0xb0: /* fine volslide down */ 296 UniEffect(UNI_S3MEFFECTD, 0xf0|(inf&0x0f)); 297 break; 298 case 0xc0: /* note cut */ 299 case 0xd0: /* note delay */ 300 case 0xe0: /* extend row */ 301 UniPTEffect(0xe,inf); 302 break; 303 } 304 break; 305 case 0x0f: /* set tempo */ 306 UniEffect(UNI_S3MEFFECTA,inf); 307 break; 308 case 0x10: /* arpeggio */ 309 UniPTEffect(0x0,inf); 310 break; 311 case 0x12: /* retrigger */ 312 UniEffect(UNI_S3MEFFECTQ,inf); 313 break; 314 case 0x13: /* set global volume */ 315 UniEffect(UNI_XMEFFECTG,inf); 316 break; 317 case 0x14: /* fine vibrato */ 318 UniEffect(UNI_GDMEFFECT14,inf); 319 break; 320 case 0x1e: /* special */ 321 switch (inf&0xf0) { 322 case 0x80: /* set pan position */ 323 UniPTEffect(0xe,inf); 324 break; 325 } 326 break; 327 case 0x1f: /* set bpm */ 328 if (inf >=0x20) 329 UniEffect(UNI_S3MEFFECTT,inf); 330 break; 331 } 332 } 333 UniNewline(); 334 } 335 return UniDup(); 336} 337 338static int GDM_Load(int curious) 339{ 340 int i,x,u,track; 341 SAMPLE *q; 342 GDMSAMPLE s; 343 ULONG position; 344 (void)curious; 345 346 /* read header */ 347 _mm_read_string(mh->id1,4,modreader); 348 _mm_read_string(mh->songname,32,modreader); 349 _mm_read_string(mh->author,32,modreader); 350 _mm_read_string(mh->eofmarker,3,modreader); 351 _mm_read_string(mh->id2,4,modreader); 352 353 mh->majorver=_mm_read_UBYTE(modreader); 354 mh->minorver=_mm_read_UBYTE(modreader); 355 mh->trackerid=_mm_read_I_UWORD(modreader); 356 mh->t_majorver=_mm_read_UBYTE(modreader); 357 mh->t_minorver=_mm_read_UBYTE(modreader); 358 _mm_read_UBYTES(mh->pantable,32,modreader); 359 mh->mastervol=_mm_read_UBYTE(modreader); 360 mh->mastertempo=_mm_read_UBYTE(modreader); 361 mh->masterbpm=_mm_read_UBYTE(modreader); 362 mh->flags=_mm_read_I_UWORD(modreader); 363 364 mh->orderloc=_mm_read_I_ULONG(modreader); 365 mh->ordernum=_mm_read_UBYTE(modreader); 366 mh->patternloc=_mm_read_I_ULONG(modreader); 367 mh->patternnum=_mm_read_UBYTE(modreader); 368 mh->samhead=_mm_read_I_ULONG(modreader); 369 mh->samdata=_mm_read_I_ULONG(modreader); 370 mh->samnum=_mm_read_UBYTE(modreader); 371 mh->messageloc=_mm_read_I_ULONG(modreader); 372 mh->messagelen=_mm_read_I_ULONG(modreader); 373 mh->scrollyloc=_mm_read_I_ULONG(modreader); 374 mh->scrollylen=_mm_read_I_UWORD(modreader); 375 mh->graphicloc=_mm_read_I_ULONG(modreader); 376 mh->graphiclen=_mm_read_I_UWORD(modreader); 377 378 /* have we ended abruptly? */ 379 if (_mm_eof(modreader)) { 380 _mm_errno=MMERR_LOADING_HEADER; 381 return 0; 382 } 383 384 /* any orders? */ 385 if(mh->ordernum==255) { 386 _mm_errno=MMERR_LOADING_PATTERN; 387 return 0; 388 } 389 390 /* now we fill */ 391 of.modtype=MikMod_strdup(GDM_Version); 392 of.modtype[18]=mh->majorver+'0'; 393 of.modtype[20]=mh->minorver/10+'0'; 394 of.modtype[21]=mh->minorver%10+'0'; 395 of.songname=DupStr(mh->songname,32,0); 396 of.numpat=mh->patternnum+1; 397 of.reppos=0; 398 of.numins=of.numsmp=mh->samnum+1; 399 of.initspeed=mh->mastertempo; 400 of.inittempo=mh->masterbpm; 401 of.initvolume=mh->mastervol<<1; 402 of.flags|=UF_S3MSLIDES | UF_PANNING; 403 /* XXX whenever possible, we should try to determine the original format. 404 Here we assume it was S3M-style wrt bpmlimit... */ 405 of.bpmlimit = 32; 406 407 /* read the order data */ 408 if (!AllocPositions(mh->ordernum+1)) { 409 _mm_errno=MMERR_OUT_OF_MEMORY; 410 return 0; 411 } 412 413 _mm_fseek(modreader,mh->orderloc,SEEK_SET); 414 for (i=0;i<mh->ordernum+1;i++) 415 of.positions[i]=_mm_read_UBYTE(modreader); 416 417 of.numpos=0; 418 for (i=0;i<mh->ordernum+1;i++) { 419 int order=of.positions[i]; 420 if(order==255) order=LAST_PATTERN; 421 of.positions[of.numpos]=order; 422 if (of.positions[i]<254) of.numpos++; 423 } 424 425 /* have we ended abruptly yet? */ 426 if (_mm_eof(modreader)) { 427 _mm_errno=MMERR_LOADING_HEADER; 428 return 0; 429 } 430 431 /* time to load the samples */ 432 if (!AllocSamples()) { 433 _mm_errno=MMERR_OUT_OF_MEMORY; 434 return 0; 435 } 436 437 q=of.samples; 438 position=mh->samdata; 439 440 /* seek to instrument position */ 441 _mm_fseek(modreader,mh->samhead,SEEK_SET); 442 443 for (i=0;i<of.numins;i++) { 444 /* load sample info */ 445 _mm_read_UBYTES(s.sampname,32,modreader); 446 _mm_read_UBYTES(s.filename,12,modreader); 447 s.ems=_mm_read_UBYTE(modreader); 448 s.length=_mm_read_I_ULONG(modreader); 449 s.loopbeg=_mm_read_I_ULONG(modreader); 450 s.loopend=_mm_read_I_ULONG(modreader); 451 s.flags=_mm_read_UBYTE(modreader); 452 s.c4spd=_mm_read_I_UWORD(modreader); 453 s.vol=_mm_read_UBYTE(modreader); 454 s.pan=_mm_read_UBYTE(modreader); 455 456 if (_mm_eof(modreader)) { 457 _mm_errno=MMERR_LOADING_SAMPLEINFO; 458 return 0; 459 } 460 q->samplename=DupStr(s.sampname,32,0); 461 q->speed=s.c4spd; 462 q->length=s.length; 463 q->loopstart=s.loopbeg; 464 q->loopend=s.loopend; 465 q->volume=64; 466 q->seekpos=position; 467 468 position +=s.length; 469 470 /* Only use the sample volume byte if bit 2 is set. When bit 3 is set, 471 the sample panning is supposed to be used, but 2GDM isn't capable 472 of making a GDM using this feature; the panning byte is always 0xFF 473 or junk. Likewise, bit 5 is unused (supposed to be LZW compression). */ 474 if (s.flags&1) 475 q->flags |=SF_LOOP; 476 if (s.flags&2) 477 q->flags |=SF_16BITS; 478 if ((s.flags&4) && s.vol<=64) 479 q->volume=s.vol; 480 if (s.flags&16) 481 q->flags |=SF_STEREO; 482 q++; 483 } 484 485 /* set the panning */ 486 for (i=x=0;i<32;i++) { 487 of.panning[i]=mh->pantable[i]; 488 if (!of.panning[i]) 489 of.panning[i]=PAN_LEFT; 490 else if (of.panning[i]==8) 491 of.panning[i]=PAN_CENTER; 492 else if (of.panning[i]==15) 493 of.panning[i]=PAN_RIGHT; 494 else if (of.panning[i]==16) 495 of.panning[i]=PAN_SURROUND; 496 else if (of.panning[i]==255) 497 of.panning[i]=128; 498 else 499 of.panning[i]<<=3; 500 if (mh->pantable[i]!=255) 501 x=i; 502 } 503 504 of.numchn=x+1; 505 if (of.numchn<1) 506 of.numchn=1; /* for broken counts */ 507 508 /* load the pattern info */ 509 of.numtrk=of.numpat*of.numchn; 510 511 /* jump to patterns */ 512 _mm_fseek(modreader,mh->patternloc,SEEK_SET); 513 514 if (!AllocTracks()) { 515 _mm_errno=MMERR_OUT_OF_MEMORY; 516 return 0; 517 } 518 519 if (!AllocPatterns()) { 520 _mm_errno=MMERR_OUT_OF_MEMORY; 521 return 0; 522 } 523 524 for (i=track=0;i<of.numpat;i++) { 525 if (!GDM_ReadPattern()) { 526 _mm_errno=MMERR_LOADING_PATTERN; 527 return 0; 528 } 529 for (u=0;u<of.numchn;u++,track++) { 530 of.tracks[track]=GDM_ConvertTrack(&gdmbuf[u<<6]); 531 if (!of.tracks[track]) { 532 _mm_errno=MMERR_LOADING_TRACK; 533 return 0; 534 } 535 } 536 } 537 return 1; 538} 539 540static CHAR *GDM_LoadTitle(void) 541{ 542 CHAR s[32]; 543 544 _mm_fseek(modreader,4,SEEK_SET); 545 if (!_mm_read_UBYTES(s,32,modreader)) return NULL; 546 547 return DupStr(s,28,0); 548} 549 550MIKMODAPI MLOADER load_gdm= 551{ 552 NULL, 553 "GDM", 554 "GDM (General DigiMusic)", 555 GDM_Init, 556 GDM_Test, 557 GDM_Load, 558 GDM_Cleanup, 559 GDM_LoadTitle 560}; 561 562/* ex:set ts=4: */