1 /* MikMod sound library
2 (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file
3 AUTHORS for complete list.
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.
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.
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
21 /*==============================================================================
23 $Id: load_dsm.c,v 1.3 2005/04/07 19:57:38 realtech Exp $
25 DSIK internal format (DSM) module loader
27 ==============================================================================*/
43 #include "mikmod_internals.h"
46 extern int fprintf(FILE *, const char *, ...);
49 /*========== Module structure */
51 #define DSM_MAXCHAN (16)
52 #define DSM_MAXORDERS (128)
54 typedef struct DSMSONG
{
67 UBYTE panpos
[DSM_MAXCHAN
];
68 UBYTE orders
[DSM_MAXORDERS
];
71 typedef struct DSMINST
{
84 typedef struct DSMNOTE
{
85 UBYTE note
,ins
,vol
,cmd
,inf
;
88 #define DSM_SURROUND (0xa4)
90 /*========== Loader variables */
92 static CHAR
* SONGID
="SONG";
93 static CHAR
* INSTID
="INST";
94 static CHAR
* PATTID
="PATT";
96 static UBYTE blockid
[4];
99 static DSMSONG
* mh
=NULL
;
100 static DSMNOTE
* dsmbuf
=NULL
;
102 static CHAR DSM_Version
[]="DSIK DSM-format";
104 static unsigned char DSMSIG
[4+4]={'R','I','F','F','D','S','M','F'};
106 /*========== Loader code */
112 if(!_mm_read_UBYTES(id
,12,modreader
)) return 0;
113 if(!memcmp(id
,DSMSIG
,4) && !memcmp(id
+8,DSMSIG
+4,4)) return 1;
120 if(!(dsmbuf
=(DSMNOTE
*)MikMod_malloc(DSM_MAXCHAN
*64*sizeof(DSMNOTE
)))) return 0;
121 if(!(mh
=(DSMSONG
*)MikMod_calloc(1,sizeof(DSMSONG
)))) return 0;
125 void DSM_Cleanup(void)
131 static int GetBlockHeader(void)
133 /* make sure we're at the right position for reading the
134 next riff block, no matter how many bytes read */
135 _mm_fseek(modreader
, blocklp
+blockln
, SEEK_SET
);
138 _mm_read_UBYTES(blockid
,4,modreader
);
139 blockln
=_mm_read_I_ULONG(modreader
);
140 if(_mm_eof(modreader
)) {
141 _mm_errno
= MMERR_LOADING_HEADER
;
145 if(memcmp(blockid
,SONGID
,4) && memcmp(blockid
,INSTID
,4) &&
146 memcmp(blockid
,PATTID
,4)) {
148 fprintf(stderr
,"\rDSM: Skipping unknown block type %4.4s\n",blockid
);
150 _mm_fseek(modreader
, blockln
, SEEK_CUR
);
155 blocklp
= _mm_ftell(modreader
);
160 static int DSM_ReadPattern(void)
166 /* clear pattern data */
167 memset(dsmbuf
,255,DSM_MAXCHAN
*64*sizeof(DSMNOTE
));
168 length
=_mm_read_I_SWORD(modreader
);
171 flag
=_mm_read_UBYTE(modreader
);
172 if((_mm_eof(modreader
))||(--length
<0)) {
173 _mm_errno
= MMERR_LOADING_PATTERN
;
178 n
=&dsmbuf
[((flag
&0xf)*64)+row
];
179 if(flag
&0x80) n
->note
=_mm_read_UBYTE(modreader
);
180 if(flag
&0x40) n
->ins
=_mm_read_UBYTE(modreader
);
181 if(flag
&0x20) n
->vol
=_mm_read_UBYTE(modreader
);
183 n
->cmd
=_mm_read_UBYTE(modreader
);
184 n
->inf
=_mm_read_UBYTE(modreader
);
193 static UBYTE
*DSM_ConvertTrack(DSMNOTE
*tr
)
196 UBYTE note
,ins
,vol
,cmd
,inf
;
206 if(ins
!=0 && ins
!=255) UniInstrument(ins
-1);
207 if(note
!=255) UniNote(note
-1); /* normal note */
208 if(vol
<65) UniPTEffect(0xc,vol
);
212 if(inf
==DSM_SURROUND
)
213 UniEffect(UNI_ITEFFECTS0
,0x91);
216 inf
=(inf
<0x80)?inf
<<1:255;
217 UniPTEffect(cmd
,inf
);
221 if(inf
<=0x7f) UniPTEffect(cmd
,inf
);
223 /* Convert pattern jump from Dec to Hex */
225 inf
= (((inf
&0xf0)>>4)*10)+(inf
&0xf);
226 UniPTEffect(cmd
,inf
);
234 int DSM_Load(int curious
)
239 int cursmp
=0,curpat
=0,track
=0;
244 if(!GetBlockHeader()) return 0;
245 if(memcmp(blockid
,SONGID
,4)) {
246 _mm_errno
= MMERR_LOADING_HEADER
;
250 _mm_read_UBYTES(mh
->songname
,28,modreader
);
251 mh
->version
=_mm_read_I_UWORD(modreader
);
252 mh
->flags
=_mm_read_I_UWORD(modreader
);
253 mh
->reserved2
=_mm_read_I_ULONG(modreader
);
254 mh
->numord
=_mm_read_I_UWORD(modreader
);
255 mh
->numsmp
=_mm_read_I_UWORD(modreader
);
256 mh
->numpat
=_mm_read_I_UWORD(modreader
);
257 mh
->numtrk
=_mm_read_I_UWORD(modreader
);
258 mh
->globalvol
=_mm_read_UBYTE(modreader
);
259 mh
->mastervol
=_mm_read_UBYTE(modreader
);
260 mh
->speed
=_mm_read_UBYTE(modreader
);
261 mh
->bpm
=_mm_read_UBYTE(modreader
);
262 _mm_read_UBYTES(mh
->panpos
,DSM_MAXCHAN
,modreader
);
263 _mm_read_UBYTES(mh
->orders
,DSM_MAXORDERS
,modreader
);
265 /* set module variables */
266 of
.initspeed
=mh
->speed
;
267 of
.inittempo
=mh
->bpm
;
268 of
.modtype
=StrDup(DSM_Version
);
269 of
.numchn
=mh
->numtrk
;
270 of
.numpat
=mh
->numpat
;
271 of
.numtrk
=of
.numchn
*of
.numpat
;
272 of
.songname
=DupStr(mh
->songname
,28,1); /* make a cstr of songname */
274 of
.flags
|= UF_PANNING
;
275 /* XXX whenever possible, we should try to determine the original format.
276 Here we assume it was S3M-style wrt bpmlimit... */
279 for(t
=0;t
<DSM_MAXCHAN
;t
++)
280 of
.panning
[t
]=mh
->panpos
[t
]==DSM_SURROUND
?PAN_SURROUND
:
281 mh
->panpos
[t
]<0x80?(mh
->panpos
[t
]<<1):255;
283 if(!AllocPositions(mh
->numord
)) return 0;
285 for(t
=0;t
<mh
->numord
;t
++) {
286 int order
=mh
->orders
[t
];
287 if(order
==255) order
=LAST_PATTERN
;
288 of
.positions
[of
.numpos
]=order
;
289 if(mh
->orders
[t
]<254) of
.numpos
++;
292 of
.numins
=of
.numsmp
=mh
->numsmp
;
294 if(!AllocSamples()) return 0;
295 if(!AllocTracks()) return 0;
296 if(!AllocPatterns()) return 0;
298 while(cursmp
<of
.numins
||curpat
<of
.numpat
) {
299 if(!GetBlockHeader()) return 0;
300 if(!memcmp(blockid
,INSTID
,4) && cursmp
<of
.numins
) {
301 q
=&of
.samples
[cursmp
];
303 /* try to read sample info */
304 _mm_read_UBYTES(s
.filename
,13,modreader
);
305 s
.flags
=_mm_read_I_UWORD(modreader
);
306 s
.volume
=_mm_read_UBYTE(modreader
);
307 s
.length
=_mm_read_I_ULONG(modreader
);
308 s
.loopstart
=_mm_read_I_ULONG(modreader
);
309 s
.loopend
=_mm_read_I_ULONG(modreader
);
310 s
.reserved1
=_mm_read_I_ULONG(modreader
);
311 s
.c2spd
=_mm_read_I_UWORD(modreader
);
312 s
.period
=_mm_read_I_UWORD(modreader
);
313 _mm_read_UBYTES(s
.samplename
,28,modreader
);
315 q
->samplename
=DupStr(s
.samplename
,28,1);
316 q
->seekpos
=_mm_ftell(modreader
);
319 q
->loopstart
=s
.loopstart
;
320 q
->loopend
=s
.loopend
;
323 if(s
.flags
&1) q
->flags
|=SF_LOOP
;
324 if(s
.flags
&2) q
->flags
|=SF_SIGNED
;
325 /* (s.flags&4) means packed sample,
326 but did they really exist in dsm ?*/
329 if(!memcmp(blockid
,PATTID
,4) && curpat
<of
.numpat
) {
331 for(t
=0;t
<of
.numchn
;t
++)
332 if(!(of
.tracks
[track
++]=DSM_ConvertTrack(&dsmbuf
[t
*64]))) return 0;
340 CHAR
*DSM_LoadTitle(void)
344 _mm_fseek(modreader
,12,SEEK_SET
);
345 if(!_mm_read_UBYTES(s
,28,modreader
)) return NULL
;
347 return(DupStr(s
,28,1));
350 /*========== Loader information */
352 MIKMODAPI MLOADER load_dsm
={
355 "DSM (DSIK internal format)",