A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 410 lines 10 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 Farandole (FAR) 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 51typedef struct FARHEADER1 { 52 UBYTE id[4]; /* file magic */ 53 CHAR songname[40]; /* songname */ 54 CHAR blah[3]; /* 13,10,26 */ 55 UWORD headerlen; /* remaining length of header in bytes */ 56 UBYTE version; 57 UBYTE onoff[16]; 58 UBYTE edit1[9]; 59 UBYTE speed; 60 UBYTE panning[16]; 61 UBYTE edit2[4]; 62 UWORD stlen; 63} FARHEADER1; 64 65typedef struct FARHEADER2 { 66 UBYTE orders[256]; 67 UBYTE numpat; 68 UBYTE snglen; 69 UBYTE loopto; 70 UWORD patsiz[256]; 71} FARHEADER2; 72 73typedef struct FARSAMPLE { 74 CHAR samplename[32]; 75 ULONG length; 76 UBYTE finetune; 77 UBYTE volume; 78 ULONG reppos; 79 ULONG repend; 80 UBYTE type; 81 UBYTE loop; 82} FARSAMPLE; 83 84typedef struct FARNOTE { 85 UBYTE note,ins,vol,eff; 86} FARNOTE; 87 88/*========== Loader variables */ 89 90static CHAR FAR_Version[] = "Farandole"; 91static FARHEADER1 *mh1 = NULL; 92static FARHEADER2 *mh2 = NULL; 93static FARNOTE *pat = NULL; 94 95static const unsigned char FARSIG[4+3]={'F','A','R',0xfe,13,10,26}; 96static const UWORD FAR_MAXPATSIZE=(256*16*4)+2; 97 98/*========== Loader code */ 99 100static int FAR_Test(void) 101{ 102 UBYTE id[47]; 103 104 if(!_mm_read_UBYTES(id,47,modreader)) return 0; 105 if((memcmp(id,FARSIG,4))||(memcmp(id+44,FARSIG+4,3))) return 0; 106 return 1; 107} 108 109static int FAR_Init(void) 110{ 111 if(!(mh1 = (FARHEADER1*)MikMod_malloc(sizeof(FARHEADER1)))) return 0; 112 if(!(mh2 = (FARHEADER2*)MikMod_malloc(sizeof(FARHEADER2)))) return 0; 113 if(!(pat = (FARNOTE*)MikMod_malloc(256*16*4*sizeof(FARNOTE)))) return 0; 114 115 return 1; 116} 117 118static void FAR_Cleanup(void) 119{ 120 MikMod_free(mh1); 121 MikMod_free(mh2); 122 MikMod_free(pat); 123 mh1 = NULL; 124 mh2 = NULL; 125 pat = NULL; 126} 127 128static UBYTE *FAR_ConvertTrack(FARNOTE* n,int rows) 129{ 130 int t,vibdepth=1; 131 132 UniReset(); 133 for(t=0;t<rows;t++) { 134 if(n->note) { 135 UniInstrument(n->ins); 136 UniNote(n->note+3*OCTAVE-1); 137 } 138 if (n->vol>=0x01 && n->vol<=0x10) UniPTEffect(0xc,(n->vol - 1)<<2); 139 if (n->eff) 140 switch(n->eff>>4) { 141 case 0x0: /* global effects */ 142 switch(n->eff & 0xf) { 143 case 0x3: /* fulfill loop */ 144 UniEffect(UNI_KEYFADE, 0); 145 break; 146 case 0x4: /* old tempo mode */ 147 case 0x5: /* new tempo mode */ 148 break; 149 } 150 break; 151 case 0x1: /* pitch adjust up */ 152 UniEffect(UNI_FAREFFECT1, n->eff & 0xf); 153 break; 154 case 0x2: /* pitch adjust down */ 155 UniEffect(UNI_FAREFFECT2, n->eff & 0xf); 156 break; 157 case 0x3: /* porta to note */ 158 UniEffect(UNI_FAREFFECT3, n->eff & 0xf); 159 break; 160 case 0x4: /* retrigger */ 161 UniEffect(UNI_FAREFFECT4, n->eff & 0xf); 162 break; 163 case 0x5: /* set vibrato depth */ 164 vibdepth=n->eff&0xf; 165 break; 166 case 0x6: /* vibrato */ 167 UniEffect(UNI_FAREFFECT6,((n->eff&0xf)<<4)|vibdepth); 168 break; 169 case 0x7: /* volume slide up */ 170 UniPTEffect(0xa,(n->eff&0xf)<<4); 171 break; 172 case 0x8: /* volume slide down */ 173 UniPTEffect(0xa,n->eff&0xf); 174 break; 175 case 0x9: /* sustained vibrato */ 176 break; 177 case 0xb: /* panning */ 178 UniPTEffect(0xe,0x80|(n->eff&0xf)); 179 break; 180 case 0xc: /* note offset */ 181 break; 182 case 0xd: /* fine tempo down */ 183 UniEffect(UNI_FAREFFECTD, n->eff & 0xf); 184 break; 185 case 0xe: /* fine tempo up */ 186 UniEffect(UNI_FAREFFECTE, n->eff & 0xf); 187 break; 188 case 0xf: /* set speed */ 189 UniEffect(UNI_FAREFFECTF,n->eff&0xf); 190 break; 191 192 /* others not yet implemented */ 193 default: 194#ifdef MIKMOD_DEBUG 195 fprintf(stderr,"\rFAR: unsupported effect %02X\n",n->eff); 196#endif 197 break; 198 } 199 200 UniNewline(); 201 n+=16; 202 } 203 return UniDup(); 204} 205 206static int FAR_Load(int curious) 207{ 208 int r,t,u,tracks=0; 209 SAMPLE *q; 210 FARSAMPLE s; 211 FARNOTE *crow; 212 UBYTE smap[8]; 213 UBYTE addextrapattern; 214 (void)curious; 215 216 /* try to read module header (first part) */ 217 _mm_read_UBYTES(mh1->id,4,modreader); 218 _mm_read_SBYTES(mh1->songname,40,modreader); 219 _mm_read_SBYTES(mh1->blah,3,modreader); 220 mh1->headerlen = _mm_read_I_UWORD (modreader); 221 mh1->version = _mm_read_UBYTE (modreader); 222 _mm_read_UBYTES(mh1->onoff,16,modreader); 223 _mm_read_UBYTES(mh1->edit1,9,modreader); 224 mh1->speed = _mm_read_UBYTE(modreader); 225 _mm_read_UBYTES(mh1->panning,16,modreader); 226 _mm_read_UBYTES(mh1->edit2,4,modreader); 227 mh1->stlen = _mm_read_I_UWORD (modreader); 228 229 /* init modfile data */ 230 of.modtype = MikMod_strdup(FAR_Version); 231 of.songname = DupStr(mh1->songname,40,1); 232 of.numchn = 16; 233 of.initspeed = mh1->speed != 0 ? mh1->speed : 4; 234 of.bpmlimit = 5; 235 of.flags |= UF_PANNING | UF_FARTEMPO | UF_HIGHBPM; 236 for(t=0;t<16;t++) of.panning[t]=mh1->panning[t]<<4; 237 238 /* read songtext into comment field */ 239 if(mh1->stlen) 240 if (!ReadLinedComment(mh1->stlen, 132)) return 0; 241 242 if(_mm_eof(modreader)) { 243 _mm_errno = MMERR_LOADING_HEADER; 244 return 0; 245 } 246 247 /* try to read module header (second part) */ 248 _mm_read_UBYTES(mh2->orders,256,modreader); 249 mh2->numpat = _mm_read_UBYTE(modreader); 250 mh2->snglen = _mm_read_UBYTE(modreader); 251 mh2->loopto = _mm_read_UBYTE(modreader); 252 _mm_read_I_UWORDS(mh2->patsiz,256,modreader); 253 254 of.numpos = mh2->snglen; 255 of.reppos = mh2->loopto; 256 257 if(!AllocPositions(of.numpos)) return 0; 258 259 /* count number of patterns stored in file */ 260 of.numpat = 0; 261 for(t=0;t<256;t++) 262 if(mh2->patsiz[t]) 263 if((t+1)>of.numpat) of.numpat=t+1; 264 265 addextrapattern = 0; 266 for (t = 0; t < of.numpos; t++) { 267 if (mh2->orders[t] == 0xff) break; 268 of.positions[t] = mh2->orders[t]; 269 if (of.positions[t] >= of.numpat) { 270 of.positions[t] = of.numpat; 271 addextrapattern = 1; 272 } 273 } 274 275 if (addextrapattern) 276 of.numpat++; 277 278 of.numtrk = of.numpat*of.numchn; 279 280 /* seek across eventual new data */ 281 _mm_fseek(modreader,mh1->headerlen-(869+mh1->stlen),SEEK_CUR); 282 283 /* alloc track and pattern structures */ 284 if(!AllocTracks()) return 0; 285 if(!AllocPatterns()) return 0; 286 287 for(t=0;t<of.numpat;t++) { 288 memset(pat,0,256*16*4*sizeof(FARNOTE)); 289 if(mh2->patsiz[t]) { 290 /* Break position byte is always 1 less than the final row index, 291 i.e. it is 2 less than the total row count. */ 292 UWORD rows = _mm_read_UBYTE(modreader) + 2; 293 _mm_skip_BYTE(modreader); /* tempo */ 294 295 crow = pat; 296 /* file often allocates 64 rows even if there are less in pattern */ 297 /* Also, don't allow more than 256 rows. */ 298 if (mh2->patsiz[t]<2+(rows*16*4) || rows>256 || mh2->patsiz[t]>FAR_MAXPATSIZE) { 299 _mm_errno = MMERR_LOADING_PATTERN; 300 return 0; 301 } 302 for(u=(mh2->patsiz[t]-2)/4;u;u--,crow++) { 303 crow->note = _mm_read_UBYTE(modreader); 304 crow->ins = _mm_read_UBYTE(modreader); 305 crow->vol = _mm_read_UBYTE(modreader); 306 crow->eff = _mm_read_UBYTE(modreader); 307 } 308 309 if(_mm_eof(modreader)) { 310 _mm_errno = MMERR_LOADING_PATTERN; 311 return 0; 312 } 313 314 crow=pat; 315 of.pattrows[t] = rows; 316 for(u=16;u;u--,crow++) 317 if(!(of.tracks[tracks++]=FAR_ConvertTrack(crow,rows))) { 318 _mm_errno=MMERR_LOADING_PATTERN; 319 return 0; 320 } 321 } else { 322 // Farandole Composer normally use a 64 rows blank track for patterns with 0 rows 323 for (u = 0; u < 16; u++) { 324 UniReset(); 325 for (r = 0; r < 64; r++) { 326 UniNewline(); 327 } 328 of.tracks[tracks++] = UniDup(); 329 } 330 of.pattrows[t] = 64; 331 } 332 } 333 334 /* read sample map */ 335 if(!_mm_read_UBYTES(smap,8,modreader)) { 336 _mm_errno = MMERR_LOADING_HEADER; 337 return 0; 338 } 339 340 /* count number of samples used */ 341 of.numins = 0; 342 for(t=0;t<64;t++) 343 if(smap[t>>3]&(1<<(t&7))) of.numins=t+1; 344 of.numsmp = of.numins; 345 346 /* alloc sample structs */ 347 if(!AllocSamples()) return 0; 348 349 q = of.samples; 350 for(t=0;t<of.numsmp;t++) { 351 q->speed = 8363; 352 q->flags = SF_SIGNED; 353 if(smap[t>>3]&(1<<(t&7))) { 354 _mm_read_SBYTES(s.samplename,32,modreader); 355 s.length = _mm_read_I_ULONG(modreader); 356 s.finetune = _mm_read_UBYTE(modreader); 357 s.volume = _mm_read_UBYTE(modreader); 358 s.reppos = _mm_read_I_ULONG(modreader); 359 s.repend = _mm_read_I_ULONG(modreader); 360 s.type = _mm_read_UBYTE(modreader); 361 s.loop = _mm_read_UBYTE(modreader); 362 363 q->samplename = DupStr(s.samplename,32,1); 364 q->length = s.length; 365 q->loopstart = s.reppos; 366 q->loopend = s.repend; 367 q->volume = s.volume<<2; 368 369 if(s.type&1) { 370 q->flags|=SF_16BITS; 371 q->length >>= 1; 372 q->loopstart >>= 1; 373 q->loopend >>= 1; 374 } 375 376 if(s.loop&8) q->flags|=SF_LOOP; 377 378 q->seekpos = _mm_ftell(modreader); 379 _mm_fseek(modreader,s.length,SEEK_CUR); 380 } else 381 q->samplename = MikMod_strdup(""); 382 q++; 383 } 384 return 1; 385} 386 387static CHAR *FAR_LoadTitle(void) 388{ 389 CHAR s[40]; 390 391 _mm_fseek(modreader,4,SEEK_SET); 392 if(!_mm_read_UBYTES(s,40,modreader)) return NULL; 393 394 return (DupStr(s,40,1)); 395} 396 397/*========== Loader information */ 398 399MIKMODAPI MLOADER load_far={ 400 NULL, 401 "FAR", 402 "FAR (Farandole Composer)", 403 FAR_Init, 404 FAR_Test, 405 FAR_Load, 406 FAR_Cleanup, 407 FAR_LoadTitle 408}; 409 410/* ex:set ts=4: */