diff options
| author | Frank Gevaerts <frank@gevaerts.be> | 2010-12-12 15:03:30 +0000 |
|---|---|---|
| committer | Frank Gevaerts <frank@gevaerts.be> | 2010-12-12 15:03:30 +0000 |
| commit | 26f2bfde03420edad4de1f22cb3d515dc063b20d (patch) | |
| tree | 4a8c4abaf4795f38da70a4657c1a0fb3ba9debeb /apps/plugins/mikmod/load_dsm.c | |
| parent | d192bdf11e06e50645ecb5726658d4b691480a9a (diff) | |
| download | rockbox-26f2bfde03420edad4de1f22cb3d515dc063b20d.zip rockbox-26f2bfde03420edad4de1f22cb3d515dc063b20d.tar.gz rockbox-26f2bfde03420edad4de1f22cb3d515dc063b20d.tar.bz2 rockbox-26f2bfde03420edad4de1f22cb3d515dc063b20d.tar.xz | |
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
Diffstat (limited to 'apps/plugins/mikmod/load_dsm.c')
| -rw-r--r-- | apps/plugins/mikmod/load_dsm.c | 364 |
1 files changed, 364 insertions, 0 deletions
diff --git a/apps/plugins/mikmod/load_dsm.c b/apps/plugins/mikmod/load_dsm.c new file mode 100644 index 0000000..09d6d3e --- /dev/null +++ b/apps/plugins/mikmod/load_dsm.c @@ -0,0 +1,364 @@ +/* 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_dsm.c,v 1.3 2005/04/07 19:57:38 realtech Exp $ + + DSIK internal format (DSM) module loader + +==============================================================================*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#include <stdio.h> +#ifdef HAVE_MEMORY_H +#include <memory.h> +#endif +#include <string.h> + +#include "mikmod_internals.h" + +#ifdef SUNOS +extern int fprintf(FILE *, const char *, ...); +#endif + +/*========== Module structure */ + +#define DSM_MAXCHAN (16) +#define DSM_MAXORDERS (128) + +typedef struct DSMSONG { + CHAR songname[28]; + UWORD version; + UWORD flags; + ULONG reserved2; + UWORD numord; + UWORD numsmp; + UWORD numpat; + UWORD numtrk; + UBYTE globalvol; + UBYTE mastervol; + UBYTE speed; + UBYTE bpm; + UBYTE panpos[DSM_MAXCHAN]; + UBYTE orders[DSM_MAXORDERS]; +} DSMSONG; + +typedef struct DSMINST { + CHAR filename[13]; + UWORD flags; + UBYTE volume; + ULONG length; + ULONG loopstart; + ULONG loopend; + ULONG reserved1; + UWORD c2spd; + UWORD period; + CHAR samplename[28]; +} DSMINST; + +typedef struct DSMNOTE { + UBYTE note,ins,vol,cmd,inf; +} DSMNOTE; + +#define DSM_SURROUND (0xa4) + +/*========== Loader variables */ + +static CHAR* SONGID="SONG"; +static CHAR* INSTID="INST"; +static CHAR* PATTID="PATT"; + +static UBYTE blockid[4]; +static ULONG blockln; +static ULONG blocklp; +static DSMSONG* mh=NULL; +static DSMNOTE* dsmbuf=NULL; + +static CHAR DSM_Version[]="DSIK DSM-format"; + +static unsigned char DSMSIG[4+4]={'R','I','F','F','D','S','M','F'}; + +/*========== Loader code */ + +int DSM_Test(void) +{ + UBYTE id[12]; + + if(!_mm_read_UBYTES(id,12,modreader)) return 0; + if(!memcmp(id,DSMSIG,4) && !memcmp(id+8,DSMSIG+4,4)) return 1; + + return 0; +} + +int DSM_Init(void) +{ + if(!(dsmbuf=(DSMNOTE *)MikMod_malloc(DSM_MAXCHAN*64*sizeof(DSMNOTE)))) return 0; + if(!(mh=(DSMSONG *)MikMod_calloc(1,sizeof(DSMSONG)))) return 0; + return 1; +} + +void DSM_Cleanup(void) +{ + MikMod_free(dsmbuf); + MikMod_free(mh); +} + +static int GetBlockHeader(void) +{ + /* make sure we're at the right position for reading the + next riff block, no matter how many bytes read */ + _mm_fseek(modreader, blocklp+blockln, SEEK_SET); + + while(1) { + _mm_read_UBYTES(blockid,4,modreader); + blockln=_mm_read_I_ULONG(modreader); + if(_mm_eof(modreader)) { + _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + if(memcmp(blockid,SONGID,4) && memcmp(blockid,INSTID,4) && + memcmp(blockid,PATTID,4)) { +#ifdef MIKMOD_DEBUG + fprintf(stderr,"\rDSM: Skipping unknown block type %4.4s\n",blockid); +#endif + _mm_fseek(modreader, blockln, SEEK_CUR); + } else + break; + } + + blocklp = _mm_ftell(modreader); + + return 1; +} + +static int DSM_ReadPattern(void) +{ + int flag,row=0; + SWORD length; + DSMNOTE *n; + + /* clear pattern data */ + memset(dsmbuf,255,DSM_MAXCHAN*64*sizeof(DSMNOTE)); + length=_mm_read_I_SWORD(modreader); + + while(row<64) { + flag=_mm_read_UBYTE(modreader); + if((_mm_eof(modreader))||(--length<0)) { + _mm_errno = MMERR_LOADING_PATTERN; + return 0; + } + + if(flag) { + n=&dsmbuf[((flag&0xf)*64)+row]; + if(flag&0x80) n->note=_mm_read_UBYTE(modreader); + if(flag&0x40) n->ins=_mm_read_UBYTE(modreader); + if(flag&0x20) n->vol=_mm_read_UBYTE(modreader); + if(flag&0x10) { + n->cmd=_mm_read_UBYTE(modreader); + n->inf=_mm_read_UBYTE(modreader); + } + } else + row++; + } + + return 1; +} + +static UBYTE *DSM_ConvertTrack(DSMNOTE *tr) +{ + int t; + UBYTE note,ins,vol,cmd,inf; + + UniReset(); + for(t=0;t<64;t++) { + note=tr[t].note; + ins=tr[t].ins; + vol=tr[t].vol; + cmd=tr[t].cmd; + inf=tr[t].inf; + + if(ins!=0 && ins!=255) UniInstrument(ins-1); + if(note!=255) UniNote(note-1); /* normal note */ + if(vol<65) UniPTEffect(0xc,vol); + + if(cmd!=255) { + if(cmd==0x8) { + if(inf==DSM_SURROUND) + UniEffect(UNI_ITEFFECTS0,0x91); + else + if(inf<=0x80) { + inf=(inf<0x80)?inf<<1:255; + UniPTEffect(cmd,inf); + } + } else + if(cmd==0xb) { + if(inf<=0x7f) UniPTEffect(cmd,inf); + } else { + /* Convert pattern jump from Dec to Hex */ + if(cmd == 0xd) + inf = (((inf&0xf0)>>4)*10)+(inf&0xf); + UniPTEffect(cmd,inf); + } + } + UniNewline(); + } + return UniDup(); +} + +int DSM_Load(int curious) +{ + int t; + DSMINST s; + SAMPLE *q; + int cursmp=0,curpat=0,track=0; + + blocklp=0; + blockln=12; + + if(!GetBlockHeader()) return 0; + if(memcmp(blockid,SONGID,4)) { + _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + _mm_read_UBYTES(mh->songname,28,modreader); + mh->version=_mm_read_I_UWORD(modreader); + mh->flags=_mm_read_I_UWORD(modreader); + mh->reserved2=_mm_read_I_ULONG(modreader); + mh->numord=_mm_read_I_UWORD(modreader); + mh->numsmp=_mm_read_I_UWORD(modreader); + mh->numpat=_mm_read_I_UWORD(modreader); + mh->numtrk=_mm_read_I_UWORD(modreader); + mh->globalvol=_mm_read_UBYTE(modreader); + mh->mastervol=_mm_read_UBYTE(modreader); + mh->speed=_mm_read_UBYTE(modreader); + mh->bpm=_mm_read_UBYTE(modreader); + _mm_read_UBYTES(mh->panpos,DSM_MAXCHAN,modreader); + _mm_read_UBYTES(mh->orders,DSM_MAXORDERS,modreader); + + /* set module variables */ + of.initspeed=mh->speed; + of.inittempo=mh->bpm; + of.modtype=StrDup(DSM_Version); + of.numchn=mh->numtrk; + of.numpat=mh->numpat; + of.numtrk=of.numchn*of.numpat; + of.songname=DupStr(mh->songname,28,1); /* make a cstr of songname */ + of.reppos=0; + of.flags |= UF_PANNING; + /* XXX whenever possible, we should try to determine the original format. + Here we assume it was S3M-style wrt bpmlimit... */ + of.bpmlimit = 32; + + for(t=0;t<DSM_MAXCHAN;t++) + of.panning[t]=mh->panpos[t]==DSM_SURROUND?PAN_SURROUND: + mh->panpos[t]<0x80?(mh->panpos[t]<<1):255; + + if(!AllocPositions(mh->numord)) return 0; + of.numpos=0; + for(t=0;t<mh->numord;t++) { + int order=mh->orders[t]; + if(order==255) order=LAST_PATTERN; + of.positions[of.numpos]=order; + if(mh->orders[t]<254) of.numpos++; + } + + of.numins=of.numsmp=mh->numsmp; + + if(!AllocSamples()) return 0; + if(!AllocTracks()) return 0; + if(!AllocPatterns()) return 0; + + while(cursmp<of.numins||curpat<of.numpat) { + if(!GetBlockHeader()) return 0; + if(!memcmp(blockid,INSTID,4) && cursmp<of.numins) { + q=&of.samples[cursmp]; + + /* try to read sample info */ + _mm_read_UBYTES(s.filename,13,modreader); + s.flags=_mm_read_I_UWORD(modreader); + s.volume=_mm_read_UBYTE(modreader); + s.length=_mm_read_I_ULONG(modreader); + s.loopstart=_mm_read_I_ULONG(modreader); + s.loopend=_mm_read_I_ULONG(modreader); + s.reserved1=_mm_read_I_ULONG(modreader); + s.c2spd=_mm_read_I_UWORD(modreader); + s.period=_mm_read_I_UWORD(modreader); + _mm_read_UBYTES(s.samplename,28,modreader); + + q->samplename=DupStr(s.samplename,28,1); + q->seekpos=_mm_ftell(modreader); + q->speed=s.c2spd; + q->length=s.length; + q->loopstart=s.loopstart; + q->loopend=s.loopend; + q->volume=s.volume; + + if(s.flags&1) q->flags|=SF_LOOP; + if(s.flags&2) q->flags|=SF_SIGNED; + /* (s.flags&4) means packed sample, + but did they really exist in dsm ?*/ + cursmp++; + } else + if(!memcmp(blockid,PATTID,4) && curpat<of.numpat) { + DSM_ReadPattern(); + for(t=0;t<of.numchn;t++) + if(!(of.tracks[track++]=DSM_ConvertTrack(&dsmbuf[t*64]))) return 0; + curpat++; + } + } + + return 1; +} + +CHAR *DSM_LoadTitle(void) +{ + CHAR s[28]; + + _mm_fseek(modreader,12,SEEK_SET); + if(!_mm_read_UBYTES(s,28,modreader)) return NULL; + + return(DupStr(s,28,1)); +} + +/*========== Loader information */ + +MIKMODAPI MLOADER load_dsm={ + NULL, + "DSM", + "DSM (DSIK internal format)", + DSM_Init, + DSM_Test, + DSM_Load, + DSM_Cleanup, + DSM_LoadTitle +}; + + +/* ex:set ts=4: */ |