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_gdm.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_gdm.c')
| -rw-r--r-- | apps/plugins/mikmod/load_gdm.c | 558 |
1 files changed, 558 insertions, 0 deletions
diff --git a/apps/plugins/mikmod/load_gdm.c b/apps/plugins/mikmod/load_gdm.c new file mode 100644 index 0000000..616a2b5 --- /dev/null +++ b/apps/plugins/mikmod/load_gdm.c @@ -0,0 +1,558 @@ +/* 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_gdm.c,v 1.3 2005/04/07 19:57:38 realtech Exp $ + + General DigiMusic (GDM) module loader + +==============================================================================*/ + +/* + + Written by Kev Vance<kvance@zeux.org> + based on the file format description written by 'MenTaLguY' + <mental@kludge.org> + +*/ + +#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 + +typedef struct GDMNOTE { + UBYTE note; + UBYTE samp; + struct { + UBYTE effect; + UBYTE param; + } effect[4]; +} GDMNOTE; + +typedef GDMNOTE GDMTRACK[64]; + +typedef struct GDMHEADER { + CHAR id1[4]; + CHAR songname[32]; + CHAR author[32]; + CHAR eofmarker[3]; + CHAR id2[4]; + + UBYTE majorver; + UBYTE minorver; + UWORD trackerid; + UBYTE t_majorver; + UBYTE t_minorver; + UBYTE pantable[32]; + UBYTE mastervol; + UBYTE mastertempo; + UBYTE masterbpm; + UWORD flags; + + ULONG orderloc; + UBYTE ordernum; + ULONG patternloc; + UBYTE patternnum; + ULONG samhead; + ULONG samdata; + UBYTE samnum; + ULONG messageloc; + ULONG messagelen; + ULONG scrollyloc; + UWORD scrollylen; + ULONG graphicloc; + UWORD graphiclen; +} GDMHEADER; + +typedef struct GDMSAMPLE { + CHAR sampname[32]; + CHAR filename[13]; + UBYTE ems; + ULONG length; + ULONG loopbeg; + ULONG loopend; + UBYTE flags; + UWORD c4spd; + UBYTE vol; + UBYTE pan; +} GDMSAMPLE; + +static GDMHEADER *mh=NULL; /* pointer to GDM header */ +static GDMNOTE *gdmbuf=NULL; /* pointer to a complete GDM pattern */ + +CHAR GDM_Version[]="General DigiMusic 1.xx"; + +int GDM_Test(void) +{ + /* test for gdm magic numbers */ + UBYTE id[4]; + + _mm_fseek(modreader,0x00,SEEK_SET); + if (!_mm_read_UBYTES(id,4,modreader)) + return 0; + if (!memcmp(id,"GDM\xfe",4)) { + _mm_fseek(modreader,71,SEEK_SET); + if (!_mm_read_UBYTES(id,4,modreader)) + return 0; + if (!memcmp(id,"GMFS",4)) + return 1; + } + return 0; +} + +int GDM_Init(void) +{ + if (!(gdmbuf=(GDMNOTE*)MikMod_malloc(32*64*sizeof(GDMNOTE)))) return 0; + if (!(mh=(GDMHEADER*)MikMod_malloc(sizeof(GDMHEADER)))) return 0; + + return 1; +} + +void GDM_Cleanup(void) +{ + MikMod_free(mh); + MikMod_free(gdmbuf); +} + +int GDM_ReadPattern(void) +{ + int pos,flag,ch,i,maxch; + GDMNOTE n; + UWORD length,x=0; + + /* get pattern length */ + length=_mm_read_I_UWORD(modreader)-2; + + /* clear pattern data */ + memset(gdmbuf,255,32*64*sizeof(GDMNOTE)); + pos=0; + maxch=0; + + while (x<length) { + memset(&n,255,sizeof(GDMNOTE)); + flag=_mm_read_UBYTE(modreader); + x++; + + if (_mm_eof(modreader)) { + _mm_errno=MMERR_LOADING_PATTERN; + return 0; + } + + ch=flag&31; + if (ch>maxch) maxch=ch; + if (!flag) { + pos++; + continue; + } + if (flag&0x60) { + if (flag&0x20) { + /* new note */ + n.note=_mm_read_UBYTE(modreader)&127; + n.samp=_mm_read_UBYTE(modreader); + x +=2; + } + if (flag&0x40) { + do { + /* effect channel set */ + i=_mm_read_UBYTE(modreader); + n.effect[i>>6].effect=i&31; + n.effect[i>>6].param=_mm_read_UBYTE(modreader); + x +=2; + } while (i&32); + } + memcpy(gdmbuf+(64U*ch)+pos,&n,sizeof(GDMNOTE)); + } + } + return 1; +} + +UBYTE *GDM_ConvertTrack(GDMNOTE*tr) +{ + int t,i=0; + UBYTE note,ins,inf; + + UniReset(); + for (t=0;t<64;t++) { + note=tr[t].note; + ins=tr[t].samp; + + if ((ins)&&(ins!=255)) + UniInstrument(ins-1); + if (note!=255) { + UniNote(((note>>4)*OCTAVE)+(note&0xf)-1); + } + for (i=0;i<4;i++) { + inf = tr[t].effect[i].param; + switch (tr[t].effect[i].effect) { + case 1: /* toneslide up */ + UniEffect(UNI_S3MEFFECTF,inf); + break; + case 2: /* toneslide down */ + UniEffect(UNI_S3MEFFECTE,inf); + break; + case 3: /* glissando to note */ + UniEffect(UNI_ITEFFECTG,inf); + break; + case 4: /* vibrato */ + UniEffect(UNI_ITEFFECTH,inf); + break; + case 5: /* portamento+volslide */ + UniEffect(UNI_ITEFFECTG,0); + UniEffect(UNI_S3MEFFECTD,inf); + break; + case 6: /* vibrato+volslide */ + UniEffect(UNI_ITEFFECTH,0); + UniEffect(UNI_S3MEFFECTD,inf); + break; + case 7: /* tremolo */ + UniEffect(UNI_S3MEFFECTR,inf); + break; + case 8: /* tremor */ + UniEffect(UNI_S3MEFFECTI,inf); + break; + case 9: /* offset */ + UniPTEffect(0x09,inf); + break; + case 0x0a: /* volslide */ + UniEffect(UNI_S3MEFFECTD,inf); + break; + case 0x0b: /* jump to order */ + UniPTEffect(0x0b,inf); + break; + case 0x0c: /* volume set */ + UniPTEffect(0x0c,inf); + break; + case 0x0d: /* pattern break */ + UniPTEffect(0x0d,inf); + break; + case 0x0e: /* extended */ + switch (inf&0xf0) { + case 0x10: /* fine portamento up */ + UniEffect(UNI_S3MEFFECTF, 0x0f|((inf<<4)&0x0f)); + break; + case 0x20: /* fine portamento down */ + UniEffect(UNI_S3MEFFECTE, 0xf0|(inf&0x0f)); + break; + case 0x30: /* glissando control */ + UniEffect(SS_GLISSANDO, inf&0x0f); + break; + case 0x40: /* vibrato waveform */ + UniEffect(SS_VIBWAVE, inf&0x0f); + break; + case 0x50: /* set c4spd */ + UniEffect(SS_FINETUNE, inf&0x0f); + break; + case 0x60: /* loop fun */ + UniEffect(UNI_ITEFFECTS0, (inf&0x0f)|0xb0); + break; + case 0x70: /* tremolo waveform */ + UniEffect(SS_TREMWAVE, inf&0x0f); + break; + case 0x80: /* extra fine porta up */ + UniEffect(UNI_S3MEFFECTF, 0x0e|((inf<<4)&0x0f)); + break; + case 0x90: /* extra fine porta down */ + UniEffect(UNI_S3MEFFECTE, 0xe0|(inf&0x0f)); + break; + case 0xa0: /* fine volslide up */ + UniEffect(UNI_S3MEFFECTD, 0x0f|((inf<<4)&0x0f)); + break; + case 0xb0: /* fine volslide down */ + UniEffect(UNI_S3MEFFECTE, 0xf0|(inf&0x0f)); + break; + case 0xc0: /* note cut */ + case 0xd0: /* note delay */ + case 0xe0: /* extend row */ + UniPTEffect(0xe,inf); + break; + } + break; + case 0x0f: /* set tempo */ + UniEffect(UNI_S3MEFFECTA,inf); + break; + case 0x10: /* arpeggio */ + UniPTEffect(0x0,inf); + break; + case 0x12: /* retrigger */ + UniEffect(UNI_S3MEFFECTQ,inf); + break; + case 0x13: /* set global volume */ + UniEffect(UNI_XMEFFECTG,inf<<1); + break; + case 0x14: /* fine vibrato */ + UniEffect(UNI_ITEFFECTU,inf); + break; + case 0x1e: /* special */ + switch (inf&0xf0) { + case 8: /* set pan position */ + if (inf >=128) + UniPTEffect(0x08,255); + else + UniPTEffect(0x08,inf<<1); + break; + } + break; + case 0x1f: /* set bpm */ + if (inf >=0x20) + UniEffect(UNI_S3MEFFECTT,inf); + break; + } + } + UniNewline(); + } + return UniDup(); +} + +int GDM_Load(int curious) +{ + int i,x,u,track; + SAMPLE *q; + GDMSAMPLE s; + ULONG position; + + /* read header */ + _mm_read_string(mh->id1,4,modreader); + _mm_read_string(mh->songname,32,modreader); + _mm_read_string(mh->author,32,modreader); + _mm_read_string(mh->eofmarker,3,modreader); + _mm_read_string(mh->id2,4,modreader); + + mh->majorver=_mm_read_UBYTE(modreader); + mh->minorver=_mm_read_UBYTE(modreader); + mh->trackerid=_mm_read_I_UWORD(modreader); + mh->t_majorver=_mm_read_UBYTE(modreader); + mh->t_minorver=_mm_read_UBYTE(modreader); + _mm_read_UBYTES(mh->pantable,32,modreader); + mh->mastervol=_mm_read_UBYTE(modreader); + mh->mastertempo=_mm_read_UBYTE(modreader); + mh->masterbpm=_mm_read_UBYTE(modreader); + mh->flags=_mm_read_I_UWORD(modreader); + + mh->orderloc=_mm_read_I_ULONG(modreader); + mh->ordernum=_mm_read_UBYTE(modreader); + mh->patternloc=_mm_read_I_ULONG(modreader); + mh->patternnum=_mm_read_UBYTE(modreader); + mh->samhead=_mm_read_I_ULONG(modreader); + mh->samdata=_mm_read_I_ULONG(modreader); + mh->samnum=_mm_read_UBYTE(modreader); + mh->messageloc=_mm_read_I_ULONG(modreader); + mh->messagelen=_mm_read_I_ULONG(modreader); + mh->scrollyloc=_mm_read_I_ULONG(modreader); + mh->scrollylen=_mm_read_I_UWORD(modreader); + mh->graphicloc=_mm_read_I_ULONG(modreader); + mh->graphiclen=_mm_read_I_UWORD(modreader); + + /* have we ended abruptly? */ + if (_mm_eof(modreader)) { + _mm_errno=MMERR_LOADING_HEADER; + return 0; + } + + /* any orders? */ + if(mh->ordernum==255) { + _mm_errno=MMERR_LOADING_PATTERN; + return 0; + } + + /* now we fill */ + of.modtype=StrDup(GDM_Version); + of.modtype[18]=mh->majorver+'0'; + of.modtype[20]=mh->minorver/10+'0'; + of.modtype[21]=mh->minorver%10+'0'; + of.songname=DupStr(mh->songname,32,0); + of.numpat=mh->patternnum+1; + of.reppos=0; + of.numins=of.numsmp=mh->samnum+1; + of.initspeed=mh->mastertempo; + of.inittempo=mh->masterbpm; + of.initvolume=mh->mastervol<<1; + of.flags|=UF_S3MSLIDES | 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; + + /* read the order data */ + if (!AllocPositions(mh->ordernum+1)) { + _mm_errno=MMERR_OUT_OF_MEMORY; + return 0; + } + + _mm_fseek(modreader,mh->orderloc,SEEK_SET); + for (i=0;i<mh->ordernum+1;i++) + of.positions[i]=_mm_read_UBYTE(modreader); + + of.numpos=0; + for (i=0;i<mh->ordernum+1;i++) { + int order=of.positions[i]; + if(order==255) order=LAST_PATTERN; + of.positions[of.numpos]=order; + if (of.positions[i]<254) of.numpos++; + } + + /* have we ended abruptly yet? */ + if (_mm_eof(modreader)) { + _mm_errno=MMERR_LOADING_HEADER; + return 0; + } + + /* time to load the samples */ + if (!AllocSamples()) { + _mm_errno=MMERR_OUT_OF_MEMORY; + return 0; + } + + q=of.samples; + position=mh->samdata; + + /* seek to instrument position */ + _mm_fseek(modreader,mh->samhead,SEEK_SET); + + for (i=0;i<of.numins;i++) { + /* load sample info */ + _mm_read_UBYTES(s.sampname,32,modreader); + _mm_read_UBYTES(s.filename,12,modreader); + s.ems=_mm_read_UBYTE(modreader); + s.length=_mm_read_I_ULONG(modreader); + s.loopbeg=_mm_read_I_ULONG(modreader); + s.loopend=_mm_read_I_ULONG(modreader); + s.flags=_mm_read_UBYTE(modreader); + s.c4spd=_mm_read_I_UWORD(modreader); + s.vol=_mm_read_UBYTE(modreader); + s.pan=_mm_read_UBYTE(modreader); + + if (_mm_eof(modreader)) { + _mm_errno=MMERR_LOADING_SAMPLEINFO; + return 0; + } + q->samplename=DupStr(s.sampname,32,0); + q->speed=s.c4spd; + q->length=s.length; + q->loopstart=s.loopbeg; + q->loopend=s.loopend; + q->volume=s.vol; + q->panning=s.pan; + q->seekpos=position; + + position +=s.length; + + if (s.flags&1) + q->flags |=SF_LOOP; + if (s.flags&2) + q->flags |=SF_16BITS; + if (s.flags&16) + q->flags |=SF_STEREO; + q++; + } + + /* set the panning */ + for (i=x=0;i<32;i++) { + of.panning[i]=mh->pantable[i]; + if (!of.panning[i]) + of.panning[i]=PAN_LEFT; + else if (of.panning[i]==8) + of.panning[i]=PAN_CENTER; + else if (of.panning[i]==15) + of.panning[i]=PAN_RIGHT; + else if (of.panning[i]==16) + of.panning[i]=PAN_SURROUND; + else if (of.panning[i]==255) + of.panning[i]=128; + else + of.panning[i]<<=3; + if (mh->pantable[i]!=255) + x=i; + } + + of.numchn=x+1; + if (of.numchn<1) + of.numchn=1; /* for broken counts */ + + /* load the pattern info */ + of.numtrk=of.numpat*of.numchn; + + /* jump to patterns */ + _mm_fseek(modreader,mh->patternloc,SEEK_SET); + + if (!AllocTracks()) { + _mm_errno=MMERR_OUT_OF_MEMORY; + return 0; + } + + if (!AllocPatterns()) { + _mm_errno=MMERR_OUT_OF_MEMORY; + return 0; + } + + for (i=track=0;i<of.numpat;i++) { + if (!GDM_ReadPattern()) { + _mm_errno=MMERR_LOADING_PATTERN; + return 0; + } + for (u=0;u<of.numchn;u++,track++) { + of.tracks[track]=GDM_ConvertTrack(&gdmbuf[u<<6]); + if (!of.tracks[track]) { + _mm_errno=MMERR_LOADING_TRACK; + return 0; + } + } + } + return 1; +} + +CHAR *GDM_LoadTitle(void) +{ + CHAR s[32]; + + _mm_fseek(modreader,4,SEEK_SET); + if (!_mm_read_UBYTES(s,32,modreader)) return NULL; + + return DupStr(s,28,0); +} + +MIKMODAPI MLOADER load_gdm= +{ + NULL, + "GDM", + "GDM (General DigiMusic)", + GDM_Init, + GDM_Test, + GDM_Load, + GDM_Cleanup, + GDM_LoadTitle +}; + +/* ex:set ts=4: */ |