home *** CD-ROM | disk | FTP | other *** search
- /* MikMod sound library
- (c) 1998 Miodrag Vallat and others - see file AUTHORS for complete list
-
- This library is free software; you can redistribute it and/or modify
- it under the terms of the GNU Library General Public License as
- published by the Free Software Foundation; either version 2 of
- the License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
- /*==============================================================================
-
- $Id: load_m15.c,v 1.15 1998/12/07 06:00:15 miod Exp $
-
- 15 instrument MOD loader
- Also supports Ultimate Sound Tracker (old M15 format)
-
- ==============================================================================*/
-
- #ifdef HAVE_CONFIG_H
- #include "config.h"
- #endif
-
- #include <string.h>
-
- #include <mikmod_internals.h>
-
- /*========== Module Structure */
-
- typedef struct MSAMPINFO {
- CHAR samplename[23]; /* 22 in module, 23 in memory */
- UWORD length;
- UBYTE finetune;
- UBYTE volume;
- UWORD reppos;
- UWORD replen;
- } MSAMPINFO;
-
- typedef struct MODULEHEADER {
- CHAR songname[21]; /* the songname.., 20 in module, 21 in memory */
- MSAMPINFO samples[15]; /* all sampleinfo */
- UBYTE songlength; /* number of patterns used */
- UBYTE magic1; /* should be 127 */
- UBYTE positions[128]; /* which pattern to play at pos */
- } MODULEHEADER;
-
- typedef struct MODNOTE {
- UBYTE a,b,c,d;
- } MODNOTE;
-
- /*========== Loader variables */
-
- static MODULEHEADER *mh = NULL;
- static MODNOTE *patbuf = NULL;
- static BOOL ust_loader = 0; /* if TRUE, load as an ust module. */
-
- /* known file formats which can confuse the loader */
- #define REJECT 2
- static char *signatures[REJECT]={
- "CAKEWALK", /* cakewalk midi files */
- "SZDD" /* Microsoft compressed files */
- };
-
- /*========== Loader code */
-
- BOOL LoadModuleHeader(MODULEHEADER *mh)
- {
- int t;
-
- _mm_read_string(mh->songname,20,modfp);
- mh->songname[20]=0; /* just in case */
-
- for(t=0;t<15;t++) {
- MSAMPINFO *s=&mh->samples[t];
-
- _mm_read_string(s->samplename,22,modfp);
- s->samplename[22]=0; /* just in case */
- s->length =_mm_read_M_UWORD(modfp);
- s->finetune =_mm_read_UBYTE(modfp);
- s->volume =_mm_read_UBYTE(modfp);
- s->reppos =_mm_read_M_UWORD(modfp);
- s->replen =_mm_read_M_UWORD(modfp);
- }
-
- mh->songlength =_mm_read_UBYTE(modfp);
- mh->magic1 =_mm_read_UBYTE(modfp); /* should be 127 */
- _mm_read_UBYTES(mh->positions,128,modfp);
-
- return(!feof(modfp));
- }
-
- /* Checks the patterns in the modfile for UST / 15-inst indications.
- For example, if an effect 3xx is found, it is assumed that the song
- is 15-inst. If a 1xx effect has dat greater than 0x20, it is UST.
-
- Returns: 0 indecisive; 1 = UST; 2 = 15-inst */
- int CheckPatternType(int numpat)
- {
- int t;
- UBYTE eff, dat;
-
- for(t=0;t<numpat*(64U*4);t++) {
- /* Load the pattern into the temp buffer and convert it */
- _mm_read_UBYTE(modfp);_mm_read_UBYTE(modfp);
- eff = _mm_read_UBYTE(modfp);
- dat = _mm_read_UBYTE(modfp);
-
- switch(eff) {
- case 1:
- if(dat>0x1f) return 1;
- if(dat<0x3) return 2;
- break;
- case 2:
- if(dat>0x1f) return 1;
- return 2;
- case 3:
- if (dat) return 2;
- break;
- default:
- return 2;
- }
- }
- return 0;
- }
-
- BOOL M15_Test(void)
- {
- int t, numpat;
- MODULEHEADER mh;
-
- ust_loader = 0;
- if(!LoadModuleHeader(&mh)) return 0;
-
- /* reject other file types */
- for(t=0;t<REJECT;t++)
- if(!memcmp(mh.songname,signatures[t],strlen(signatures[t]))) return 0;
-
- if(mh.magic1>127) return 0;
- if((!mh.songlength)||(mh.songlength>mh.magic1)) return 0;
-
- for(t=0;t<15;t++) {
- /* all finetunes should be zero */
- if(mh.samples[t].finetune) return 0;
-
- /* all volumes should be <= 64 */
- if(mh.samples[t].volume>64) return 0;
-
- /* all instrument names should begin with s, st-, or a number */
- if(mh.samples[t].samplename[0]=='s') {
- if((memcmp(mh.samples[t].samplename,"st-",3)) &&
- (memcmp(mh.samples[t].samplename,"ST-",3)) &&
- (*mh.samples[t].samplename))
- ust_loader = 1;
- } else
- if((mh.samples[t].samplename[0]<'0')||
- (mh.samples[t].samplename[0]>'9'))
- ust_loader = 1;
-
- if(mh.samples[t].length>4999) {
- ust_loader = 0;
- if(mh.samples[t].length>32768) return 0;
- }
-
- if(!ust_loader) return 1;
-
- if((mh.samples[t].reppos+mh.samples[t].replen)>(mh.samples[t].length+10)) {
- ust_loader = 1;
- return 1;
- }
- }
-
- for(numpat=0,t=0;t<mh.songlength;t++)
- if(mh.positions[t]>numpat)
- numpat = mh.positions[t];
- numpat++;
- switch(CheckPatternType(numpat)) {
- case 0: /* indecisive, so check more clues... */
- break;
- case 1:
- ust_loader = 1;
- break;
- case 2:
- ust_loader = 0;
- break;
- }
- return 1;
- }
-
- BOOL M15_Init(void)
- {
- if(!(mh=(MODULEHEADER*)_mm_malloc(sizeof(MODULEHEADER)))) return 0;
- return 1;
- }
-
- void M15_Cleanup(void)
- {
- if(mh) free(mh);
- if(patbuf) free(patbuf);
-
- mh = NULL;
- patbuf = NULL;
- }
-
- /*
- Old (amiga) noteinfo:
-
- _____byte 1_____ byte2_ _____byte 3_____ byte4_
- / \ / \ / \ / \
- 0000 0000-00000000 0000 0000-00000000
-
- Upper four 12 bits for Lower four Effect command.
- bits of sam- note period. bits of sam-
- ple number. ple number.
- */
-
- void M15_ConvertNote(MODNOTE* n)
- {
- UBYTE instrument,effect,effdat,note;
- UWORD period;
- UBYTE lastnote=0;
-
- /* decode the 4 bytes that make up a single note */
- instrument = n->c>>4;
- period = (((UWORD)n->a&0xf)<<8)+n->b;
- effect = n->c&0xf;
- effdat = n->d;
-
- /* Convert the period to a note number */
- note=0;
- if(period) {
- for(note=0;note<7*OCTAVE;note++)
- if(period>=npertab[note]) break;
- if(note==7*OCTAVE) note=0;
- else note++;
- }
-
- if(instrument) {
- UniInstrument(instrument-1);
- if(!note) note=lastnote;
- }
- if(note) {
- UniNote(note+2*OCTAVE-1);
- lastnote=note;
- }
-
- /* Convert pattern jump from Dec to Hex */
- if(effect == 0xd)
- effdat=(((effdat&0xf0)>>4)*10)+(effdat&0xf);
-
- if(ust_loader) {
- switch(effect) {
- case 0:
- case 3:
- break;
- case 1:
- UniPTEffect(0,effdat);
- break;
- case 2:
- if(effdat&0xf) UniPTEffect(1,effdat&0xf);
- if(effdat>>2) UniPTEffect(2,effdat>>2);
- break;
- default:
- UniPTEffect(effect,effdat);
- break;
- }
- } else {
- /* finetune conversion to Lxx */
- if(effect==5)
- S3MIT_ProcessCmd(0xc,effdat,1);
- else
- UniPTEffect(effect,effdat);
- }
- }
-
- UBYTE *M15_ConvertTrack(MODNOTE* n)
- {
- int t;
-
- UniReset();
- for(t=0;t<64;t++) {
- M15_ConvertNote(n);
- UniNewline();
- n+=4;
- }
- return UniDup();
- }
-
- /* Loads all patterns of a modfile and converts them into the 3 byte format. */
- BOOL M15_LoadPatterns(void)
- {
- int t,s,tracks=0;
-
- if(!AllocPatterns()) return 0;
- if(!AllocTracks()) return 0;
-
- /* Allocate temporary buffer for loading and converting the patterns */
- if(!(patbuf=(MODNOTE*)_mm_calloc(64U*4,sizeof(MODNOTE)))) return 0;
-
- for(t=0;t<of.numpat;t++) {
- /* Load the pattern into the temp buffer and convert it */
- for(s=0;s<(64U*4);s++) {
- patbuf[s].a=_mm_read_UBYTE(modfp);
- patbuf[s].b=_mm_read_UBYTE(modfp);
- patbuf[s].c=_mm_read_UBYTE(modfp);
- patbuf[s].d=_mm_read_UBYTE(modfp);
- }
-
- for(s=0;s<4;s++)
- if(!(of.tracks[tracks++]=M15_ConvertTrack(patbuf+s))) return 0;
- }
- return 1;
- }
-
- BOOL M15_Load(BOOL curious)
- {
- int t,scan;
- SAMPLE *q;
- MSAMPINFO *s;
-
- /* try to read module header */
- if(!LoadModuleHeader(mh)) {
- _mm_errno = MMERR_LOADING_HEADER;
- return 0;
- }
-
- if(ust_loader)
- of.modtype = strdup("Ultimate Soundtracker");
- else
- of.modtype = strdup("Soundtracker");
-
- /* set module variables */
- of.initspeed = 6;
- of.inittempo = 125;
- of.numchn = 4;
- of.songname = DupStr(mh->songname,21);
- of.numpos = mh->songlength;
- of.reppos = 0;
-
- /* Count the number of patterns */
- of.numpat = 0;
- for(t=0;t<of.numpos;t++)
- if(mh->positions[t]>of.numpat)
- of.numpat=mh->positions[t];
- /* since some old modules embed extra patterns, we have to check the
- whole list to get the samples' file offsets right - however we can find
- garbage here, so check carefully */
- scan=1;
- for(t=of.numpos;t<128;t++)
- if(mh->positions[t]>=0x80) scan=0;
- if (scan)
- for(t=of.numpos;t<128;t++) {
- if(mh->positions[t]>of.numpat)
- of.numpat=mh->positions[t];
- if((curious)&&(mh->positions[t])) of.numpos=t+1;
- }
- of.numpat++;
- of.numtrk = of.numpat*of.numchn;
-
- if(!AllocPositions(of.numpos)) return 0;
- for(t=0;t<of.numpos;t++)
- of.positions[t]=mh->positions[t];
-
- /* Finally, init the sampleinfo structures */
- of.numins=of.numsmp=15;
- if(!AllocSamples()) return 0;
-
- s = mh->samples;
- q = of.samples;
-
- for(t=0;t<of.numins;t++) {
- /* convert the samplename */
- q->samplename = DupStr(s->samplename,23);
-
- /* init the sampleinfo variables and convert the size pointers */
- q->speed = finetune[s->finetune&0xf];
- q->volume = s->volume;
- if(ust_loader)
- q->loopstart = s->reppos;
- else
- q->loopstart = s->reppos<<1;
- q->loopend = q->loopstart+(s->replen<<1);
- q->length = s->length<<1;
-
- q->flags = SF_SIGNED | SF_UST_LOOP;
- if(s->replen>1) q->flags |= SF_LOOP;
-
- /* fix replen if repend>length */
- if(q->loopend>q->length) q->loopend = q->length;
-
- s++;
- q++;
- }
-
- if(!M15_LoadPatterns()) return 0;
- ust_loader = 0;
-
- return 1;
- }
-
- CHAR *M15_LoadTitle(void)
- {
- CHAR s[21];
-
- fseek(modfp,0,SEEK_SET);
- if(!fread(s,20,1,modfp)) return NULL;
- s[20]=0; /* just in case */
- return(DupStr(s,21));
- }
-
- /*========== Loader information */
-
- MLOADER load_m15={
- NULL,
- "15-instrument module",
- "MOD-15 loader v1.0",
- M15_Init,
- M15_Test,
- M15_Load,
- M15_Cleanup,
- M15_LoadTitle
- };
-