All kernel objects in code shared amongs targets (core, plugins, codecs) should be...
[kugel-rb.git] / apps / plugins / mikmod / load_dsm.c
blob09d6d3e297ac08b0f483fba12e9780af7e261d7f
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
18 02111-1307, USA.
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 ==============================================================================*/
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
33 #ifdef HAVE_UNISTD_H
34 #include <unistd.h>
35 #endif
37 #include <stdio.h>
38 #ifdef HAVE_MEMORY_H
39 #include <memory.h>
40 #endif
41 #include <string.h>
43 #include "mikmod_internals.h"
45 #ifdef SUNOS
46 extern int fprintf(FILE *, const char *, ...);
47 #endif
49 /*========== Module structure */
51 #define DSM_MAXCHAN (16)
52 #define DSM_MAXORDERS (128)
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;
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;
84 typedef struct DSMNOTE {
85 UBYTE note,ins,vol,cmd,inf;
86 } DSMNOTE;
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];
97 static ULONG blockln;
98 static ULONG blocklp;
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 */
108 int DSM_Test(void)
110 UBYTE id[12];
112 if(!_mm_read_UBYTES(id,12,modreader)) return 0;
113 if(!memcmp(id,DSMSIG,4) && !memcmp(id+8,DSMSIG+4,4)) return 1;
115 return 0;
118 int DSM_Init(void)
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;
125 void DSM_Cleanup(void)
127 MikMod_free(dsmbuf);
128 MikMod_free(mh);
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);
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;
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;
155 blocklp = _mm_ftell(modreader);
157 return 1;
160 static int DSM_ReadPattern(void)
162 int flag,row=0;
163 SWORD length;
164 DSMNOTE *n;
166 /* clear pattern data */
167 memset(dsmbuf,255,DSM_MAXCHAN*64*sizeof(DSMNOTE));
168 length=_mm_read_I_SWORD(modreader);
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;
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);
186 } else
187 row++;
190 return 1;
193 static UBYTE *DSM_ConvertTrack(DSMNOTE *tr)
195 int t;
196 UBYTE note,ins,vol,cmd,inf;
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;
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);
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);
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);
229 UniNewline();
231 return UniDup();
234 int DSM_Load(int curious)
236 int t;
237 DSMINST s;
238 SAMPLE *q;
239 int cursmp=0,curpat=0,track=0;
241 blocklp=0;
242 blockln=12;
244 if(!GetBlockHeader()) return 0;
245 if(memcmp(blockid,SONGID,4)) {
246 _mm_errno = MMERR_LOADING_HEADER;
247 return 0;
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 */
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;
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;
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++;
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);
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;
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++;
337 return 1;
340 CHAR *DSM_LoadTitle(void)
342 CHAR s[28];
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={
353 NULL,
354 "DSM",
355 "DSM (DSIK internal format)",
356 DSM_Init,
357 DSM_Test,
358 DSM_Load,
359 DSM_Cleanup,
360 DSM_LoadTitle
364 /* ex:set ts=4: */