1 /* MikMod sound library
\r
2 (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file
\r
3 AUTHORS for complete list.
\r
5 This library is free software; you can redistribute it and/or modify
\r
6 it under the terms of the GNU Library General Public License as
\r
7 published by the Free Software Foundation; either version 2 of
\r
8 the License, or (at your option) any later version.
\r
10 This program is distributed in the hope that it will be useful,
\r
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
13 GNU Library General Public License for more details.
\r
15 You should have received a copy of the GNU Library General Public
\r
16 License along with this library; if not, write to the Free Software
\r
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
\r
21 /*==============================================================================
\r
23 $Id: load_m15.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $
\r
25 15 instrument MOD loader
\r
26 Also supports Ultimate Sound Tracker (old M15 format)
\r
28 ==============================================================================*/
\r
30 #ifdef HAVE_CONFIG_H
\r
34 #ifdef HAVE_UNISTD_H
\r
38 //#include <ctype.h>
\r
40 #ifdef HAVE_MEMORY_H
\r
45 #include "mikmod_internals.h"
\r
48 extern int fprintf(FILE *, const char *, ...);
\r
51 /*========== Module Structure */
\r
53 typedef struct MSAMPINFO {
\r
54 CHAR samplename[23]; /* 22 in module, 23 in memory */
\r
62 typedef struct MODULEHEADER {
\r
63 CHAR songname[21]; /* the songname.., 20 in module, 21 in memory */
\r
64 MSAMPINFO samples[15]; /* all sampleinfo */
\r
65 UBYTE songlength; /* number of patterns used */
\r
66 UBYTE magic1; /* should be 127 */
\r
67 UBYTE positions[128]; /* which pattern to play at pos */
\r
70 typedef struct MODNOTE {
\r
74 /*========== Loader variables */
\r
76 static MODULEHEADER *mh = NULL;
\r
77 static MODNOTE *patbuf = NULL;
\r
78 static BOOL ust_loader = 0; /* if TRUE, load as an ust module. */
\r
80 /* known file formats which can confuse the loader */
\r
82 static char *signatures[REJECT]={
\r
83 "CAKEWALK", /* cakewalk midi files */
\r
84 "SZDD" /* Microsoft compressed files */
\r
86 static int siglen[REJECT]={8,4};
\r
88 /*========== Loader code */
\r
90 static BOOL LoadModuleHeader(MODULEHEADER *mh)
\r
94 _mm_read_string(mh->songname,20,modreader);
\r
95 mh->songname[20]=0; /* just in case */
\r
97 /* sanity check : title should contain printable characters and a bunch
\r
100 if((mh->songname[t])&&(mh->songname[t]<32)) return 0;
\r
101 for(t=0;(mh->songname[t])&&(t<20);t++);
\r
102 if(t<20) for(;t<20;t++) if(mh->songname[t]) return 0;
\r
104 for(t=0;t<15;t++) {
\r
105 MSAMPINFO *s=&mh->samples[t];
\r
107 _mm_read_string(s->samplename,22,modreader);
\r
108 s->samplename[22]=0; /* just in case */
\r
109 s->length =_mm_read_M_UWORD(modreader);
\r
110 s->finetune =_mm_read_UBYTE(modreader);
\r
111 s->volume =_mm_read_UBYTE(modreader);
\r
112 s->reppos =_mm_read_M_UWORD(modreader);
\r
113 s->replen =_mm_read_M_UWORD(modreader);
\r
115 /* sanity check : sample title should contain printable characters and
\r
116 a bunch of null chars */
\r
118 if((s->samplename[u])&&(s->samplename[u]</*32*/14)) return 0;
\r
119 for(u=0;(s->samplename[u])&&(u<20);u++);
\r
120 if(u<20) for(;u<20;u++) if(s->samplename[u]) return 0;
\r
122 /* sanity check : finetune values */
\r
123 if(s->finetune>>4) return 0;
\r
126 mh->songlength =_mm_read_UBYTE(modreader);
\r
127 mh->magic1 =_mm_read_UBYTE(modreader); /* should be 127 */
\r
129 /* sanity check : no more than 128 positions, restart position in range */
\r
130 if((!mh->songlength)||(mh->songlength>128)) return 0;
\r
131 /* values encountered so far are 0x6a and 0x78 */
\r
132 if(((mh->magic1&0xf8)!=0x78)&&(mh->magic1!=0x6a)&&(mh->magic1>mh->songlength)) return 0;
\r
134 _mm_read_UBYTES(mh->positions,128,modreader);
\r
136 /* sanity check : pattern range is 0..63 */
\r
138 if(mh->positions[t]>63) return 0;
\r
140 return(!_mm_eof(modreader));
\r
143 /* Checks the patterns in the modfile for UST / 15-inst indications.
\r
144 For example, if an effect 3xx is found, it is assumed that the song
\r
145 is 15-inst. If a 1xx effect has dat greater than 0x20, it is UST.
\r
147 Returns: 0 indecisive; 1 = UST; 2 = 15-inst */
\r
148 static int CheckPatternType(int numpat)
\r
153 for(t=0;t<numpat*(64U*4);t++) {
\r
154 /* Load the pattern into the temp buffer and scan it */
\r
155 _mm_read_UBYTE(modreader);_mm_read_UBYTE(modreader);
\r
156 eff = _mm_read_UBYTE(modreader);
\r
157 dat = _mm_read_UBYTE(modreader);
\r
161 if(dat>0x1f) return 1;
\r
162 if(dat<0x3) return 2;
\r
165 if(dat>0x1f) return 1;
\r
177 static BOOL M15_Test(void)
\r
183 if(!LoadModuleHeader(&mh)) return 0;
\r
185 /* reject other file types */
\r
186 for(t=0;t<REJECT;t++)
\r
187 if(!memcmp(mh.songname,signatures[t],siglen[t])) return 0;
\r
189 if(mh.magic1>127) return 0;
\r
190 if((!mh.songlength)||(mh.songlength>mh.magic1)) return 0;
\r
192 for(t=0;t<15;t++) {
\r
193 /* all finetunes should be zero */
\r
194 if(mh.samples[t].finetune) return 0;
\r
196 /* all volumes should be <= 64 */
\r
197 if(mh.samples[t].volume>64) return 0;
\r
199 /* all instrument names should begin with s, st-, or a number */
\r
200 if((mh.samples[t].samplename[0]=='s')||
\r
201 (mh.samples[t].samplename[0]=='S')) {
\r
202 if((memcmp(mh.samples[t].samplename,"st-",3)) &&
\r
203 (memcmp(mh.samples[t].samplename,"ST-",3)) &&
\r
204 (*mh.samples[t].samplename))
\r
207 if(!isdigit((int)mh.samples[t].samplename[0]))
\r
210 if(mh.samples[t].length>4999||mh.samples[t].reppos>9999) {
\r
212 if(mh.samples[t].length>32768) return 0;
\r
215 /* if loop information is incorrect as words, but correct as bytes,
\r
216 this is likely to be an ust-style module */
\r
217 if((mh.samples[t].reppos+mh.samples[t].replen>mh.samples[t].length)&&
\r
218 (mh.samples[t].reppos+mh.samples[t].replen<(mh.samples[t].length<<1))){
\r
223 if(!ust_loader) return 1;
\r
226 for(numpat=0,t=0;t<mh.songlength;t++)
\r
227 if(mh.positions[t]>numpat)
\r
228 numpat = mh.positions[t];
\r
230 switch(CheckPatternType(numpat)) {
\r
231 case 0: /* indecisive, so check more clues... */
\r
243 static BOOL M15_Init(void)
\r
245 if(!(mh=(MODULEHEADER*)_mm_malloc(sizeof(MODULEHEADER)))) return 0;
\r
249 static void M15_Cleanup(void)
\r
256 Old (amiga) noteinfo:
\r
258 _____byte 1_____ byte2_ _____byte 3_____ byte4_
\r
260 0000 0000-00000000 0000 0000-00000000
\r
262 Upper four 12 bits for Lower four Effect command.
\r
263 bits of sam- note period. bits of sam-
\r
264 ple number. ple number.
\r
267 static UBYTE M15_ConvertNote(MODNOTE* n, UBYTE lasteffect)
\r
269 UBYTE instrument,effect,effdat,note;
\r
273 /* decode the 4 bytes that make up a single note */
\r
274 instrument = n->c>>4;
\r
275 period = (((UWORD)n->a&0xf)<<8)+n->b;
\r
279 /* Convert the period to a note number */
\r
282 for(note=0;note<7*OCTAVE;note++)
\r
283 if(period>=npertab[note]) break;
\r
284 if(note==7*OCTAVE) note=0;
\r
289 /* if instrument does not exist, note cut */
\r
290 if((instrument>15)||(!mh->samples[instrument-1].length)) {
\r
291 UniPTEffect(0xc,0);
\r
292 if(effect==0xc) effect=effdat=0;
\r
294 /* if we had a note, then change instrument... */
\r
296 UniInstrument(instrument-1);
\r
297 /* ...otherwise, only adjust volume... */
\r
299 /* ...unless an effect was specified, which forces a new note
\r
301 if(effect||effdat) {
\r
302 UniInstrument(instrument-1);
\r
305 UniPTEffect(0xc,mh->samples[instrument-1].volume&0x7f);
\r
310 UniNote(note+2*OCTAVE-1);
\r
314 /* Convert pattern jump from Dec to Hex */
\r
316 effdat=(((effdat&0xf0)>>4)*10)+(effdat&0xf);
\r
318 /* Volume slide, up has priority */
\r
319 if((effect==0xa)&&(effdat&0xf)&&(effdat&0xf0))
\r
322 /* Handle ``heavy'' volumes correctly */
\r
323 if ((effect == 0xc) && (effdat > 0x40))
\r
332 UniPTEffect(0,effdat);
\r
335 if(effdat&0xf) UniPTEffect(1,effdat&0xf);
\r
336 else if(effdat>>2) UniPTEffect(2,effdat>>2);
\r
339 UniPTEffect(effect,effdat);
\r
343 /* An isolated 100, 200 or 300 effect should be ignored (no
\r
344 "standalone" porta memory in mod files). However, a sequence
\r
345 such as 1XX, 100, 100, 100 is fine. */
\r
346 if ((!effdat) && ((effect == 1)||(effect == 2)||(effect ==3)) &&
\r
347 (lasteffect < 0x10) && (effect != lasteffect))
\r
350 UniPTEffect(effect,effdat);
\r
353 of.flags |= UF_PANNING;
\r
358 static UBYTE *M15_ConvertTrack(MODNOTE* n)
\r
361 UBYTE lasteffect = 0x10; /* non existant effect */
\r
364 for(t=0;t<64;t++) {
\r
365 lasteffect = M15_ConvertNote(n,lasteffect);
\r
372 /* Loads all patterns of a modfile and converts them into the 3 byte format. */
\r
373 static BOOL M15_LoadPatterns(void)
\r
377 if(!AllocPatterns()) return 0;
\r
378 if(!AllocTracks()) return 0;
\r
380 /* Allocate temporary buffer for loading and converting the patterns */
\r
381 if(!(patbuf=(MODNOTE*)_mm_calloc(64U*4,sizeof(MODNOTE)))) return 0;
\r
383 for(t=0;t<of.numpat;t++) {
\r
384 /* Load the pattern into the temp buffer and convert it */
\r
385 for(s=0;s<(64U*4);s++) {
\r
386 patbuf[s].a=_mm_read_UBYTE(modreader);
\r
387 patbuf[s].b=_mm_read_UBYTE(modreader);
\r
388 patbuf[s].c=_mm_read_UBYTE(modreader);
\r
389 patbuf[s].d=_mm_read_UBYTE(modreader);
\r
393 if(!(of.tracks[tracks++]=M15_ConvertTrack(patbuf+s))) return 0;
\r
398 static BOOL M15_Load(BOOL curious)
\r
404 /* try to read module header */
\r
405 if(!LoadModuleHeader(mh)) {
\r
406 _mm_errno = MMERR_LOADING_HEADER;
\r
411 of.modtype = strdup("Ultimate Soundtracker");
\r
413 of.modtype = strdup("Soundtracker");
\r
415 /* set module variables */
\r
417 of.inittempo = 125;
\r
419 of.songname = DupStr(mh->songname,21,1);
\r
420 of.numpos = mh->songlength;
\r
423 /* Count the number of patterns */
\r
425 for(t=0;t<of.numpos;t++)
\r
426 if(mh->positions[t]>of.numpat)
\r
427 of.numpat=mh->positions[t];
\r
428 /* since some old modules embed extra patterns, we have to check the
\r
429 whole list to get the samples' file offsets right - however we can find
\r
430 garbage here, so check carefully */
\r
432 for(t=of.numpos;t<128;t++)
\r
433 if(mh->positions[t]>=0x80) scan=0;
\r
435 for(t=of.numpos;t<128;t++) {
\r
436 if(mh->positions[t]>of.numpat)
\r
437 of.numpat=mh->positions[t];
\r
438 if((curious)&&(mh->positions[t])) of.numpos=t+1;
\r
441 of.numtrk = of.numpat*of.numchn;
\r
443 if(!AllocPositions(of.numpos)) return 0;
\r
444 for(t=0;t<of.numpos;t++)
\r
445 of.positions[t]=mh->positions[t];
\r
447 /* Finally, init the sampleinfo structures */
\r
448 of.numins=of.numsmp=15;
\r
449 if(!AllocSamples()) return 0;
\r
454 for(t=0;t<of.numins;t++) {
\r
455 /* convert the samplename */
\r
456 q->samplename = DupStr(s->samplename,23,1);
\r
458 /* init the sampleinfo variables and convert the size pointers */
\r
459 q->speed = finetune[s->finetune&0xf];
\r
460 q->volume = s->volume;
\r
462 q->loopstart = s->reppos;
\r
464 q->loopstart = s->reppos<<1;
\r
465 q->loopend = q->loopstart+(s->replen<<1);
\r
466 q->length = s->length<<1;
\r
468 q->flags = SF_SIGNED;
\r
469 if(ust_loader) q->flags |= SF_UST_LOOP;
\r
470 if(s->replen>2) q->flags |= SF_LOOP;
\r
476 if(!M15_LoadPatterns()) return 0;
\r
482 static CHAR *M15_LoadTitle(void)
\r
486 _mm_fseek(modreader,0,SEEK_SET);
\r
487 if(!_mm_read_UBYTES(s,20,modreader)) return NULL;
\r
488 s[20]=0; /* just in case */
\r
489 return(DupStr(s,21,1));
\r
492 /*========== Loader information */
\r
494 MIKMODAPI MLOADER load_m15={
\r
496 "15-instrument module",
\r
497 "MOD (15 instrument)",
\r