--- /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_669.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $\r
+\r
+ Composer 669 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
+/* header */\r
+typedef struct S69HEADER { \r
+ UBYTE marker[2];\r
+ CHAR message[108];\r
+ UBYTE nos;\r
+ UBYTE nopa;\r
+ UBYTE looporder;\r
+ UBYTE orders[0x80];\r
+ UBYTE tempos[0x80];\r
+ UBYTE breaks[0x80];\r
+} S69HEADER;\r
+\r
+/* sample information */\r
+typedef struct S69SAMPLE {\r
+ CHAR filename[13];\r
+ SLONG length;\r
+ SLONG loopbeg;\r
+ SLONG loopend;\r
+} S69SAMPLE;\r
+\r
+/* encoded note */\r
+typedef struct S69NOTE {\r
+ UBYTE a,b,c;\r
+} S69NOTE;\r
+\r
+/*========== Loader variables */\r
+\r
+/* current pattern */\r
+static S69NOTE* s69pat=NULL;\r
+/* Module header */\r
+static S69HEADER* mh=NULL;\r
+\r
+/* file type identification */\r
+static CHAR* S69_Version[]={\r
+ "Composer 669",\r
+ "Extended 669"\r
+};\r
+\r
+/*========== Loader code */\r
+\r
+BOOL S69_Test(void)\r
+{\r
+ UBYTE buf[0x80];\r
+\r
+ if(!_mm_read_UBYTES(buf,2,modreader))\r
+ return 0;\r
+ /* look for id */\r
+ if(!memcmp(buf,"if",2) || !memcmp(buf,"JN",2)) {\r
+ int i;\r
+\r
+ /* skip song message */\r
+ _mm_fseek(modreader,108,SEEK_CUR);\r
+ /* sanity checks */\r
+ if(_mm_read_UBYTE(modreader) > 64) return 0;\r
+ if(_mm_read_UBYTE(modreader) > 128) return 0;\r
+ if(_mm_read_UBYTE(modreader) > 127) return 0;\r
+ /* check order table */\r
+ if(!_mm_read_UBYTES(buf,0x80,modreader)) return 0;\r
+ for(i=0;i<0x80;i++)\r
+ if((buf[i]>=0x80)&&(buf[i]!=0xff)) return 0;\r
+ /* check tempos table */\r
+ if(!_mm_read_UBYTES(buf,0x80,modreader)) return 0;\r
+ for(i=0;i<0x80;i++)\r
+ if((!buf[i])||(buf[i]>32)) return 0;\r
+ /* check pattern length table */\r
+ if(!_mm_read_UBYTES(buf,0x80,modreader)) return 0;\r
+ for(i=0;i<0x80;i++)\r
+ if(buf[i]>0x3f) return 0;\r
+ } else\r
+ return 0;\r
+\r
+ return 1;\r
+}\r
+\r
+BOOL S69_Init(void)\r
+{\r
+ if(!(s69pat=(S69NOTE *)_mm_malloc(64*8*sizeof(S69NOTE)))) return 0;\r
+ if(!(mh=(S69HEADER *)_mm_malloc(sizeof(S69HEADER)))) return 0;\r
+\r
+ return 1;\r
+}\r
+\r
+void S69_Cleanup(void)\r
+{\r
+ _mm_free(s69pat);\r
+ _mm_free(mh);\r
+}\r
+\r
+static BOOL S69_LoadPatterns(void)\r
+{\r
+ int track,row,channel;\r
+ UBYTE note,inst,vol,effect,lastfx,lastval;\r
+ S69NOTE *cur;\r
+ int tracks=0;\r
+ \r
+ if(!AllocPatterns()) return 0;\r
+ if(!AllocTracks()) return 0;\r
+\r
+ for(track=0;track<of.numpat;track++) {\r
+ /* set pattern break locations */\r
+ of.pattrows[track]=mh->breaks[track]+1;\r
+\r
+ /* load the 669 pattern */\r
+ cur=s69pat;\r
+ for(row=0;row<64;row++) {\r
+ for(channel=0;channel<8;channel++,cur++) {\r
+ cur->a = _mm_read_UBYTE(modreader);\r
+ cur->b = _mm_read_UBYTE(modreader);\r
+ cur->c = _mm_read_UBYTE(modreader);\r
+ }\r
+ }\r
+\r
+ if(_mm_eof(modreader)) {\r
+ _mm_errno = MMERR_LOADING_PATTERN;\r
+ return 0;\r
+ }\r
+\r
+ /* translate the pattern */\r
+ for(channel=0;channel<8;channel++) {\r
+ UniReset();\r
+ /* set pattern tempo */\r
+ UniPTEffect(0xf,78);\r
+ UniPTEffect(0xf,mh->tempos[track]);\r
+\r
+ lastfx=0xff,lastval=0;\r
+\r
+ for(row=0;row<=mh->breaks[track];row++) {\r
+ int a,b,c;\r
+\r
+ /* fetch the encoded note */\r
+ a=s69pat[(row*8)+channel].a;\r
+ b=s69pat[(row*8)+channel].b;\r
+ c=s69pat[(row*8)+channel].c;\r
+\r
+ /* decode it */\r
+ note=a>>2;\r
+ inst=((a&0x3)<<4)|((b&0xf0)>>4);\r
+ vol=b&0xf;\r
+\r
+ if (a<0xff) {\r
+ if (a<0xfe) {\r
+ UniInstrument(inst);\r
+ UniNote(note+2*OCTAVE);\r
+ lastfx=0xff; /* reset background effect memory */\r
+ }\r
+ UniPTEffect(0xc,vol<<2);\r
+ }\r
+\r
+ if ((c!=0xff)||(lastfx!=0xff)) {\r
+ if(c==0xff)\r
+ c=lastfx,effect=lastval;\r
+ else\r
+ effect=c&0xf;\r
+\r
+ switch(c>>4) {\r
+ case 0: /* porta up */\r
+ UniPTEffect(0x1,effect);\r
+ lastfx=c,lastval=effect;\r
+ break;\r
+ case 1: /* porta down */\r
+ UniPTEffect(0x2,effect);\r
+ lastfx=c,lastval=effect;\r
+ break;\r
+ case 2: /* porta to note */\r
+ UniPTEffect(0x3,effect);\r
+ lastfx=c,lastval=effect;\r
+ break;\r
+ case 3: /* frequency adjust */\r
+ /* DMP converts this effect to S3M FF1. Why not ? */\r
+ UniEffect(UNI_S3MEFFECTF,0xf0|effect);\r
+ break;\r
+ case 4: /* vibrato */\r
+ UniPTEffect(0x4,effect);\r
+ lastfx=c,lastval=effect;\r
+ break;\r
+ case 5: /* set speed */\r
+ if (effect)\r
+ UniPTEffect(0xf,effect);\r
+ else \r
+ if(mh->marker[0]!=0x69) {\r
+#ifdef MIKMOD_DEBUG\r
+ fprintf(stderr,"\r669: unsupported super fast tempo at pat=%d row=%d chan=%d\n",\r
+ track,row,channel);\r
+#endif\r
+ }\r
+ break;\r
+ }\r
+ }\r
+ UniNewline();\r
+ }\r
+ if(!(of.tracks[tracks++]=UniDup())) return 0;\r
+ }\r
+ }\r
+\r
+ return 1;\r
+}\r
+\r
+BOOL S69_Load(BOOL curious)\r
+{\r
+ int i;\r
+ SAMPLE *current;\r
+ S69SAMPLE sample;\r
+ (void)curious;\r
+\r
+ /* module header */\r
+ _mm_read_UBYTES(mh->marker,2,modreader);\r
+ _mm_read_UBYTES(mh->message,108,modreader);\r
+ mh->nos=_mm_read_UBYTE(modreader);\r
+ mh->nopa=_mm_read_UBYTE(modreader);\r
+ mh->looporder=_mm_read_UBYTE(modreader);\r
+ _mm_read_UBYTES(mh->orders,0x80,modreader);\r
+ for(i=0;i<0x80;i++)\r
+ if ((mh->orders[i]>=0x80)&&(mh->orders[i]!=0xff)) {\r
+ _mm_errno=MMERR_NOT_A_MODULE;\r
+ return 1;\r
+ }\r
+ _mm_read_UBYTES(mh->tempos,0x80,modreader);\r
+ for(i=0;i<0x80;i++)\r
+ if ((!mh->tempos[i])||(mh->tempos[i]>32)) {\r
+ _mm_errno=MMERR_NOT_A_MODULE;\r
+ return 1;\r
+ }\r
+ _mm_read_UBYTES(mh->breaks,0x80,modreader);\r
+ for(i=0;i<0x80;i++)\r
+ if (mh->breaks[i]>0x3f) {\r
+ _mm_errno=MMERR_NOT_A_MODULE;\r
+ return 1;\r
+ }\r
+\r
+ /* set module variables */\r
+ of.initspeed=4;\r
+ of.inittempo=78;\r
+ of.songname=DupStr(mh->message,36,1);\r
+ of.modtype=strdup(S69_Version[memcmp(mh->marker,"JN",2)==0]);\r
+ of.numchn=8;\r
+ of.numpat=mh->nopa;\r
+ of.numins=of.numsmp=mh->nos;\r
+ of.numtrk=of.numchn*of.numpat;\r
+ of.flags=UF_XMPERIODS|UF_LINEAR;\r
+\r
+ for(i= 35;(i>= 0)&&(mh->message[i]==' ');i--) mh->message[i]=0;\r
+ for(i=36+35;(i>=36+0)&&(mh->message[i]==' ');i--) mh->message[i]=0;\r
+ for(i=72+35;(i>=72+0)&&(mh->message[i]==' ');i--) mh->message[i]=0;\r
+ if((mh->message[0])||(mh->message[36])||(mh->message[72]))\r
+ if((of.comment=(CHAR*)_mm_malloc(3*(36+1)+1))) {\r
+ strncpy(of.comment,mh->message,36);\r
+ strcat(of.comment,"\r");\r
+ if (mh->message[36]) strncat(of.comment,mh->message+36,36);\r
+ strcat(of.comment,"\r");\r
+ if (mh->message[72]) strncat(of.comment,mh->message+72,36);\r
+ strcat(of.comment,"\r");\r
+ of.comment[3*(36+1)]=0;\r
+ }\r
+\r
+ if(!AllocPositions(0x80)) return 0;\r
+ for(i=0;i<0x80;i++) {\r
+ if(mh->orders[i]>=mh->nopa) break;\r
+ of.positions[i]=mh->orders[i];\r
+ }\r
+ of.numpos=i;\r
+ of.reppos=mh->looporder<of.numpos?mh->looporder:0;\r
+\r
+ if(!AllocSamples()) return 0;\r
+ current=of.samples;\r
+\r
+ for(i=0;i<of.numins;i++) {\r
+ /* sample information */\r
+ _mm_read_UBYTES((UBYTE*)sample.filename,13,modreader);\r
+ sample.length=_mm_read_I_SLONG(modreader);\r
+ sample.loopbeg=_mm_read_I_SLONG(modreader);\r
+ sample.loopend=_mm_read_I_SLONG(modreader);\r
+ if (sample.loopend==0xfffff) sample.loopend=0;\r
+\r
+ if((sample.length<0)||(sample.loopbeg<-1)||(sample.loopend<-1)) {\r
+ _mm_errno = MMERR_LOADING_HEADER;\r
+ return 0;\r
+ }\r
+\r
+ current->samplename=DupStr(sample.filename,13,1);\r
+ current->seekpos=0;\r
+ current->speed=0;\r
+ current->length=sample.length;\r
+ current->loopstart=sample.loopbeg;\r
+ current->loopend=sample.loopend;\r
+ current->flags=(sample.loopbeg<sample.loopend)?SF_LOOP:0;\r
+ current->volume=64;\r
+\r
+ current++;\r
+ }\r
+\r
+ if(!S69_LoadPatterns()) return 0;\r
+\r
+ return 1;\r
+}\r
+\r
+CHAR *S69_LoadTitle(void)\r
+{\r
+ CHAR s[36];\r
+\r
+ _mm_fseek(modreader,2,SEEK_SET);\r
+ if(!_mm_read_UBYTES(s,36,modreader)) return NULL;\r
+\r
+ return(DupStr(s,36,1));\r
+}\r
+\r
+/*========== Loader information */\r
+\r
+MIKMODAPI MLOADER load_669={\r
+ NULL,\r
+ "669",\r
+ "669 (Composer 669, Unis 669)",\r
+ S69_Init,\r
+ S69_Test,\r
+ S69_Load,\r
+ S69_Cleanup,\r
+ S69_LoadTitle\r
+};\r
+\r
+/* ex:set ts=4: */\r