diff options
Diffstat (limited to 'apps/plugins/mikmod/load_dsm.c')
-rw-r--r-- | apps/plugins/mikmod/load_dsm.c | 364 |
1 files changed, 364 insertions, 0 deletions
diff --git a/apps/plugins/mikmod/load_dsm.c b/apps/plugins/mikmod/load_dsm.c new file mode 100644 index 0000000000..09d6d3e297 --- /dev/null +++ b/apps/plugins/mikmod/load_dsm.c | |||
@@ -0,0 +1,364 @@ | |||
1 | /* MikMod sound library | ||
2 | (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file | ||
3 | AUTHORS for complete list. | ||
4 | |||
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. | ||
9 | |||
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. | ||
14 | |||
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 | ||
18 | 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | /*============================================================================== | ||
22 | |||
23 | $Id: load_dsm.c,v 1.3 2005/04/07 19:57:38 realtech Exp $ | ||
24 | |||
25 | DSIK internal format (DSM) module loader | ||
26 | |||
27 | ==============================================================================*/ | ||
28 | |||
29 | #ifdef HAVE_CONFIG_H | ||
30 | #include "config.h" | ||
31 | #endif | ||
32 | |||
33 | #ifdef HAVE_UNISTD_H | ||
34 | #include <unistd.h> | ||
35 | #endif | ||
36 | |||
37 | #include <stdio.h> | ||
38 | #ifdef HAVE_MEMORY_H | ||
39 | #include <memory.h> | ||
40 | #endif | ||
41 | #include <string.h> | ||
42 | |||
43 | #include "mikmod_internals.h" | ||
44 | |||
45 | #ifdef SUNOS | ||
46 | extern int fprintf(FILE *, const char *, ...); | ||
47 | #endif | ||
48 | |||
49 | /*========== Module structure */ | ||
50 | |||
51 | #define DSM_MAXCHAN (16) | ||
52 | #define DSM_MAXORDERS (128) | ||
53 | |||
54 | typedef struct DSMSONG { | ||
55 | CHAR songname[28]; | ||
56 | UWORD version; | ||
57 | UWORD flags; | ||
58 | ULONG reserved2; | ||
59 | UWORD numord; | ||
60 | UWORD numsmp; | ||
61 | UWORD numpat; | ||
62 | UWORD numtrk; | ||
63 | UBYTE globalvol; | ||
64 | UBYTE mastervol; | ||
65 | UBYTE speed; | ||
66 | UBYTE bpm; | ||
67 | UBYTE panpos[DSM_MAXCHAN]; | ||
68 | UBYTE orders[DSM_MAXORDERS]; | ||
69 | } DSMSONG; | ||
70 | |||
71 | typedef struct DSMINST { | ||
72 | CHAR filename[13]; | ||
73 | UWORD flags; | ||
74 | UBYTE volume; | ||
75 | ULONG length; | ||
76 | ULONG loopstart; | ||
77 | ULONG loopend; | ||
78 | ULONG reserved1; | ||
79 | UWORD c2spd; | ||
80 | UWORD period; | ||
81 | CHAR samplename[28]; | ||
82 | } DSMINST; | ||
83 | |||
84 | typedef struct DSMNOTE { | ||
85 | UBYTE note,ins,vol,cmd,inf; | ||
86 | } DSMNOTE; | ||
87 | |||
88 | #define DSM_SURROUND (0xa4) | ||
89 | |||
90 | /*========== Loader variables */ | ||
91 | |||
92 | static CHAR* SONGID="SONG"; | ||
93 | static CHAR* INSTID="INST"; | ||
94 | static CHAR* PATTID="PATT"; | ||
95 | |||
96 | static UBYTE blockid[4]; | ||
97 | static ULONG blockln; | ||
98 | static ULONG blocklp; | ||
99 | static DSMSONG* mh=NULL; | ||
100 | static DSMNOTE* dsmbuf=NULL; | ||
101 | |||
102 | static CHAR DSM_Version[]="DSIK DSM-format"; | ||
103 | |||
104 | static unsigned char DSMSIG[4+4]={'R','I','F','F','D','S','M','F'}; | ||
105 | |||
106 | /*========== Loader code */ | ||
107 | |||
108 | int DSM_Test(void) | ||
109 | { | ||
110 | UBYTE id[12]; | ||
111 | |||
112 | if(!_mm_read_UBYTES(id,12,modreader)) return 0; | ||
113 | if(!memcmp(id,DSMSIG,4) && !memcmp(id+8,DSMSIG+4,4)) return 1; | ||
114 | |||
115 | return 0; | ||
116 | } | ||
117 | |||
118 | int DSM_Init(void) | ||
119 | { | ||
120 | if(!(dsmbuf=(DSMNOTE *)MikMod_malloc(DSM_MAXCHAN*64*sizeof(DSMNOTE)))) return 0; | ||
121 | if(!(mh=(DSMSONG *)MikMod_calloc(1,sizeof(DSMSONG)))) return 0; | ||
122 | return 1; | ||
123 | } | ||
124 | |||
125 | void DSM_Cleanup(void) | ||
126 | { | ||
127 | MikMod_free(dsmbuf); | ||
128 | MikMod_free(mh); | ||
129 | } | ||
130 | |||
131 | static int GetBlockHeader(void) | ||
132 | { | ||
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); | ||
136 | |||
137 | while(1) { | ||
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; | ||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | if(memcmp(blockid,SONGID,4) && memcmp(blockid,INSTID,4) && | ||
146 | memcmp(blockid,PATTID,4)) { | ||
147 | #ifdef MIKMOD_DEBUG | ||
148 | fprintf(stderr,"\rDSM: Skipping unknown block type %4.4s\n",blockid); | ||
149 | #endif | ||
150 | _mm_fseek(modreader, blockln, SEEK_CUR); | ||
151 | } else | ||
152 | break; | ||
153 | } | ||
154 | |||
155 | blocklp = _mm_ftell(modreader); | ||
156 | |||
157 | return 1; | ||
158 | } | ||
159 | |||
160 | static int DSM_ReadPattern(void) | ||
161 | { | ||
162 | int flag,row=0; | ||
163 | SWORD length; | ||
164 | DSMNOTE *n; | ||
165 | |||
166 | /* clear pattern data */ | ||
167 | memset(dsmbuf,255,DSM_MAXCHAN*64*sizeof(DSMNOTE)); | ||
168 | length=_mm_read_I_SWORD(modreader); | ||
169 | |||
170 | while(row<64) { | ||
171 | flag=_mm_read_UBYTE(modreader); | ||
172 | if((_mm_eof(modreader))||(--length<0)) { | ||
173 | _mm_errno = MMERR_LOADING_PATTERN; | ||
174 | return 0; | ||
175 | } | ||
176 | |||
177 | if(flag) { | ||
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); | ||
182 | if(flag&0x10) { | ||
183 | n->cmd=_mm_read_UBYTE(modreader); | ||
184 | n->inf=_mm_read_UBYTE(modreader); | ||
185 | } | ||
186 | } else | ||
187 | row++; | ||
188 | } | ||
189 | |||
190 | return 1; | ||
191 | } | ||
192 | |||
193 | static UBYTE *DSM_ConvertTrack(DSMNOTE *tr) | ||
194 | { | ||
195 | int t; | ||
196 | UBYTE note,ins,vol,cmd,inf; | ||
197 | |||
198 | UniReset(); | ||
199 | for(t=0;t<64;t++) { | ||
200 | note=tr[t].note; | ||
201 | ins=tr[t].ins; | ||
202 | vol=tr[t].vol; | ||
203 | cmd=tr[t].cmd; | ||
204 | inf=tr[t].inf; | ||
205 | |||
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); | ||
209 | |||
210 | if(cmd!=255) { | ||
211 | if(cmd==0x8) { | ||
212 | if(inf==DSM_SURROUND) | ||
213 | UniEffect(UNI_ITEFFECTS0,0x91); | ||
214 | else | ||
215 | if(inf<=0x80) { | ||
216 | inf=(inf<0x80)?inf<<1:255; | ||
217 | UniPTEffect(cmd,inf); | ||
218 | } | ||
219 | } else | ||
220 | if(cmd==0xb) { | ||
221 | if(inf<=0x7f) UniPTEffect(cmd,inf); | ||
222 | } else { | ||
223 | /* Convert pattern jump from Dec to Hex */ | ||
224 | if(cmd == 0xd) | ||
225 | inf = (((inf&0xf0)>>4)*10)+(inf&0xf); | ||
226 | UniPTEffect(cmd,inf); | ||
227 | } | ||
228 | } | ||
229 | UniNewline(); | ||
230 | } | ||
231 | return UniDup(); | ||
232 | } | ||
233 | |||
234 | int DSM_Load(int curious) | ||
235 | { | ||
236 | int t; | ||
237 | DSMINST s; | ||
238 | SAMPLE *q; | ||
239 | int cursmp=0,curpat=0,track=0; | ||
240 | |||
241 | blocklp=0; | ||
242 | blockln=12; | ||
243 | |||
244 | if(!GetBlockHeader()) return 0; | ||
245 | if(memcmp(blockid,SONGID,4)) { | ||
246 | _mm_errno = MMERR_LOADING_HEADER; | ||
247 | return 0; | ||
248 | } | ||
249 | |||
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); | ||
264 | |||
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 */ | ||
273 | of.reppos=0; | ||
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... */ | ||
277 | of.bpmlimit = 32; | ||
278 | |||
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; | ||
282 | |||
283 | if(!AllocPositions(mh->numord)) return 0; | ||
284 | of.numpos=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++; | ||
290 | } | ||
291 | |||
292 | of.numins=of.numsmp=mh->numsmp; | ||
293 | |||
294 | if(!AllocSamples()) return 0; | ||
295 | if(!AllocTracks()) return 0; | ||
296 | if(!AllocPatterns()) return 0; | ||
297 | |||
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]; | ||
302 | |||
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); | ||
314 | |||
315 | q->samplename=DupStr(s.samplename,28,1); | ||
316 | q->seekpos=_mm_ftell(modreader); | ||
317 | q->speed=s.c2spd; | ||
318 | q->length=s.length; | ||
319 | q->loopstart=s.loopstart; | ||
320 | q->loopend=s.loopend; | ||
321 | q->volume=s.volume; | ||
322 | |||
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 ?*/ | ||
327 | cursmp++; | ||
328 | } else | ||
329 | if(!memcmp(blockid,PATTID,4) && curpat<of.numpat) { | ||
330 | DSM_ReadPattern(); | ||
331 | for(t=0;t<of.numchn;t++) | ||
332 | if(!(of.tracks[track++]=DSM_ConvertTrack(&dsmbuf[t*64]))) return 0; | ||
333 | curpat++; | ||
334 | } | ||
335 | } | ||
336 | |||
337 | return 1; | ||
338 | } | ||
339 | |||
340 | CHAR *DSM_LoadTitle(void) | ||
341 | { | ||
342 | CHAR s[28]; | ||
343 | |||
344 | _mm_fseek(modreader,12,SEEK_SET); | ||
345 | if(!_mm_read_UBYTES(s,28,modreader)) return NULL; | ||
346 | |||
347 | return(DupStr(s,28,1)); | ||
348 | } | ||
349 | |||
350 | /*========== Loader information */ | ||
351 | |||
352 | MIKMODAPI MLOADER load_dsm={ | ||
353 | NULL, | ||
354 | "DSM", | ||
355 | "DSM (DSIK internal format)", | ||
356 | DSM_Init, | ||
357 | DSM_Test, | ||
358 | DSM_Load, | ||
359 | DSM_Cleanup, | ||
360 | DSM_LoadTitle | ||
361 | }; | ||
362 | |||
363 | |||
364 | /* ex:set ts=4: */ | ||