summaryrefslogtreecommitdiff
path: root/apps/plugins/mikmod/load_dsm.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/mikmod/load_dsm.c')
-rw-r--r--apps/plugins/mikmod/load_dsm.c364
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
46extern int fprintf(FILE *, const char *, ...);
47#endif
48
49/*========== Module structure */
50
51#define DSM_MAXCHAN (16)
52#define DSM_MAXORDERS (128)
53
54typedef 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
71typedef 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
84typedef struct DSMNOTE {
85 UBYTE note,ins,vol,cmd,inf;
86} DSMNOTE;
87
88#define DSM_SURROUND (0xa4)
89
90/*========== Loader variables */
91
92static CHAR* SONGID="SONG";
93static CHAR* INSTID="INST";
94static CHAR* PATTID="PATT";
95
96static UBYTE blockid[4];
97static ULONG blockln;
98static ULONG blocklp;
99static DSMSONG* mh=NULL;
100static DSMNOTE* dsmbuf=NULL;
101
102static CHAR DSM_Version[]="DSIK DSM-format";
103
104static unsigned char DSMSIG[4+4]={'R','I','F','F','D','S','M','F'};
105
106/*========== Loader code */
107
108int 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
118int 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
125void DSM_Cleanup(void)
126{
127 MikMod_free(dsmbuf);
128 MikMod_free(mh);
129}
130
131static 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
160static 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
193static 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
234int 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
340CHAR *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
352MIKMODAPI 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: */