1 /* MikMod sound library
\r
2 (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file
\r
3 AUTHORS for complete list.
\r
5 This library is free software; you can redistribute it and/or modify
\r
6 it under the terms of the GNU Library General Public License as
\r
7 published by the Free Software Foundation; either version 2 of
\r
8 the License, or (at your option) any later version.
\r
10 This program is distributed in the hope that it will be useful,
\r
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
13 GNU Library General Public License for more details.
\r
15 You should have received a copy of the GNU Library General Public
\r
16 License along with this library; if not, write to the Free Software
\r
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
\r
21 /*==============================================================================
\r
23 $Id: load_dsm.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $
\r
25 DSIK internal format (DSM) module loader
\r
27 ==============================================================================*/
\r
29 #ifdef HAVE_CONFIG_H
\r
33 #ifdef HAVE_UNISTD_H
\r
38 #ifdef HAVE_MEMORY_H
\r
43 #include "mikmod_internals.h"
\r
46 extern int fprintf(FILE *, const char *, ...);
\r
49 /*========== Module structure */
\r
51 #define DSM_MAXCHAN (16)
\r
52 #define DSM_MAXORDERS (128)
\r
54 typedef struct DSMSONG {
\r
67 UBYTE panpos[DSM_MAXCHAN];
\r
68 UBYTE orders[DSM_MAXORDERS];
\r
71 typedef struct DSMINST {
\r
81 CHAR samplename[28];
\r
84 typedef struct DSMNOTE {
\r
85 UBYTE note,ins,vol,cmd,inf;
\r
88 #define DSM_SURROUND (0xa4)
\r
90 /*========== Loader variables */
\r
92 static CHAR* SONGID="SONG";
\r
93 static CHAR* INSTID="INST";
\r
94 static CHAR* PATTID="PATT";
\r
96 static UBYTE blockid[4];
\r
97 static ULONG blockln;
\r
98 static ULONG blocklp;
\r
99 static DSMSONG* mh=NULL;
\r
100 static DSMNOTE* dsmbuf=NULL;
\r
102 static CHAR DSM_Version[]="DSIK DSM-format";
\r
104 static unsigned char DSMSIG[4+4]={'R','I','F','F','D','S','M','F'};
\r
106 /*========== Loader code */
\r
108 BOOL DSM_Test(void)
\r
112 if(!_mm_read_UBYTES(id,12,modreader)) return 0;
\r
113 if(!memcmp(id,DSMSIG,4) && !memcmp(id+8,DSMSIG+4,4)) return 1;
\r
118 BOOL DSM_Init(void)
\r
120 if(!(dsmbuf=(DSMNOTE *)_mm_malloc(DSM_MAXCHAN*64*sizeof(DSMNOTE)))) return 0;
\r
121 if(!(mh=(DSMSONG *)_mm_calloc(1,sizeof(DSMSONG)))) return 0;
\r
125 void DSM_Cleanup(void)
\r
131 static BOOL GetBlockHeader(void)
\r
133 /* make sure we're at the right position for reading the
\r
134 next riff block, no matter how many bytes read */
\r
135 _mm_fseek(modreader, blocklp+blockln, SEEK_SET);
\r
138 _mm_read_UBYTES(blockid,4,modreader);
\r
139 blockln=_mm_read_I_ULONG(modreader);
\r
140 if(_mm_eof(modreader)) {
\r
141 _mm_errno = MMERR_LOADING_HEADER;
\r
145 if(memcmp(blockid,SONGID,4) && memcmp(blockid,INSTID,4) &&
\r
146 memcmp(blockid,PATTID,4)) {
\r
147 #ifdef MIKMOD_DEBUG
\r
148 fprintf(stderr,"\rDSM: Skipping unknown block type %4.4s\n",blockid);
\r
150 _mm_fseek(modreader, blockln, SEEK_CUR);
\r
155 blocklp = _mm_ftell(modreader);
\r
160 static BOOL DSM_ReadPattern(void)
\r
166 /* clear pattern data */
\r
167 memset(dsmbuf,255,DSM_MAXCHAN*64*sizeof(DSMNOTE));
\r
168 length=_mm_read_I_SWORD(modreader);
\r
171 flag=_mm_read_UBYTE(modreader);
\r
172 if((_mm_eof(modreader))||(--length<0)) {
\r
173 _mm_errno = MMERR_LOADING_PATTERN;
\r
178 n=&dsmbuf[((flag&0xf)*64)+row];
\r
179 if(flag&0x80) n->note=_mm_read_UBYTE(modreader);
\r
180 if(flag&0x40) n->ins=_mm_read_UBYTE(modreader);
\r
181 if(flag&0x20) n->vol=_mm_read_UBYTE(modreader);
\r
183 n->cmd=_mm_read_UBYTE(modreader);
\r
184 n->inf=_mm_read_UBYTE(modreader);
\r
193 static UBYTE *DSM_ConvertTrack(DSMNOTE *tr)
\r
196 UBYTE note,ins,vol,cmd,inf;
\r
199 for(t=0;t<64;t++) {
\r
206 if(ins!=0 && ins!=255) UniInstrument(ins-1);
\r
207 if(note!=255) UniNote(note-1); /* normal note */
\r
208 if(vol<65) UniPTEffect(0xc,vol);
\r
212 if(inf==DSM_SURROUND)
\r
213 UniEffect(UNI_ITEFFECTS0,0x91);
\r
216 inf=(inf<0x80)?inf<<1:255;
\r
217 UniPTEffect(cmd,inf);
\r
221 if(inf<=0x7f) UniPTEffect(cmd,inf);
\r
223 /* Convert pattern jump from Dec to Hex */
\r
225 inf = (((inf&0xf0)>>4)*10)+(inf&0xf);
\r
226 UniPTEffect(cmd,inf);
\r
234 BOOL DSM_Load(BOOL curious)
\r
239 int cursmp=0,curpat=0,track=0;
\r
245 if(!GetBlockHeader()) return 0;
\r
246 if(memcmp(blockid,SONGID,4)) {
\r
247 _mm_errno = MMERR_LOADING_HEADER;
\r
251 _mm_read_UBYTES(mh->songname,28,modreader);
\r
252 mh->version=_mm_read_I_UWORD(modreader);
\r
253 mh->flags=_mm_read_I_UWORD(modreader);
\r
254 mh->reserved2=_mm_read_I_ULONG(modreader);
\r
255 mh->numord=_mm_read_I_UWORD(modreader);
\r
256 mh->numsmp=_mm_read_I_UWORD(modreader);
\r
257 mh->numpat=_mm_read_I_UWORD(modreader);
\r
258 mh->numtrk=_mm_read_I_UWORD(modreader);
\r
259 mh->globalvol=_mm_read_UBYTE(modreader);
\r
260 mh->mastervol=_mm_read_UBYTE(modreader);
\r
261 mh->speed=_mm_read_UBYTE(modreader);
\r
262 mh->bpm=_mm_read_UBYTE(modreader);
\r
263 _mm_read_UBYTES(mh->panpos,DSM_MAXCHAN,modreader);
\r
264 _mm_read_UBYTES(mh->orders,DSM_MAXORDERS,modreader);
\r
266 /* set module variables */
\r
267 of.initspeed=mh->speed;
\r
268 of.inittempo=mh->bpm;
\r
269 of.modtype=strdup(DSM_Version);
\r
270 of.numchn=mh->numtrk;
\r
271 of.numpat=mh->numpat;
\r
272 of.numtrk=of.numchn*of.numpat;
\r
273 of.songname=DupStr(mh->songname,28,1); /* make a cstr of songname */
\r
275 of.flags |= UF_PANNING;
\r
276 /* XXX whenever possible, we should try to determine the original format.
\r
277 Here we assume it was S3M-style wrt bpmlimit... */
\r
280 for(t=0;t<DSM_MAXCHAN;t++)
\r
281 of.panning[t]=mh->panpos[t]==DSM_SURROUND?PAN_SURROUND:
\r
282 mh->panpos[t]<0x80?(mh->panpos[t]<<1):255;
\r
284 if(!AllocPositions(mh->numord)) return 0;
\r
286 for(t=0;t<mh->numord;t++) {
\r
287 int order=mh->orders[t];
\r
288 if(order==255) order=LAST_PATTERN;
\r
289 of.positions[of.numpos]=order;
\r
290 if(mh->orders[t]<254) of.numpos++;
\r
293 of.numins=of.numsmp=mh->numsmp;
\r
295 if(!AllocSamples()) return 0;
\r
296 if(!AllocTracks()) return 0;
\r
297 if(!AllocPatterns()) return 0;
\r
299 while(cursmp<of.numins||curpat<of.numpat) {
\r
300 if(!GetBlockHeader()) return 0;
\r
301 if(!memcmp(blockid,INSTID,4) && cursmp<of.numins) {
\r
302 q=&of.samples[cursmp];
\r
304 /* try to read sample info */
\r
305 _mm_read_UBYTES(s.filename,13,modreader);
\r
306 s.flags=_mm_read_I_UWORD(modreader);
\r
307 s.volume=_mm_read_UBYTE(modreader);
\r
308 s.length=_mm_read_I_ULONG(modreader);
\r
309 s.loopstart=_mm_read_I_ULONG(modreader);
\r
310 s.loopend=_mm_read_I_ULONG(modreader);
\r
311 s.reserved1=_mm_read_I_ULONG(modreader);
\r
312 s.c2spd=_mm_read_I_UWORD(modreader);
\r
313 s.period=_mm_read_I_UWORD(modreader);
\r
314 _mm_read_UBYTES(s.samplename,28,modreader);
\r
316 q->samplename=DupStr(s.samplename,28,1);
\r
317 q->seekpos=_mm_ftell(modreader);
\r
319 q->length=s.length;
\r
320 q->loopstart=s.loopstart;
\r
321 q->loopend=s.loopend;
\r
322 q->volume=s.volume;
\r
324 if(s.flags&1) q->flags|=SF_LOOP;
\r
325 if(s.flags&2) q->flags|=SF_SIGNED;
\r
326 /* (s.flags&4) means packed sample,
\r
327 but did they really exist in dsm ?*/
\r
330 if(!memcmp(blockid,PATTID,4) && curpat<of.numpat) {
\r
332 for(t=0;t<of.numchn;t++)
\r
333 if(!(of.tracks[track++]=DSM_ConvertTrack(&dsmbuf[t*64]))) return 0;
\r
341 CHAR *DSM_LoadTitle(void)
\r
345 _mm_fseek(modreader,12,SEEK_SET);
\r
346 if(!_mm_read_UBYTES(s,28,modreader)) return NULL;
\r
348 return(DupStr(s,28,1));
\r
351 /*========== Loader information */
\r
353 MIKMODAPI MLOADER load_dsm={
\r
356 "DSM (DSIK internal format)",
\r