--- /dev/null
+/* MikMod sound library\r
+ (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file\r
+ AUTHORS for complete list.\r
+\r
+ This library is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU Library General Public License as\r
+ published by the Free Software Foundation; either version 2 of\r
+ the License, or (at your option) any later version.\r
+ \r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU Library General Public License for more details.\r
+ \r
+ You should have received a copy of the GNU Library General Public\r
+ License along with this library; if not, write to the Free Software\r
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA\r
+ 02111-1307, USA.\r
+*/\r
+\r
+/*==============================================================================\r
+\r
+ $Id: load_far.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $\r
+\r
+ Farandole (FAR) module loader\r
+\r
+==============================================================================*/\r
+\r
+#ifdef HAVE_CONFIG_H\r
+#include "config.h"\r
+#endif\r
+\r
+#ifdef HAVE_UNISTD_H\r
+#include <unistd.h>\r
+#endif\r
+\r
+#include <stdio.h>\r
+#ifdef HAVE_MEMORY_H\r
+#include <memory.h>\r
+#endif\r
+#include <string.h>\r
+\r
+#include "mikmod_internals.h"\r
+\r
+#ifdef SUNOS\r
+extern int fprintf(FILE *, const char *, ...);\r
+#endif\r
+\r
+/*========== Module structure */\r
+\r
+typedef struct FARHEADER1 {\r
+ UBYTE id[4]; /* file magic */\r
+ CHAR songname[40]; /* songname */\r
+ CHAR blah[3]; /* 13,10,26 */\r
+ UWORD headerlen; /* remaining length of header in bytes */\r
+ UBYTE version;\r
+ UBYTE onoff[16];\r
+ UBYTE edit1[9];\r
+ UBYTE speed;\r
+ UBYTE panning[16];\r
+ UBYTE edit2[4];\r
+ UWORD stlen;\r
+} FARHEADER1;\r
+\r
+typedef struct FARHEADER2 {\r
+ UBYTE orders[256];\r
+ UBYTE numpat;\r
+ UBYTE snglen;\r
+ UBYTE loopto;\r
+ UWORD patsiz[256];\r
+} FARHEADER2;\r
+\r
+typedef struct FARSAMPLE {\r
+ CHAR samplename[32];\r
+ ULONG length;\r
+ UBYTE finetune;\r
+ UBYTE volume;\r
+ ULONG reppos;\r
+ ULONG repend;\r
+ UBYTE type;\r
+ UBYTE loop;\r
+} FARSAMPLE;\r
+\r
+typedef struct FARNOTE {\r
+ UBYTE note,ins,vol,eff;\r
+} FARNOTE;\r
+\r
+/*========== Loader variables */\r
+\r
+static CHAR FAR_Version[] = "Farandole";\r
+static FARHEADER1 *mh1 = NULL;\r
+static FARHEADER2 *mh2 = NULL;\r
+static FARNOTE *pat = NULL;\r
+\r
+static unsigned char FARSIG[4+3]={'F','A','R',0xfe,13,10,26};\r
+\r
+/*========== Loader code */\r
+\r
+BOOL FAR_Test(void)\r
+{\r
+ UBYTE id[47];\r
+\r
+ if(!_mm_read_UBYTES(id,47,modreader)) return 0;\r
+ if((memcmp(id,FARSIG,4))||(memcmp(id+44,FARSIG+4,3))) return 0;\r
+ return 1;\r
+}\r
+\r
+BOOL FAR_Init(void)\r
+{\r
+ if(!(mh1 = (FARHEADER1*)_mm_malloc(sizeof(FARHEADER1)))) return 0;\r
+ if(!(mh2 = (FARHEADER2*)_mm_malloc(sizeof(FARHEADER2)))) return 0;\r
+ if(!(pat = (FARNOTE*)_mm_malloc(256*16*4*sizeof(FARNOTE)))) return 0;\r
+\r
+ return 1;\r
+}\r
+\r
+void FAR_Cleanup(void)\r
+{\r
+ _mm_free(mh1);\r
+ _mm_free(mh2);\r
+ _mm_free(pat);\r
+}\r
+\r
+static UBYTE *FAR_ConvertTrack(FARNOTE* n,int rows)\r
+{\r
+ int t,vibdepth=1;\r
+\r
+ UniReset();\r
+ for(t=0;t<rows;t++) {\r
+ if(n->note) {\r
+ UniInstrument(n->ins);\r
+ UniNote(n->note+3*OCTAVE-1);\r
+ }\r
+ if (n->vol&0xf) UniPTEffect(0xc,(n->vol&0xf)<<2);\r
+ if (n->eff)\r
+ switch(n->eff>>4) {\r
+ case 0x3: /* porta to note */\r
+ UniPTEffect(0x3,(n->eff&0xf)<<4);\r
+ break;\r
+ case 0x4: /* retrigger */\r
+ UniPTEffect(0x0e, 0x90 | (n->eff & 0x0f));\r
+ break;\r
+ case 0x5: /* set vibrato depth */\r
+ vibdepth=n->eff&0xf;\r
+ break;\r
+ case 0x6: /* vibrato */\r
+ UniPTEffect(0x4,((n->eff&0xf)<<4)|vibdepth);\r
+ break;\r
+ case 0x7: /* volume slide up */\r
+ UniPTEffect(0xa,(n->eff&0xf)<<4);\r
+ break;\r
+ case 0x8: /* volume slide down */\r
+ UniPTEffect(0xa,n->eff&0xf);\r
+ break;\r
+ case 0xb: /* panning */\r
+ UniPTEffect(0xe,0x80|(n->eff&0xf));\r
+ break;\r
+ case 0xf: /* set speed */\r
+ UniPTEffect(0xf,n->eff&0xf);\r
+ break;\r
+\r
+ /* others not yet implemented */\r
+ default:\r
+#ifdef MIKMOD_DEBUG\r
+ fprintf(stderr,"\rFAR: unsupported effect %02X\n",n->eff);\r
+#endif\r
+ break;\r
+ }\r
+\r
+ UniNewline();\r
+ n+=16;\r
+ }\r
+ return UniDup();\r
+}\r
+\r
+BOOL FAR_Load(BOOL curious)\r
+{\r
+ int t,u,tracks=0;\r
+ SAMPLE *q;\r
+ FARSAMPLE s;\r
+ FARNOTE *crow;\r
+ UBYTE smap[8];\r
+ (void)curious;\r
+\r
+ /* try to read module header (first part) */\r
+ _mm_read_UBYTES(mh1->id,4,modreader);\r
+ _mm_read_SBYTES(mh1->songname,40,modreader);\r
+ _mm_read_SBYTES(mh1->blah,3,modreader);\r
+ mh1->headerlen = _mm_read_I_UWORD (modreader);\r
+ mh1->version = _mm_read_UBYTE (modreader);\r
+ _mm_read_UBYTES(mh1->onoff,16,modreader);\r
+ _mm_read_UBYTES(mh1->edit1,9,modreader);\r
+ mh1->speed = _mm_read_UBYTE(modreader);\r
+ _mm_read_UBYTES(mh1->panning,16,modreader);\r
+ _mm_read_UBYTES(mh1->edit2,4,modreader);\r
+ mh1->stlen = _mm_read_I_UWORD (modreader);\r
+\r
+ /* init modfile data */\r
+ of.modtype = strdup(FAR_Version);\r
+ of.songname = DupStr(mh1->songname,40,1);\r
+ of.numchn = 16;\r
+ of.initspeed = mh1->speed;\r
+ of.inittempo = 80;\r
+ of.reppos = 0;\r
+ of.flags |= UF_PANNING;\r
+ for(t=0;t<16;t++) of.panning[t]=mh1->panning[t]<<4;\r
+\r
+ /* read songtext into comment field */\r
+ if(mh1->stlen)\r
+ if (!ReadLinedComment(mh1->stlen, 66)) return 0;\r
+\r
+ /* try to read module header (second part) */\r
+ _mm_read_UBYTES(mh2->orders,256,modreader);\r
+ mh2->numpat = _mm_read_UBYTE(modreader);\r
+ mh2->snglen = _mm_read_UBYTE(modreader);\r
+ mh2->loopto = _mm_read_UBYTE(modreader);\r
+ _mm_read_I_UWORDS(mh2->patsiz,256,modreader);\r
+\r
+ of.numpos = mh2->snglen;\r
+ if(!AllocPositions(of.numpos)) return 0;\r
+ for(t=0;t<of.numpos;t++) {\r
+ if(mh2->orders[t]==0xff) break;\r
+ of.positions[t] = mh2->orders[t];\r
+ }\r
+\r
+ /* count number of patterns stored in file */\r
+ of.numpat = 0;\r
+ for(t=0;t<256;t++)\r
+ if(mh2->patsiz[t])\r
+ if((t+1)>of.numpat) of.numpat=t+1;\r
+ of.numtrk = of.numpat*of.numchn;\r
+\r
+ /* seek across eventual new data */\r
+ _mm_fseek(modreader,mh1->headerlen-(869+mh1->stlen),SEEK_CUR);\r
+\r
+ /* alloc track and pattern structures */\r
+ if(!AllocTracks()) return 0;\r
+ if(!AllocPatterns()) return 0;\r
+\r
+ for(t=0;t<of.numpat;t++) {\r
+ UBYTE rows=0,tempo;\r
+\r
+ memset(pat,0,256*16*4*sizeof(FARNOTE));\r
+ if(mh2->patsiz[t]) {\r
+ rows = _mm_read_UBYTE(modreader);\r
+ tempo = _mm_read_UBYTE(modreader);\r
+\r
+ crow = pat;\r
+ /* file often allocates 64 rows even if there are less in pattern */\r
+ if (mh2->patsiz[t]<2+(rows*16*4)) {\r
+ _mm_errno = MMERR_LOADING_PATTERN;\r
+ return 0;\r
+ }\r
+ for(u=(mh2->patsiz[t]-2)/4;u;u--,crow++) {\r
+ crow->note = _mm_read_UBYTE(modreader);\r
+ crow->ins = _mm_read_UBYTE(modreader);\r
+ crow->vol = _mm_read_UBYTE(modreader);\r
+ crow->eff = _mm_read_UBYTE(modreader);\r
+ }\r
+\r
+ if(_mm_eof(modreader)) {\r
+ _mm_errno = MMERR_LOADING_PATTERN;\r
+ return 0;\r
+ }\r
+\r
+ crow=pat;\r
+ of.pattrows[t] = rows;\r
+ for(u=16;u;u--,crow++)\r
+ if(!(of.tracks[tracks++]=FAR_ConvertTrack(crow,rows))) {\r
+ _mm_errno=MMERR_LOADING_PATTERN;\r
+ return 0;\r
+ }\r
+ } else\r
+ tracks+=16;\r
+ }\r
+\r
+ /* read sample map */\r
+ if(!_mm_read_UBYTES(smap,8,modreader)) {\r
+ _mm_errno = MMERR_LOADING_HEADER;\r
+ return 0;\r
+ }\r
+\r
+ /* count number of samples used */\r
+ of.numins = 0;\r
+ for(t=0;t<64;t++)\r
+ if(smap[t>>3]&(1<<(t&7))) of.numins=t+1;\r
+ of.numsmp = of.numins; \r
+\r
+ /* alloc sample structs */\r
+ if(!AllocSamples()) return 0;\r
+\r
+ q = of.samples;\r
+ for(t=0;t<of.numsmp;t++) {\r
+ q->speed = 8363;\r
+ q->flags = SF_SIGNED;\r
+ if(smap[t>>3]&(1<<(t&7))) {\r
+ _mm_read_SBYTES(s.samplename,32,modreader);\r
+ s.length = _mm_read_I_ULONG(modreader);\r
+ s.finetune = _mm_read_UBYTE(modreader);\r
+ s.volume = _mm_read_UBYTE(modreader);\r
+ s.reppos = _mm_read_I_ULONG(modreader);\r
+ s.repend = _mm_read_I_ULONG(modreader);\r
+ s.type = _mm_read_UBYTE(modreader);\r
+ s.loop = _mm_read_UBYTE(modreader);\r
+\r
+ q->samplename = DupStr(s.samplename,32,1);\r
+ q->length = s.length;\r
+ q->loopstart = s.reppos;\r
+ q->loopend = s.repend;\r
+ q->volume = s.volume<<2;\r
+\r
+ if(s.type&1) q->flags|=SF_16BITS;\r
+ if(s.loop&8) q->flags|=SF_LOOP;\r
+\r
+ q->seekpos = _mm_ftell(modreader);\r
+ _mm_fseek(modreader,q->length,SEEK_CUR);\r
+ } else \r
+ q->samplename = DupStr(NULL,0,0);\r
+ q++;\r
+ }\r
+ return 1;\r
+}\r
+\r
+CHAR *FAR_LoadTitle(void)\r
+{\r
+ CHAR s[40];\r
+\r
+ _mm_fseek(modreader,4,SEEK_SET);\r
+ if(!_mm_read_UBYTES(s,40,modreader)) return NULL;\r
+ \r
+ return(DupStr(s,40,1));\r
+}\r
+\r
+/*========== Loader information */\r
+\r
+MIKMODAPI MLOADER load_far={\r
+ NULL,\r
+ "FAR",\r
+ "FAR (Farandole Composer)",\r
+ FAR_Init,\r
+ FAR_Test,\r
+ FAR_Load,\r
+ FAR_Cleanup,\r
+ FAR_LoadTitle\r
+};\r
+\r
+/* ex:set ts=4: */\r