--- /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_dsm.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $\r
+\r
+ DSIK internal format (DSM) 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
+#define DSM_MAXCHAN (16)\r
+#define DSM_MAXORDERS (128)\r
+\r
+typedef struct DSMSONG {\r
+ CHAR songname[28];\r
+ UWORD version;\r
+ UWORD flags;\r
+ ULONG reserved2;\r
+ UWORD numord;\r
+ UWORD numsmp;\r
+ UWORD numpat;\r
+ UWORD numtrk;\r
+ UBYTE globalvol;\r
+ UBYTE mastervol;\r
+ UBYTE speed;\r
+ UBYTE bpm;\r
+ UBYTE panpos[DSM_MAXCHAN];\r
+ UBYTE orders[DSM_MAXORDERS];\r
+} DSMSONG;\r
+\r
+typedef struct DSMINST {\r
+ CHAR filename[13];\r
+ UWORD flags;\r
+ UBYTE volume;\r
+ ULONG length;\r
+ ULONG loopstart;\r
+ ULONG loopend;\r
+ ULONG reserved1;\r
+ UWORD c2spd;\r
+ UWORD period;\r
+ CHAR samplename[28];\r
+} DSMINST;\r
+\r
+typedef struct DSMNOTE {\r
+ UBYTE note,ins,vol,cmd,inf;\r
+} DSMNOTE;\r
+\r
+#define DSM_SURROUND (0xa4)\r
+\r
+/*========== Loader variables */\r
+\r
+static CHAR* SONGID="SONG";\r
+static CHAR* INSTID="INST";\r
+static CHAR* PATTID="PATT";\r
+\r
+static UBYTE blockid[4];\r
+static ULONG blockln;\r
+static ULONG blocklp;\r
+static DSMSONG* mh=NULL;\r
+static DSMNOTE* dsmbuf=NULL;\r
+\r
+static CHAR DSM_Version[]="DSIK DSM-format";\r
+\r
+static unsigned char DSMSIG[4+4]={'R','I','F','F','D','S','M','F'};\r
+\r
+/*========== Loader code */\r
+\r
+BOOL DSM_Test(void)\r
+{\r
+ UBYTE id[12];\r
+\r
+ if(!_mm_read_UBYTES(id,12,modreader)) return 0;\r
+ if(!memcmp(id,DSMSIG,4) && !memcmp(id+8,DSMSIG+4,4)) return 1;\r
+\r
+ return 0;\r
+}\r
+\r
+BOOL DSM_Init(void)\r
+{\r
+ if(!(dsmbuf=(DSMNOTE *)_mm_malloc(DSM_MAXCHAN*64*sizeof(DSMNOTE)))) return 0;\r
+ if(!(mh=(DSMSONG *)_mm_calloc(1,sizeof(DSMSONG)))) return 0;\r
+ return 1;\r
+}\r
+\r
+void DSM_Cleanup(void)\r
+{\r
+ _mm_free(dsmbuf);\r
+ _mm_free(mh);\r
+}\r
+\r
+static BOOL GetBlockHeader(void)\r
+{\r
+ /* make sure we're at the right position for reading the\r
+ next riff block, no matter how many bytes read */\r
+ _mm_fseek(modreader, blocklp+blockln, SEEK_SET);\r
+ \r
+ while(1) {\r
+ _mm_read_UBYTES(blockid,4,modreader);\r
+ blockln=_mm_read_I_ULONG(modreader);\r
+ if(_mm_eof(modreader)) {\r
+ _mm_errno = MMERR_LOADING_HEADER;\r
+ return 0;\r
+ }\r
+\r
+ if(memcmp(blockid,SONGID,4) && memcmp(blockid,INSTID,4) &&\r
+ memcmp(blockid,PATTID,4)) {\r
+#ifdef MIKMOD_DEBUG\r
+ fprintf(stderr,"\rDSM: Skipping unknown block type %4.4s\n",blockid);\r
+#endif\r
+ _mm_fseek(modreader, blockln, SEEK_CUR);\r
+ } else\r
+ break;\r
+ }\r
+\r
+ blocklp = _mm_ftell(modreader);\r
+\r
+ return 1;\r
+}\r
+\r
+static BOOL DSM_ReadPattern(void)\r
+{\r
+ int flag,row=0;\r
+ SWORD length;\r
+ DSMNOTE *n;\r
+\r
+ /* clear pattern data */\r
+ memset(dsmbuf,255,DSM_MAXCHAN*64*sizeof(DSMNOTE));\r
+ length=_mm_read_I_SWORD(modreader);\r
+\r
+ while(row<64) {\r
+ flag=_mm_read_UBYTE(modreader);\r
+ if((_mm_eof(modreader))||(--length<0)) {\r
+ _mm_errno = MMERR_LOADING_PATTERN;\r
+ return 0;\r
+ }\r
+\r
+ if(flag) {\r
+ n=&dsmbuf[((flag&0xf)*64)+row];\r
+ if(flag&0x80) n->note=_mm_read_UBYTE(modreader);\r
+ if(flag&0x40) n->ins=_mm_read_UBYTE(modreader);\r
+ if(flag&0x20) n->vol=_mm_read_UBYTE(modreader);\r
+ if(flag&0x10) {\r
+ n->cmd=_mm_read_UBYTE(modreader);\r
+ n->inf=_mm_read_UBYTE(modreader);\r
+ }\r
+ } else\r
+ row++;\r
+ }\r
+\r
+ return 1;\r
+}\r
+\r
+static UBYTE *DSM_ConvertTrack(DSMNOTE *tr)\r
+{\r
+ int t;\r
+ UBYTE note,ins,vol,cmd,inf;\r
+\r
+ UniReset();\r
+ for(t=0;t<64;t++) {\r
+ note=tr[t].note;\r
+ ins=tr[t].ins;\r
+ vol=tr[t].vol;\r
+ cmd=tr[t].cmd;\r
+ inf=tr[t].inf;\r
+\r
+ if(ins!=0 && ins!=255) UniInstrument(ins-1);\r
+ if(note!=255) UniNote(note-1); /* normal note */\r
+ if(vol<65) UniPTEffect(0xc,vol);\r
+\r
+ if(cmd!=255) {\r
+ if(cmd==0x8) {\r
+ if(inf==DSM_SURROUND)\r
+ UniEffect(UNI_ITEFFECTS0,0x91);\r
+ else\r
+ if(inf<=0x80) {\r
+ inf=(inf<0x80)?inf<<1:255;\r
+ UniPTEffect(cmd,inf);\r
+ }\r
+ } else\r
+ if(cmd==0xb) {\r
+ if(inf<=0x7f) UniPTEffect(cmd,inf);\r
+ } else {\r
+ /* Convert pattern jump from Dec to Hex */\r
+ if(cmd == 0xd)\r
+ inf = (((inf&0xf0)>>4)*10)+(inf&0xf);\r
+ UniPTEffect(cmd,inf);\r
+ }\r
+ }\r
+ UniNewline();\r
+ }\r
+ return UniDup();\r
+}\r
+\r
+BOOL DSM_Load(BOOL curious)\r
+{\r
+ int t;\r
+ DSMINST s;\r
+ SAMPLE *q;\r
+ int cursmp=0,curpat=0,track=0;\r
+\r
+ blocklp=0;\r
+ blockln=12;\r
+ (void)curious;\r
+\r
+ if(!GetBlockHeader()) return 0;\r
+ if(memcmp(blockid,SONGID,4)) {\r
+ _mm_errno = MMERR_LOADING_HEADER;\r
+ return 0;\r
+ }\r
+\r
+ _mm_read_UBYTES(mh->songname,28,modreader);\r
+ mh->version=_mm_read_I_UWORD(modreader);\r
+ mh->flags=_mm_read_I_UWORD(modreader);\r
+ mh->reserved2=_mm_read_I_ULONG(modreader);\r
+ mh->numord=_mm_read_I_UWORD(modreader);\r
+ mh->numsmp=_mm_read_I_UWORD(modreader);\r
+ mh->numpat=_mm_read_I_UWORD(modreader);\r
+ mh->numtrk=_mm_read_I_UWORD(modreader);\r
+ mh->globalvol=_mm_read_UBYTE(modreader);\r
+ mh->mastervol=_mm_read_UBYTE(modreader);\r
+ mh->speed=_mm_read_UBYTE(modreader);\r
+ mh->bpm=_mm_read_UBYTE(modreader);\r
+ _mm_read_UBYTES(mh->panpos,DSM_MAXCHAN,modreader);\r
+ _mm_read_UBYTES(mh->orders,DSM_MAXORDERS,modreader);\r
+\r
+ /* set module variables */\r
+ of.initspeed=mh->speed;\r
+ of.inittempo=mh->bpm;\r
+ of.modtype=strdup(DSM_Version);\r
+ of.numchn=mh->numtrk;\r
+ of.numpat=mh->numpat;\r
+ of.numtrk=of.numchn*of.numpat;\r
+ of.songname=DupStr(mh->songname,28,1); /* make a cstr of songname */\r
+ of.reppos=0;\r
+ of.flags |= UF_PANNING;\r
+ /* XXX whenever possible, we should try to determine the original format.\r
+ Here we assume it was S3M-style wrt bpmlimit... */\r
+ of.bpmlimit = 32;\r
+\r
+ for(t=0;t<DSM_MAXCHAN;t++)\r
+ of.panning[t]=mh->panpos[t]==DSM_SURROUND?PAN_SURROUND:\r
+ mh->panpos[t]<0x80?(mh->panpos[t]<<1):255;\r
+\r
+ if(!AllocPositions(mh->numord)) return 0;\r
+ of.numpos=0;\r
+ for(t=0;t<mh->numord;t++) {\r
+ int order=mh->orders[t];\r
+ if(order==255) order=LAST_PATTERN;\r
+ of.positions[of.numpos]=order;\r
+ if(mh->orders[t]<254) of.numpos++;\r
+ }\r
+\r
+ of.numins=of.numsmp=mh->numsmp;\r
+\r
+ if(!AllocSamples()) return 0;\r
+ if(!AllocTracks()) return 0;\r
+ if(!AllocPatterns()) return 0;\r
+\r
+ while(cursmp<of.numins||curpat<of.numpat) {\r
+ if(!GetBlockHeader()) return 0;\r
+ if(!memcmp(blockid,INSTID,4) && cursmp<of.numins) {\r
+ q=&of.samples[cursmp];\r
+\r
+ /* try to read sample info */\r
+ _mm_read_UBYTES(s.filename,13,modreader);\r
+ s.flags=_mm_read_I_UWORD(modreader);\r
+ s.volume=_mm_read_UBYTE(modreader);\r
+ s.length=_mm_read_I_ULONG(modreader);\r
+ s.loopstart=_mm_read_I_ULONG(modreader);\r
+ s.loopend=_mm_read_I_ULONG(modreader);\r
+ s.reserved1=_mm_read_I_ULONG(modreader);\r
+ s.c2spd=_mm_read_I_UWORD(modreader);\r
+ s.period=_mm_read_I_UWORD(modreader);\r
+ _mm_read_UBYTES(s.samplename,28,modreader);\r
+\r
+ q->samplename=DupStr(s.samplename,28,1);\r
+ q->seekpos=_mm_ftell(modreader);\r
+ q->speed=s.c2spd;\r
+ q->length=s.length;\r
+ q->loopstart=s.loopstart;\r
+ q->loopend=s.loopend;\r
+ q->volume=s.volume;\r
+\r
+ if(s.flags&1) q->flags|=SF_LOOP;\r
+ if(s.flags&2) q->flags|=SF_SIGNED;\r
+ /* (s.flags&4) means packed sample,\r
+ but did they really exist in dsm ?*/\r
+ cursmp++;\r
+ } else\r
+ if(!memcmp(blockid,PATTID,4) && curpat<of.numpat) {\r
+ DSM_ReadPattern();\r
+ for(t=0;t<of.numchn;t++)\r
+ if(!(of.tracks[track++]=DSM_ConvertTrack(&dsmbuf[t*64]))) return 0;\r
+ curpat++;\r
+ }\r
+ }\r
+\r
+ return 1;\r
+}\r
+\r
+CHAR *DSM_LoadTitle(void)\r
+{\r
+ CHAR s[28];\r
+\r
+ _mm_fseek(modreader,12,SEEK_SET);\r
+ if(!_mm_read_UBYTES(s,28,modreader)) return NULL;\r
+ \r
+ return(DupStr(s,28,1));\r
+}\r
+\r
+/*========== Loader information */\r
+\r
+MIKMODAPI MLOADER load_dsm={\r
+ NULL,\r
+ "DSM",\r
+ "DSM (DSIK internal format)",\r
+ DSM_Init,\r
+ DSM_Test,\r
+ DSM_Load,\r
+ DSM_Cleanup,\r
+ DSM_LoadTitle\r
+};\r
+\r
+\r
+/* ex:set ts=4: */\r