added an old version of mikmod for dos
[dosdemo] / libs / oldmik / src / load_mod.c
1 /*
2
3 Name:
4 LOAD_MOD.C
5
6 Description:
7 Generic MOD loader
8
9 Portability:
10 All systems - all compilers (hopefully)
11
12 */
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <ctype.h>
17 #include "mikmod.h"
18
19 /*************************************************************************
20 *************************************************************************/
21
22
23 typedef struct MSAMPINFO{       /* sample header as it appears in a module */
24         char  samplename[22];
25         UWORD length;
26         UBYTE finetune;
27         UBYTE volume;
28         UWORD reppos;
29         UWORD replen;
30 } MSAMPINFO;
31
32
33 typedef struct MODULEHEADER{    /* verbatim module header */
34         char       songname[20];                /* the songname.. */
35         MSAMPINFO  samples[31];                         /* all sampleinfo */
36         UBYTE      songlength;                          /* number of patterns used */
37         UBYTE      magic1;                                      /* should be 127 */
38         UBYTE      positions[128];                      /* which pattern to play at pos */
39         UBYTE      magic2[4];                           /* string "M.K." or "FLT4" or "FLT8" */
40 } MODULEHEADER;
41
42 #define MODULEHEADERSIZE 1084
43
44
45 typedef struct MODTYPE{                         /* struct to identify type of module */
46         char    id[5];
47         UBYTE   channels;
48         char    *name;
49 } MODTYPE;
50
51
52 typedef struct MODNOTE{
53         UBYTE a,b,c,d;
54 } MODNOTE;
55
56
57 /*************************************************************************
58 *************************************************************************/
59
60
61 char protracker[]="Protracker";
62 char startracker[]="Startracker";
63 char fasttracker[]="Fasttracker";
64 char ins15tracker[]="15-instrument";
65 char oktalyzer[]="Oktalyzer";
66 char taketracker[]="TakeTracker";
67
68
69 MODTYPE modtypes[]={
70         "M.K.",4,protracker,    /* protracker 4 channel */
71         "M!K!",4,protracker,    /* protracker 4 channel */
72         "FLT4",4,startracker,   /* startracker 4 channel */
73         "4CHN",4,fasttracker,   /* fasttracker 4 channel */
74         "6CHN",6,fasttracker,   /* fasttracker 6 channel */
75         "8CHN",8,fasttracker,   /* fasttracker 8 channel */
76         "CD81",8,oktalyzer,     /* atari oktalyzer 8 channel */
77         "OKTA",8,oktalyzer,     /* atari oktalyzer 8 channel */
78         "16CN",16,taketracker,  /* taketracker 16 channel */
79         "32CN",32,taketracker,  /* taketracker 32 channel */
80         "    ",4,ins15tracker   /* 15-instrument 4 channel */
81 };
82
83 static MODULEHEADER *mh;        /* raw as-is module header */
84 static MODNOTE *patbuf;
85
86
87 BOOL MOD_Test(void)
88 {
89         int t;
90
91         char id[4];
92
93         _mm_fseek(modfp,MODULEHEADERSIZE-4,SEEK_SET);
94         if(!fread(id,4,1,modfp)) return 0;
95
96         /* find out which ID string */
97
98         for(t=0;t<10;t++){
99                 if(!memcmp(id,modtypes[t].id,4)) return 1;
100         }
101
102         return 0;
103 }
104
105
106 BOOL MOD_Init(void)
107 {
108         patbuf=NULL;
109         if(!(mh=(MODULEHEADER *)MyCalloc(1,sizeof(MODULEHEADER)))) return 0;
110         return 1;
111 }
112
113
114 void MOD_Cleanup(void)
115 {
116         if(mh!=NULL) free(mh);
117         if(patbuf!=NULL) free(patbuf);
118 }
119
120
121 /*
122
123 Old (amiga) noteinfo:
124
125  _____byte 1_____   byte2_    _____byte 3_____   byte4_
126 /                \ /      \  /                \ /      \
127 0000          0000-00000000  0000          0000-00000000
128
129 Upper four    12 bits for    Lower four    Effect command.
130 bits of sam-  note period.   bits of sam-
131 ple number.                  ple number.
132
133
134 */
135
136
137 UWORD npertab[60]={
138
139 /* -> Tuning 0 */
140
141         1712,1616,1524,1440,1356,1280,1208,1140,1076,1016,960,906,
142         856,808,762,720,678,640,604,570,538,508,480,453,
143         428,404,381,360,339,320,302,285,269,254,240,226,
144         214,202,190,180,170,160,151,143,135,127,120,113,
145         107,101,95,90,85,80,75,71,67,63,60,56
146 };
147
148
149 void ConvertNote(MODNOTE *n)
150 {
151         UBYTE instrument,effect,effdat,note;
152         UWORD period;
153
154         /* extract the various information from the 4 bytes that
155            make up a single note */
156
157         instrument=(n->a&0x10)|(n->c>>4);
158         period=(((UWORD)n->a&0xf)<<8)+n->b;
159         effect=n->c&0xf;
160         effdat=n->d;
161
162         /* Convert the period to a note number */
163
164         note=0;
165         if(period!=0){
166                 for(note=0;note<60;note++){
167                         if(period>=npertab[note]) break;
168                 }
169                 note++;
170                 if(note==61) note=0;
171         }
172
173         if(instrument!=0){
174                 UniInstrument(instrument-1);
175         }
176
177         if(note!=0){
178                 UniNote(note+23);
179         }
180
181         UniPTEffect(effect,effdat);
182 }
183
184
185 UBYTE *ConvertTrack(MODNOTE *n)
186 {
187         int t;
188
189         UniReset();
190         for(t=0;t<64;t++){
191                 ConvertNote(n);
192                 UniNewline();
193                 n+=of.numchn;
194         }
195         return UniDup();
196 }
197
198
199 BOOL ML_LoadPatterns(void)
200 /*
201         Loads all patterns of a modfile and converts them into the
202         3 byte format.
203 */
204 {
205         int t,s,tracks=0;
206
207         if(!AllocPatterns()) return 0;
208         if(!AllocTracks()) return 0;
209
210         /* Allocate temporary buffer for loading
211            and converting the patterns */
212
213         if(!(patbuf=(MODNOTE *)MyCalloc(64U*of.numchn,sizeof(MODNOTE)))) return 0;
214
215         for(t=0;t<of.numpat;t++){
216
217                 /* Load the pattern into the temp buffer
218                    and convert it */
219
220                 for(s=0;s<(64U*of.numchn);s++){
221                         patbuf[s].a=_mm_read_UBYTE(modfp);
222                         patbuf[s].b=_mm_read_UBYTE(modfp);
223                         patbuf[s].c=_mm_read_UBYTE(modfp);
224                         patbuf[s].d=_mm_read_UBYTE(modfp);
225                 }
226
227                 for(s=0;s<of.numchn;s++){
228                         if(!(of.tracks[tracks++]=ConvertTrack(patbuf+s))) return 0;
229                 }
230         }
231
232         return 1;
233 }
234
235
236 BOOL MOD_Load(void)
237 {
238         int t,modtype;
239         INSTRUMENT *d;          /* new sampleinfo structure */
240         SAMPLE *q;
241         MSAMPINFO *s;           /* old module sampleinfo */
242
243         /* try to read module header */
244
245         _mm_read_str((char *)mh->songname,20,modfp);
246
247         for(t=0;t<31;t++){
248                 s=&mh->samples[t];
249                 _mm_read_str(s->samplename,22,modfp);
250                 s->length       =_mm_read_M_UWORD(modfp);
251                 s->finetune     =_mm_read_UBYTE(modfp);
252                 s->volume       =_mm_read_UBYTE(modfp);
253                 s->reppos       =_mm_read_M_UWORD(modfp);
254                 s->replen       =_mm_read_M_UWORD(modfp);
255         }
256
257         mh->songlength  =_mm_read_UBYTE(modfp);
258         mh->magic1              =_mm_read_UBYTE(modfp);
259
260         _mm_read_UBYTES(mh->positions,128,modfp);
261         _mm_read_UBYTES(mh->magic2,4,modfp);
262
263         if(feof(modfp)){
264                 myerr=ERROR_LOADING_HEADER;
265                 return 0;
266         }
267
268         /* find out which ID string */
269
270         for(modtype=0;modtype<10;modtype++){
271                 if(!memcmp(mh->magic2,modtypes[modtype].id,4)) break;
272         }
273
274         if(modtype==10){
275
276                 /* unknown modtype */
277                 myerr=ERROR_NOT_A_MODULE;
278                 return 0;
279         }
280
281         /* set module variables */
282
283         of.initspeed=6;
284         of.inittempo=125;
285         of.numchn=modtypes[modtype].channels;      /* get number of channels */
286         of.modtype=strdup(modtypes[modtype].name);      /* get ascii type of mod */
287         of.songname=DupStr(mh->songname,20);            /* make a cstr of songname */
288         of.numpos=mh->songlength;               /* copy the songlength */
289         memcpy(of.positions,mh->positions,128);         /* copy the position array */
290
291         /* Count the number of patterns */
292
293         of.numpat=0;
294
295         for(t=0;t<128;t++){             /* <-- BUGFIX... have to check ALL positions */
296                 if(of.positions[t] > of.numpat){
297                         of.numpat=of.positions[t];
298                 }
299         }
300         of.numpat++;
301         of.numtrk=of.numpat*of.numchn;
302
303         /* Finally, init the sampleinfo structures */
304
305         of.numins=31;
306
307         if(!AllocInstruments()) return 0;
308
309         s=mh->samples;   /* init source pointer */
310         d=of.instruments;  /* init dest pointer */
311
312         for(t=0;t<of.numins;t++){
313
314                 d->numsmp=1;
315                 if(!AllocSamples(d)) return 0;
316
317                 q=d->samples;
318
319                 /* convert the samplename */
320
321                 d->insname=DupStr(s->samplename,22);
322
323                 /* init the sampleinfo variables and
324                    convert the size pointers to longword format */
325
326                 q->c2spd=finetune[s->finetune&0xf];
327                 q->volume=s->volume;
328                 q->loopstart=(ULONG)s->reppos<<1;
329                 q->loopend=q->loopstart+((ULONG)s->replen<<1);
330                 q->length=(ULONG)s->length<<1;
331                 q->seekpos=0;
332
333                 q->flags=SF_SIGNED;
334                 if(s->replen>1) q->flags|=SF_LOOP;
335
336                 /* fix replen if repend>length */
337
338                 if(q->loopend>q->length) q->loopend=q->length;
339
340                 s++;    /* point to next source sampleinfo */
341                 d++;    /* point to next destiny sampleinfo */
342         }
343
344         if(!ML_LoadPatterns()) return 0;
345         return 1;
346 }
347
348
349
350 LOADER load_mod={
351         NULL,
352         "Standard module",
353         "Portable MOD loader v0.11",
354         MOD_Init,
355         MOD_Test,
356         MOD_Load,
357         MOD_Cleanup
358 };