4
|
1 /*
|
|
2
|
|
3 Name: LOAD_DSM.C
|
|
4
|
|
5 Description:
|
|
6 DSIK Internal Format (DSM) module loader
|
|
7
|
|
8 Portability:
|
|
9 All systems - all compilers (hopefully)
|
|
10
|
|
11 If this module is found to not be portable to any particular platform,
|
|
12 please contact Jake Stine at dracoirs@epix.net (see MIKMOD.TXT for
|
|
13 more information on contacting the author).
|
|
14 */
|
|
15
|
|
16 #include <string.h>
|
|
17 #include "mikmod.h"
|
|
18
|
|
19
|
|
20 typedef struct DSMNOTE
|
|
21 { UBYTE note,ins,vol,cmd,inf;
|
|
22 } DSMNOTE;
|
|
23
|
|
24
|
|
25 typedef struct DSMINST
|
|
26 { CHAR filename[13];
|
|
27 UWORD flags;
|
|
28 UBYTE volume;
|
|
29 ULONG length;
|
|
30 ULONG loopstart;
|
|
31 ULONG loopend;
|
|
32 ULONG reserved1;
|
|
33 UWORD c2spd;
|
|
34 UWORD reserved2;
|
|
35 CHAR samplename[28];
|
|
36 } DSMINST;
|
|
37
|
|
38
|
|
39 typedef struct DSMSONG
|
|
40 { CHAR songname[28];
|
|
41 UWORD reserved1;
|
|
42 UWORD flags;
|
|
43 ULONG reserved2;
|
|
44 UWORD numord;
|
|
45 UWORD numsmp;
|
|
46 UWORD numpat;
|
|
47 UWORD numtrk;
|
|
48 UBYTE globalvol;
|
|
49 UBYTE mastervol;
|
|
50 UBYTE speed;
|
|
51 UBYTE bpm;
|
|
52 UBYTE panpos[16];
|
|
53 UBYTE orders[128];
|
|
54 } DSMSONG;
|
|
55
|
|
56
|
|
57
|
|
58 static CHAR *SONGID = "SONG";
|
|
59 static CHAR *INSTID = "INST";
|
|
60 static CHAR *PATTID = "PATT";
|
|
61
|
|
62
|
|
63 static UBYTE blockid[4];
|
|
64 static ULONG blockln;
|
|
65 static ULONG blocklp;
|
|
66 static DSMSONG *mh = NULL;
|
|
67 static DSMNOTE *dsmbuf = NULL;
|
|
68
|
|
69 static CHAR DSM_Version[] = "DSIK DSM-format";
|
|
70
|
|
71
|
|
72 BOOL DSM_Test(void)
|
|
73 {
|
|
74 UBYTE id[12];
|
|
75
|
|
76 if(_mm_read_UBYTES((UBYTE *)id,12,modfp)) return 0;
|
|
77 if(!memcmp(id,"RIFF",4) && !memcmp(&id[8],"DSMF",4)) return 1;
|
|
78
|
|
79 return 0;
|
|
80 }
|
|
81
|
|
82
|
|
83 BOOL DSM_Init(void)
|
|
84 {
|
|
85 if(!(dsmbuf=(DSMNOTE *)_mm_malloc(16*64*sizeof(DSMNOTE)))) return 0;
|
|
86 if(!(mh=(DSMSONG *)_mm_calloc(1,sizeof(DSMSONG)))) return 0;
|
|
87 return 1;
|
|
88 }
|
|
89
|
|
90
|
|
91 void DSM_Cleanup(void)
|
|
92 {
|
|
93 if(dsmbuf!=NULL) free(dsmbuf);
|
|
94 if(mh!=NULL) free(mh);
|
|
95
|
|
96 dsmbuf = NULL;
|
|
97 mh = NULL;
|
|
98 }
|
|
99
|
|
100
|
|
101 BOOL GetBlockHeader(void)
|
|
102 {
|
|
103 // make sure we're at the right position for reading the
|
|
104 // next riff block, no matter how many bytes read
|
|
105
|
|
106 _mm_fseek(modfp, blocklp+blockln, SEEK_SET);
|
|
107
|
|
108 while(1)
|
|
109 { _mm_read_UBYTES(blockid,4,modfp);
|
|
110 blockln = _mm_read_I_ULONG(modfp);
|
|
111 if(feof(modfp))
|
|
112 { _mm_errno = MMERR_LOADING_HEADER;
|
|
113 return 0;
|
|
114 }
|
|
115
|
|
116 if(memcmp(blockid,SONGID,4) && memcmp(blockid,INSTID,4) && memcmp(blockid,PATTID,4))
|
|
117 { //printf("Skipping unknown block type %4.4s\n",&blockid);
|
|
118 _mm_fseek(modfp, blockln, SEEK_CUR);
|
|
119 } else break;
|
|
120 }
|
|
121
|
|
122 blocklp = _mm_ftell(modfp);
|
|
123 return 1;
|
|
124 }
|
|
125
|
|
126
|
|
127 BOOL DSM_ReadPattern(void)
|
|
128 {
|
|
129 int row=0,flag;
|
|
130 DSMNOTE *n;
|
|
131
|
|
132 // clear pattern data
|
|
133 memset(dsmbuf,255,16*64*sizeof(DSMNOTE));
|
|
134 _mm_read_UBYTE(modfp);
|
|
135 _mm_read_UBYTE(modfp);
|
|
136
|
|
137 while(row<64)
|
|
138 { flag = _mm_read_UBYTE(modfp);
|
|
139 if(feof(modfp))
|
|
140 { _mm_errno = MMERR_LOADING_PATTERN;
|
|
141 return 0;
|
|
142 }
|
|
143
|
|
144 if(flag)
|
|
145 { n = &dsmbuf[((flag&0xf)*64)+row];
|
|
146 if(flag&0x80) n->note = _mm_read_UBYTE(modfp);
|
|
147 if(flag&0x40) n->ins = _mm_read_UBYTE(modfp);
|
|
148 if(flag&0x20) n->vol = _mm_read_UBYTE(modfp);
|
|
149 if(flag&0x10)
|
|
150 { n->cmd = _mm_read_UBYTE(modfp);
|
|
151 n->inf = _mm_read_UBYTE(modfp);
|
|
152 }
|
|
153 } else row++;
|
|
154 }
|
|
155 return 1;
|
|
156 }
|
|
157
|
|
158
|
|
159 UBYTE *DSM_ConvertTrack(DSMNOTE *tr)
|
|
160 {
|
|
161 int t;
|
|
162 UBYTE note,ins,vol,cmd,inf;
|
|
163
|
|
164 UniReset();
|
|
165 for(t=0; t<64; t++)
|
|
166 { note = tr[t].note;
|
|
167 ins = tr[t].ins;
|
|
168 vol = tr[t].vol;
|
|
169 cmd = tr[t].cmd;
|
|
170 inf = tr[t].inf;
|
|
171
|
|
172 if(ins!=0 && ins!=255) UniInstrument(ins-1);
|
|
173 if(note!=255) UniNote(note-1); // <- normal note
|
|
174 if(vol<65) UniPTEffect(0xc,vol);
|
|
175
|
|
176 if(cmd!=255)
|
|
177 { if(cmd==0x8)
|
|
178 { if(inf<=0x80)
|
|
179 { inf = (inf<0x80) ? inf<<1 : 255;
|
|
180 UniPTEffect(cmd,inf);
|
|
181 }
|
|
182 } else if(cmd==0xb)
|
|
183 { if(inf<=0x7f) UniPTEffect(cmd,inf);
|
|
184 } else
|
|
185 { // Convert pattern jump from Dec to Hex
|
|
186 if(cmd == 0xd)
|
|
187 inf = (((inf&0xf0)>>4)*10)+(inf&0xf);
|
|
188 UniPTEffect(cmd,inf);
|
|
189 }
|
|
190 }
|
|
191 UniNewline();
|
|
192 }
|
|
193 return UniDup();
|
|
194 }
|
|
195
|
|
196
|
|
197 BOOL DSM_Load(void)
|
|
198 {
|
|
199 int t;
|
|
200 DSMINST s;
|
|
201 SAMPLE *q;
|
|
202 int cursmp = 0, curpat = 0, track = 0;
|
|
203
|
|
204 blocklp = 0;
|
|
205 blockln = 12;
|
|
206
|
|
207 if(!GetBlockHeader()) return 0;
|
|
208 if(memcmp(blockid,SONGID,4))
|
|
209 { _mm_errno = MMERR_LOADING_HEADER;
|
|
210 return 0;
|
|
211 }
|
|
212
|
|
213 _mm_read_UBYTES(mh->songname,28,modfp);
|
|
214 mh->reserved1 = _mm_read_I_UWORD(modfp);
|
|
215 mh->flags = _mm_read_I_UWORD(modfp);
|
|
216 mh->reserved2 = _mm_read_I_ULONG(modfp);
|
|
217 mh->numord = _mm_read_I_UWORD(modfp);
|
|
218 mh->numsmp = _mm_read_I_UWORD(modfp);
|
|
219 mh->numpat = _mm_read_I_UWORD(modfp);
|
|
220 mh->numtrk = _mm_read_I_UWORD(modfp);
|
|
221 mh->globalvol = _mm_read_UBYTE(modfp);
|
|
222 mh->mastervol = _mm_read_UBYTE(modfp);
|
|
223 mh->speed = _mm_read_UBYTE(modfp);
|
|
224 mh->bpm = _mm_read_UBYTE(modfp);
|
|
225 _mm_read_UBYTES(mh->panpos,16,modfp);
|
|
226 _mm_read_UBYTES(mh->orders,128,modfp);
|
|
227
|
|
228 // set module variables
|
|
229 of.initspeed = mh->speed;
|
|
230 of.inittempo = mh->bpm;
|
|
231 of.modtype = strdup(DSM_Version);
|
|
232 of.numchn = mh->numtrk;
|
|
233 of.numpat = mh->numpat;
|
|
234 of.numtrk = of.numchn*of.numpat;
|
|
235 of.songname = DupStr(mh->songname,28); // make a cstr of songname
|
|
236
|
|
237 for(t=0; t<16; t++)
|
|
238 of.panning[t] = mh->panpos[t]<0x80 ? (mh->panpos[t]<<1) : 255;
|
|
239
|
|
240 if(!AllocPositions(mh->numord)) return 0;
|
|
241 of.numpos = 0;
|
|
242 for(t=0; t<mh->numord; t++)
|
|
243 { of.positions[of.numpos] = mh->orders[t];
|
|
244 if(mh->orders[t]<254) of.numpos++;
|
|
245 }
|
|
246
|
|
247 of.numins = of.numsmp = mh->numsmp;
|
|
248
|
|
249 if(!AllocSamples()) return 0;
|
|
250 if(!AllocTracks()) return 0;
|
|
251 if(!AllocPatterns()) return 0;
|
|
252
|
|
253 while(cursmp<of.numins || curpat<of.numpat)
|
|
254 { if(!GetBlockHeader()) return 0;
|
|
255 if(!memcmp(blockid,INSTID,4) && cursmp<of.numins)
|
|
256 { q = &of.samples[cursmp];
|
|
257
|
|
258 // try to read sample info
|
|
259 _mm_read_UBYTES(s.filename,13,modfp);
|
|
260 s.flags = _mm_read_I_UWORD(modfp);
|
|
261 s.volume = _mm_read_UBYTE(modfp);
|
|
262 s.length = _mm_read_I_ULONG(modfp);
|
|
263 s.loopstart = _mm_read_I_ULONG(modfp);
|
|
264 s.loopend = _mm_read_I_ULONG(modfp);
|
|
265 s.reserved1 = _mm_read_I_ULONG(modfp);
|
|
266 s.c2spd = _mm_read_I_UWORD(modfp);
|
|
267 s.reserved2 = _mm_read_I_UWORD(modfp);
|
|
268 _mm_read_UBYTES(s.samplename,28,modfp);
|
|
269
|
|
270 q->samplename= DupStr(s.samplename,28);
|
|
271 q->seekpos = _mm_ftell(modfp);
|
|
272 q->speed = s.c2spd;
|
|
273 q->length = s.length;
|
|
274 q->loopstart = s.loopstart;
|
|
275 q->loopend = s.loopend;
|
|
276 q->volume = s.volume;
|
|
277
|
|
278 if(s.flags&1) q->flags|=SF_LOOP;
|
|
279 if(s.flags&2) q->flags|=SF_SIGNED;
|
|
280 cursmp++;
|
|
281 } else if(!memcmp(blockid,PATTID,4) && curpat<of.numpat)
|
|
282 { DSM_ReadPattern();
|
|
283 for(t=0; t<of.numchn; t++)
|
|
284 if(!(of.tracks[track++] = DSM_ConvertTrack(&dsmbuf[t*64]))) return 0;
|
|
285 curpat++;
|
|
286 }
|
|
287 }
|
|
288
|
|
289 return 1;
|
|
290 }
|
|
291
|
|
292
|
|
293 CHAR *DSM_LoadTitle(void)
|
|
294 {
|
|
295 CHAR s[28];
|
|
296
|
|
297 _mm_fseek(modfp,12,SEEK_SET);
|
|
298 if(!fread(s,28,1,modfp)) return NULL;
|
|
299
|
|
300 return(DupStr(s,28));
|
|
301 }
|
|
302
|
|
303
|
|
304 MLOADER load_dsm =
|
|
305 { NULL,
|
|
306 "DSM",
|
|
307 "Portable DSM loader v0.1",
|
|
308 DSM_Init,
|
|
309 DSM_Test,
|
|
310 DSM_Load,
|
|
311 DSM_Cleanup,
|
|
312 DSM_LoadTitle
|
|
313 };
|
|
314
|