From 26f2bfde03420edad4de1f22cb3d515dc063b20d Mon Sep 17 00:00:00 2001 From: Frank Gevaerts Date: Sun, 12 Dec 2010 15:03:30 +0000 Subject: Add MikMod plugin, ported by Jason Yu, with some minor work by Craig Mann and William Peters (FS#8806) git-svn-id: svn://svn.rockbox.org/rockbox/trunk@28810 a1c6a512-1295-4272-9138-f99709370657 --- apps/plugins/mikmod/load_stm.c | 374 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 374 insertions(+) create mode 100644 apps/plugins/mikmod/load_stm.c (limited to 'apps/plugins/mikmod/load_stm.c') diff --git a/apps/plugins/mikmod/load_stm.c b/apps/plugins/mikmod/load_stm.c new file mode 100644 index 0000000000..57df85c92d --- /dev/null +++ b/apps/plugins/mikmod/load_stm.c @@ -0,0 +1,374 @@ +/* MikMod sound library + (c) 1998, 1999, 2000, 2001, 2002 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., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. +*/ + +/*============================================================================== + + $Id: load_stm.c,v 1.3 2005/04/07 19:57:38 realtech Exp $ + + Screamtracker 2 (STM) module loader + +==============================================================================*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif + +#include +#ifdef HAVE_MEMORY_H +#include +#endif +#include + +#include "mikmod_internals.h" + +#ifdef SUNOS +extern int fprintf(FILE *, const char *, ...); +#endif + +/*========== Module structure */ + +/* sample information */ +typedef struct STMSAMPLE { + CHAR filename[12]; + UBYTE unused; /* 0x00 */ + UBYTE instdisk; /* Instrument disk */ + UWORD reserved; + UWORD length; /* Sample length */ + UWORD loopbeg; /* Loop start point */ + UWORD loopend; /* Loop end point */ + UBYTE volume; /* Volume */ + UBYTE reserved2; + UWORD c2spd; /* Good old c2spd */ + ULONG reserved3; + UWORD isa; +} STMSAMPLE; + +/* header */ +typedef struct STMHEADER { + CHAR songname[20]; + CHAR trackername[8]; /* !Scream! for ST 2.xx */ + UBYTE unused; /* 0x1A */ + UBYTE filetype; /* 1=song, 2=module */ + UBYTE ver_major; + UBYTE ver_minor; + UBYTE inittempo; /* initspeed= stm inittempo>>4 */ + UBYTE numpat; /* number of patterns */ + UBYTE globalvol; + UBYTE reserved[13]; + STMSAMPLE sample[31]; /* STM sample data */ + UBYTE patorder[128]; /* Docs say 64 - actually 128 */ +} STMHEADER; + +typedef struct STMNOTE { + UBYTE note,insvol,volcmd,cmdinf; +} STMNOTE; + +/*========== Loader variables */ + +static STMNOTE *stmbuf = NULL; +static STMHEADER *mh = NULL; + +/* tracker identifiers */ +static CHAR* STM_Version[STM_NTRACKERS] = { + "Screamtracker 2", + "Converted by MOD2STM (STM format)", + "Wuzamod (STM format)" +}; + +/*========== Loader code */ + +int STM_Test(void) +{ + UBYTE str[44]; + int t; + + _mm_fseek(modreader,20,SEEK_SET); + _mm_read_UBYTES(str,44,modreader); + if(str[9]!=2) return 0; /* STM Module = filetype 2 */ + + /* Prevent false positives for S3M files */ + if(!memcmp(str+40,"SCRM",4)) + return 0; + + for (t=0;tnote; + ins = n->insvol>>3; + vol = (n->insvol&7)+((n->volcmd&0x70)>>1); + cmd = n->volcmd&15; + inf = n->cmdinf; + + if((ins)&&(ins<32)) UniInstrument(ins-1); + + /* special values of [SBYTE0] are handled here + we have no idea if these strange values will ever be encountered. + but it appears as those stms sound correct. */ + if((note==254)||(note==252)) { + UniPTEffect(0xc,0); /* note cut */ + n->volcmd|=0x80; + } else + /* if note < 251, then all three bytes are stored in the file */ + if(note<251) UniNote((((note>>4)+2)*OCTAVE)+(note&0xf)); + + if((!(n->volcmd&0x80))&&(vol<65)) UniPTEffect(0xc,vol); + if(cmd!=255) + switch(cmd) { + case 1: /* Axx set speed to xx */ + UniPTEffect(0xf,inf>>4); + break; + case 2: /* Bxx position jump */ + UniPTEffect(0xb,inf); + break; + case 3: /* Cxx patternbreak to row xx */ + UniPTEffect(0xd,(((inf&0xf0)>>4)*10)+(inf&0xf)); + break; + case 4: /* Dxy volumeslide */ + UniEffect(UNI_S3MEFFECTD,inf); + break; + case 5: /* Exy toneslide down */ + UniEffect(UNI_S3MEFFECTE,inf); + break; + case 6: /* Fxy toneslide up */ + UniEffect(UNI_S3MEFFECTF,inf); + break; + case 7: /* Gxx Tone portamento,speed xx */ + UniPTEffect(0x3,inf); + break; + case 8: /* Hxy vibrato */ + UniPTEffect(0x4,inf); + break; + case 9: /* Ixy tremor, ontime x, offtime y */ + UniEffect(UNI_S3MEFFECTI,inf); + break; + case 0: /* protracker arpeggio */ + if(!inf) break; + /* fall through */ + case 0xa: /* Jxy arpeggio */ + UniPTEffect(0x0,inf); + break; + case 0xb: /* Kxy Dual command H00 & Dxy */ + UniPTEffect(0x4,0); + UniEffect(UNI_S3MEFFECTD,inf); + break; + case 0xc: /* Lxy Dual command G00 & Dxy */ + UniPTEffect(0x3,0); + UniEffect(UNI_S3MEFFECTD,inf); + break; + /* Support all these above, since ST2 can LOAD these values but can + actually only play up to J - and J is only half-way implemented + in ST2 */ + case 0x18: /* Xxx amiga panning command 8xx */ + UniPTEffect(0x8,inf); + of.flags |= UF_PANNING; + break; + } +} + +static UBYTE *STM_ConvertTrack(STMNOTE *n) +{ + int t; + + UniReset(); + for(t=0;t<64;t++) { + STM_ConvertNote(n); + UniNewline(); + n+=of.numchn; + } + return UniDup(); +} + +static int STM_LoadPatterns(void) +{ + int t,s,tracks=0; + + if(!AllocPatterns()) return 0; + if(!AllocTracks()) return 0; + + /* Allocate temporary buffer for loading and converting the patterns */ + for(t=0;tsongname,20,modreader); + _mm_read_string(mh->trackername,8,modreader); + mh->unused =_mm_read_UBYTE(modreader); + mh->filetype =_mm_read_UBYTE(modreader); + mh->ver_major =_mm_read_UBYTE(modreader); + mh->ver_minor =_mm_read_UBYTE(modreader); + mh->inittempo =_mm_read_UBYTE(modreader); + if(!mh->inittempo) { + _mm_errno=MMERR_NOT_A_MODULE; + return 0; + } + mh->numpat =_mm_read_UBYTE(modreader); + mh->globalvol =_mm_read_UBYTE(modreader); + _mm_read_UBYTES(mh->reserved,13,modreader); + + for(t=0;t<31;t++) { + STMSAMPLE *s=&mh->sample[t]; /* STM sample data */ + + _mm_read_string(s->filename,12,modreader); + s->unused =_mm_read_UBYTE(modreader); + s->instdisk =_mm_read_UBYTE(modreader); + s->reserved =_mm_read_I_UWORD(modreader); + s->length =_mm_read_I_UWORD(modreader); + s->loopbeg =_mm_read_I_UWORD(modreader); + s->loopend =_mm_read_I_UWORD(modreader); + s->volume =_mm_read_UBYTE(modreader); + s->reserved2=_mm_read_UBYTE(modreader); + s->c2spd =_mm_read_I_UWORD(modreader); + s->reserved3=_mm_read_I_ULONG(modreader); + s->isa =_mm_read_I_UWORD(modreader); + } + _mm_read_UBYTES(mh->patorder,128,modreader); + + if(_mm_eof(modreader)) { + _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + /* set module variables */ + for(t=0;ttrackername,STM_Signatures[t],8)) break; + of.modtype = StrDup(STM_Version[t]); + of.songname = DupStr(mh->songname,20,1); /* make a cstr of songname */ + of.numpat = mh->numpat; + of.inittempo = 125; /* mh->inittempo+0x1c; */ + of.initspeed = mh->inittempo>>4; + of.numchn = 4; /* get number of channels */ + of.reppos = 0; + of.flags |= UF_S3MSLIDES; + of.bpmlimit = 32; + + t=0; + if(!AllocPositions(0x80)) return 0; + /* 99 terminates the patorder list */ + while((mh->patorder[t]<=99)&&(mh->patorder[t]numpat)) { + of.positions[t]=mh->patorder[t]; + t++; + } + if(mh->patorder[t]<=99) t++; + of.numpos=t; + of.numtrk=of.numpat*of.numchn; + of.numins=of.numsmp=31; + + if(!AllocSamples()) return 0; + if(!STM_LoadPatterns()) return 0; + MikMod_ISA=_mm_ftell(modreader); + MikMod_ISA=(MikMod_ISA+15)&0xfffffff0; /* normalize */ + + for(q=of.samples,t=0;tsamplename = DupStr(mh->sample[t].filename,12,1); + q->speed = (mh->sample[t].c2spd * 8363) / 8448; + q->volume = mh->sample[t].volume; + q->length = mh->sample[t].length; + if (/*(!mh->sample[t].volume)||*/(q->length==1)) q->length=0; + q->loopstart = mh->sample[t].loopbeg; + q->loopend = mh->sample[t].loopend; + q->seekpos = MikMod_ISA; + + MikMod_ISA+=q->length; + MikMod_ISA=(MikMod_ISA+15)&0xfffffff0; /* normalize */ + + /* contrary to the STM specs, sample data is signed */ + q->flags = SF_SIGNED; + + if(q->loopend && q->loopend != 0xffff) + q->flags|=SF_LOOP; + } + return 1; +} + +CHAR *STM_LoadTitle(void) +{ + CHAR s[20]; + + _mm_fseek(modreader,0,SEEK_SET); + if(!_mm_read_UBYTES(s,20,modreader)) return NULL; + + return(DupStr(s,20,1)); +} + +/*========== Loader information */ + +MIKMODAPI MLOADER load_stm={ + NULL, + "STM", + "STM (Scream Tracker)", + STM_Init, + STM_Test, + STM_Load, + STM_Cleanup, + STM_LoadTitle +}; + + +/* ex:set ts=4: */ -- cgit v1.2.3