summaryrefslogtreecommitdiffstats
path: root/apps/plugins/mikmod
diff options
context:
space:
mode:
authorFrank Gevaerts <frank@gevaerts.be>2010-12-12 15:03:30 +0000
committerFrank Gevaerts <frank@gevaerts.be>2010-12-12 15:03:30 +0000
commit26f2bfde03420edad4de1f22cb3d515dc063b20d (patch)
tree4a8c4abaf4795f38da70a4657c1a0fb3ba9debeb /apps/plugins/mikmod
parentd192bdf11e06e50645ecb5726658d4b691480a9a (diff)
downloadrockbox-26f2bfde03420edad4de1f22cb3d515dc063b20d.tar.gz
rockbox-26f2bfde03420edad4de1f22cb3d515dc063b20d.tar.bz2
rockbox-26f2bfde03420edad4de1f22cb3d515dc063b20d.zip
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')
-rw-r--r--apps/plugins/mikmod/SOURCES39
-rw-r--r--apps/plugins/mikmod/drv_nos.c107
-rw-r--r--apps/plugins/mikmod/load_669.c368
-rw-r--r--apps/plugins/mikmod/load_amf.c569
-rw-r--r--apps/plugins/mikmod/load_asy.c398
-rw-r--r--apps/plugins/mikmod/load_dsm.c364
-rw-r--r--apps/plugins/mikmod/load_far.c346
-rw-r--r--apps/plugins/mikmod/load_gdm.c558
-rw-r--r--apps/plugins/mikmod/load_gt2.c374
-rw-r--r--apps/plugins/mikmod/load_imf.c738
-rw-r--r--apps/plugins/mikmod/load_it.c1013
-rw-r--r--apps/plugins/mikmod/load_m15.c505
-rw-r--r--apps/plugins/mikmod/load_med.c719
-rw-r--r--apps/plugins/mikmod/load_mod.c512
-rw-r--r--apps/plugins/mikmod/load_mtm.c285
-rw-r--r--apps/plugins/mikmod/load_okt.c460
-rw-r--r--apps/plugins/mikmod/load_s3m.c470
-rw-r--r--apps/plugins/mikmod/load_stm.c374
-rw-r--r--apps/plugins/mikmod/load_stx.c439
-rw-r--r--apps/plugins/mikmod/load_ult.c339
-rw-r--r--apps/plugins/mikmod/load_uni.c717
-rw-r--r--apps/plugins/mikmod/load_xm.c829
-rw-r--r--apps/plugins/mikmod/mdreg.c131
-rw-r--r--apps/plugins/mikmod/mdriver.c965
-rw-r--r--apps/plugins/mikmod/mikmod.c943
-rw-r--r--apps/plugins/mikmod/mikmod.h783
-rw-r--r--apps/plugins/mikmod/mikmod.make33
-rw-r--r--apps/plugins/mikmod/mikmod_internals.h806
-rw-r--r--apps/plugins/mikmod/mikmod_supp.h79
-rw-r--r--apps/plugins/mikmod/mloader.c615
-rw-r--r--apps/plugins/mikmod/mlreg.c66
-rw-r--r--apps/plugins/mikmod/mlutil.c336
-rw-r--r--apps/plugins/mikmod/mmalloc.c179
-rw-r--r--apps/plugins/mikmod/mmerror.c213
-rw-r--r--apps/plugins/mikmod/mmio.c517
-rw-r--r--apps/plugins/mikmod/mplayer.c3409
-rw-r--r--apps/plugins/mikmod/munitrk.c303
-rw-r--r--apps/plugins/mikmod/npertab.c48
-rw-r--r--apps/plugins/mikmod/sloader.c519
-rw-r--r--apps/plugins/mikmod/strdup.c23
-rw-r--r--apps/plugins/mikmod/strstr.c21
-rw-r--r--apps/plugins/mikmod/virtch.c1319
-rw-r--r--apps/plugins/mikmod/virtch_common.c464
43 files changed, 22295 insertions, 0 deletions
diff --git a/apps/plugins/mikmod/SOURCES b/apps/plugins/mikmod/SOURCES
new file mode 100644
index 0000000000..1de5bb2149
--- /dev/null
+++ b/apps/plugins/mikmod/SOURCES
@@ -0,0 +1,39 @@
+drv_nos.c
+load_669.c
+load_amf.c
+load_asy.c
+load_dsm.c
+load_far.c
+load_gdm.c
+load_gt2.c
+load_imf.c
+load_it.c
+load_m15.c
+load_med.c
+load_mod.c
+load_mtm.c
+load_okt.c
+load_s3m.c
+load_stm.c
+load_stx.c
+load_ult.c
+load_uni.c
+load_xm.c
+mdreg.c
+mdriver.c
+mloader.c
+mlreg.c
+mlutil.c
+mmalloc.c
+mmerror.c
+mmio.c
+mplayer.c
+munitrk.c
+npertab.c
+sloader.c
+strdup.c
+strstr.c
+virtch.c
+virtch_common.c
+mikmod.c
+
diff --git a/apps/plugins/mikmod/drv_nos.c b/apps/plugins/mikmod/drv_nos.c
new file mode 100644
index 0000000000..08d70466d1
--- /dev/null
+++ b/apps/plugins/mikmod/drv_nos.c
@@ -0,0 +1,107 @@
+/* MikMod sound library
+ (c) 1998, 1999, 2000 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: drv_nos.c,v 1.2 2005/03/30 19:09:11 realtech Exp $
+
+ Driver for no output
+
+==============================================================================*/
+
+/*
+
+ Written by Jean-Paul Mikkers <mikmak@via.nl>
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "mikmod_internals.h"
+
+#define ZEROLEN 32768
+
+//static SBYTE *zerobuf=NULL;
+
+static int NS_IsThere(void)
+{
+ return 1;
+}
+
+static int NS_Init(void)
+{
+ //zerobuf=(SBYTE*)MikMod_malloc(ZEROLEN);
+ return VC_Init();
+}
+
+static void NS_Exit(void)
+{
+ VC_Exit();
+ //MikMod_free(zerobuf);
+}
+
+static void NS_Update(void)
+{
+ //if (zerobuf)
+ // VC_WriteBytes(zerobuf,ZEROLEN);
+}
+
+MIKMODAPI MDRIVER drv_nos={
+ NULL,
+ "No Sound",
+ "Nosound Driver v3.0",
+ 255,255,
+ "nosound",
+ NULL,
+ NULL,
+ NS_IsThere,
+ VC_SampleLoad,
+ VC_SampleUnload,
+ VC_SampleSpace,
+ VC_SampleLength,
+ NS_Init,
+ NS_Exit,
+ NULL,
+ VC_SetNumVoices,
+ VC_PlayStart,
+ VC_PlayStop,
+ NS_Update,
+ NULL,
+ VC_VoiceSetVolume,
+ VC_VoiceGetVolume,
+ VC_VoiceSetFrequency,
+ VC_VoiceGetFrequency,
+ VC_VoiceSetPanning,
+ VC_VoiceGetPanning,
+ VC_VoicePlay,
+ VC_VoiceStop,
+ VC_VoiceStopped,
+ VC_VoiceGetPosition,
+ VC_VoiceRealVolume
+};
+
+
+/* ex:set ts=4: */
diff --git a/apps/plugins/mikmod/load_669.c b/apps/plugins/mikmod/load_669.c
new file mode 100644
index 0000000000..95b04aa5b1
--- /dev/null
+++ b/apps/plugins/mikmod/load_669.c
@@ -0,0 +1,368 @@
+/* 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_669.c,v 1.3 2005/04/07 19:57:38 realtech Exp $
+
+ Composer 669 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 */
+
+/* header */
+typedef struct S69HEADER {
+ UBYTE marker[2];
+ CHAR message[108];
+ UBYTE nos;
+ UBYTE rbnop;
+ UBYTE looporder;
+ UBYTE orders[0x80];
+ UBYTE tempos[0x80];
+ UBYTE breaks[0x80];
+} S69HEADER;
+
+/* sample information */
+typedef struct S69SAMPLE {
+ CHAR filename[13];
+ SLONG length;
+ SLONG loopbeg;
+ SLONG loopend;
+} S69SAMPLE;
+
+/* encoded note */
+typedef struct S69NOTE {
+ UBYTE a,b,c;
+} S69NOTE;
+
+/*========== Loader variables */
+
+/* current pattern */
+static S69NOTE* s69pat=NULL;
+/* Module header */
+static S69HEADER* mh=NULL;
+
+/* file type identification */
+static CHAR* S69_Version[]={
+ "Composer 669",
+ "Extended 669"
+};
+
+/*========== Loader code */
+
+int S69_Test(void)
+{
+ UBYTE buf[0x80];
+
+ if(!_mm_read_UBYTES(buf,2,modreader))
+ return 0;
+ /* look for id */
+ if(!memcmp(buf,"if",2) || !memcmp(buf,"JN",2)) {
+ int i;
+
+ /* skip song message */
+ _mm_fseek(modreader,108,SEEK_CUR);
+ /* sanity checks */
+ if(_mm_read_UBYTE(modreader) > 64) return 0;
+ if(_mm_read_UBYTE(modreader) > 128) return 0;
+ if(_mm_read_UBYTE(modreader) > 127) return 0;
+ /* check order table */
+ if(!_mm_read_UBYTES(buf,0x80,modreader)) return 0;
+ for(i=0;i<0x80;i++)
+ if((buf[i]>=0x80)&&(buf[i]!=0xff)) return 0;
+ /* check tempos table */
+ if(!_mm_read_UBYTES(buf,0x80,modreader)) return 0;
+ for(i=0;i<0x80;i++)
+ if((!buf[i])||(buf[i]>32)) return 0;
+ /* check pattern length table */
+ if(!_mm_read_UBYTES(buf,0x80,modreader)) return 0;
+ for(i=0;i<0x80;i++)
+ if(buf[i]>0x3f) return 0;
+ } else
+ return 0;
+
+ return 1;
+}
+
+int S69_Init(void)
+{
+ if(!(s69pat=(S69NOTE *)MikMod_malloc(64*8*sizeof(S69NOTE)))) return 0;
+ if(!(mh=(S69HEADER *)MikMod_malloc(sizeof(S69HEADER)))) return 0;
+
+ return 1;
+}
+
+void S69_Cleanup(void)
+{
+ MikMod_free(s69pat);
+ MikMod_free(mh);
+}
+
+static int S69_LoadPatterns(void)
+{
+ int track,row,channel;
+ UBYTE note,inst,vol,effect,lastfx,lastval;
+ S69NOTE *cur;
+ int tracks=0;
+
+ if(!AllocPatterns()) return 0;
+ if(!AllocTracks()) return 0;
+
+ for(track=0;track<of.numpat;track++) {
+ /* set pattern break locations */
+ of.pattrows[track]=mh->breaks[track]+1;
+
+ /* load the 669 pattern */
+ cur=s69pat;
+ for(row=0;row<64;row++) {
+ for(channel=0;channel<8;channel++,cur++) {
+ cur->a = _mm_read_UBYTE(modreader);
+ cur->b = _mm_read_UBYTE(modreader);
+ cur->c = _mm_read_UBYTE(modreader);
+ }
+ }
+
+ if(_mm_eof(modreader)) {
+ _mm_errno = MMERR_LOADING_PATTERN;
+ return 0;
+ }
+
+ /* translate the pattern */
+ for(channel=0;channel<8;channel++) {
+ UniReset();
+ /* set pattern tempo */
+ UniPTEffect(0xf,78);
+ UniPTEffect(0xf,mh->tempos[track]);
+
+ lastfx=0xff,lastval=0;
+
+ for(row=0;row<=mh->breaks[track];row++) {
+ int a,b,c;
+
+ /* fetch the encoded note */
+ a=s69pat[(row*8)+channel].a;
+ b=s69pat[(row*8)+channel].b;
+ c=s69pat[(row*8)+channel].c;
+
+ /* decode it */
+ note=a>>2;
+ inst=((a&0x3)<<4)|((b&0xf0)>>4);
+ vol=b&0xf;
+
+ if (a<0xff) {
+ if (a<0xfe) {
+ UniInstrument(inst);
+ UniNote(note+2*OCTAVE);
+ lastfx=0xff; /* reset background effect memory */
+ }
+ UniPTEffect(0xc,vol<<2);
+ }
+
+ if ((c!=0xff)||(lastfx!=0xff)) {
+ if(c==0xff)
+ c=lastfx,effect=lastval;
+ else
+ effect=c&0xf;
+
+ switch(c>>4) {
+ case 0: /* porta up */
+ UniPTEffect(0x1,effect);
+ lastfx=c,lastval=effect;
+ break;
+ case 1: /* porta down */
+ UniPTEffect(0x2,effect);
+ lastfx=c,lastval=effect;
+ break;
+ case 2: /* porta to note */
+ UniPTEffect(0x3,effect);
+ lastfx=c,lastval=effect;
+ break;
+ case 3: /* frequency adjust */
+ /* DMP converts this effect to S3M FF1. Why not ? */
+ UniEffect(UNI_S3MEFFECTF,0xf0|effect);
+ break;
+ case 4: /* vibrato */
+ UniPTEffect(0x4,effect);
+ lastfx=c,lastval=effect;
+ break;
+ case 5: /* set speed */
+ if (effect)
+ UniPTEffect(0xf,effect);
+ else
+ if(mh->marker[0]!=0x69) {
+#ifdef MIKMOD_DEBUG
+ fprintf(stderr,"\r669: unsupported super fast tempo at pat=%d row=%d chan=%d\n",
+ track,row,channel);
+#endif
+ }
+ break;
+ }
+ }
+ UniNewline();
+ }
+ if(!(of.tracks[tracks++]=UniDup())) return 0;
+ }
+ }
+
+ return 1;
+}
+
+int S69_Load(int curious)
+{
+ int i;
+ SAMPLE *current;
+ S69SAMPLE sample;
+
+ /* module header */
+ _mm_read_UBYTES(mh->marker,2,modreader);
+ _mm_read_UBYTES(mh->message,108,modreader);
+ mh->nos=_mm_read_UBYTE(modreader);
+ mh->rbnop=_mm_read_UBYTE(modreader);
+ mh->looporder=_mm_read_UBYTE(modreader);
+ _mm_read_UBYTES(mh->orders,0x80,modreader);
+ for(i=0;i<0x80;i++)
+ if ((mh->orders[i]>=0x80)&&(mh->orders[i]!=0xff)) {
+ _mm_errno=MMERR_NOT_A_MODULE;
+ return 1;
+ }
+ _mm_read_UBYTES(mh->tempos,0x80,modreader);
+ for(i=0;i<0x80;i++)
+ if ((!mh->tempos[i])||(mh->tempos[i]>32)) {
+ _mm_errno=MMERR_NOT_A_MODULE;
+ return 1;
+ }
+ _mm_read_UBYTES(mh->breaks,0x80,modreader);
+ for(i=0;i<0x80;i++)
+ if (mh->breaks[i]>0x3f) {
+ _mm_errno=MMERR_NOT_A_MODULE;
+ return 1;
+ }
+
+ /* set module variables */
+ of.initspeed=4;
+ of.inittempo=78;
+ of.songname=DupStr(mh->message,36,1);
+ of.modtype=StrDup(S69_Version[memcmp(mh->marker,"JN",2)==0]);
+ of.numchn=8;
+ of.numpat=mh->rbnop;
+ of.numins=of.numsmp=mh->nos;
+ of.numtrk=of.numchn*of.numpat;
+ of.flags=UF_XMPERIODS|UF_LINEAR;
+
+ for(i= 35;(i>= 0)&&(mh->message[i]==' ');i--) mh->message[i]=0;
+ for(i=36+35;(i>=36+0)&&(mh->message[i]==' ');i--) mh->message[i]=0;
+ for(i=72+35;(i>=72+0)&&(mh->message[i]==' ');i--) mh->message[i]=0;
+ if((mh->message[0])||(mh->message[36])||(mh->message[72]))
+ if((of.comment=(CHAR*)MikMod_malloc(3*(36+1)+1))) {
+ strncpy(of.comment,mh->message,36);
+ strcat(of.comment,"\r");
+ if (mh->message[36]) strncat(of.comment,mh->message+36,36);
+ strcat(of.comment,"\r");
+ if (mh->message[72]) strncat(of.comment,mh->message+72,36);
+ strcat(of.comment,"\r");
+ of.comment[3*(36+1)]=0;
+ }
+
+ if(!AllocPositions(0x80)) return 0;
+ for(i=0;i<0x80;i++) {
+ if(mh->orders[i]>=mh->rbnop) break;
+ of.positions[i]=mh->orders[i];
+ }
+ of.numpos=i;
+ of.reppos=mh->looporder<of.numpos?mh->looporder:0;
+
+ if(!AllocSamples()) return 0;
+ current=of.samples;
+
+ for(i=0;i<of.numins;i++) {
+ /* sample information */
+ _mm_read_UBYTES((UBYTE*)sample.filename,13,modreader);
+ sample.length=_mm_read_I_SLONG(modreader);
+ sample.loopbeg=_mm_read_I_SLONG(modreader);
+ sample.loopend=_mm_read_I_SLONG(modreader);
+ if (sample.loopend==0xfffff) sample.loopend=0;
+
+ if((sample.length<0)||(sample.loopbeg<-1)||(sample.loopend<-1)) {
+ _mm_errno = MMERR_LOADING_HEADER;
+ return 0;
+ }
+
+ current->samplename=DupStr(sample.filename,13,1);
+ current->seekpos=0;
+ current->speed=0;
+ current->length=sample.length;
+ current->loopstart=sample.loopbeg;
+ current->loopend=sample.loopend;
+ current->flags=(sample.loopbeg<sample.loopend)?SF_LOOP:0;
+ current->volume=64;
+
+ current++;
+ }
+
+ if(!S69_LoadPatterns()) return 0;
+
+ return 1;
+}
+
+CHAR *S69_LoadTitle(void)
+{
+ CHAR s[36];
+
+ _mm_fseek(modreader,2,SEEK_SET);
+ if(!_mm_read_UBYTES(s,36,modreader)) return NULL;
+
+ return(DupStr(s,36,1));
+}
+
+/*========== Loader information */
+
+MIKMODAPI MLOADER load_669={
+ NULL,
+ "669",
+ "669 (Composer 669, Unis 669)",
+ S69_Init,
+ S69_Test,
+ S69_Load,
+ S69_Cleanup,
+ S69_LoadTitle
+};
+
+/* ex:set ts=4: */
diff --git a/apps/plugins/mikmod/load_amf.c b/apps/plugins/mikmod/load_amf.c
new file mode 100644
index 0000000000..12e0af0738
--- /dev/null
+++ b/apps/plugins/mikmod/load_amf.c
@@ -0,0 +1,569 @@
+/* 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_amf.c,v 1.3 2005/04/07 19:57:38 realtech Exp $
+
+ DMP Advanced Module Format 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 */
+
+typedef struct AMFHEADER {
+ UBYTE id[3]; /* AMF file marker */
+ UBYTE version; /* upper major, lower nibble minor version number */
+ CHAR songname[32]; /* ASCIIZ songname */
+ UBYTE numsamples; /* number of samples saved */
+ UBYTE numorders;
+ UWORD numtracks; /* number of tracks saved */
+ UBYTE numchannels; /* number of channels used */
+ SBYTE panpos[32]; /* voice pan positions */
+ UBYTE songbpm;
+ UBYTE songspd;
+} AMFHEADER;
+
+typedef struct AMFSAMPLE {
+ UBYTE type;
+ CHAR samplename[32];
+ CHAR filename[13];
+ ULONG offset;
+ ULONG length;
+ UWORD c2spd;
+ UBYTE volume;
+ ULONG reppos;
+ ULONG repend;
+} AMFSAMPLE;
+
+typedef struct AMFNOTE {
+ UBYTE note,instr,volume,fxcnt;
+ UBYTE effect[3];
+ SBYTE parameter[3];
+} AMFNOTE;
+
+/*========== Loader variables */
+
+static AMFHEADER *mh = NULL;
+#define AMFTEXTLEN 22
+static CHAR AMF_Version[AMFTEXTLEN+1] = "DSMI Module Format 0.0";
+static AMFNOTE *track = NULL;
+
+/*========== Loader code */
+
+int AMF_Test(void)
+{
+ UBYTE id[3],ver;
+
+ if(!_mm_read_UBYTES(id,3,modreader)) return 0;
+ if(memcmp(id,"AMF",3)) return 0;
+
+ ver=_mm_read_UBYTE(modreader);
+ if((ver>=10)&&(ver<=14)) return 1;
+ return 0;
+}
+
+int AMF_Init(void)
+{
+ if(!(mh=(AMFHEADER*)MikMod_malloc(sizeof(AMFHEADER)))) return 0;
+ if(!(track=(AMFNOTE*)MikMod_calloc(64,sizeof(AMFNOTE)))) return 0;
+
+ return 1;
+}
+
+void AMF_Cleanup(void)
+{
+ MikMod_free(mh);
+ MikMod_free(track);
+}
+
+static int AMF_UnpackTrack(MREADER* modreader)
+{
+ ULONG tracksize;
+ UBYTE row,cmd;
+ SBYTE arg;
+
+ /* empty track */
+ memset(track,0,64*sizeof(AMFNOTE));
+
+ /* read packed track */
+ if (modreader) {
+ tracksize=_mm_read_I_UWORD(modreader);
+ tracksize+=((ULONG)_mm_read_UBYTE(modreader))<<16;
+ if (tracksize)
+ while(tracksize--) {
+ row=_mm_read_UBYTE(modreader);
+ cmd=_mm_read_UBYTE(modreader);
+ arg=_mm_read_SBYTE(modreader);
+ /* unexpected end of track */
+ if(!tracksize) {
+ if((row==0xff)&&(cmd==0xff)&&(arg==-1))
+ break;
+ /* the last triplet should be FF FF FF, but this is not
+ always the case... maybe a bug in m2amf ?
+ else
+ return 0;
+ */
+
+ }
+ /* invalid row (probably unexpected end of row) */
+ if (row>=64)
+ return 0;
+ if (cmd<0x7f) {
+ /* note, vol */
+ track[row].note=cmd;
+ track[row].volume=(UBYTE)arg+1;
+ } else
+ if (cmd==0x7f) {
+ /* duplicate row */
+ if ((arg<0)&&(row+arg>=0)) {
+ memcpy(track+row,track+(row+arg),sizeof(AMFNOTE));
+ }
+ } else
+ if (cmd==0x80) {
+ /* instr */
+ track[row].instr=arg+1;
+ } else
+ if (cmd==0x83) {
+ /* volume without note */
+ track[row].volume=(UBYTE)arg+1;
+ } else
+ if (cmd==0xff) {
+ /* apparently, some M2AMF version fail to estimate the
+ size of the compressed patterns correctly, and end
+ up with blanks, i.e. dead triplets. Those are marked
+ with cmd == 0xff. Let's ignore them. */
+ } else
+ if(track[row].fxcnt<3) {
+ /* effect, param */
+ if(cmd>0x97)
+ return 0;
+ track[row].effect[track[row].fxcnt]=cmd&0x7f;
+ track[row].parameter[track[row].fxcnt]=arg;
+ track[row].fxcnt++;
+ } else
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static UBYTE* AMF_ConvertTrack(void)
+{
+ int row,fx4memory=0;
+
+ /* convert track */
+ UniReset();
+ for (row=0;row<64;row++) {
+ if (track[row].instr) UniInstrument(track[row].instr-1);
+ if (track[row].note>OCTAVE) UniNote(track[row].note-OCTAVE);
+
+ /* AMF effects */
+ while(track[row].fxcnt--) {
+ SBYTE inf=track[row].parameter[track[row].fxcnt];
+
+ switch(track[row].effect[track[row].fxcnt]) {
+ case 1: /* Set speed */
+ UniEffect(UNI_S3MEFFECTA,inf);
+ break;
+ case 2: /* Volume slide */
+ if(inf) {
+ UniWriteByte(UNI_S3MEFFECTD);
+ if (inf>=0)
+ UniWriteByte((inf&0xf)<<4);
+ else
+ UniWriteByte((-inf)&0xf);
+ }
+ break;
+ /* effect 3, set channel volume, done in UnpackTrack */
+ case 4: /* Porta up/down */
+ if(inf) {
+ if(inf>0) {
+ UniEffect(UNI_S3MEFFECTE,inf);
+ fx4memory=UNI_S3MEFFECTE;
+ } else {
+ UniEffect(UNI_S3MEFFECTF,-inf);
+ fx4memory=UNI_S3MEFFECTF;
+ }
+ } else if(fx4memory)
+ UniEffect(fx4memory,0);
+ break;
+ /* effect 5, "Porta abs", not supported */
+ case 6: /* Porta to note */
+ UniEffect(UNI_ITEFFECTG,inf);
+ break;
+ case 7: /* Tremor */
+ UniEffect(UNI_S3MEFFECTI,inf);
+ break;
+ case 8: /* Arpeggio */
+ UniPTEffect(0x0,inf);
+ break;
+ case 9: /* Vibrato */
+ UniPTEffect(0x4,inf);
+ break;
+ case 0xa: /* Porta + Volume slide */
+ UniPTEffect(0x3,0);
+ if(inf) {
+ UniWriteByte(UNI_S3MEFFECTD);
+ if (inf>=0)
+ UniWriteByte((inf&0xf)<<4);
+ else
+ UniWriteByte((-inf)&0xf);
+ }
+ break;
+ case 0xb: /* Vibrato + Volume slide */
+ UniPTEffect(0x4,0);
+ if(inf) {
+ UniWriteByte(UNI_S3MEFFECTD);
+ if (inf>=0)
+ UniWriteByte((inf&0xf)<<4);
+ else
+ UniWriteByte((-inf)&0xf);
+ }
+ break;
+ case 0xc: /* Pattern break (in hex) */
+ UniPTEffect(0xd,inf);
+ break;
+ case 0xd: /* Pattern jump */
+ UniPTEffect(0xb,inf);
+ break;
+ /* effect 0xe, "Sync", not supported */
+ case 0xf: /* Retrig */
+ UniEffect(UNI_S3MEFFECTQ,inf&0xf);
+ break;
+ case 0x10: /* Sample offset */
+ UniPTEffect(0x9,inf);
+ break;
+ case 0x11: /* Fine volume slide */
+ if(inf) {
+ UniWriteByte(UNI_S3MEFFECTD);
+ if (inf>=0)
+ UniWriteByte((inf&0xf)<<4|0xf);
+ else
+ UniWriteByte(0xf0|((-inf)&0xf));
+ }
+ break;
+ case 0x12: /* Fine portamento */
+ if(inf) {
+ if(inf>0) {
+ UniEffect(UNI_S3MEFFECTE,0xf0|(inf&0xf));
+ fx4memory=UNI_S3MEFFECTE;
+ } else {
+ UniEffect(UNI_S3MEFFECTF,0xf0|((-inf)&0xf));
+ fx4memory=UNI_S3MEFFECTF;
+ }
+ } else if(fx4memory)
+ UniEffect(fx4memory,0);
+ break;
+ case 0x13: /* Delay note */
+ UniPTEffect(0xe,0xd0|(inf&0xf));
+ break;
+ case 0x14: /* Note cut */
+ UniPTEffect(0xc,0);
+ track[row].volume=0;
+ break;
+ case 0x15: /* Set tempo */
+ UniEffect(UNI_S3MEFFECTT,inf);
+ break;
+ case 0x16: /* Extra fine portamento */
+ if(inf) {
+ if(inf>0) {
+ UniEffect(UNI_S3MEFFECTE,0xe0|((inf>>2)&0xf));
+ fx4memory=UNI_S3MEFFECTE;
+ } else {
+ UniEffect(UNI_S3MEFFECTF,0xe0|(((-inf)>>2)&0xf));
+ fx4memory=UNI_S3MEFFECTF;
+ }
+ } else if(fx4memory)
+ UniEffect(fx4memory,0);
+ break;
+ case 0x17: /* Panning */
+ if (inf>64)
+ UniEffect(UNI_ITEFFECTS0,0x91); /* surround */
+ else
+ UniPTEffect(0x8,(inf==64)?255:(inf+64)<<1);
+ of.flags |= UF_PANNING;
+ break;
+ }
+
+ }
+ if (track[row].volume) UniVolEffect(VOL_VOLUME,track[row].volume-1);
+ UniNewline();
+ }
+ return UniDup();
+}
+
+int AMF_Load(int curious)
+{
+ int t,u,realtrackcnt,realsmpcnt,defaultpanning;
+ AMFSAMPLE s;
+ SAMPLE *q;
+ UWORD *track_remap;
+ ULONG samplepos;
+ int channel_remap[16];
+
+ /* try to read module header */
+ _mm_read_UBYTES(mh->id,3,modreader);
+ mh->version =_mm_read_UBYTE(modreader);
+ _mm_read_string(mh->songname,32,modreader);
+ mh->numsamples =_mm_read_UBYTE(modreader);
+ mh->numorders =_mm_read_UBYTE(modreader);
+ mh->numtracks =_mm_read_I_UWORD(modreader);
+ mh->numchannels =_mm_read_UBYTE(modreader);
+ if((!mh->numchannels)||(mh->numchannels>(mh->version>=12?32:16))) {
+ _mm_errno=MMERR_NOT_A_MODULE;
+ return 0;
+ }
+
+ if(mh->version>=11) {
+ memset(mh->panpos,0,32);
+ _mm_read_SBYTES(mh->panpos,(mh->version>=13)?32:16,modreader);
+ } else
+ _mm_read_UBYTES(channel_remap,16,modreader);
+
+ if (mh->version>=13) {
+ mh->songbpm=_mm_read_UBYTE(modreader);
+ if(mh->songbpm<32) {
+ _mm_errno=MMERR_NOT_A_MODULE;
+ return 0;
+ }
+ mh->songspd=_mm_read_UBYTE(modreader);
+ if(mh->songspd>32) {
+ _mm_errno=MMERR_NOT_A_MODULE;
+ return 0;
+ }
+ } else {
+ mh->songbpm=125;
+ mh->songspd=6;
+ }
+
+ if(_mm_eof(modreader)) {
+ _mm_errno = MMERR_LOADING_HEADER;
+ return 0;
+ }
+
+ /* set module variables */
+ of.initspeed = mh->songspd;
+ of.inittempo = mh->songbpm;
+ AMF_Version[AMFTEXTLEN-3]='0'+(mh->version/10);
+ AMF_Version[AMFTEXTLEN-1]='0'+(mh->version%10);
+ of.modtype = StrDup(AMF_Version);
+ of.numchn = mh->numchannels;
+ of.numtrk = mh->numorders*mh->numchannels;
+ if (mh->numtracks>of.numtrk)
+ of.numtrk=mh->numtracks;
+ of.numtrk++; /* add room for extra, empty track */
+ of.songname = DupStr(mh->songname,32,1);
+ of.numpos = mh->numorders;
+ of.numpat = mh->numorders;
+ of.reppos = 0;
+ of.flags |= UF_S3MSLIDES;
+ /* XXX whenever possible, we should try to determine the original format.
+ Here we assume it was S3M-style wrt bpmlimit... */
+ of.bpmlimit = 32;
+
+ /*
+ * Play with the panning table. Although the AMF format embeds a
+ * panning table, if the module was a MOD or an S3M with default
+ * panning and didn't use any panning commands, don't flag
+ * UF_PANNING, to use our preferred panning table for this case.
+ */
+ defaultpanning = 1;
+ for (t = 0; t < 32; t++) {
+ if (mh->panpos[t] > 64) {
+ of.panning[t] = PAN_SURROUND;
+ defaultpanning = 0;
+ } else
+ if (mh->panpos[t] == 64)
+ of.panning[t] = PAN_RIGHT;
+ else
+ of.panning[t] = (mh->panpos[t] + 64) << 1;
+ }
+ if (defaultpanning) {
+ for (t = 0; t < of.numchn; t++)
+ if (of.panning[t] == (((t + 1) & 2) ? PAN_RIGHT : PAN_LEFT)) {
+ defaultpanning = 0; /* not MOD canonical panning */
+ break;
+ }
+ }
+ if (defaultpanning)
+ of.flags |= UF_PANNING;
+
+ of.numins=of.numsmp=mh->numsamples;
+
+ if(!AllocPositions(of.numpos)) return 0;
+ for(t=0;t<of.numpos;t++)
+ of.positions[t]=t;
+
+ if(!AllocTracks()) return 0;
+ if(!AllocPatterns()) return 0;
+
+ /* read AMF order table */
+ for (t=0;t<of.numpat;t++) {
+ if (mh->version>=14)
+ /* track size */
+ of.pattrows[t]=_mm_read_I_UWORD(modreader);
+ if (mh->version>=10)
+ _mm_read_I_UWORDS(of.patterns+(t*of.numchn),of.numchn,modreader);
+ else
+ for(u=0;u<of.numchn;u++)
+ of.patterns[t*of.numchn+channel_remap[u]]=_mm_read_I_UWORD(modreader);
+ }
+ if(_mm_eof(modreader)) {
+ _mm_errno = MMERR_LOADING_HEADER;
+ return 0;
+ }
+
+ /* read sample information */
+ if(!AllocSamples()) return 0;
+ q=of.samples;
+ for(t=0;t<of.numins;t++) {
+ /* try to read sample info */
+ s.type=_mm_read_UBYTE(modreader);
+ _mm_read_string(s.samplename,32,modreader);
+ _mm_read_string(s.filename,13,modreader);
+ s.offset =_mm_read_I_ULONG(modreader);
+ s.length =_mm_read_I_ULONG(modreader);
+ s.c2spd =_mm_read_I_UWORD(modreader);
+ if(s.c2spd==8368) s.c2spd=8363;
+ s.volume =_mm_read_UBYTE(modreader);
+ if(mh->version>=11) {
+ s.reppos =_mm_read_I_ULONG(modreader);
+ s.repend =_mm_read_I_ULONG(modreader);
+ } else {
+ s.reppos =_mm_read_I_UWORD(modreader);
+ s.repend =s.length;
+ }
+
+ if(_mm_eof(modreader)) {
+ _mm_errno = MMERR_LOADING_SAMPLEINFO;
+ return 0;
+ }
+
+ q->samplename = DupStr(s.samplename,32,1);
+ q->speed = s.c2spd;
+ q->volume = s.volume;
+ if (s.type) {
+ q->seekpos = s.offset;
+ q->length = s.length;
+ q->loopstart = s.reppos;
+ q->loopend = s.repend;
+ if((s.repend-s.reppos)>2) q->flags |= SF_LOOP;
+ }
+ q++;
+ }
+
+ /* read track table */
+ if(!(track_remap=MikMod_calloc(mh->numtracks+1,sizeof(UWORD))))
+ return 0;
+ _mm_read_I_UWORDS(track_remap+1,mh->numtracks,modreader);
+ if(_mm_eof(modreader)) {
+ MikMod_free(track_remap);
+ _mm_errno=MMERR_LOADING_TRACK;
+ return 0;
+ }
+
+ for(realtrackcnt=t=0;t<=mh->numtracks;t++)
+ if (realtrackcnt<track_remap[t])
+ realtrackcnt=track_remap[t];
+ for(t=0;t<of.numpat*of.numchn;t++)
+ of.patterns[t]=(of.patterns[t]<=mh->numtracks)?
+ track_remap[of.patterns[t]]-1:realtrackcnt;
+
+ MikMod_free(track_remap);
+
+ /* unpack tracks */
+ for(t=0;t<realtrackcnt;t++) {
+ if(_mm_eof(modreader)) {
+ _mm_errno = MMERR_LOADING_TRACK;
+ return 0;
+ }
+ if (!AMF_UnpackTrack(modreader)) {
+ _mm_errno = MMERR_LOADING_TRACK;
+ return 0;
+ }
+ if(!(of.tracks[t]=AMF_ConvertTrack()))
+ return 0;
+ }
+ /* add an extra void track */
+ UniReset();
+ for(t=0;t<64;t++) UniNewline();
+ of.tracks[realtrackcnt++]=UniDup();
+ for(t=realtrackcnt;t<of.numtrk;t++) of.tracks[t]=NULL;
+
+ /* compute sample offsets */
+ samplepos=_mm_ftell(modreader);
+ for(realsmpcnt=t=0;t<of.numsmp;t++)
+ if(realsmpcnt<of.samples[t].seekpos)
+ realsmpcnt=of.samples[t].seekpos;
+ for(t=1;t<=realsmpcnt;t++) {
+ q=of.samples;
+ while(q->seekpos!=t) q++;
+ q->seekpos=samplepos;
+ samplepos+=q->length;
+ }
+
+ return 1;
+}
+
+CHAR *AMF_LoadTitle(void)
+{
+ CHAR s[32];
+
+ _mm_fseek(modreader,4,SEEK_SET);
+ if(!_mm_read_UBYTES(s,32,modreader)) return NULL;
+
+ return(DupStr(s,32,1));
+}
+
+/*========== Loader information */
+
+MIKMODAPI MLOADER load_amf={
+ NULL,
+ "AMF",
+ "AMF (DSMI Advanced Module Format)",
+ AMF_Init,
+ AMF_Test,
+ AMF_Load,
+ AMF_Cleanup,
+ AMF_LoadTitle
+};
+
+/* ex:set ts=4: */
diff --git a/apps/plugins/mikmod/load_asy.c b/apps/plugins/mikmod/load_asy.c
new file mode 100644
index 0000000000..356a686d92
--- /dev/null
+++ b/apps/plugins/mikmod/load_asy.c
@@ -0,0 +1,398 @@
+/* MikMod sound library
+ (c) 2004, Raphael Assenat 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_asy.c,v 1.3 2005/04/07 19:57:38 realtech Exp $
+
+ ASYLUM Music Format v1.0 (.amf) loader
+ adapted from load_mod.c by Raphael Assenat <raph@raphnet.net>,
+ with the help of the AMF2MOD utility sourcecode,
+ written to convert crusader's amf files into 8
+ channels mod file in 1995 by Mr. P / Powersource
+ mrp@fish.share.net, ac054@sfn.saskatoon.sk.ca
+
+
+==============================================================================*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <ctype.h>
+#include <string.h>
+
+#include "mikmod_internals.h"
+
+/*========== Module structure */
+
+typedef struct MSAMPINFO {
+ CHAR samplename[24];
+ UBYTE finetune;
+ UBYTE volume;
+ ULONG length;
+ ULONG reppos;
+ ULONG replen;
+} MSAMPINFO;
+
+typedef struct MODULEHEADER {
+ CHAR songname[21];
+ UBYTE num_patterns; /* number of patterns used */
+ UBYTE num_orders;
+ UBYTE positions[256]; /* which pattern to play at pos */
+ MSAMPINFO samples[64]; /* all sampleinfo */
+} MODULEHEADER;
+
+typedef struct MODTYPE {
+ CHAR id[5];
+ UBYTE channels;
+ CHAR *name;
+} MODTYPE;
+
+typedef struct MODNOTE {
+ UBYTE a, b, c, d;
+} MODNOTE;
+
+/* This table is taken from AMF2MOD.C
+ * written in 1995 by Mr. P / Powersource
+ * mrp@fish.share.net, ac054@sfn.saskatoon.sk.ca */
+UWORD periodtable[]={6848,6464,6096,5760,5424,5120,4832,4560,4304,
+ 4064,3840,3628,3424,3232,3048,2880,2712,2560,
+ 2416,2280,2152,2032,1920,1814,1712,1616,1524,
+ 1440,1356,1280,1208,1140,1076,1016, 960, 907,
+ 856, 808, 762, 720, 678, 640, 604, 570, 538,
+ 508, 480, 453, 428, 404, 381, 360, 339, 320,
+ 302, 285, 269, 254, 240, 226, 214, 202, 190,
+ 180, 170, 160, 151, 143, 135, 127, 120, 113,
+ 107, 101, 95, 90, 85, 80, 75, 71, 67,
+ 63, 60, 56, 53, 50, 47, 45, 42, 40,
+ 37, 35, 33, 31, 30, 28};
+
+/*========== Loader variables */
+
+static CHAR asylum[] = "Asylum 1.0";
+
+static MODULEHEADER *mh = NULL;
+static MODNOTE *patbuf = NULL;
+static int modtype = 0;
+
+/*========== Loader code */
+
+static int ASY_CheckType(UBYTE *id, UBYTE *numchn, CHAR **descr)
+{
+ if (!memcmp(id, "ASYLUM Music Format V1.0", 24))
+ {
+ *descr = asylum;
+ *numchn = 8;
+ modtype = 1;
+ return 1;
+ }
+
+ return 0;
+}
+
+static int ASY_Test(void)
+{
+ UBYTE namestring[24], numchn;
+ CHAR *descr;
+
+ /* Read the magic string */
+ _mm_fseek(modreader, 0, SEEK_SET);
+ if (!_mm_read_UBYTES(namestring, 24, modreader))
+ return 0;
+
+ /* Test if the string is what we expect */
+ if (ASY_CheckType(namestring, &numchn, &descr))
+ return 1;
+
+ return 0;
+}
+
+static int ASY_Init(void)
+{
+ if (!(mh = (MODULEHEADER *)MikMod_malloc(sizeof(MODULEHEADER))))
+ return 0;
+ return 1;
+}
+
+static void ASY_Cleanup(void)
+{
+ MikMod_free(mh);
+ MikMod_free(patbuf);
+}
+
+static void ConvertNote(MODNOTE *n)
+{
+ UBYTE instrument, effect, effdat, note;
+ UWORD period;
+ UBYTE lastnote = 0;
+
+ instrument = n->b&0x1f;
+ effect = n->c;
+ effdat = n->d;
+
+ /* convert amf note to mod period */
+ if (n->a) {
+ period = periodtable[n->a];
+ } else {
+ period = 0;
+ }
+
+ /* 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) {
+ /* if instrument does not exist, note cut */
+ if ((instrument > 31) || (!mh->samples[instrument - 1].length)) {
+ UniPTEffect(0xc, 0);
+ if (effect == 0xc)
+ effect = effdat = 0;
+ } else {
+ /* Protracker handling */
+ if (!modtype) {
+ /* if we had a note, then change instrument...*/
+ if (note)
+ UniInstrument(instrument - 1);
+ /* ...otherwise, only adjust volume... */
+ else {
+ /* ...unless an effect was specified,
+ * which forces a new note to be
+ * played */
+ if (effect || effdat) {
+ UniInstrument(instrument - 1);
+ note = lastnote;
+ } else
+ UniPTEffect(0xc,
+ mh->samples[instrument -
+ 1].volume & 0x7f);
+ }
+ } else {
+ /* Fasttracker handling */
+ 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);
+
+ /* Volume slide, up has priority */
+ if ((effect == 0xa) && (effdat & 0xf) && (effdat & 0xf0))
+ effdat &= 0xf0;
+
+ UniPTEffect(effect, effdat);
+}
+
+static UBYTE *ConvertTrack(MODNOTE *n)
+{
+ int t;
+
+ UniReset();
+ for (t = 0; t < 64; t++) {
+ ConvertNote(n);
+ UniNewline();
+ n += of.numchn;
+ }
+ return UniDup();
+}
+
+/* Loads all patterns of a modfile and converts them into the 3 byte format. */
+static int ML_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 *)MikMod_calloc(64U * of.numchn, sizeof(MODNOTE))))
+ return 0;
+
+
+ /* patterns start here */
+ _mm_fseek(modreader, 0xA66, SEEK_SET);
+ for (t = 0; t < of.numpat; t++) {
+ /* Load the pattern into the temp buffer and convert it */
+ for (s = 0; s < (64U * of.numchn); s++) {
+ patbuf[s].a = _mm_read_UBYTE(modreader);
+ patbuf[s].b = _mm_read_UBYTE(modreader);
+ patbuf[s].c = _mm_read_UBYTE(modreader);
+ patbuf[s].d = _mm_read_UBYTE(modreader);
+ }
+ for (s = 0; s < of.numchn; s++) {
+ if (!(of.tracks[tracks++] = ConvertTrack(patbuf + s))) {
+ return 0;
+ }
+ }
+ }
+ return 1;
+}
+
+static int ASY_Load(int curious)
+{
+ int t;
+ SAMPLE *q;
+ MSAMPINFO *s;
+ CHAR *descr=asylum;
+ ULONG seekpos;
+
+ // no title in asylum amf files :(
+ strcpy(mh->songname, "");
+
+ _mm_fseek(modreader, 0x23, SEEK_SET);
+ mh->num_patterns = _mm_read_UBYTE(modreader);
+ mh->num_orders = _mm_read_UBYTE(modreader);
+
+ // skip unknown byte
+ _mm_read_UBYTE(modreader);
+ _mm_read_UBYTES(mh->positions, 256, modreader);
+
+ /* read samples headers*/
+ for (t = 0; t < 64; t++) {
+ s = &mh->samples[t];
+
+ _mm_fseek(modreader, 0x126 + (t*37), SEEK_SET);
+
+ _mm_read_string(s->samplename, 22, modreader);
+ s->samplename[21] = 0; /* just in case */
+
+ s->finetune = _mm_read_UBYTE(modreader);
+ s->volume = _mm_read_UBYTE(modreader);
+ _mm_read_UBYTE(modreader); // skip unknown byte
+ s->length = _mm_read_I_ULONG(modreader);
+ s->reppos = _mm_read_I_ULONG(modreader);
+ s->replen = _mm_read_I_ULONG(modreader);
+ }
+
+ if (_mm_eof(modreader)) {
+ _mm_errno = MMERR_LOADING_HEADER;
+ return 0;
+ }
+
+ /* set module variables */
+ of.initspeed = 6;
+ of.inittempo = 125;
+ of.numchn = 8;
+ modtype = 0;
+ of.songname = DupStr(mh->songname, 21, 1);
+ of.numpos = mh->num_orders;
+ of.reppos = 0;
+ of.numpat = mh->num_patterns;
+ of.numtrk = of.numpat * of.numchn;
+
+
+ /* Copy positions (orders) */
+ 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 = 31;
+ of.numsmp = 31;
+ if (!AllocSamples())
+ return 0;
+ s = mh->samples;
+ q = of.samples;
+ seekpos = 2662+(2048*(of.numpat));
+ for (t = 0; t < of.numins; t++) {
+ /* convert the samplename */
+ q->samplename = DupStr(s->samplename, 23, 1);
+
+ /* init the sampleinfo variables */
+ q->speed = finetune[s->finetune & 0xf];
+ q->volume = s->volume & 0x7f;
+
+ q->loopstart = (ULONG)s->reppos;
+ q->loopend = (ULONG)q->loopstart + (s->replen);
+ q->length = (ULONG)s->length;
+
+ q->flags = SF_SIGNED;
+
+ q->seekpos = seekpos;
+ seekpos += q->length;
+
+ if ((s->replen) > 2) {
+ q->flags |= SF_LOOP;
+ }
+
+ /* fix replen if repend > length */
+ if (q->loopend > q->length)
+ q->loopend = q->length;
+
+ s++;
+ q++;
+ }
+
+ of.modtype = StrDup(descr);
+
+ if (!ML_LoadPatterns())
+ return 0;
+
+ return 1;
+}
+
+static CHAR *ASY_LoadTitle(void)
+{
+ CHAR *s = ""; // no titles
+
+ return (DupStr(s, 21, 1));
+}
+
+/*========== Loader information */
+
+MLOADER load_asy = {
+ NULL,
+ "AMF",
+ "AMF (ASYLUM Music Format V1.0)",
+ ASY_Init,
+ ASY_Test,
+ ASY_Load,
+ ASY_Cleanup,
+ ASY_LoadTitle
+};
+
+/* ex:set ts=4: */
diff --git a/apps/plugins/mikmod/load_dsm.c b/apps/plugins/mikmod/load_dsm.c
new file mode 100644
index 0000000000..09d6d3e297
--- /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: */
diff --git a/apps/plugins/mikmod/load_far.c b/apps/plugins/mikmod/load_far.c
new file mode 100644
index 0000000000..69d48d6b96
--- /dev/null
+++ b/apps/plugins/mikmod/load_far.c
@@ -0,0 +1,346 @@
+/* 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_far.c,v 1.3 2005/04/07 19:57:38 realtech Exp $
+
+ Farandole (FAR) 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 */
+
+typedef struct FARHEADER1 {
+ UBYTE id[4]; /* file magic */
+ CHAR songname[40]; /* songname */
+ CHAR blah[3]; /* 13,10,26 */
+ UWORD headerlen; /* remaining length of header in bytes */
+ UBYTE version;
+ UBYTE onoff[16];
+ UBYTE edit1[9];
+ UBYTE speed;
+ UBYTE panning[16];
+ UBYTE edit2[4];
+ UWORD stlen;
+} FARHEADER1;
+
+typedef struct FARHEADER2 {
+ UBYTE orders[256];
+ UBYTE numpat;
+ UBYTE snglen;
+ UBYTE loopto;
+ UWORD patsiz[256];
+} FARHEADER2;
+
+typedef struct FARSAMPLE {
+ CHAR samplename[32];
+ ULONG length;
+ UBYTE finetune;
+ UBYTE volume;
+ ULONG reppos;
+ ULONG repend;
+ UBYTE type;
+ UBYTE loop;
+} FARSAMPLE;
+
+typedef struct FARNOTE {
+ UBYTE note,ins,vol,eff;
+} FARNOTE;
+
+/*========== Loader variables */
+
+static CHAR FAR_Version[] = "Farandole";
+static FARHEADER1 *mh1 = NULL;
+static FARHEADER2 *mh2 = NULL;
+static FARNOTE *pat = NULL;
+
+static unsigned char FARSIG[4+3]={'F','A','R',0xfe,13,10,26};
+
+/*========== Loader code */
+
+int FAR_Test(void)
+{
+ UBYTE id[47];
+
+ if(!_mm_read_UBYTES(id,47,modreader)) return 0;
+ if((memcmp(id,FARSIG,4))||(memcmp(id+44,FARSIG+4,3))) return 0;
+ return 1;
+}
+
+int FAR_Init(void)
+{
+ if(!(mh1 = (FARHEADER1*)MikMod_malloc(sizeof(FARHEADER1)))) return 0;
+ if(!(mh2 = (FARHEADER2*)MikMod_malloc(sizeof(FARHEADER2)))) return 0;
+ if(!(pat = (FARNOTE*)MikMod_malloc(256*16*4*sizeof(FARNOTE)))) return 0;
+
+ return 1;
+}
+
+void FAR_Cleanup(void)
+{
+ MikMod_free(mh1);
+ MikMod_free(mh2);
+ MikMod_free(pat);
+}
+
+static UBYTE *FAR_ConvertTrack(FARNOTE* n,int rows)
+{
+ int t,vibdepth=1;
+
+ UniReset();
+ for(t=0;t<rows;t++) {
+ if(n->note) {
+ UniInstrument(n->ins);
+ UniNote(n->note+3*OCTAVE-1);
+ }
+ if (n->vol&0xf) UniPTEffect(0xc,(n->vol&0xf)<<2);
+ if (n->eff)
+ switch(n->eff>>4) {
+ case 0x3: /* porta to note */
+ UniPTEffect(0x3,(n->eff&0xf)<<4);
+ break;
+ case 0x4: /* retrigger */
+ UniPTEffect(0x0e, 0x90 | (n->eff & 0x0f));
+ break;
+ case 0x5: /* set vibrato depth */
+ vibdepth=n->eff&0xf;
+ break;
+ case 0x6: /* vibrato */
+ UniPTEffect(0x4,((n->eff&0xf)<<4)|vibdepth);
+ break;
+ case 0x7: /* volume slide up */
+ UniPTEffect(0xa,(n->eff&0xf)<<4);
+ break;
+ case 0x8: /* volume slide down */
+ UniPTEffect(0xa,n->eff&0xf);
+ break;
+ case 0xb: /* panning */
+ UniPTEffect(0xe,0x80|(n->eff&0xf));
+ break;
+ case 0xf: /* set speed */
+ UniPTEffect(0xf,n->eff&0xf);
+ break;
+
+ /* others not yet implemented */
+ default:
+#ifdef MIKMOD_DEBUG
+ fprintf(stderr,"\rFAR: unsupported effect %02X\n",n->eff);
+#endif
+ break;
+ }
+
+ UniNewline();
+ n+=16;
+ }
+ return UniDup();
+}
+
+int FAR_Load(int curious)
+{
+ int t,u,tracks=0;
+ SAMPLE *q;
+ FARSAMPLE s;
+ FARNOTE *crow;
+ UBYTE smap[8];
+
+ /* try to read module header (first part) */
+ _mm_read_UBYTES(mh1->id,4,modreader);
+ _mm_read_SBYTES(mh1->songname,40,modreader);
+ _mm_read_SBYTES(mh1->blah,3,modreader);
+ mh1->headerlen = _mm_read_I_UWORD (modreader);
+ mh1->version = _mm_read_UBYTE (modreader);
+ _mm_read_UBYTES(mh1->onoff,16,modreader);
+ _mm_read_UBYTES(mh1->edit1,9,modreader);
+ mh1->speed = _mm_read_UBYTE(modreader);
+ _mm_read_UBYTES(mh1->panning,16,modreader);
+ _mm_read_UBYTES(mh1->edit2,4,modreader);
+ mh1->stlen = _mm_read_I_UWORD (modreader);
+
+ /* init modfile data */
+ of.modtype = StrDup(FAR_Version);
+ of.songname = DupStr(mh1->songname,40,1);
+ of.numchn = 16;
+ of.initspeed = mh1->speed;
+ of.inittempo = 80;
+ of.reppos = 0;
+ of.flags |= UF_PANNING;
+ for(t=0;t<16;t++) of.panning[t]=mh1->panning[t]<<4;
+
+ /* read songtext into comment field */
+ if(mh1->stlen)
+ if (!ReadLinedComment(mh1->stlen, 66)) return 0;
+
+ /* try to read module header (second part) */
+ _mm_read_UBYTES(mh2->orders,256,modreader);
+ mh2->numpat = _mm_read_UBYTE(modreader);
+ mh2->snglen = _mm_read_UBYTE(modreader);
+ mh2->loopto = _mm_read_UBYTE(modreader);
+ _mm_read_I_UWORDS(mh2->patsiz,256,modreader);
+
+ of.numpos = mh2->snglen;
+ if(!AllocPositions(of.numpos)) return 0;
+ for(t=0;t<of.numpos;t++) {
+ if(mh2->orders[t]==0xff) break;
+ of.positions[t] = mh2->orders[t];
+ }
+
+ /* count number of patterns stored in file */
+ of.numpat = 0;
+ for(t=0;t<256;t++)
+ if(mh2->patsiz[t])
+ if((t+1)>of.numpat) of.numpat=t+1;
+ of.numtrk = of.numpat*of.numchn;
+
+ /* seek across eventual new data */
+ _mm_fseek(modreader,mh1->headerlen-(869+mh1->stlen),SEEK_CUR);
+
+ /* alloc track and pattern structures */
+ if(!AllocTracks()) return 0;
+ if(!AllocPatterns()) return 0;
+
+ for(t=0;t<of.numpat;t++) {
+ UBYTE rows=0,tempo;
+
+ memset(pat,0,256*16*4*sizeof(FARNOTE));
+ if(mh2->patsiz[t]) {
+ rows = _mm_read_UBYTE(modreader);
+ tempo = _mm_read_UBYTE(modreader);
+
+ crow = pat;
+ /* file often allocates 64 rows even if there are less in pattern */
+ if (mh2->patsiz[t]<2+(rows*16*4)) {
+ _mm_errno = MMERR_LOADING_PATTERN;
+ return 0;
+ }
+ for(u=(mh2->patsiz[t]-2)/4;u;u--,crow++) {
+ crow->note = _mm_read_UBYTE(modreader);
+ crow->ins = _mm_read_UBYTE(modreader);
+ crow->vol = _mm_read_UBYTE(modreader);
+ crow->eff = _mm_read_UBYTE(modreader);
+ }
+
+ if(_mm_eof(modreader)) {
+ _mm_errno = MMERR_LOADING_PATTERN;
+ return 0;
+ }
+
+ crow=pat;
+ of.pattrows[t] = rows;
+ for(u=16;u;u--,crow++)
+ if(!(of.tracks[tracks++]=FAR_ConvertTrack(crow,rows))) {
+ _mm_errno=MMERR_LOADING_PATTERN;
+ return 0;
+ }
+ } else
+ tracks+=16;
+ }
+
+ /* read sample map */
+ if(!_mm_read_UBYTES(smap,8,modreader)) {
+ _mm_errno = MMERR_LOADING_HEADER;
+ return 0;
+ }
+
+ /* count number of samples used */
+ of.numins = 0;
+ for(t=0;t<64;t++)
+ if(smap[t>>3]&(1<<(t&7))) of.numins=t+1;
+ of.numsmp = of.numins;
+
+ /* alloc sample structs */
+ if(!AllocSamples()) return 0;
+
+ q = of.samples;
+ for(t=0;t<of.numsmp;t++) {
+ q->speed = 8363;
+ q->flags = SF_SIGNED;
+ if(smap[t>>3]&(1<<(t&7))) {
+ _mm_read_SBYTES(s.samplename,32,modreader);
+ s.length = _mm_read_I_ULONG(modreader);
+ s.finetune = _mm_read_UBYTE(modreader);
+ s.volume = _mm_read_UBYTE(modreader);
+ s.reppos = _mm_read_I_ULONG(modreader);
+ s.repend = _mm_read_I_ULONG(modreader);
+ s.type = _mm_read_UBYTE(modreader);
+ s.loop = _mm_read_UBYTE(modreader);
+
+ q->samplename = DupStr(s.samplename,32,1);
+ q->length = s.length;
+ q->loopstart = s.reppos;
+ q->loopend = s.repend;
+ q->volume = s.volume<<2;
+
+ if(s.type&1) q->flags|=SF_16BITS;
+ if(s.loop&8) q->flags|=SF_LOOP;
+
+ q->seekpos = _mm_ftell(modreader);
+ _mm_fseek(modreader,q->length,SEEK_CUR);
+ } else
+ q->samplename = DupStr(NULL,0,0);
+ q++;
+ }
+ return 1;
+}
+
+CHAR *FAR_LoadTitle(void)
+{
+ CHAR s[40];
+
+ _mm_fseek(modreader,4,SEEK_SET);
+ if(!_mm_read_UBYTES(s,40,modreader)) return NULL;
+
+ return(DupStr(s,40,1));
+}
+
+/*========== Loader information */
+
+MIKMODAPI MLOADER load_far={
+ NULL,
+ "FAR",
+ "FAR (Farandole Composer)",
+ FAR_Init,
+ FAR_Test,
+ FAR_Load,
+ FAR_Cleanup,
+ FAR_LoadTitle
+};
+
+/* ex:set ts=4: */
diff --git a/apps/plugins/mikmod/load_gdm.c b/apps/plugins/mikmod/load_gdm.c
new file mode 100644
index 0000000000..616a2b56a3
--- /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: */
diff --git a/apps/plugins/mikmod/load_gt2.c b/apps/plugins/mikmod/load_gt2.c
new file mode 100644
index 0000000000..996de0e61e
--- /dev/null
+++ b/apps/plugins/mikmod/load_gt2.c
@@ -0,0 +1,374 @@
+/* MikMod sound library
+ (c) 2003-2004 Raphael Assenat 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_gt2.c,v 1.2 2005/03/30 19:09:35 realtech Exp $
+
+ Graoumf tracker format (.GT2)
+
+==============================================================================*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <ctype.h>
+#include <stdio.h>
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+#include <string.h>
+
+#include "mikmod_internals.h"
+
+typedef struct GT_NOTE {
+ UBYTE note; /* 24-127, 48 is middle C-2. 0 for no note */
+ UBYTE inst; /* instrument, 1-255, 0 for none */
+ UWORD effect; /* 0 for no FX */
+ UBYTE vv; /* volume, 1-255, 0 for no volume */
+} GT_NOTE;
+
+/* general info chunk */
+typedef struct GT2_CHUNK {
+ UBYTE magic[4]; /* must be 'GT2' */
+ UBYTE version; /* 01 = v0.7, 02=v0.726, 03=v0.731 */
+ ULONG chunk_size;
+ CHAR module_name[33]; /* 32 bytes in file */
+ CHAR comments_author[161]; /* 160 bytes in file */
+ UBYTE date_day;
+ UBYTE date_month;
+ UWORD date_year;
+ CHAR tracker_name[25]; /* 24 in file */
+ UWORD initial_speed;
+ UWORD initial_tempo;
+ UWORD initial_master_volume; /* 000 - fff */
+ UWORD num_voices; /* for the following panning section */
+ UWORD *voice_pannings; /* 000 - 800 - fff */
+} GT2_CHUNK;
+
+/* track volume chunk */
+typedef struct TVOL_CHUNK {
+ UBYTE id[4]; /* must be TVOL */
+ ULONG chunk_size;
+ UWORD num_tracks; /* for the following array */
+ UWORD *track_volumes; /* 0000 - 1000 - FFFF */
+} TVOL_CHUNK;
+
+/* extra-comment chunk */
+typedef struct XCOM_CHUNK {
+ UBYTE id[4]; /* must be XCOM */
+ ULONG chunk_size;
+ ULONG comment_len;
+ CHAR *comment; /* comment_len + 1 allocated */
+} XCOM_CHUNK;
+
+/* song chunk */
+typedef struct SONG_CHUNK {
+ UBYTE id[4]; /* must be SONG */
+ ULONG chunk_size;
+ UWORD song_length;
+ UWORD song_repeat_point;
+ UWORD *patterns; /* pattern numbers */
+} SONG_CHUNK;
+
+/* pattern set chunk */
+typedef struct PATS_CHUNK {
+ UBYTE id[4]; /* must be PATS */
+ ULONG chunk_size;
+ UWORD num_tracks; /* total number of tracks for the song */
+ UWORD num_patterns; /* number of patterns saved */
+} PATS_CHUNK;
+
+/* pattern chunk */
+typedef struct PATD_CHUNK {
+ UBYTE id[4]; /* must be PATD */
+ ULONG chunk_size;
+ UWORD pattern_number;
+ CHAR pattern_name[17]; /* 16 in file */
+ UWORD codage_version; /* only 0 expected for now */
+ /* version 0 (full pattern) */
+ UWORD num_lines;
+ UWORD num_tracks;
+ GT_NOTE *notes; /* sizeof(GT_NOTE) * num_lines * num_tracks */
+} PATD_CHUNK;
+
+/* instrument set chunk */
+typedef struct ORCH_CHUNK {
+ UBYTE id[4]; /* must be ORCH */
+ ULONG chunk_size;
+ UWORD num_instruments; /* number of instruments saved */
+} ORCH_CHUNK;
+
+typedef struct INST_NOTE {
+ UBYTE samp_number;/* sample number for midi note */
+ CHAR tranp; /* transposition for note */
+} INST_NOTE;
+
+/* instrument chunk */
+typedef struct INST_CHUNK {
+ UBYTE id[4]; /* must be INST */
+ ULONG chunk_size;
+ UWORD instrument_number;
+ CHAR name[29]; /* 28 in file */
+ UWORD type; /* 0 = sample */
+ UWORD volume; /* volume, 0-255 */
+ UWORD auto_panning; /* autopanning, 000 - 800 - fff, -1 no autopanning */
+ UWORD volume_enveloppe_number;
+ UWORD tone_enveloppe_number;
+ UWORD pan_enveloppe_number;
+ UBYTE reserved[10];
+ INST_NOTE note[128];
+} INST_CHUNK;
+
+typedef struct SAMP_CHUNK {
+ UBYTE id[4]; /* must be SAMP */
+ ULONG chunk_size;
+ UWORD sample_number;
+ CHAR name[29]; /* 28 in file */
+ UWORD flags; /* bit0: 0 = mono, 1 = stereo bit1: 0 normal loop, bit2: ping pong loop */
+ UWORD autopanning; /* 000 - 800 - fff */
+ UWORD num_bits; /* 8 or 16 */
+ UWORD rate; /* between 2000 and 65000 */
+ ULONG length; /* bytes */
+ ULONG loop_start; /* bytes */
+ ULONG loop_len; /* bytes */
+ UWORD volume; /* 0 - 255 */
+ UWORD finetune; /* (-8..+7 -> -1..+7/8 halftone) */
+ UWORD codage; /* 0 */
+ UBYTE *data;
+} SAMP_CHUNK;
+
+typedef struct xENV_CHUNK {
+ UBYTE id[4]; /* must be VENV, TENV or PENV */
+ ULONG chunk_size;
+ UWORD envelope_number;
+ CHAR name[21]; /* 20 in file */
+ UWORD keyoff_offset;
+ UBYTE *data;
+} xENV_CHUNK;
+
+typedef struct ENDC_CHUNK {
+ UBYTE id[4]; /* must be ENDC */
+ ULONG chunk_size;
+ ULONG total_module_size;
+} ENDC_CHUNK;
+
+
+typedef union GT_CHUNK
+{
+ UBYTE id[4]; /* must be TVOL */
+ GT2_CHUNK gt2;
+ TVOL_CHUNK tvol;
+ XCOM_CHUNK xcom;
+ SONG_CHUNK song;
+ PATS_CHUNK pats;
+ PATD_CHUNK patd;
+ ORCH_CHUNK orch;
+ INST_CHUNK inst;
+ SAMP_CHUNK samp;
+ xENV_CHUNK xenv;
+ ENDC_CHUNK endc;
+} GT_CHUNK;
+
+GT_CHUNK *loadChunk(void)
+{
+ GT_CHUNK *new_chunk = MikMod_malloc(sizeof(GT_CHUNK));
+
+ /* the file chunk id only use 3 bytes, others 4 */
+ _mm_read_UBYTES(new_chunk->id, 3, modreader);
+ if (! (new_chunk->id[0]=='G' &&
+ new_chunk->id[1]=='T' &&
+ new_chunk->id[2]=='2')
+ )
+ {
+ _mm_read_UBYTES(&new_chunk->id[3], 1, modreader);
+ }
+ else
+ {
+ new_chunk->id[3] = ' ';
+ }
+
+ printf(">> %c%c%c%c\n", new_chunk->id[0], new_chunk->id[1], new_chunk->id[2], new_chunk->id[3]);
+
+ if (!memcmp(new_chunk, "GT2", 3)) {
+ _mm_read_UBYTES(&new_chunk->gt2.version, 1, modreader);
+ _mm_read_M_ULONGS(&new_chunk->gt2.chunk_size, 1, modreader);
+ new_chunk->gt2.module_name[32] = 0;
+ _mm_read_UBYTES(&new_chunk->gt2.module_name, 32, modreader);
+ new_chunk->gt2.module_name[160] = 0;
+ _mm_read_UBYTES(&new_chunk->gt2.comments_author, 160, modreader);
+ _mm_read_UBYTES(&new_chunk->gt2.date_day, 1, modreader);
+ _mm_read_UBYTES(&new_chunk->gt2.date_month, 1, modreader);
+ _mm_read_M_UWORDS(&new_chunk->gt2.date_year, 1, modreader);
+ new_chunk->gt2.tracker_name[24] = 0;
+ _mm_read_UBYTES(&new_chunk->gt2.tracker_name, 24, modreader);
+ _mm_read_M_UWORDS(&new_chunk->gt2.initial_speed, 1, modreader);
+ _mm_read_M_UWORDS(&new_chunk->gt2.initial_tempo, 1, modreader);
+ _mm_read_M_UWORDS(&new_chunk->gt2.initial_master_volume, 1, modreader);
+ _mm_read_M_UWORDS(&new_chunk->gt2.num_voices, 1, modreader);
+ new_chunk->gt2.voice_pannings = MikMod_malloc(2*new_chunk->gt2.num_voices);
+ _mm_read_M_UWORDS(new_chunk->gt2.voice_pannings, new_chunk->gt2.num_voices, modreader);
+ return new_chunk;
+ }
+
+ if (!memcmp(new_chunk, "TVOL", 4)) {
+ new_chunk->tvol.chunk_size = _mm_read_M_ULONG(modreader);
+ new_chunk->tvol.num_tracks = _mm_read_M_UWORD(modreader);
+ new_chunk->tvol.track_volumes = MikMod_malloc(new_chunk->tvol.num_tracks * 2);
+ _mm_read_M_UWORDS(new_chunk->tvol.track_volumes, new_chunk->tvol.num_tracks, modreader);
+ return new_chunk;
+ }
+
+ if (!memcmp(new_chunk, "XCOM", 4)) {
+ new_chunk->xcom.chunk_size = _mm_read_M_ULONG(modreader);
+ new_chunk->xcom.comment_len = _mm_read_M_ULONG(modreader);
+ new_chunk->xcom.comment = MikMod_malloc(new_chunk->xcom.comment_len + 1);
+ _mm_read_UBYTES(new_chunk->xcom.comment, new_chunk->xcom.comment_len, modreader);
+ return new_chunk;
+ }
+
+ if (!memcmp(new_chunk, "SONG", 4)) {
+ new_chunk->song.chunk_size = _mm_read_M_ULONG(modreader);
+ new_chunk->song.song_length = _mm_read_M_UWORD(modreader);
+ new_chunk->song.song_repeat_point = _mm_read_M_UWORD(modreader);
+ new_chunk->song.patterns = MikMod_malloc(2*new_chunk->song.song_length);
+ _mm_read_M_UWORDS(new_chunk->song.patterns, new_chunk->song.song_length, modreader);
+ return new_chunk;
+ }
+
+ if (!memcmp(new_chunk, "PATS", 4)) {
+ new_chunk->pats.chunk_size = _mm_read_M_ULONG(modreader);
+ new_chunk->pats.num_tracks = _mm_read_M_UWORD(modreader);
+ new_chunk->pats.num_patterns = _mm_read_M_UWORD(modreader);
+ return new_chunk;
+ }
+
+ if (!memcmp(new_chunk, "PATD", 4)) {
+ new_chunk->patd.chunk_size = _mm_read_M_ULONG(modreader);
+ new_chunk->patd.pattern_number = _mm_read_M_UWORD(modreader);
+ new_chunk->patd.pattern_name[16] = 0;
+ _mm_read_UBYTES(new_chunk->patd.pattern_name, 16, modreader);
+ new_chunk->patd.codage_version = _mm_read_M_UWORD(modreader);
+ new_chunk->patd.num_lines = _mm_read_M_UWORD(modreader);
+ new_chunk->patd.num_tracks = _mm_read_M_UWORD(modreader);
+ new_chunk->patd.notes = MikMod_malloc(5 *
+ new_chunk->patd.num_lines *
+ new_chunk->patd.num_tracks);
+ _mm_read_UBYTES(new_chunk->patd.notes,
+ new_chunk->patd.num_lines * new_chunk->patd.num_tracks * 5,
+ modreader);
+ return new_chunk;
+ }
+
+ if (!memcmp(new_chunk, "ORCH", 4)) {
+ new_chunk->orch.chunk_size = _mm_read_M_ULONG(modreader);
+ new_chunk->orch.num_instruments = _mm_read_M_UWORD(modreader);
+ return new_chunk;
+ }
+ if (!memcmp(new_chunk, "INST", 4)) {
+ return new_chunk;
+ }
+ if (!memcmp(new_chunk, "SAMP", 4)) {
+ return new_chunk;
+ }
+ if (!memcmp(new_chunk, "VENV", 4)) {
+ return new_chunk;
+ }
+ if (!memcmp(new_chunk, "TENV", 4)) {
+ return new_chunk;
+ }
+ if (!memcmp(new_chunk, "PENV", 4)) {
+ return new_chunk;
+ }
+ if (!memcmp(new_chunk, "ENDC", 4)) {
+ return new_chunk;
+ }
+
+ printf("?? %c%c%c%c\n", new_chunk->id[0], new_chunk->id[1], new_chunk->id[2], new_chunk->id[3]);
+
+ MikMod_free(new_chunk);
+ return NULL; // unknown chunk
+}
+
+int GT2_Init(void)
+{
+ return 1;
+}
+
+int GT2_Test(void)
+{
+ UBYTE magic[3];
+ _mm_fseek(modreader, 0, SEEK_SET);
+
+ _mm_read_UBYTES(magic, 3, modreader);
+
+ if (magic[0] == 'G' && magic[1] == 'T' && magic[2] == '2') { return 1; }
+
+ return 0;
+}
+
+int GT2_Load(int curious)
+{
+ GT_CHUNK *tmp;
+
+ _mm_fseek(modreader, 0, SEEK_SET);
+ while ( (tmp = loadChunk() ))
+ {
+ printf("%c%c%c%c\n", tmp->id[0], tmp->id[1], tmp->id[2], tmp->id[3]);
+
+ }
+
+ return 0;
+}
+
+void GT2_Cleanup(void)
+{
+}
+
+CHAR *GT2_LoadTitle(void)
+{
+ CHAR title[33];
+ _mm_fseek(modreader, 8, SEEK_SET);
+
+ _mm_read_UBYTES(title, 32, modreader);
+ title[32]=0;
+
+ return (DupStr(title, 32, 1));
+}
+
+
+MIKMODAPI MLOADER load_gt2 = {
+ NULL,
+ "Graoumf Tracker 2 module",
+ "Graoumf Tracker 2",
+ GT2_Init,
+ GT2_Test,
+ GT2_Load,
+ GT2_Cleanup,
+ GT2_LoadTitle
+};
+
+
+
diff --git a/apps/plugins/mikmod/load_imf.c b/apps/plugins/mikmod/load_imf.c
new file mode 100644
index 0000000000..0b85c0ecc3
--- /dev/null
+++ b/apps/plugins/mikmod/load_imf.c
@@ -0,0 +1,738 @@
+/* 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_imf.c,v 1.3 2005/04/07 19:57:38 realtech Exp $
+
+ Imago Orpheus (IMF) 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 */
+
+/* module header */
+typedef struct IMFHEADER {
+ CHAR songname[32];
+ UWORD ordnum;
+ UWORD patnum;
+ UWORD insnum;
+ UWORD flags;
+ UBYTE initspeed;
+ UBYTE inittempo;
+ UBYTE mastervol;
+ UBYTE mastermult;
+ UBYTE orders[256];
+} IMFHEADER;
+
+/* channel settings */
+typedef struct IMFCHANNEL {
+ CHAR name[12];
+ UBYTE chorus;
+ UBYTE reverb;
+ UBYTE pan;
+ UBYTE status;
+} IMFCHANNEL;
+
+/* instrument header */
+#define IMFNOTECNT (10*OCTAVE)
+#define IMFENVCNT (16*2)
+typedef struct IMFINSTHEADER {
+ CHAR name[32];
+ UBYTE what[IMFNOTECNT];
+ UWORD volenv[IMFENVCNT];
+ UWORD panenv[IMFENVCNT];
+ UWORD pitenv[IMFENVCNT];
+ UBYTE volpts;
+ UBYTE volsus;
+ UBYTE volbeg;
+ UBYTE volend;
+ UBYTE volflg;
+ UBYTE panpts;
+ UBYTE pansus;
+ UBYTE panbeg;
+ UBYTE panend;
+ UBYTE panflg;
+ UBYTE pitpts;
+ UBYTE pitsus;
+ UBYTE pitbeg;
+ UBYTE pitend;
+ UBYTE pitflg;
+ UWORD volfade;
+ UWORD numsmp;
+ ULONG signature;
+} IMFINSTHEADER;
+
+/* sample header */
+typedef struct IMFWAVHEADER {
+ CHAR samplename[13];
+ ULONG length;
+ ULONG loopstart;
+ ULONG loopend;
+ ULONG samplerate;
+ UBYTE volume;
+ UBYTE pan;
+ UBYTE flags;
+} IMFWAVHEADER;
+
+typedef struct IMFNOTE {
+ UBYTE note,ins,eff1,dat1,eff2,dat2;
+} IMFNOTE;
+
+/*========== Loader variables */
+
+static CHAR IMF_Version[]="Imago Orpheus";
+
+static IMFNOTE *imfpat=NULL;
+static IMFHEADER *mh=NULL;
+
+/*========== Loader code */
+
+int IMF_Test(void)
+{
+ UBYTE id[4];
+
+ _mm_fseek(modreader,0x3c,SEEK_SET);
+ if(!_mm_read_UBYTES(id,4,modreader)) return 0;
+ if(!memcmp(id,"IM10",4)) return 1;
+ return 0;
+}
+
+int IMF_Init(void)
+{
+ if(!(imfpat=(IMFNOTE*)MikMod_malloc(32*256*sizeof(IMFNOTE)))) return 0;
+ if(!(mh=(IMFHEADER*)MikMod_malloc(sizeof(IMFHEADER)))) return 0;
+
+ return 1;
+}
+
+void IMF_Cleanup(void)
+{
+ FreeLinear();
+
+ MikMod_free(imfpat);
+ MikMod_free(mh);
+}
+
+static int IMF_ReadPattern(SLONG size,UWORD rows)
+{
+ int row=0,flag,ch;
+ IMFNOTE *n,dummy;
+
+ /* clear pattern data */
+ memset(imfpat,255,32*256*sizeof(IMFNOTE));
+
+ while((size>0)&&(row<rows)) {
+ flag=_mm_read_UBYTE(modreader);size--;
+
+ if(_mm_eof(modreader)) {
+ _mm_errno=MMERR_LOADING_PATTERN;
+ return 0;
+ }
+
+ if(flag) {
+ ch=remap[flag&31];
+
+ if(ch!=-1)
+ n=&imfpat[256*ch+row];
+ else
+ n=&dummy;
+
+ if(flag&32) {
+ n->note=_mm_read_UBYTE(modreader);
+ if(n->note>=0xa0) n->note=0xa0; /* note off */
+ n->ins =_mm_read_UBYTE(modreader);
+ size-=2;
+ }
+ if(flag&64) {
+ size-=2;
+ n->eff2=_mm_read_UBYTE(modreader);
+ n->dat2=_mm_read_UBYTE(modreader);
+ }
+ if(flag&128) {
+ n->eff1=_mm_read_UBYTE(modreader);
+ n->dat1=_mm_read_UBYTE(modreader);
+ size-=2;
+ }
+ } else row++;
+ }
+ if((size)||(row!=rows)) {
+ _mm_errno=MMERR_LOADING_PATTERN;
+ return 0;
+ }
+ return 1;
+}
+
+static void IMF_ProcessCmd(UBYTE eff,UBYTE inf)
+{
+ if((eff)&&(eff!=255))
+ switch (eff) {
+ case 0x01: /* set tempo */
+ UniEffect(UNI_S3MEFFECTA,inf);
+ break;
+ case 0x02: /* set BPM */
+ if(inf>=0x20) UniEffect(UNI_S3MEFFECTT,inf);
+ break;
+ case 0x03: /* tone portamento */
+ UniEffect(UNI_ITEFFECTG,inf);
+ break;
+ case 0x04: /* porta + volslide */
+ UniEffect(UNI_ITEFFECTG,inf);
+ UniEffect(UNI_S3MEFFECTD,0);
+ break;
+ case 0x05: /* vibrato */
+ UniEffect(UNI_XMEFFECT4,inf);
+ break;
+ case 0x06: /* vibrato + volslide */
+ UniEffect(UNI_XMEFFECT6,inf);
+ break;
+ case 0x07: /* fine vibrato */
+ UniEffect(UNI_ITEFFECTU,inf);
+ break;
+ case 0x08: /* tremolo */
+ UniEffect(UNI_S3MEFFECTR,inf);
+ break;
+ case 0x09: /* arpeggio */
+ UniPTEffect(0x0,inf);
+ break;
+ case 0x0a: /* panning */
+ UniPTEffect(0x8,(inf>=128)?255:(inf<<1));
+ break;
+ case 0x0b: /* pan slide */
+ UniEffect(UNI_XMEFFECTP,inf);
+ break;
+ case 0x0c: /* set channel volume */
+ if(inf<=64) UniPTEffect(0xc,inf);
+ break;
+ case 0x0d: /* volume slide */
+ UniEffect(UNI_S3MEFFECTD,inf);
+ break;
+ case 0x0e: /* fine volume slide */
+ if(inf) {
+ if(inf>>4)
+ UniEffect(UNI_S3MEFFECTD,0x0f|inf);
+ else
+ UniEffect(UNI_S3MEFFECTD,0xf0|inf);
+ } else
+ UniEffect(UNI_S3MEFFECTD,0);
+ break;
+ case 0x0f: /* set finetune */
+ UniPTEffect(0xe,0x50|(inf>>4));
+ break;
+#ifdef MIKMOD_DEBUG
+ case 0x10: /* note slide up */
+ case 0x11: /* not slide down */
+ fprintf(stderr,"\rIMF effect 0x10/0x11 (note slide)"
+ " not implemented (eff=%2X inf=%2X)\n",eff,inf);
+ break;
+#endif
+ case 0x12: /* slide up */
+ UniEffect(UNI_S3MEFFECTF,inf);
+ break;
+ case 0x13: /* slide down */
+ UniEffect(UNI_S3MEFFECTE,inf);
+ break;
+ case 0x14: /* fine slide up */
+ if (inf) {
+ if (inf<0x40)
+ UniEffect(UNI_S3MEFFECTF,0xe0|(inf>>2));
+ else
+ UniEffect(UNI_S3MEFFECTF,0xf0|(inf>>4));
+ } else
+ UniEffect(UNI_S3MEFFECTF,0);
+ break;
+ case 0x15: /* fine slide down */
+ if (inf) {
+ if (inf<0x40)
+ UniEffect(UNI_S3MEFFECTE,0xe0|(inf>>2));
+ else
+ UniEffect(UNI_S3MEFFECTE,0xf0|(inf>>4));
+ } else
+ UniEffect(UNI_S3MEFFECTE,0);
+ break;
+ /* 0x16 set filter cutoff (awe32) */
+ /* 0x17 filter side + resonance (awe32) */
+ case 0x18: /* sample offset */
+ UniPTEffect(0x9,inf);
+ break;
+#ifdef MIKMOD_DEBUG
+ case 0x19: /* set fine sample offset */
+ fprintf(stderr,"\rIMF effect 0x19 (fine sample offset)"
+ " not implemented (inf=%2X)\n",inf);
+ break;
+#endif
+ case 0x1a: /* keyoff */
+ UniWriteByte(UNI_KEYOFF);
+ break;
+ case 0x1b: /* retrig */
+ UniEffect(UNI_S3MEFFECTQ,inf);
+ break;
+ case 0x1c: /* tremor */
+ UniEffect(UNI_S3MEFFECTI,inf);
+ break;
+ case 0x1d: /* position jump */
+ UniPTEffect(0xb,inf);
+ break;
+ case 0x1e: /* pattern break */
+ UniPTEffect(0xd,(inf>>4)*10+(inf&0xf));
+ break;
+ case 0x1f: /* set master volume */
+ if(inf<=64) UniEffect(UNI_XMEFFECTG,inf<<1);
+ break;
+ case 0x20: /* master volume slide */
+ UniEffect(UNI_XMEFFECTH,inf);
+ break;
+ case 0x21: /* extended effects */
+ switch(inf>>4) {
+ case 0x1: /* set filter */
+ case 0x5: /* vibrato waveform */
+ case 0x8: /* tremolo waveform */
+ UniPTEffect(0xe,inf-0x10);
+ break;
+ case 0xa: /* pattern loop */
+ UniPTEffect(0xe,0x60|(inf&0xf));
+ break;
+ case 0xb: /* pattern delay */
+ UniPTEffect(0xe,0xe0|(inf&0xf));
+ break;
+ case 0x3: /* glissando */
+ case 0xc: /* note cut */
+ case 0xd: /* note delay */
+ case 0xf: /* invert loop */
+ UniPTEffect(0xe,inf);
+ break;
+ case 0xe: /* ignore envelope */
+ UniEffect(UNI_ITEFFECTS0, 0x77); /* vol */
+ UniEffect(UNI_ITEFFECTS0, 0x79); /* pan */
+ UniEffect(UNI_ITEFFECTS0, 0x7b); /* pit */
+ break;
+ }
+ break;
+ /* 0x22 chorus (awe32) */
+ /* 0x23 reverb (awe32) */
+ }
+}
+
+static UBYTE* IMF_ConvertTrack(IMFNOTE* tr,UWORD rows)
+{
+ int t;
+ UBYTE note,ins;
+
+ UniReset();
+ for(t=0;t<rows;t++) {
+ note=tr[t].note;
+ ins=tr[t].ins;
+
+ if((ins)&&(ins!=255)) UniInstrument(ins-1);
+ if(note!=255) {
+ if(note==0xa0) {
+ UniPTEffect(0xc,0); /* Note cut */
+ if(tr[t].eff1==0x0c) tr[t].eff1=0;
+ if(tr[t].eff2==0x0c) tr[t].eff2=0;
+ } else
+ UniNote(((note>>4)*OCTAVE)+(note&0xf));
+ }
+
+ IMF_ProcessCmd(tr[t].eff1,tr[t].dat1);
+ IMF_ProcessCmd(tr[t].eff2,tr[t].dat2);
+ UniNewline();
+ }
+ return UniDup();
+}
+
+int IMF_Load(int curious)
+{
+#define IMF_SMPINCR 64
+ int t,u,track=0,oldnumsmp;
+ IMFCHANNEL channels[32];
+ INSTRUMENT *d;
+ SAMPLE *q;
+ IMFWAVHEADER *wh=NULL,*s=NULL;
+ ULONG *nextwav=NULL;
+ UWORD wavcnt=0;
+ UBYTE id[4];
+
+ /* try to read the module header */
+ _mm_read_string(mh->songname,32,modreader);
+ mh->ordnum=_mm_read_I_UWORD(modreader);
+ mh->patnum=_mm_read_I_UWORD(modreader);
+ mh->insnum=_mm_read_I_UWORD(modreader);
+ mh->flags =_mm_read_I_UWORD(modreader);
+ _mm_fseek(modreader,8,SEEK_CUR);
+ mh->initspeed =_mm_read_UBYTE(modreader);
+ mh->inittempo =_mm_read_UBYTE(modreader);
+ mh->mastervol =_mm_read_UBYTE(modreader);
+ mh->mastermult=_mm_read_UBYTE(modreader);
+ _mm_fseek(modreader,64,SEEK_SET);
+
+ if(_mm_eof(modreader)) {
+ _mm_errno = MMERR_LOADING_HEADER;
+ return 0;
+ }
+
+ /* set module variables */
+ of.songname=DupStr(mh->songname,31,1);
+ of.modtype=StrDup(IMF_Version);
+ of.numpat=mh->patnum;
+ of.numins=mh->insnum;
+ of.reppos=0;
+ of.initspeed=mh->initspeed;
+ of.inittempo=mh->inittempo;
+ of.initvolume=mh->mastervol<<1;
+ of.flags |= UF_INST | UF_ARPMEM | UF_PANNING;
+ if(mh->flags&1) of.flags |= UF_LINEAR;
+ of.bpmlimit=32;
+
+ /* read channel information */
+ of.numchn=0;
+ memset(remap,-1,32*sizeof(UBYTE));
+ for(t=0;t<32;t++) {
+ _mm_read_string(channels[t].name,12,modreader);
+ channels[t].chorus=_mm_read_UBYTE(modreader);
+ channels[t].reverb=_mm_read_UBYTE(modreader);
+ channels[t].pan =_mm_read_UBYTE(modreader);
+ channels[t].status=_mm_read_UBYTE(modreader);
+ }
+ /* bug in Imago Orpheus ? If only channel 1 is enabled, in fact we have to
+ enable 16 channels */
+ if(!channels[0].status) {
+ for(t=1;t<16;t++) if(channels[t].status!=1) break;
+ if(t==16) for(t=1;t<16;t++) channels[t].status=0;
+ }
+ for(t=0;t<32;t++) {
+ if(channels[t].status!=2)
+ remap[t]=of.numchn++;
+ else
+ remap[t]=-1;
+ }
+ for(t=0;t<32;t++)
+ if(remap[t]!=-1) {
+ of.panning[remap[t]]=channels[t].pan;
+ of.chanvol[remap[t]]=channels[t].status?0:64;
+ }
+
+ if(_mm_eof(modreader)) {
+ _mm_errno = MMERR_LOADING_HEADER;
+ return 0;
+ }
+
+ /* read order list */
+ _mm_read_UBYTES(mh->orders,256,modreader);
+ if(_mm_eof(modreader)) {
+ _mm_errno = MMERR_LOADING_HEADER;
+ return 0;
+ }
+
+ of.numpos=0;
+ for(t=0;t<mh->ordnum;t++)
+ if(mh->orders[t]!=0xff) of.numpos++;
+ if(!AllocPositions(of.numpos)) return 0;
+ for(t=u=0;t<mh->ordnum;t++)
+ if(mh->orders[t]!=0xff) of.positions[u++]=mh->orders[t];
+
+ /* load pattern info */
+ of.numtrk=of.numpat*of.numchn;
+ if(!AllocTracks()) return 0;
+ if(!AllocPatterns()) return 0;
+
+ for(t=0;t<of.numpat;t++) {
+ SLONG size;
+ UWORD rows;
+
+ size=(SLONG)_mm_read_I_UWORD(modreader);
+ rows=_mm_read_I_UWORD(modreader);
+ if((rows>256)||(size<4)) {
+ _mm_errno=MMERR_LOADING_PATTERN;
+ return 0;
+ }
+
+ of.pattrows[t]=rows;
+ if(!IMF_ReadPattern(size-4,rows)) return 0;
+ for(u=0;u<of.numchn;u++)
+ if(!(of.tracks[track++]=IMF_ConvertTrack(&imfpat[u*256],rows)))
+ return 0;
+ }
+
+ /* load instruments */
+ if(!AllocInstruments()) return 0;
+ d=of.instruments;
+
+ for(oldnumsmp=t=0;t<of.numins;t++) {
+ IMFINSTHEADER ih;
+
+ memset(d->samplenumber,0xff,INSTNOTES*sizeof(UWORD));
+
+ /* read instrument header */
+ _mm_read_string(ih.name,32,modreader);
+ d->insname=DupStr(ih.name,31,1);
+ _mm_read_UBYTES(ih.what,IMFNOTECNT,modreader);
+ _mm_fseek(modreader,8,SEEK_CUR);
+ _mm_read_I_UWORDS(ih.volenv,IMFENVCNT,modreader);
+ _mm_read_I_UWORDS(ih.panenv,IMFENVCNT,modreader);
+ _mm_read_I_UWORDS(ih.pitenv,IMFENVCNT,modreader);
+
+#if defined __STDC__ || defined _MSC_VER || defined MPW_C
+#define IMF_FinishLoadingEnvelope(name) \
+ ih. name##pts=_mm_read_UBYTE(modreader); \
+ ih. name##sus=_mm_read_UBYTE(modreader); \
+ ih. name##beg=_mm_read_UBYTE(modreader); \
+ ih. name##end=_mm_read_UBYTE(modreader); \
+ ih. name##flg=_mm_read_UBYTE(modreader); \
+ _mm_read_UBYTE(modreader); \
+ _mm_read_UBYTE(modreader); \
+ _mm_read_UBYTE(modreader)
+#else
+#define IMF_FinishLoadingEnvelope(name) \
+ ih. name/**/pts=_mm_read_UBYTE(modreader); \
+ ih. name/**/sus=_mm_read_UBYTE(modreader); \
+ ih. name/**/beg=_mm_read_UBYTE(modreader); \
+ ih. name/**/end=_mm_read_UBYTE(modreader); \
+ ih. name/**/flg=_mm_read_UBYTE(modreader); \
+ _mm_read_UBYTE(modreader); \
+ _mm_read_UBYTE(modreader); \
+ _mm_read_UBYTE(modreader)
+#endif
+
+ IMF_FinishLoadingEnvelope(vol);
+ IMF_FinishLoadingEnvelope(pan);
+ IMF_FinishLoadingEnvelope(pit);
+
+ ih.volfade=_mm_read_I_UWORD(modreader);
+ ih.numsmp =_mm_read_I_UWORD(modreader);
+
+ _mm_read_UBYTES(id,4,modreader);
+ /* Looks like Imago Orpheus forgets the signature for empty
+ instruments following a multi-sample instrument... */
+ if(memcmp(id,"II10",4) &&
+ (oldnumsmp && memcmp(id,"\x0\x0\x0\x0",4))) {
+ if(nextwav) MikMod_free(nextwav);
+ if(wh) MikMod_free(wh);
+ _mm_errno=MMERR_LOADING_SAMPLEINFO;
+ return 0;
+ }
+ oldnumsmp=ih.numsmp;
+
+ if((ih.numsmp>16)||(ih.volpts>IMFENVCNT/2)||(ih.panpts>IMFENVCNT/2)||
+ (ih.pitpts>IMFENVCNT/2)||(_mm_eof(modreader))) {
+ if(nextwav) MikMod_free(nextwav);
+ if(wh) MikMod_free(wh);
+ _mm_errno=MMERR_LOADING_SAMPLEINFO;
+ return 0;
+ }
+
+ for(u=0;u<IMFNOTECNT;u++)
+ d->samplenumber[u]=ih.what[u]>ih.numsmp?0xffff:ih.what[u]+of.numsmp;
+ d->volfade=ih.volfade;
+
+#if defined __STDC__ || defined _MSC_VER || defined MPW_C
+#define IMF_ProcessEnvelope(name) \
+ for (u = 0; u < (IMFENVCNT >> 1); u++) { \
+ d-> name##env[u].pos = ih. name##env[u << 1]; \
+ d-> name##env[u].val = ih. name##env[(u << 1)+ 1]; \
+ } \
+ if (ih. name##flg&1) d-> name##flg|=EF_ON; \
+ if (ih. name##flg&2) d-> name##flg|=EF_SUSTAIN; \
+ if (ih. name##flg&4) d-> name##flg|=EF_LOOP; \
+ d-> name##susbeg=d-> name##susend=ih. name##sus; \
+ d-> name##beg=ih. name##beg; \
+ d-> name##end=ih. name##end; \
+ d-> name##pts=ih. name##pts; \
+ \
+ if ((d-> name##flg&EF_ON)&&(d-> name##pts<2)) \
+ d-> name##flg&=~EF_ON
+#else
+#define IMF_ProcessEnvelope(name) \
+ for (u = 0; u < (IMFENVCNT >> 1); u++) { \
+ d-> name/**/env[u].pos = ih. name/**/env[u << 1]; \
+ d-> name/**/env[u].val = ih. name/**/env[(u << 1)+ 1]; \
+ } \
+ if (ih. name/**/flg&1) d-> name/**/flg|=EF_ON; \
+ if (ih. name/**/flg&2) d-> name/**/flg|=EF_SUSTAIN; \
+ if (ih. name/**/flg&4) d-> name/**/flg|=EF_LOOP; \
+ d-> name/**/susbeg=d-> name/**/susend=ih. name/**/sus; \
+ d-> name/**/beg=ih. name/**/beg; \
+ d-> name/**/end=ih. name/**/end; \
+ d-> name/**/pts=ih. name/**/pts; \
+ \
+ if ((d-> name/**/flg&EF_ON)&&(d-> name/**/pts<2)) \
+ d-> name/**/flg&=~EF_ON
+#endif
+
+ IMF_ProcessEnvelope(vol);
+ IMF_ProcessEnvelope(pan);
+ IMF_ProcessEnvelope(pit);
+#undef IMF_ProcessEnvelope
+
+ if(ih.pitflg&1) {
+ d->pitflg&=~EF_ON;
+#ifdef MIKMOD_DEBUG
+ fprintf(stderr, "\rFilter envelopes not supported yet\n");
+#endif
+ }
+
+ /* gather sample information */
+ for(u=0;u<ih.numsmp;u++,s++) {
+ /* allocate more room for sample information if necessary */
+ if(of.numsmp+u==wavcnt) {
+ wavcnt+=IMF_SMPINCR;
+ if(!(nextwav=MikMod_realloc(nextwav,wavcnt*sizeof(ULONG)))) {
+ if(wh) MikMod_free(wh);
+ _mm_errno=MMERR_OUT_OF_MEMORY;
+ return 0;
+ }
+ if(!(wh=MikMod_realloc(wh,wavcnt*sizeof(IMFWAVHEADER)))) {
+ MikMod_free(nextwav);
+ _mm_errno=MMERR_OUT_OF_MEMORY;
+ return 0;
+ }
+ s=wh+(wavcnt-IMF_SMPINCR);
+ }
+
+ _mm_read_string(s->samplename,13,modreader);
+ _mm_read_UBYTE(modreader);_mm_read_UBYTE(modreader);_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->samplerate=_mm_read_I_ULONG(modreader);
+ s->volume =_mm_read_UBYTE(modreader)&0x7f;
+ s->pan =_mm_read_UBYTE(modreader);
+ _mm_fseek(modreader,14,SEEK_CUR);
+ s->flags =_mm_read_UBYTE(modreader);
+ _mm_fseek(modreader,11,SEEK_CUR);
+ _mm_read_UBYTES(id,4,modreader);
+ if(((memcmp(id,"IS10",4))&&(memcmp(id,"IW10",4)))||
+ (_mm_eof(modreader))) {
+ MikMod_free(nextwav);MikMod_free(wh);
+ _mm_errno=MMERR_LOADING_SAMPLEINFO;
+ return 0;
+ }
+ nextwav[of.numsmp+u]=_mm_ftell(modreader);
+ _mm_fseek(modreader,s->length,SEEK_CUR);
+ }
+
+ of.numsmp+=ih.numsmp;
+ d++;
+ }
+
+ /* sanity check */
+ if(!of.numsmp) {
+ if(nextwav) MikMod_free(nextwav);
+ if(wh) MikMod_free(wh);
+ _mm_errno=MMERR_LOADING_SAMPLEINFO;
+ return 0;
+ }
+
+ /* load samples */
+ if(!AllocSamples()) {
+ MikMod_free(nextwav);MikMod_free(wh);
+ return 0;
+ }
+ if(!AllocLinear()) {
+ MikMod_free(nextwav);MikMod_free(wh);
+ return 0;
+ }
+ q=of.samples;
+ s=wh;
+ for(u=0;u<of.numsmp;u++,s++,q++) {
+ q->samplename=DupStr(s->samplename,12,1);
+ q->length =s->length;
+ q->loopstart=s->loopstart;
+ q->loopend =s->loopend;
+ q->volume =s->volume;
+ q->speed =s->samplerate;
+ if(of.flags&UF_LINEAR)
+ q->speed=speed_to_finetune(s->samplerate<<1,u);
+ q->panning =s->pan;
+ q->seekpos =nextwav[u];
+
+ q->flags|=SF_SIGNED;
+ if(s->flags&0x1) q->flags|=SF_LOOP;
+ if(s->flags&0x2) q->flags|=SF_BIDI;
+ if(s->flags&0x8) q->flags|=SF_OWNPAN;
+ if(s->flags&0x4) {
+ q->flags|=SF_16BITS;
+ q->length >>=1;
+ q->loopstart>>=1;
+ q->loopend >>=1;
+ }
+ }
+
+ d=of.instruments;
+ s=wh;
+ for(u=0;u<of.numins;u++,d++) {
+ for(t=0;t<IMFNOTECNT;t++) {
+ if(d->samplenumber[t]>=of.numsmp)
+ d->samplenote[t]=255;
+ else if (of.flags&UF_LINEAR) {
+ int note=(int)d->samplenote[u]+noteindex[d->samplenumber[u]];
+ d->samplenote[u]=(note<0)?0:(note>255?255:note);
+ } else
+ d->samplenote[t]=t;
+ }
+ }
+
+ MikMod_free(wh);MikMod_free(nextwav);
+ return 1;
+}
+
+CHAR *IMF_LoadTitle(void)
+{
+ CHAR s[31];
+
+ _mm_fseek(modreader,0,SEEK_SET);
+ if(!_mm_read_UBYTES(s,31,modreader)) return NULL;
+
+ return(DupStr(s,31,1));
+}
+
+/*========== Loader information */
+
+MIKMODAPI MLOADER load_imf={
+ NULL,
+ "IMF",
+ "IMF (Imago Orpheus)",
+ IMF_Init,
+ IMF_Test,
+ IMF_Load,
+ IMF_Cleanup,
+ IMF_LoadTitle
+};
+
+/* ex:set ts=4: */
diff --git a/apps/plugins/mikmod/load_it.c b/apps/plugins/mikmod/load_it.c
new file mode 100644
index 0000000000..6ce3a1ce65
--- /dev/null
+++ b/apps/plugins/mikmod/load_it.c
@@ -0,0 +1,1013 @@
+/* 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_it.c,v 1.4 2010/01/12 03:30:32 realtech Exp $
+
+ Impulse tracker (IT) module loader
+
+==============================================================================*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <ctype.h>
+#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 *, ...);
+extern int toupper(int);
+#endif
+
+/*========== Module structure */
+
+/* header */
+typedef struct ITHEADER {
+ CHAR songname[26];
+ UBYTE blank01[2];
+ UWORD ordnum;
+ UWORD insnum;
+ UWORD smpnum;
+ UWORD patnum;
+ UWORD cwt; /* Created with tracker (y.xx = 0x0yxx) */
+ UWORD cmwt; /* Compatible with tracker ver > than val. */
+ UWORD flags;
+ UWORD special; /* bit 0 set = song message attached */
+ UBYTE globvol;
+ UBYTE mixvol; /* mixing volume [ignored] */
+ UBYTE initspeed;
+ UBYTE inittempo;
+ UBYTE pansep; /* panning separation between channels */
+ UBYTE zerobyte;
+ UWORD msglength;
+ ULONG msgoffset;
+ UBYTE blank02[4];
+ UBYTE pantable[64];
+ UBYTE voltable[64];
+} ITHEADER;
+
+/* sample information */
+typedef struct ITSAMPLE {
+ CHAR filename[12];
+ UBYTE zerobyte;
+ UBYTE globvol;
+ UBYTE flag;
+ UBYTE volume;
+ UBYTE panning;
+ CHAR sampname[28];
+ UWORD convert; /* sample conversion flag */
+ ULONG length;
+ ULONG loopbeg;
+ ULONG loopend;
+ ULONG c5spd;
+ ULONG susbegin;
+ ULONG susend;
+ ULONG sampoffset;
+ UBYTE vibspeed;
+ UBYTE vibdepth;
+ UBYTE vibrate;
+ UBYTE vibwave; /* 0=sine, 1=rampdown, 2=square, 3=random (speed ignored) */
+} ITSAMPLE;
+
+/* instrument information */
+
+#define ITENVCNT 25
+#define ITNOTECNT 120
+typedef struct ITINSTHEADER {
+ ULONG size; /* (dword) Instrument size */
+ CHAR filename[12]; /* (char) Instrument filename */
+ UBYTE zerobyte; /* (byte) Instrument type (always 0) */
+ UBYTE volflg;
+ UBYTE volpts;
+ UBYTE volbeg; /* (byte) Volume loop start (node) */
+ UBYTE volend; /* (byte) Volume loop end (node) */
+ UBYTE volsusbeg; /* (byte) Volume sustain begin (node) */
+ UBYTE volsusend; /* (byte) Volume Sustain end (node) */
+ UBYTE panflg;
+ UBYTE panpts;
+ UBYTE panbeg; /* (byte) channel loop start (node) */
+ UBYTE panend; /* (byte) channel loop end (node) */
+ UBYTE pansusbeg; /* (byte) channel sustain begin (node) */
+ UBYTE pansusend; /* (byte) channel Sustain end (node) */
+ UBYTE pitflg;
+ UBYTE pitpts;
+ UBYTE pitbeg; /* (byte) pitch loop start (node) */
+ UBYTE pitend; /* (byte) pitch loop end (node) */
+ UBYTE pitsusbeg; /* (byte) pitch sustain begin (node) */
+ UBYTE pitsusend; /* (byte) pitch Sustain end (node) */
+ UWORD blank;
+ UBYTE globvol;
+ UBYTE chanpan;
+ UWORD fadeout; /* Envelope end / NNA volume fadeout */
+ UBYTE dnc; /* Duplicate note check */
+ UBYTE dca; /* Duplicate check action */
+ UBYTE dct; /* Duplicate check type */
+ UBYTE nna; /* New Note Action [0,1,2,3] */
+ UWORD trkvers; /* tracker version used to save [files only] */
+ UBYTE ppsep; /* Pitch-pan Separation */
+ UBYTE ppcenter; /* Pitch-pan Center */
+ UBYTE rvolvar; /* random volume varations */
+ UBYTE rpanvar; /* random panning varations */
+ UWORD numsmp; /* Number of samples in instrument [files only] */
+ CHAR name[26]; /* Instrument name */
+ UBYTE blank01[6];
+ UWORD samptable[ITNOTECNT];/* sample for each note [note / samp pairs] */
+ UBYTE volenv[200]; /* volume envelope (IT 1.x stuff) */
+ UBYTE oldvoltick[ITENVCNT];/* volume tick position (IT 1.x stuff) */
+ UBYTE volnode[ITENVCNT]; /* amplitude of volume nodes */
+ UWORD voltick[ITENVCNT]; /* tick value of volume nodes */
+ SBYTE pannode[ITENVCNT]; /* panenv - node points */
+ UWORD pantick[ITENVCNT]; /* tick value of panning nodes */
+ SBYTE pitnode[ITENVCNT]; /* pitchenv - node points */
+ UWORD pittick[ITENVCNT]; /* tick value of pitch nodes */
+} ITINSTHEADER;
+
+/* unpacked note */
+
+typedef struct ITNOTE {
+ UBYTE note,ins,volpan,cmd,inf;
+} ITNOTE;
+
+/*========== Loader data */
+
+static ULONG *paraptr=NULL; /* parapointer array (see IT docs) */
+static ITHEADER *mh=NULL;
+static ITNOTE *itpat=NULL; /* allocate to space for one full pattern */
+static UBYTE *mask=NULL; /* arrays allocated to 64 elements and used for */
+static ITNOTE *last=NULL; /* uncompressing IT's pattern information */
+static int numtrk=0;
+static unsigned int old_effect; /* if set, use S3M old-effects stuffs */
+
+static CHAR* IT_Version[]={
+ "ImpulseTracker . ",
+ "Compressed ImpulseTracker . ",
+ "ImpulseTracker 2.14p3",
+ "Compressed ImpulseTracker 2.14p3",
+ "ImpulseTracker 2.14p4",
+ "Compressed ImpulseTracker 2.14p4",
+};
+
+/* table for porta-to-note command within volume/panning column */
+static UBYTE portatable[10]= {0,1,4,8,16,32,64,96,128,255};
+
+/*========== Loader code */
+
+int IT_Test(void)
+{
+ UBYTE id[4];
+
+ if(!_mm_read_UBYTES(id,4,modreader)) return 0;
+ if(!memcmp(id,"IMPM",4)) return 1;
+ return 0;
+}
+
+int IT_Init(void)
+{
+ if(!(mh=(ITHEADER*)MikMod_malloc(sizeof(ITHEADER)))) return 0;
+ if(!(poslookup=(UBYTE*)MikMod_malloc(256*sizeof(UBYTE)))) return 0;
+ if(!(itpat=(ITNOTE*)MikMod_malloc(200*64*sizeof(ITNOTE)))) return 0;
+ if(!(mask=(UBYTE*)MikMod_malloc(64*sizeof(UBYTE)))) return 0;
+ if(!(last=(ITNOTE*)MikMod_malloc(64*sizeof(ITNOTE)))) return 0;
+
+ return 1;
+}
+
+void IT_Cleanup(void)
+{
+ FreeLinear();
+
+ MikMod_free(mh);
+ MikMod_free(poslookup);
+ MikMod_free(itpat);
+ MikMod_free(mask);
+ MikMod_free(last);
+ MikMod_free(paraptr);
+ MikMod_free(origpositions);
+}
+
+/* Because so many IT files have 64 channels as the set number used, but really
+ only use far less (usually from 8 to 24 still), I had to make this function,
+ which determines the number of channels that are actually USED by a pattern.
+
+ NOTE: You must first seek to the file location of the pattern before calling
+ this procedure.
+
+ Returns 1 on error
+*/
+static int IT_GetNumChannels(UWORD patrows)
+{
+ int row=0,flag,ch;
+
+ do {
+ if((flag=_mm_read_UBYTE(modreader))==EOF) {
+ _mm_errno=MMERR_LOADING_PATTERN;
+ return 1;
+ }
+ if(!flag)
+ row++;
+ else {
+ ch=(flag-1)&63;
+ remap[ch]=0;
+ if(flag & 128) mask[ch]=_mm_read_UBYTE(modreader);
+ if(mask[ch]&1) _mm_read_UBYTE(modreader);
+ if(mask[ch]&2) _mm_read_UBYTE(modreader);
+ if(mask[ch]&4) _mm_read_UBYTE(modreader);
+ if(mask[ch]&8) { _mm_read_UBYTE(modreader);_mm_read_UBYTE(modreader); }
+ }
+ } while(row<patrows);
+
+ return 0;
+}
+
+static UBYTE* IT_ConvertTrack(ITNOTE* tr,UWORD numrows)
+{
+ int t;
+ UBYTE note,ins,volpan;
+
+ UniReset();
+
+ for(t=0;t<numrows;t++) {
+ note=tr[t*of.numchn].note;
+ ins=tr[t*of.numchn].ins;
+ volpan=tr[t*of.numchn].volpan;
+
+ if(note!=255) {
+ if(note==253)
+ UniWriteByte(UNI_KEYOFF);
+ else if(note==254) {
+ UniPTEffect(0xc,-1); /* note cut command */
+ volpan=255;
+ } else
+ UniNote(note);
+ }
+
+ if((ins)&&(ins<100))
+ UniInstrument(ins-1);
+ else if(ins==253)
+ UniWriteByte(UNI_KEYOFF);
+ else if(ins!=255) { /* crap */
+ _mm_errno=MMERR_LOADING_PATTERN;
+ return NULL;
+ }
+
+ /* process volume / panning column
+ volume / panning effects do NOT all share the same memory address
+ yet. */
+ if(volpan<=64)
+ UniVolEffect(VOL_VOLUME,volpan);
+ else if(volpan==65) /* fine volume slide up (65-74) - A0 case */
+ UniVolEffect(VOL_VOLSLIDE,0);
+ else if(volpan<=74) { /* fine volume slide up (65-74) - general case */
+ UniVolEffect(VOL_VOLSLIDE,0x0f+((volpan-65)<<4));
+ } else if(volpan==75) /* fine volume slide down (75-84) - B0 case */
+ UniVolEffect(VOL_VOLSLIDE,0);
+ else if(volpan<=84) { /* fine volume slide down (75-84) - general case*/
+ UniVolEffect(VOL_VOLSLIDE,0xf0+(volpan-75));
+ } else if(volpan<=94) /* volume slide up (85-94) */
+ UniVolEffect(VOL_VOLSLIDE,((volpan-85)<<4));
+ else if(volpan<=104)/* volume slide down (95-104) */
+ UniVolEffect(VOL_VOLSLIDE,(volpan-95));
+ else if(volpan<=114)/* pitch slide down (105-114) */
+ UniVolEffect(VOL_PITCHSLIDEDN,(volpan-105));
+ else if(volpan<=124)/* pitch slide up (115-124) */
+ UniVolEffect(VOL_PITCHSLIDEUP,(volpan-115));
+ else if(volpan<=127) { /* crap */
+ _mm_errno=MMERR_LOADING_PATTERN;
+ return NULL;
+ } else if(volpan<=192)
+ UniVolEffect(VOL_PANNING,((volpan-128)==64)?255:((volpan-128)<<2));
+ else if(volpan<=202)/* portamento to note */
+ UniVolEffect(VOL_PORTAMENTO,portatable[volpan-193]);
+ else if(volpan<=212)/* vibrato */
+ UniVolEffect(VOL_VIBRATO,(volpan-203));
+ else if((volpan!=239)&&(volpan!=255)) { /* crap */
+ _mm_errno=MMERR_LOADING_PATTERN;
+ return NULL;
+ }
+
+ S3MIT_ProcessCmd(tr[t*of.numchn].cmd,tr[t*of.numchn].inf,
+ old_effect|S3MIT_IT);
+
+ UniNewline();
+ }
+ return UniDup();
+}
+
+static int IT_ReadPattern(UWORD patrows)
+{
+ int row=0,flag,ch,blah;
+ ITNOTE *itt=itpat,dummy,*n,*l;
+
+ memset(itt,255,200*64*sizeof(ITNOTE));
+
+ do {
+ if((flag=_mm_read_UBYTE(modreader))==EOF) {
+ _mm_errno = MMERR_LOADING_PATTERN;
+ return 0;
+ }
+ if(!flag) {
+ itt=&itt[of.numchn];
+ row++;
+ } else {
+ ch=remap[(flag-1)&63];
+ if(ch!=-1) {
+ n=&itt[ch];
+ l=&last[ch];
+ } else
+ n=l=&dummy;
+
+ if(flag&128) mask[ch]=_mm_read_UBYTE(modreader);
+ if(mask[ch]&1)
+ /* convert IT note off to internal note off */
+ if((l->note=n->note=_mm_read_UBYTE(modreader))==255)
+ l->note=n->note=253;
+ if(mask[ch]&2)
+ l->ins=n->ins=_mm_read_UBYTE(modreader);
+ if(mask[ch]&4)
+ l->volpan=n->volpan=_mm_read_UBYTE(modreader);
+ if(mask[ch]&8) {
+ l->cmd=n->cmd=_mm_read_UBYTE(modreader);
+ l->inf=n->inf=_mm_read_UBYTE(modreader);
+ }
+ if(mask[ch]&16)
+ n->note=l->note;
+ if(mask[ch]&32)
+ n->ins=l->ins;
+ if(mask[ch]&64)
+ n->volpan=l->volpan;
+ if(mask[ch]&128) {
+ n->cmd=l->cmd;
+ n->inf=l->inf;
+ }
+ }
+ } while(row<patrows);
+
+ for(blah=0;blah<of.numchn;blah++) {
+ if(!(of.tracks[numtrk++]=IT_ConvertTrack(&itpat[blah],patrows)))
+ return 0;
+ }
+
+ return 1;
+}
+
+static void LoadMidiString(MREADER* modreader,CHAR* dest)
+{
+ CHAR *cur,*last;
+
+ _mm_read_UBYTES(dest,32,modreader);
+ cur=last=dest;
+ /* remove blanks and uppercase all */
+ while(*last) {
+ if(isalnum((int)*last)) *(cur++)=toupper((int)*last);
+ last++;
+ }
+ *cur=0;
+}
+
+/* Load embedded midi information for resonant filters */
+static void IT_LoadMidiConfiguration(MREADER* modreader)
+{
+ int i;
+
+ memset(filtermacros,0,sizeof(filtermacros));
+ memset(filtersettings,0,sizeof(filtersettings));
+
+ if (modreader) { /* information is embedded in file */
+ UWORD dat;
+ CHAR midiline[33];
+
+ dat=_mm_read_I_UWORD(modreader);
+ _mm_fseek(modreader,8*dat+0x120,SEEK_CUR);
+
+ /* read midi macros */
+ for(i=0;i<UF_MAXMACRO;i++) {
+ LoadMidiString(modreader,midiline);
+ if((!strncmp(midiline,"F0F00",5))&&
+ ((midiline[5]=='0')||(midiline[5]=='1')))
+ filtermacros[i]=(midiline[5]-'0')|0x80;
+ }
+
+ /* read standalone filters */
+ for(i=0x80;i<0x100;i++) {
+ LoadMidiString(modreader,midiline);
+ if((!strncmp(midiline,"F0F00",5))&&
+ ((midiline[5]=='0')||(midiline[5]=='1'))) {
+ filtersettings[i].filter=(midiline[5]-'0')|0x80;
+ dat=(midiline[6])?(midiline[6]-'0'):0;
+ if(midiline[7])dat=(dat<<4)|(midiline[7]-'0');
+ filtersettings[i].inf=dat;
+ }
+ }
+ } else { /* use default information */
+ filtermacros[0]=FILT_CUT;
+ for(i=0x80;i<0x90;i++) {
+ filtersettings[i].filter=FILT_RESONANT;
+ filtersettings[i].inf=(i&0x7f)<<3;
+ }
+ }
+ activemacro=0;
+ for(i=0;i<0x80;i++) {
+ filtersettings[i].filter=filtermacros[0];
+ filtersettings[i].inf=i;
+ }
+}
+
+int IT_Load(int curious)
+{
+ int t,u,lp;
+ INSTRUMENT *d;
+ SAMPLE *q;
+ int compressed=0;
+
+ numtrk=0;
+ filters=0;
+
+ /* try to read module header */
+ _mm_read_I_ULONG(modreader); /* kill the 4 byte header */
+ _mm_read_string(mh->songname,26,modreader);
+ _mm_read_UBYTES(mh->blank01,2,modreader);
+ mh->ordnum =_mm_read_I_UWORD(modreader);
+ mh->insnum =_mm_read_I_UWORD(modreader);
+ mh->smpnum =_mm_read_I_UWORD(modreader);
+ mh->patnum =_mm_read_I_UWORD(modreader);
+ mh->cwt =_mm_read_I_UWORD(modreader);
+ mh->cmwt =_mm_read_I_UWORD(modreader);
+ mh->flags =_mm_read_I_UWORD(modreader);
+ mh->special =_mm_read_I_UWORD(modreader);
+ mh->globvol =_mm_read_UBYTE(modreader);
+ mh->mixvol =_mm_read_UBYTE(modreader);
+ mh->initspeed =_mm_read_UBYTE(modreader);
+ mh->inittempo =_mm_read_UBYTE(modreader);
+ mh->pansep =_mm_read_UBYTE(modreader);
+ mh->zerobyte =_mm_read_UBYTE(modreader);
+ mh->msglength =_mm_read_I_UWORD(modreader);
+ mh->msgoffset =_mm_read_I_ULONG(modreader);
+ _mm_read_UBYTES(mh->blank02,4,modreader);
+ _mm_read_UBYTES(mh->pantable,64,modreader);
+ _mm_read_UBYTES(mh->voltable,64,modreader);
+
+ if(_mm_eof(modreader)) {
+ _mm_errno=MMERR_LOADING_HEADER;
+ return 0;
+ }
+
+ /* set module variables */
+ of.songname = DupStr(mh->songname,26,0); /* make a cstr of songname */
+ of.reppos = 0;
+ of.numpat = mh->patnum;
+ of.numins = mh->insnum;
+ of.numsmp = mh->smpnum;
+ of.initspeed = mh->initspeed;
+ of.inittempo = mh->inittempo;
+ of.initvolume = mh->globvol;
+ of.flags |= UF_BGSLIDES | UF_ARPMEM;
+ if (!(mh->flags & 1))
+ of.flags |= UF_PANNING;
+ of.bpmlimit=32;
+
+ if(mh->songname[25]) {
+ of.numvoices=1+mh->songname[25];
+#ifdef MIKMOD_DEBUG
+ fprintf(stderr,"Embedded IT limitation to %d voices\n",of.numvoices);
+#endif
+ }
+
+ /* set the module type */
+ /* 2.17 : IT 2.14p4 */
+ /* 2.16 : IT 2.14p3 with resonant filters */
+ /* 2.15 : IT 2.14p3 (improved compression) */
+ if((mh->cwt<=0x219)&&(mh->cwt>=0x217))
+ of.modtype=StrDup(IT_Version[mh->cmwt<0x214?4:5]);
+ else if (mh->cwt>=0x215)
+ of.modtype=StrDup(IT_Version[mh->cmwt<0x214?2:3]);
+ else {
+ of.modtype = StrDup(IT_Version[mh->cmwt<0x214?0:1]);
+ of.modtype[mh->cmwt<0x214?15:26] = (mh->cwt>>8)+'0';
+ of.modtype[mh->cmwt<0x214?17:28] = ((mh->cwt>>4)&0xf)+'0';
+ of.modtype[mh->cmwt<0x214?18:29] = ((mh->cwt)&0xf)+'0';
+ }
+
+ if(mh->flags&8)
+ of.flags |= UF_XMPERIODS | UF_LINEAR;
+
+ if((mh->cwt>=0x106)&&(mh->flags&16))
+ old_effect=S3MIT_OLDSTYLE;
+ else
+ old_effect=0;
+
+ /* set panning positions */
+ if (mh->flags & 1)
+ for(t=0;t<64;t++) {
+ mh->pantable[t]&=0x7f;
+ if(mh->pantable[t]<64)
+ of.panning[t]=mh->pantable[t]<<2;
+ else if(mh->pantable[t]==64)
+ of.panning[t]=255;
+ else if(mh->pantable[t]==100)
+ of.panning[t]=PAN_SURROUND;
+ else if(mh->pantable[t]==127)
+ of.panning[t]=PAN_CENTER;
+ else {
+ _mm_errno=MMERR_LOADING_HEADER;
+ return 0;
+ }
+ }
+ else
+ for(t=0;t<64;t++)
+ of.panning[t]=PAN_CENTER;
+
+ /* set channel volumes */
+ memcpy(of.chanvol,mh->voltable,64);
+
+ /* read the order data */
+ if(!AllocPositions(mh->ordnum)) return 0;
+ if(!(origpositions=MikMod_calloc(mh->ordnum,sizeof(UWORD)))) return 0;
+
+ for(t=0;t<mh->ordnum;t++) {
+ origpositions[t]=_mm_read_UBYTE(modreader);
+ if((origpositions[t]>mh->patnum)&&(origpositions[t]<254))
+ origpositions[t]=255;
+ }
+
+ if(_mm_eof(modreader)) {
+ _mm_errno = MMERR_LOADING_HEADER;
+ return 0;
+ }
+
+ poslookupcnt=mh->ordnum;
+ S3MIT_CreateOrders(curious);
+
+ if(!(paraptr=(ULONG*)MikMod_malloc((mh->insnum+mh->smpnum+of.numpat)*
+ sizeof(ULONG)))) return 0;
+
+ /* read the instrument, sample, and pattern parapointers */
+ _mm_read_I_ULONGS(paraptr,mh->insnum+mh->smpnum+of.numpat,modreader);
+
+ if(_mm_eof(modreader)) {
+ _mm_errno = MMERR_LOADING_HEADER;
+ return 0;
+ }
+
+ /* Check for and load midi information for resonant filters */
+ if(mh->cmwt>=0x216) {
+ if(mh->special&8) {
+ IT_LoadMidiConfiguration(modreader);
+ if(_mm_eof(modreader)) {
+ _mm_errno = MMERR_LOADING_HEADER;
+ return 0;
+ }
+ } else
+ IT_LoadMidiConfiguration(NULL);
+ filters=1;
+ }
+
+ /* Check for and load song comment */
+ if((mh->special&1)&&(mh->cwt>=0x104)&&(mh->msglength)) {
+ _mm_fseek(modreader,(long)(mh->msgoffset),SEEK_SET);
+ if(!ReadComment(mh->msglength)) return 0;
+ }
+
+ if(!(mh->flags&4)) of.numins=of.numsmp;
+ if(!AllocSamples()) return 0;
+
+ if(!AllocLinear()) return 0;
+
+ /* Load all samples */
+ q = of.samples;
+ for(t=0;t<mh->smpnum;t++) {
+ ITSAMPLE s;
+
+ /* seek to sample position */
+ _mm_fseek(modreader,(long)(paraptr[mh->insnum+t]+4),SEEK_SET);
+
+ /* load sample info */
+ _mm_read_string(s.filename,12,modreader);
+ s.zerobyte = _mm_read_UBYTE(modreader);
+ s.globvol = _mm_read_UBYTE(modreader);
+ s.flag = _mm_read_UBYTE(modreader);
+ s.volume = _mm_read_UBYTE(modreader);
+ _mm_read_string(s.sampname,26,modreader);
+ s.convert = _mm_read_UBYTE(modreader);
+ s.panning = _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.c5spd = _mm_read_I_ULONG(modreader);
+ s.susbegin = _mm_read_I_ULONG(modreader);
+ s.susend = _mm_read_I_ULONG(modreader);
+ s.sampoffset = _mm_read_I_ULONG(modreader);
+ s.vibspeed = _mm_read_UBYTE(modreader);
+ s.vibdepth = _mm_read_UBYTE(modreader);
+ s.vibrate = _mm_read_UBYTE(modreader);
+ s.vibwave = _mm_read_UBYTE(modreader);
+
+ /* Generate an error if c5spd is > 512k, or samplelength > 256 megs
+ (nothing would EVER be that high) */
+
+ if(_mm_eof(modreader)||(s.c5spd>0x7ffffL)||(s.length>0xfffffffUL)) {
+ _mm_errno = MMERR_LOADING_SAMPLEINFO;
+ return 0;
+ }
+
+ /* Reality check for sample loop information */
+ if((s.flag&16)&&
+ ((s.loopbeg>0xfffffffUL)||(s.loopend>0xfffffffUL))) {
+ _mm_errno = MMERR_LOADING_SAMPLEINFO;
+ return 0;
+ }
+
+ q->samplename = DupStr(s.sampname,26,0);
+ q->speed = s.c5spd / 2;
+ q->panning = ((s.panning&127)==64)?255:(s.panning&127)<<2;
+ q->length = s.length;
+ q->loopstart = s.loopbeg;
+ q->loopend = s.loopend;
+ q->volume = s.volume;
+ q->globvol = s.globvol;
+ q->seekpos = s.sampoffset;
+
+ /* Convert speed to XM linear finetune */
+ if(of.flags&UF_LINEAR)
+ q->speed=speed_to_finetune(s.c5spd,t);
+
+ if(s.panning&128) q->flags|=SF_OWNPAN;
+
+ if(s.vibrate) {
+ q->vibflags |= AV_IT;
+ q->vibtype = s.vibwave;
+ q->vibsweep = s.vibrate * 2;
+ q->vibdepth = s.vibdepth;
+ q->vibrate = s.vibspeed;
+ }
+
+ if(s.flag&2) q->flags|=SF_16BITS;
+ if((s.flag&8)&&(mh->cwt>=0x214)) {
+ q->flags|=SF_ITPACKED;
+ compressed=1;
+ }
+ if(s.flag&16) q->flags|=SF_LOOP;
+ if(s.flag&64) q->flags|=SF_BIDI;
+
+ if(mh->cwt>=0x200) {
+ if(s.convert&1) q->flags|=SF_SIGNED;
+ if(s.convert&4) q->flags|=SF_DELTA;
+ }
+ q++;
+ }
+
+ /* Load instruments if instrument mode flag enabled */
+ if(mh->flags&4) {
+ if(!AllocInstruments()) return 0;
+ d=of.instruments;
+ of.flags|=UF_NNA|UF_INST;
+
+ for(t=0;t<mh->insnum;t++) {
+ ITINSTHEADER ih;
+
+ /* seek to instrument position */
+ _mm_fseek(modreader,paraptr[t]+4,SEEK_SET);
+
+ /* load instrument info */
+ _mm_read_string(ih.filename,12,modreader);
+ ih.zerobyte = _mm_read_UBYTE(modreader);
+ if(mh->cwt<0x200) {
+ /* load IT 1.xx inst header */
+ ih.volflg = _mm_read_UBYTE(modreader);
+ ih.volbeg = _mm_read_UBYTE(modreader);
+ ih.volend = _mm_read_UBYTE(modreader);
+ ih.volsusbeg = _mm_read_UBYTE(modreader);
+ ih.volsusend = _mm_read_UBYTE(modreader);
+ _mm_read_I_UWORD(modreader);
+ ih.fadeout = _mm_read_I_UWORD(modreader);
+ ih.nna = _mm_read_UBYTE(modreader);
+ ih.dnc = _mm_read_UBYTE(modreader);
+ } else {
+ /* Read IT200+ header */
+ ih.nna = _mm_read_UBYTE(modreader);
+ ih.dct = _mm_read_UBYTE(modreader);
+ ih.dca = _mm_read_UBYTE(modreader);
+ ih.fadeout = _mm_read_I_UWORD(modreader);
+ ih.ppsep = _mm_read_UBYTE(modreader);
+ ih.ppcenter = _mm_read_UBYTE(modreader);
+ ih.globvol = _mm_read_UBYTE(modreader);
+ ih.chanpan = _mm_read_UBYTE(modreader);
+ ih.rvolvar = _mm_read_UBYTE(modreader);
+ ih.rpanvar = _mm_read_UBYTE(modreader);
+ }
+
+ ih.trkvers = _mm_read_I_UWORD(modreader);
+ ih.numsmp = _mm_read_UBYTE(modreader);
+ _mm_read_UBYTE(modreader);
+ _mm_read_string(ih.name,26,modreader);
+ _mm_read_UBYTES(ih.blank01,6,modreader);
+ _mm_read_I_UWORDS(ih.samptable,ITNOTECNT,modreader);
+ if(mh->cwt<0x200) {
+ /* load IT 1xx volume envelope */
+ _mm_read_UBYTES(ih.volenv,200,modreader);
+ for(lp=0;lp<ITENVCNT;lp++) {
+ ih.oldvoltick[lp] = _mm_read_UBYTE(modreader);
+ ih.volnode[lp] = _mm_read_UBYTE(modreader);
+ }
+ } else {
+ /* load IT 2xx volume, pan and pitch envelopes */
+#if defined __STDC__ || defined _MSC_VER || defined MPW_C
+#define IT_LoadEnvelope(name,type) \
+ ih. name##flg =_mm_read_UBYTE(modreader); \
+ ih. name##pts =_mm_read_UBYTE(modreader); \
+ ih. name##beg =_mm_read_UBYTE(modreader); \
+ ih. name##end =_mm_read_UBYTE(modreader); \
+ ih. name##susbeg=_mm_read_UBYTE(modreader); \
+ ih. name##susend=_mm_read_UBYTE(modreader); \
+ for(lp=0;lp<ITENVCNT;lp++) { \
+ ih. name##node[lp]=_mm_read_##type (modreader); \
+ ih. name##tick[lp]=_mm_read_I_UWORD(modreader); \
+ } \
+ _mm_read_UBYTE(modreader)
+#else
+#define IT_LoadEnvelope(name,type) \
+ ih. name/**/flg =_mm_read_UBYTE(modreader); \
+ ih. name/**/pts =_mm_read_UBYTE(modreader); \
+ ih. name/**/beg =_mm_read_UBYTE(modreader); \
+ ih. name/**/end =_mm_read_UBYTE(modreader); \
+ ih. name/**/susbeg=_mm_read_UBYTE(modreader); \
+ ih. name/**/susend=_mm_read_UBYTE(modreader); \
+ for(lp=0;lp<ITENVCNT;lp++) { \
+ ih. name/**/node[lp]=_mm_read_/**/type (modreader); \
+ ih. name/**/tick[lp]=_mm_read_I_UWORD(modreader); \
+ } \
+ _mm_read_UBYTE(modreader)
+#endif
+
+ IT_LoadEnvelope(vol,UBYTE);
+ IT_LoadEnvelope(pan,SBYTE);
+ IT_LoadEnvelope(pit,SBYTE);
+#undef IT_LoadEnvelope
+ }
+
+ if(_mm_eof(modreader)) {
+ _mm_errno = MMERR_LOADING_SAMPLEINFO;
+ return 0;
+ }
+
+ d->volflg|=EF_VOLENV;
+ d->insname = DupStr(ih.name,26,0);
+ d->nnatype = ih.nna & NNA_MASK;
+
+ if(mh->cwt<0x200) {
+ d->volfade=ih.fadeout<< 6;
+ if(ih.dnc) {
+ d->dct=DCT_NOTE;
+ d->dca=DCA_CUT;
+ }
+
+ if(ih.volflg&1) d->volflg|=EF_ON;
+ if(ih.volflg&2) d->volflg|=EF_LOOP;
+ if(ih.volflg&4) d->volflg|=EF_SUSTAIN;
+
+ /* XM conversion of IT envelope Array */
+ d->volbeg = ih.volbeg;
+ d->volend = ih.volend;
+ d->volsusbeg = ih.volsusbeg;
+ d->volsusend = ih.volsusend;
+
+ if(ih.volflg&1) {
+ for(u=0;u<ITENVCNT;u++)
+ if(ih.oldvoltick[d->volpts]!=0xff) {
+ d->volenv[d->volpts].val=(ih.volnode[d->volpts]<<2);
+ d->volenv[d->volpts].pos=ih.oldvoltick[d->volpts];
+ d->volpts++;
+ } else
+ break;
+ }
+ } else {
+ d->panning=((ih.chanpan&127)==64)?255:(ih.chanpan&127)<<2;
+ if(!(ih.chanpan&128)) d->flags|=IF_OWNPAN;
+
+ if(!(ih.ppsep & 128)) {
+ d->pitpansep=ih.ppsep<<2;
+ d->pitpancenter=ih.ppcenter;
+ d->flags|=IF_PITCHPAN;
+ }
+ d->globvol=ih.globvol>>1;
+ d->volfade=ih.fadeout<<5;
+ d->dct =ih.dct;
+ d->dca =ih.dca;
+
+ if(mh->cwt>=0x204) {
+ d->rvolvar = ih.rvolvar;
+ d->rpanvar = ih.rpanvar;
+ }
+
+#if defined __STDC__ || defined _MSC_VER || defined MPW_C
+#define IT_ProcessEnvelope(name) \
+ if(ih. name##flg&1) d-> name##flg|=EF_ON; \
+ if(ih. name##flg&2) d-> name##flg|=EF_LOOP; \
+ if(ih. name##flg&4) d-> name##flg|=EF_SUSTAIN; \
+ d-> name##pts=ih. name##pts; \
+ d-> name##beg=ih. name##beg; \
+ d-> name##end=ih. name##end; \
+ d-> name##susbeg=ih. name##susbeg; \
+ d-> name##susend=ih. name##susend; \
+ \
+ for(u=0;u<ih. name##pts;u++) \
+ d-> name##env[u].pos=ih. name##tick[u]; \
+ \
+ if((d-> name##flg&EF_ON)&&(d-> name##pts<2)) \
+ d-> name##flg&=~EF_ON
+#else
+#define IT_ProcessEnvelope(name) \
+ if(ih. name/**/flg&1) d-> name/**/flg|=EF_ON; \
+ if(ih. name/**/flg&2) d-> name/**/flg|=EF_LOOP; \
+ if(ih. name/**/flg&4) d-> name/**/flg|=EF_SUSTAIN; \
+ d-> name/**/pts=ih. name/**/pts; \
+ d-> name/**/beg=ih. name/**/beg; \
+ d-> name/**/end=ih. name/**/end; \
+ d-> name/**/susbeg=ih. name/**/susbeg; \
+ d-> name/**/susend=ih. name/**/susend; \
+ \
+ for(u=0;u<ih. name/**/pts;u++) \
+ d-> name/**/env[u].pos=ih. name/**/tick[u]; \
+ \
+ if((d-> name/**/flg&EF_ON)&&(d-> name/**/pts<2)) \
+ d-> name/**/flg&=~EF_ON
+#endif
+
+ IT_ProcessEnvelope(vol);
+
+ // Secunia SA37775
+ if (ih.volpts>= ENVPOINTS)
+ ih.volpts = ENVPOINTS-1;
+
+ for(u=0;u<ih.volpts;u++)
+ d->volenv[u].val=(ih.volnode[u]<<2);
+
+ IT_ProcessEnvelope(pan);
+ for(u=0;u<ih.panpts;u++)
+ d->panenv[u].val=
+ ih.pannode[u]==32?255:(ih.pannode[u]+32)<<2;
+
+ IT_ProcessEnvelope(pit);
+ for(u=0;u<ih.pitpts;u++)
+ d->pitenv[u].val=ih.pitnode[u]+32;
+#undef IT_ProcessEnvelope
+
+ if(ih.pitflg&0x80) {
+ /* filter envelopes not supported yet */
+ d->pitflg&=~EF_ON;
+ ih.pitpts=ih.pitbeg=ih.pitend=0;
+#ifdef MIKMOD_DEBUG
+ {
+ static int warn=0;
+
+ if(!warn)
+ fprintf(stderr, "\rFilter envelopes not supported yet\n");
+ warn=1;
+ }
+#endif
+ }
+ }
+
+ for(u=0;u<ITNOTECNT;u++) {
+ d->samplenote[u]=(ih.samptable[u]&255);
+ d->samplenumber[u]=
+ (ih.samptable[u]>>8)?((ih.samptable[u]>>8)-1):0xffff;
+ if(d->samplenumber[u]>=of.numsmp)
+ d->samplenote[u]=255;
+ else if (of.flags&UF_LINEAR) {
+ int note=(int)d->samplenote[u]+noteindex[d->samplenumber[u]];
+ d->samplenote[u]=(note<0)?0:(note>255?255:note);
+ }
+ }
+
+ d++;
+ }
+ } else if(of.flags & UF_LINEAR) {
+ if(!AllocInstruments()) return 0;
+ d=of.instruments;
+ of.flags|=UF_INST;
+
+ for(t=0;t<mh->smpnum;t++,d++)
+ for(u=0;u<ITNOTECNT;u++) {
+ if(d->samplenumber[u]>=of.numsmp)
+ d->samplenote[u]=255;
+ else {
+ int note=(int)d->samplenote[u]+noteindex[d->samplenumber[u]];
+ d->samplenote[u]=(note<0)?0:(note>255?255:note);
+ }
+ }
+ }
+
+ /* Figure out how many channels this song actually uses */
+ of.numchn=0;
+ memset(remap,-1,UF_MAXCHAN*sizeof(UBYTE));
+ for(t=0;t<of.numpat;t++) {
+ UWORD packlen;
+
+ /* seek to pattern position */
+ if(paraptr[mh->insnum+mh->smpnum+t]) { /* 0 -> empty 64 row pattern */
+ _mm_fseek(modreader,((long)paraptr[mh->insnum+mh->smpnum+t]),SEEK_SET);
+ _mm_read_I_UWORD(modreader);
+ /* read pattern length (# of rows)
+ Impulse Tracker never creates patterns with less than 32 rows,
+ but some other trackers do, so we only check for more than 256
+ rows */
+ packlen=_mm_read_I_UWORD(modreader);
+ if(packlen>256) {
+ _mm_errno=MMERR_LOADING_PATTERN;
+ return 0;
+ }
+ _mm_read_I_ULONG(modreader);
+ if(IT_GetNumChannels(packlen)) return 0;
+ }
+ }
+
+ /* give each of them a different number */
+ for(t=0;t<UF_MAXCHAN;t++)
+ if(!remap[t])
+ remap[t]=of.numchn++;
+
+ of.numtrk = of.numpat*of.numchn;
+ if(of.numvoices)
+ if (of.numvoices<of.numchn) of.numvoices=of.numchn;
+
+ if(!AllocPatterns()) return 0;
+ if(!AllocTracks()) return 0;
+
+ for(t=0;t<of.numpat;t++) {
+ UWORD packlen;
+
+ /* seek to pattern position */
+ if(!paraptr[mh->insnum+mh->smpnum+t]) { /* 0 -> empty 64 row pattern */
+ of.pattrows[t]=64;
+ for(u=0;u<of.numchn;u++) {
+ int k;
+
+ UniReset();
+ for(k=0;k<64;k++) UniNewline();
+ of.tracks[numtrk++]=UniDup();
+ }
+ } else {
+ _mm_fseek(modreader,((long)paraptr[mh->insnum+mh->smpnum+t]),SEEK_SET);
+ packlen=_mm_read_I_UWORD(modreader);
+ of.pattrows[t]=_mm_read_I_UWORD(modreader);
+ _mm_read_I_ULONG(modreader);
+ if(!IT_ReadPattern(of.pattrows[t])) return 0;
+ }
+ }
+
+ return 1;
+}
+
+CHAR *IT_LoadTitle(void)
+{
+ CHAR s[26];
+
+ _mm_fseek(modreader,4,SEEK_SET);
+ if(!_mm_read_UBYTES(s,26,modreader)) return NULL;
+
+ return(DupStr(s,26,0));
+}
+
+/*========== Loader information */
+
+MIKMODAPI MLOADER load_it={
+ NULL,
+ "IT",
+ "IT (Impulse Tracker)",
+ IT_Init,
+ IT_Test,
+ IT_Load,
+ IT_Cleanup,
+ IT_LoadTitle
+};
+
+/* ex:set ts=4: */
diff --git a/apps/plugins/mikmod/load_m15.c b/apps/plugins/mikmod/load_m15.c
new file mode 100644
index 0000000000..d97378aab3
--- /dev/null
+++ b/apps/plugins/mikmod/load_m15.c
@@ -0,0 +1,505 @@
+/* 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_m15.c,v 1.3 2005/04/07 19:57:38 realtech Exp $
+
+ 15 instrument MOD loader
+ Also supports Ultimate Sound Tracker (old M15 format)
+
+==============================================================================*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <ctype.h>
+#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 */
+
+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 int 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 */
+};
+static int siglen[REJECT]={8,4};
+
+/*========== Loader code */
+
+static int LoadModuleHeader(MODULEHEADER *mh)
+{
+ int t,u;
+
+ _mm_read_string(mh->songname,20,modreader);
+ mh->songname[20]=0; /* just in case */
+
+ /* sanity check : title should contain printable characters and a bunch
+ of null chars */
+ for(t=0;t<20;t++)
+ if((mh->songname[t])&&(mh->songname[t]<32)) return 0;
+ for(t=0;(mh->songname[t])&&(t<20);t++);
+ if(t<20) for(;t<20;t++) if(mh->songname[t]) return 0;
+
+ for(t=0;t<15;t++) {
+ MSAMPINFO *s=&mh->samples[t];
+
+ _mm_read_string(s->samplename,22,modreader);
+ s->samplename[22]=0; /* just in case */
+ s->length =_mm_read_M_UWORD(modreader);
+ s->finetune =_mm_read_UBYTE(modreader);
+ s->volume =_mm_read_UBYTE(modreader);
+ s->reppos =_mm_read_M_UWORD(modreader);
+ s->replen =_mm_read_M_UWORD(modreader);
+
+ /* sanity check : sample title should contain printable characters and
+ a bunch of null chars */
+ for(u=0;u<20;u++)
+ if((s->samplename[u])&&(s->samplename[u]</*32*/14)) return 0;
+ for(u=0;(s->samplename[u])&&(u<20);u++);
+ if(u<20) for(;u<20;u++) if(s->samplename[u]) return 0;
+
+ /* sanity check : finetune values */
+ if(s->finetune>>4) return 0;
+ }
+
+ mh->songlength =_mm_read_UBYTE(modreader);
+ mh->magic1 =_mm_read_UBYTE(modreader); /* should be 127 */
+
+ /* sanity check : no more than 128 positions, restart position in range */
+ if((!mh->songlength)||(mh->songlength>128)) return 0;
+ /* values encountered so far are 0x6a and 0x78 */
+ if(((mh->magic1&0xf8)!=0x78)&&(mh->magic1!=0x6a)&&(mh->magic1>mh->songlength)) return 0;
+
+ _mm_read_UBYTES(mh->positions,128,modreader);
+
+ /* sanity check : pattern range is 0..63 */
+ for(t=0;t<128;t++)
+ if(mh->positions[t]>63) return 0;
+
+ return(!_mm_eof(modreader));
+}
+
+/* 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 */
+static 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 scan it */
+ _mm_read_UBYTE(modreader);_mm_read_UBYTE(modreader);
+ eff = _mm_read_UBYTE(modreader);
+ dat = _mm_read_UBYTE(modreader);
+
+ 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;
+}
+
+static int 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],siglen[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')||
+ (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(!isdigit((int)mh.samples[t].samplename[0]))
+ ust_loader = 1;
+
+ if(mh.samples[t].length>4999||mh.samples[t].reppos>9999) {
+ ust_loader = 0;
+ if(mh.samples[t].length>32768) return 0;
+ }
+
+ /* if loop information is incorrect as words, but correct as bytes,
+ this is likely to be an ust-style module */
+ if((mh.samples[t].reppos+mh.samples[t].replen>mh.samples[t].length)&&
+ (mh.samples[t].reppos+mh.samples[t].replen<(mh.samples[t].length<<1))){
+ ust_loader = 1;
+ return 1;
+ }
+
+ if(!ust_loader) 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;
+}
+
+static int M15_Init(void)
+{
+ if(!(mh=(MODULEHEADER*)MikMod_malloc(sizeof(MODULEHEADER)))) return 0;
+ return 1;
+}
+
+static void M15_Cleanup(void)
+{
+ MikMod_free(mh);
+ MikMod_free(patbuf);
+}
+
+/*
+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.
+*/
+
+static UBYTE M15_ConvertNote(MODNOTE* n, UBYTE lasteffect)
+{
+ 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) {
+ /* if instrument does not exist, note cut */
+ if((instrument>15)||(!mh->samples[instrument-1].length)) {
+ UniPTEffect(0xc,0);
+ if(effect==0xc) effect=effdat=0;
+ } else {
+ /* if we had a note, then change instrument... */
+ if(note)
+ UniInstrument(instrument-1);
+ /* ...otherwise, only adjust volume... */
+ else {
+ /* ...unless an effect was specified, which forces a new note
+ to be played */
+ if(effect||effdat) {
+ UniInstrument(instrument-1);
+ note=lastnote;
+ } else
+ UniPTEffect(0xc,mh->samples[instrument-1].volume&0x7f);
+ }
+ }
+ }
+ 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);
+
+ /* Volume slide, up has priority */
+ if((effect==0xa)&&(effdat&0xf)&&(effdat&0xf0))
+ effdat&=0xf0;
+
+ /* Handle ``heavy'' volumes correctly */
+ if ((effect == 0xc) && (effdat > 0x40))
+ effdat = 0x40;
+
+ 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);
+ else if(effdat>>2) UniPTEffect(2,effdat>>2);
+ break;
+ default:
+ UniPTEffect(effect,effdat);
+ break;
+ }
+ } else {
+ /* An isolated 100, 200 or 300 effect should be ignored (no
+ "standalone" porta memory in mod files). However, a sequence
+ such as 1XX, 100, 100, 100 is fine. */
+ if ((!effdat) && ((effect == 1)||(effect == 2)||(effect ==3)) &&
+ (lasteffect < 0x10) && (effect != lasteffect))
+ effect = 0;
+
+ UniPTEffect(effect,effdat);
+ }
+ if (effect == 8)
+ of.flags |= UF_PANNING;
+
+ return effect;
+}
+
+static UBYTE *M15_ConvertTrack(MODNOTE* n)
+{
+ int t;
+ UBYTE lasteffect = 0x10; /* non existant effect */
+
+ UniReset();
+ for(t=0;t<64;t++) {
+ lasteffect = M15_ConvertNote(n,lasteffect);
+ UniNewline();
+ n+=4;
+ }
+ return UniDup();
+}
+
+/* Loads all patterns of a modfile and converts them into the 3 byte format. */
+static int 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*)MikMod_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(modreader);
+ patbuf[s].b=_mm_read_UBYTE(modreader);
+ patbuf[s].c=_mm_read_UBYTE(modreader);
+ patbuf[s].d=_mm_read_UBYTE(modreader);
+ }
+
+ for(s=0;s<4;s++)
+ if(!(of.tracks[tracks++]=M15_ConvertTrack(patbuf+s))) return 0;
+ }
+ return 1;
+}
+
+static int M15_Load(int 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,1);
+ 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,1);
+
+ /* 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;
+ if(ust_loader) q->flags |= SF_UST_LOOP;
+ if(s->replen>2) q->flags |= SF_LOOP;
+
+ s++;
+ q++;
+ }
+
+ if(!M15_LoadPatterns()) return 0;
+ ust_loader = 0;
+
+ return 1;
+}
+
+static CHAR *M15_LoadTitle(void)
+{
+ CHAR s[21];
+
+ _mm_fseek(modreader,0,SEEK_SET);
+ if(!_mm_read_UBYTES(s,20,modreader)) return NULL;
+ s[20]=0; /* just in case */
+ return(DupStr(s,21,1));
+}
+
+/*========== Loader information */
+
+MIKMODAPI MLOADER load_m15={
+ NULL,
+ "15-instrument module",
+ "MOD (15 instrument)",
+ M15_Init,
+ M15_Test,
+ M15_Load,
+ M15_Cleanup,
+ M15_LoadTitle
+};
+
+/* ex:set ts=4: */
diff --git a/apps/plugins/mikmod/load_med.c b/apps/plugins/mikmod/load_med.c
new file mode 100644
index 0000000000..21a85b39a0
--- /dev/null
+++ b/apps/plugins/mikmod/load_med.c
@@ -0,0 +1,719 @@
+/* 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_med.c,v 1.3 2005/04/07 19:57:38 realtech Exp $
+
+ Amiga MED 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 information */
+
+typedef struct MEDHEADER {
+ ULONG id;
+ ULONG modlen;
+ ULONG MEDSONGP; /* struct MEDSONG *song; */
+ UWORD psecnum; /* for the player routine, MMD2 only */
+ UWORD pseq; /* " " " " */
+ ULONG MEDBlockPP; /* struct MEDBlock **blockarr; */
+ ULONG reserved1;
+ ULONG MEDINSTHEADERPP; /* struct MEDINSTHEADER **smplarr; */
+ ULONG reserved2;
+ ULONG MEDEXPP; /* struct MEDEXP *expdata; */
+ ULONG reserved3;
+ UWORD pstate; /* some data for the player routine */
+ UWORD pblock;
+ UWORD pline;
+ UWORD pseqnum;
+ SWORD actplayline;
+ UBYTE counter;
+ UBYTE extra_songs; /* number of songs - 1 */
+} MEDHEADER;
+
+typedef struct MEDSAMPLE {
+ UWORD rep, replen; /* offs: 0(s), 2(s) */
+ UBYTE midich; /* offs: 4(s) */
+ UBYTE midipreset; /* offs: 5(s) */
+ UBYTE svol; /* offs: 6(s) */
+ SBYTE strans; /* offs: 7(s) */
+} MEDSAMPLE;
+
+typedef struct MEDSONG {
+ MEDSAMPLE sample[63]; /* 63 * 8 bytes = 504 bytes */
+ UWORD numblocks; /* offs: 504 */
+ UWORD songlen; /* offs: 506 */
+ UBYTE playseq[256]; /* offs: 508 */
+ UWORD deftempo; /* offs: 764 */
+ SBYTE playtransp; /* offs: 766 */
+ UBYTE flags; /* offs: 767 */
+ UBYTE flags2; /* offs: 768 */
+ UBYTE tempo2; /* offs: 769 */
+ UBYTE trkvol[16]; /* offs: 770 */
+ UBYTE mastervol; /* offs: 786 */
+ UBYTE numsamples; /* offs: 787 */
+} MEDSONG;
+
+typedef struct MEDEXP {
+ ULONG nextmod; /* pointer to next module */
+ ULONG exp_smp; /* pointer to MEDINSTEXT array */
+ UWORD s_ext_entries;
+ UWORD s_ext_entrsz;
+ ULONG annotxt; /* pointer to annotation text */
+ ULONG annolen;
+ ULONG iinfo; /* pointer to MEDINSTINFO array */
+ UWORD i_ext_entries;
+ UWORD i_ext_entrsz;
+ ULONG jumpmask;
+ ULONG rgbtable;
+ ULONG channelsplit;
+ ULONG n_info;
+ ULONG songname; /* pointer to songname */
+ ULONG songnamelen;
+ ULONG dumps;
+ ULONG reserved2[7];
+} MEDEXP;
+
+typedef struct MMD0NOTE {
+ UBYTE a, b, c;
+} MMD0NOTE;
+
+typedef struct MMD1NOTE {
+ UBYTE a, b, c, d;
+} MMD1NOTE;
+
+typedef struct MEDINSTHEADER {
+ ULONG length;
+ SWORD type;
+ /* Followed by actual data */
+} MEDINSTHEADER;
+
+typedef struct MEDINSTEXT {
+ UBYTE hold;
+ UBYTE decay;
+ UBYTE suppress_midi_off;
+ SBYTE finetune;
+} MEDINSTEXT;
+
+typedef struct MEDINSTINFO {
+ UBYTE name[40];
+} MEDINSTINFO;
+
+/*========== Loader variables */
+
+#define MMD0_string 0x4D4D4430
+#define MMD1_string 0x4D4D4431
+
+static MEDHEADER *mh = NULL;
+static MEDSONG *ms = NULL;
+static MEDEXP *me = NULL;
+static ULONG *ba = NULL;
+static MMD0NOTE *mmd0pat = NULL;
+static MMD1NOTE *mmd1pat = NULL;
+
+static int decimalvolumes;
+static int bpmtempos;
+
+#define d0note(row,col) mmd0pat[((row)*(UWORD)of.numchn)+(col)]
+#define d1note(row,col) mmd1pat[((row)*(UWORD)of.numchn)+(col)]
+
+static CHAR MED_Version[] = "OctaMED (MMDx)";
+
+/*========== Loader code */
+
+int MED_Test(void)
+{
+ UBYTE id[4];
+
+ if (!_mm_read_UBYTES(id, 4, modreader))
+ return 0;
+ if ((!memcmp(id, "MMD0", 4)) || (!memcmp(id, "MMD1", 4)))
+ return 1;
+ return 0;
+}
+
+int MED_Init(void)
+{
+ if (!(me = (MEDEXP *)MikMod_malloc(sizeof(MEDEXP))))
+ return 0;
+ if (!(mh = (MEDHEADER *)MikMod_malloc(sizeof(MEDHEADER))))
+ return 0;
+ if (!(ms = (MEDSONG *)MikMod_malloc(sizeof(MEDSONG))))
+ return 0;
+ return 1;
+}
+
+void MED_Cleanup(void)
+{
+ MikMod_free(me);
+ MikMod_free(mh);
+ MikMod_free(ms);
+ MikMod_free(ba);
+ MikMod_free(mmd0pat);
+ MikMod_free(mmd1pat);
+}
+
+static void EffectCvt(UBYTE eff, UBYTE dat)
+{
+ switch (eff) {
+ /* 0x0 0x1 0x2 0x3 0x4 PT effects */
+ case 0x5: /* PT vibrato with speed/depth nibbles swapped */
+ UniPTEffect(0x4, (dat >> 4) | ((dat & 0xf) << 4));
+ break;
+ /* 0x6 0x7 not used */
+ case 0x6:
+ case 0x7:
+ break;
+ case 0x8: /* midi hold/decay */
+ break;
+ case 0x9:
+ if (bpmtempos) {
+ if (!dat)
+ dat = of.initspeed;
+ UniEffect(UNI_S3MEFFECTA, dat);
+ } else {
+ if (dat <= 0x20) {
+ if (!dat)
+ dat = of.initspeed;
+ else
+ dat /= 4;
+ UniPTEffect(0xf, dat);
+ } else
+ UniEffect(UNI_MEDSPEED, ((UWORD)dat * 125) / (33 * 4));
+ }
+ break;
+ /* 0xa 0xb PT effects */
+ case 0xc:
+ if (decimalvolumes)
+ dat = (dat >> 4) * 10 + (dat & 0xf);
+ UniPTEffect(0xc, dat);
+ break;
+ case 0xd: /* same as PT volslide */
+ UniPTEffect(0xa, dat);
+ break;
+ case 0xe: /* synth jmp - midi */
+ break;
+ case 0xf:
+ switch (dat) {
+ case 0: /* patternbreak */
+ UniPTEffect(0xd, 0);
+ break;
+ case 0xf1: /* play note twice */
+ UniWriteByte(UNI_MEDEFFECTF1);
+ break;
+ case 0xf2: /* delay note */
+ UniWriteByte(UNI_MEDEFFECTF2);
+ break;
+ case 0xf3: /* play note three times */
+ UniWriteByte(UNI_MEDEFFECTF3);
+ break;
+ case 0xfe: /* stop playing */
+ UniPTEffect(0xb, of.numpat);
+ break;
+ case 0xff: /* note cut */
+ UniPTEffect(0xc, 0);
+ break;
+ default:
+ if (dat <= 10)
+ UniPTEffect(0xf, dat);
+ else if (dat <= 240) {
+ if (bpmtempos)
+ UniPTEffect(0xf, (dat < 32) ? 32 : dat);
+ else
+ UniEffect(UNI_MEDSPEED, ((UWORD)dat * 125) / 33);
+ }
+ }
+ break;
+ default: /* all normal PT effects are handled here */
+ UniPTEffect(eff, dat);
+ break;
+ }
+}
+
+static UBYTE *MED_Convert1(int count, int col)
+{
+ int t;
+ UBYTE inst, note, eff, dat;
+ MMD1NOTE *n;
+
+ UniReset();
+ for (t = 0; t < count; t++) {
+ n = &d1note(t, col);
+
+ note = n->a & 0x7f;
+ inst = n->b & 0x3f;
+ eff = n->c & 0xf;
+ dat = n->d;
+
+ if (inst)
+ UniInstrument(inst - 1);
+ if (note)
+ UniNote(note + 3 * OCTAVE - 1);
+ EffectCvt(eff, dat);
+ UniNewline();
+ }
+ return UniDup();
+}
+
+static UBYTE *MED_Convert0(int count, int col)
+{
+ int t;
+ UBYTE a, b, inst, note, eff, dat;
+ MMD0NOTE *n;
+
+ UniReset();
+ for (t = 0; t < count; t++) {
+ n = &d0note(t, col);
+ a = n->a;
+ b = n->b;
+
+ note = a & 0x3f;
+ a >>= 6;
+ a = ((a & 1) << 1) | (a >> 1);
+ inst = (b >> 4) | (a << 4);
+ eff = b & 0xf;
+ dat = n->c;
+
+ if (inst)
+ UniInstrument(inst - 1);
+ if (note)
+ UniNote(note + 3 * OCTAVE - 1);
+ EffectCvt(eff, dat);
+ UniNewline();
+ }
+ return UniDup();
+}
+
+static int LoadMEDPatterns(void)
+{
+ int t, row, col;
+ UWORD numtracks, numlines, maxlines = 0, track = 0;
+ MMD0NOTE *mmdp;
+
+ /* first, scan patterns to see how many channels are used */
+ for (t = 0; t < of.numpat; t++) {
+ _mm_fseek(modreader, ba[t], SEEK_SET);
+ numtracks = _mm_read_UBYTE(modreader);
+ numlines = _mm_read_UBYTE(modreader);
+
+ if (numtracks > of.numchn)
+ of.numchn = numtracks;
+ if (numlines > maxlines)
+ maxlines = numlines;
+ }
+
+ of.numtrk = of.numpat * of.numchn;
+ if (!AllocTracks())
+ return 0;
+ if (!AllocPatterns())
+ return 0;
+
+ if (!
+ (mmd0pat =
+ (MMD0NOTE *)MikMod_calloc(of.numchn * (maxlines + 1),
+ sizeof(MMD0NOTE)))) return 0;
+
+ /* second read: read and convert patterns */
+ for (t = 0; t < of.numpat; t++) {
+ _mm_fseek(modreader, ba[t], SEEK_SET);
+ numtracks = _mm_read_UBYTE(modreader);
+ numlines = _mm_read_UBYTE(modreader);
+
+ of.pattrows[t] = ++numlines;
+ memset(mmdp = mmd0pat, 0, of.numchn * maxlines * sizeof(MMD0NOTE));
+ for (row = numlines; row; row--) {
+ for (col = numtracks; col; col--, mmdp++) {
+ mmdp->a = _mm_read_UBYTE(modreader);
+ mmdp->b = _mm_read_UBYTE(modreader);
+ mmdp->c = _mm_read_UBYTE(modreader);
+ }
+ }
+
+ for (col = 0; col < of.numchn; col++)
+ of.tracks[track++] = MED_Convert0(numlines, col);
+ }
+ return 1;
+}
+
+static int LoadMMD1Patterns(void)
+{
+ int t, row, col;
+ UWORD numtracks, numlines, maxlines = 0, track = 0;
+ MMD1NOTE *mmdp;
+
+ /* first, scan patterns to see how many channels are used */
+ for (t = 0; t < of.numpat; t++) {
+ _mm_fseek(modreader, ba[t], SEEK_SET);
+ numtracks = _mm_read_M_UWORD(modreader);
+ numlines = _mm_read_M_UWORD(modreader);
+ if (numtracks > of.numchn)
+ of.numchn = numtracks;
+ if (numlines > maxlines)
+ maxlines = numlines;
+ }
+
+ of.numtrk = of.numpat * of.numchn;
+ if (!AllocTracks())
+ return 0;
+ if (!AllocPatterns())
+ return 0;
+
+ if (!
+ (mmd1pat =
+ (MMD1NOTE *)MikMod_calloc(of.numchn * (maxlines + 1),
+ sizeof(MMD1NOTE)))) return 0;
+
+ /* second read: really read and convert patterns */
+ for (t = 0; t < of.numpat; t++) {
+ _mm_fseek(modreader, ba[t], SEEK_SET);
+ numtracks = _mm_read_M_UWORD(modreader);
+ numlines = _mm_read_M_UWORD(modreader);
+
+ _mm_fseek(modreader, sizeof(ULONG), SEEK_CUR);
+ of.pattrows[t] = ++numlines;
+ memset(mmdp = mmd1pat, 0, of.numchn * maxlines * sizeof(MMD1NOTE));
+
+ for (row = numlines; row; row--) {
+ for (col = numtracks; col; col--, mmdp++) {
+ mmdp->a = _mm_read_UBYTE(modreader);
+ mmdp->b = _mm_read_UBYTE(modreader);
+ mmdp->c = _mm_read_UBYTE(modreader);
+ mmdp->d = _mm_read_UBYTE(modreader);
+ }
+ }
+
+ for (col = 0; col < of.numchn; col++)
+ of.tracks[track++] = MED_Convert1(numlines, col);
+ }
+ return 1;
+}
+
+int MED_Load(int curious)
+{
+ int t;
+ ULONG sa[64];
+ MEDINSTHEADER s;
+ SAMPLE *q;
+ MEDSAMPLE *mss;
+
+ /* try to read module header */
+ mh->id = _mm_read_M_ULONG(modreader);
+ mh->modlen = _mm_read_M_ULONG(modreader);
+ mh->MEDSONGP = _mm_read_M_ULONG(modreader);
+ mh->psecnum = _mm_read_M_UWORD(modreader);
+ mh->pseq = _mm_read_M_UWORD(modreader);
+ mh->MEDBlockPP = _mm_read_M_ULONG(modreader);
+ mh->reserved1 = _mm_read_M_ULONG(modreader);
+ mh->MEDINSTHEADERPP = _mm_read_M_ULONG(modreader);
+ mh->reserved2 = _mm_read_M_ULONG(modreader);
+ mh->MEDEXPP = _mm_read_M_ULONG(modreader);
+ mh->reserved3 = _mm_read_M_ULONG(modreader);
+ mh->pstate = _mm_read_M_UWORD(modreader);
+ mh->pblock = _mm_read_M_UWORD(modreader);
+ mh->pline = _mm_read_M_UWORD(modreader);
+ mh->pseqnum = _mm_read_M_UWORD(modreader);
+ mh->actplayline = _mm_read_M_SWORD(modreader);
+ mh->counter = _mm_read_UBYTE(modreader);
+ mh->extra_songs = _mm_read_UBYTE(modreader);
+
+ /* Seek to MEDSONG struct */
+ _mm_fseek(modreader, mh->MEDSONGP, SEEK_SET);
+
+ /* Load the MED Song Header */
+ mss = ms->sample; /* load the sample data first */
+ for (t = 63; t; t--, mss++) {
+ mss->rep = _mm_read_M_UWORD(modreader);
+ mss->replen = _mm_read_M_UWORD(modreader);
+ mss->midich = _mm_read_UBYTE(modreader);
+ mss->midipreset = _mm_read_UBYTE(modreader);
+ mss->svol = _mm_read_UBYTE(modreader);
+ mss->strans = _mm_read_SBYTE(modreader);
+ }
+
+ ms->numblocks = _mm_read_M_UWORD(modreader);
+ ms->songlen = _mm_read_M_UWORD(modreader);
+ _mm_read_UBYTES(ms->playseq, 256, modreader);
+ ms->deftempo = _mm_read_M_UWORD(modreader);
+ ms->playtransp = _mm_read_SBYTE(modreader);
+ ms->flags = _mm_read_UBYTE(modreader);
+ ms->flags2 = _mm_read_UBYTE(modreader);
+ ms->tempo2 = _mm_read_UBYTE(modreader);
+ _mm_read_UBYTES(ms->trkvol, 16, modreader);
+ ms->mastervol = _mm_read_UBYTE(modreader);
+ ms->numsamples = _mm_read_UBYTE(modreader);
+
+ /* check for a bad header */
+ if (_mm_eof(modreader)) {
+ _mm_errno = MMERR_LOADING_HEADER;
+ return 0;
+ }
+
+ /* load extension structure */
+ if (mh->MEDEXPP) {
+ _mm_fseek(modreader, mh->MEDEXPP, SEEK_SET);
+ me->nextmod = _mm_read_M_ULONG(modreader);
+ me->exp_smp = _mm_read_M_ULONG(modreader);
+ me->s_ext_entries = _mm_read_M_UWORD(modreader);
+ me->s_ext_entrsz = _mm_read_M_UWORD(modreader);
+ me->annotxt = _mm_read_M_ULONG(modreader);
+ me->annolen = _mm_read_M_ULONG(modreader);
+ me->iinfo = _mm_read_M_ULONG(modreader);
+ me->i_ext_entries = _mm_read_M_UWORD(modreader);
+ me->i_ext_entrsz = _mm_read_M_UWORD(modreader);
+ me->jumpmask = _mm_read_M_ULONG(modreader);
+ me->rgbtable = _mm_read_M_ULONG(modreader);
+ me->channelsplit = _mm_read_M_ULONG(modreader);
+ me->n_info = _mm_read_M_ULONG(modreader);
+ me->songname = _mm_read_M_ULONG(modreader);
+ me->songnamelen = _mm_read_M_ULONG(modreader);
+ me->dumps = _mm_read_M_ULONG(modreader);
+ }
+
+ /* seek to and read the samplepointer array */
+ _mm_fseek(modreader, mh->MEDINSTHEADERPP, SEEK_SET);
+ if (!_mm_read_M_ULONGS(sa, ms->numsamples, modreader)) {
+ _mm_errno = MMERR_LOADING_HEADER;
+ return 0;
+ }
+
+ /* alloc and read the blockpointer array */
+ if (!(ba = (ULONG *)MikMod_calloc(ms->numblocks, sizeof(ULONG))))
+ return 0;
+ _mm_fseek(modreader, mh->MEDBlockPP, SEEK_SET);
+ if (!_mm_read_M_ULONGS(ba, ms->numblocks, modreader)) {
+ _mm_errno = MMERR_LOADING_HEADER;
+ return 0;
+ }
+
+ /* copy song positions */
+ if (!AllocPositions(ms->songlen))
+ return 0;
+ for (t = 0; t < ms->songlen; t++)
+ of.positions[t] = ms->playseq[t];
+
+ decimalvolumes = (ms->flags & 0x10) ? 0 : 1;
+ bpmtempos = (ms->flags2 & 0x20) ? 1 : 0;
+
+ if (bpmtempos) {
+ int bpmlen = (ms->flags2 & 0x1f) + 1;
+ of.initspeed = ms->tempo2;
+ of.inittempo = ms->deftempo * bpmlen / 4;
+
+ if (bpmlen != 4) {
+ /* Let's do some math : compute GCD of BPM beat length and speed */
+ int a, b;
+
+ a = bpmlen;
+ b = ms->tempo2;
+
+ if (a > b) {
+ t = b;
+ b = a;
+ a = t;
+ }
+ while ((a != b) && (a)) {
+ t = a;
+ a = b - a;
+ b = t;
+ if (a > b) {
+ t = b;
+ b = a;
+ a = t;
+ }
+ }
+
+ of.initspeed /= b;
+ of.inittempo = ms->deftempo * bpmlen / (4 * b);
+ }
+ } else {
+ of.initspeed = ms->tempo2;
+ of.inittempo = ms->deftempo ? ((UWORD)ms->deftempo * 125) / 33 : 128;
+ if ((ms->deftempo <= 10) && (ms->deftempo))
+ of.inittempo = (of.inittempo * 33) / 6;
+ of.flags |= UF_HIGHBPM;
+ }
+ MED_Version[12] = mh->id;
+ of.modtype = StrDup(MED_Version);
+ of.numchn = 0; /* will be counted later */
+ of.numpat = ms->numblocks;
+ of.numpos = ms->songlen;
+ of.numins = ms->numsamples;
+ of.numsmp = of.numins;
+ of.reppos = 0;
+ if ((mh->MEDEXPP) && (me->songname) && (me->songnamelen)) {
+ char *name;
+
+ _mm_fseek(modreader, me->songname, SEEK_SET);
+ name = MikMod_malloc(me->songnamelen);
+ _mm_read_UBYTES(name, me->songnamelen, modreader);
+ of.songname = DupStr(name, me->songnamelen, 1);
+ MikMod_free(name);
+ } else
+ of.songname = DupStr(NULL, 0, 0);
+ if ((mh->MEDEXPP) && (me->annotxt) && (me->annolen)) {
+ _mm_fseek(modreader, me->annotxt, SEEK_SET);
+ ReadComment(me->annolen);
+ }
+
+ if (!AllocSamples())
+ return 0;
+ q = of.samples;
+ for (t = 0; t < of.numins; t++) {
+ q->flags = SF_SIGNED;
+ q->volume = 64;
+ if (sa[t]) {
+ _mm_fseek(modreader, sa[t], SEEK_SET);
+ s.length = _mm_read_M_ULONG(modreader);
+ s.type = _mm_read_M_SWORD(modreader);
+
+ if (s.type) {
+#ifdef MIKMOD_DEBUG
+ fprintf(stderr, "\rNon-sample instruments not supported in MED loader yet\n");
+#endif
+ if (!curious) {
+ _mm_errno = MMERR_MED_SYNTHSAMPLES;
+ return 0;
+ }
+ s.length = 0;
+ }
+
+ if (_mm_eof(modreader)) {
+ _mm_errno = MMERR_LOADING_SAMPLEINFO;
+ return 0;
+ }
+
+ q->length = s.length;
+ q->seekpos = _mm_ftell(modreader);
+ q->loopstart = ms->sample[t].rep << 1;
+ q->loopend = q->loopstart + (ms->sample[t].replen << 1);
+
+ if (ms->sample[t].replen > 1)
+ q->flags |= SF_LOOP;
+
+ /* don't load sample if length>='MMD0'...
+ such kluges make libmikmod's code unique !!! */
+ if (q->length >= MMD0_string)
+ q->length = 0;
+ } else
+ q->length = 0;
+
+ if ((mh->MEDEXPP) && (me->exp_smp) &&
+ (t < me->s_ext_entries) && (me->s_ext_entrsz >= 4)) {
+ MEDINSTEXT ie;
+
+ _mm_fseek(modreader, me->exp_smp + t * me->s_ext_entrsz,
+ SEEK_SET);
+ ie.hold = _mm_read_UBYTE(modreader);
+ ie.decay = _mm_read_UBYTE(modreader);
+ ie.suppress_midi_off = _mm_read_UBYTE(modreader);
+ ie.finetune = _mm_read_SBYTE(modreader);
+
+ q->speed = finetune[ie.finetune & 0xf];
+ } else
+ q->speed = 8363;
+
+ if ((mh->MEDEXPP) && (me->iinfo) &&
+ (t < me->i_ext_entries) && (me->i_ext_entrsz >= 40)) {
+ MEDINSTINFO ii;
+
+ _mm_fseek(modreader, me->iinfo + t * me->i_ext_entrsz, SEEK_SET);
+ _mm_read_UBYTES(ii.name, 40, modreader);
+ q->samplename = DupStr((char*)ii.name, 40, 1);
+ } else
+ q->samplename = NULL;
+
+ q++;
+ }
+
+ if (mh->id == MMD0_string) {
+ if (!LoadMEDPatterns()) {
+ _mm_errno = MMERR_LOADING_PATTERN;
+ return 0;
+ }
+ } else if (mh->id == MMD1_string) {
+ if (!LoadMMD1Patterns()) {
+ _mm_errno = MMERR_LOADING_PATTERN;
+ return 0;
+ }
+ } else {
+ _mm_errno = MMERR_NOT_A_MODULE;
+ return 0;
+ }
+ return 1;
+}
+
+CHAR *MED_LoadTitle(void)
+{
+ ULONG posit, namelen;
+ CHAR *name, *retvalue = NULL;
+
+ _mm_fseek(modreader, 0x20, SEEK_SET);
+ posit = _mm_read_M_ULONG(modreader);
+
+ if (posit) {
+ _mm_fseek(modreader, posit + 0x2C, SEEK_SET);
+ posit = _mm_read_M_ULONG(modreader);
+ namelen = _mm_read_M_ULONG(modreader);
+
+ _mm_fseek(modreader, posit, SEEK_SET);
+ name = MikMod_malloc(namelen);
+ _mm_read_UBYTES(name, namelen, modreader);
+ retvalue = DupStr(name, namelen, 1);
+ MikMod_free(name);
+ }
+
+ return retvalue;
+}
+
+/*========== Loader information */
+
+MIKMODAPI MLOADER load_med = {
+ NULL,
+ "MED",
+ "MED (OctaMED)",
+ MED_Init,
+ MED_Test,
+ MED_Load,
+ MED_Cleanup,
+ MED_LoadTitle
+};
+
+/* ex:set ts=4: */
diff --git a/apps/plugins/mikmod/load_mod.c b/apps/plugins/mikmod/load_mod.c
new file mode 100644
index 0000000000..92b9787c50
--- /dev/null
+++ b/apps/plugins/mikmod/load_mod.c
@@ -0,0 +1,512 @@
+/* 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_mod.c,v 1.3 2005/04/07 19:57:38 realtech Exp $
+
+ Generic MOD loader (Protracker, StarTracker, FastTracker, etc)
+
+==============================================================================*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <ctype.h>
+#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 */
+
+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[31]; /* all sampleinfo */
+ UBYTE songlength; /* number of patterns used */
+ UBYTE magic1; /* should be 127 */
+ UBYTE positions[128]; /* which pattern to play at pos */
+ UBYTE magic2[4]; /* string "M.K." or "FLT4" or "FLT8" */
+} MODULEHEADER;
+
+typedef struct MODTYPE {
+ CHAR id[5];
+ UBYTE channels;
+ CHAR *name;
+} MODTYPE;
+
+typedef struct MODNOTE {
+ UBYTE a, b, c, d;
+} MODNOTE;
+
+/*========== Loader variables */
+
+#define MODULEHEADERSIZE 0x438
+
+static CHAR protracker[] = "Protracker";
+static CHAR startrekker[] = "Startrekker";
+static CHAR fasttracker[] = "Fasttracker";
+static CHAR oktalyser[] = "Oktalyser";
+static CHAR oktalyzer[] = "Oktalyzer";
+static CHAR taketracker[] = "TakeTracker";
+static CHAR orpheus[] = "Imago Orpheus (MOD format)";
+
+static MODULEHEADER *mh = NULL;
+static MODNOTE *patbuf = NULL;
+static int modtype, trekker;
+
+/*========== Loader code */
+
+/* given the module ID, determine the number of channels and the tracker
+ description ; also alters modtype */
+static int MOD_CheckType(UBYTE *id, UBYTE *numchn, CHAR **descr)
+{
+ modtype = trekker = 0;
+
+ /* Protracker and variants */
+ if ((!memcmp(id, "M.K.", 4)) || (!memcmp(id, "M!K!", 4))) {
+ *descr = protracker;
+ modtype = 0;
+ *numchn = 4;
+ return 1;
+ }
+
+ /* Star Tracker */
+ if (((!memcmp(id, "FLT", 3)) || (!memcmp(id, "EXO", 3))) &&
+ (isdigit(id[3]))) {
+ *descr = startrekker;
+ modtype = trekker = 1;
+ *numchn = id[3] - '0';
+ if (*numchn == 4 || *numchn == 8)
+ return 1;
+#ifdef MIKMOD_DEBUG
+ else
+ fprintf(stderr, "\rUnknown FLT%d module type\n", *numchn);
+#endif
+ return 0;
+ }
+
+ /* Oktalyzer (Amiga) */
+ if (!memcmp(id, "OKTA", 4)) {
+ *descr = oktalyzer;
+ modtype = 1;
+ *numchn = 8;
+ return 1;
+ }
+
+ /* Oktalyser (Atari) */
+ if (!memcmp(id, "CD81", 4)) {
+ *descr = oktalyser;
+ modtype = 1;
+ *numchn = 8;
+ return 1;
+ }
+
+ /* Fasttracker */
+ if ((!memcmp(id + 1, "CHN", 3)) && (isdigit(id[0]))) {
+ *descr = fasttracker;
+ modtype = 1;
+ *numchn = id[0] - '0';
+ return 1;
+ }
+ /* Fasttracker or Taketracker */
+ if (((!memcmp(id + 2, "CH", 2)) || (!memcmp(id + 2, "CN", 2)))
+ && (isdigit(id[0])) && (isdigit(id[1]))) {
+ if (id[3] == 'H') {
+ *descr = fasttracker;
+ modtype = 2; /* this can also be Imago Orpheus */
+ } else {
+ *descr = taketracker;
+ modtype = 1;
+ }
+ *numchn = (id[0] - '0') * 10 + (id[1] - '0');
+ return 1;
+ }
+
+ return 0;
+}
+
+static int MOD_Test(void)
+{
+ UBYTE id[4], numchn;
+ CHAR *descr;
+
+ _mm_fseek(modreader, MODULEHEADERSIZE, SEEK_SET);
+ if (!_mm_read_UBYTES(id, 4, modreader))
+ return 0;
+
+ if (MOD_CheckType(id, &numchn, &descr))
+ return 1;
+
+ return 0;
+}
+
+static int MOD_Init(void)
+{
+ if (!(mh = (MODULEHEADER *)MikMod_malloc(sizeof(MODULEHEADER))))
+ return 0;
+ return 1;
+}
+
+static void MOD_Cleanup(void)
+{
+ MikMod_free(mh);
+ MikMod_free(patbuf);
+}
+
+/*
+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.
+
+*/
+
+static UBYTE ConvertNote(MODNOTE *n, UBYTE lasteffect)
+{
+ UBYTE instrument, effect, effdat, note;
+ UWORD period;
+ UBYTE lastnote = 0;
+
+ /* extract the various information from the 4 bytes that make up a note */
+ instrument = (n->a & 0x10) | (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) {
+ /* if instrument does not exist, note cut */
+ if ((instrument > 31) || (!mh->samples[instrument - 1].length)) {
+ UniPTEffect(0xc, 0);
+ if (effect == 0xc)
+ effect = effdat = 0;
+ } else {
+ /* Protracker handling */
+ if (!modtype) {
+ /* if we had a note, then change instrument... */
+ if (note)
+ UniInstrument(instrument - 1);
+ /* ...otherwise, only adjust volume... */
+ else {
+ /* ...unless an effect was specified, which forces a new
+ note to be played */
+ if (effect || effdat) {
+ UniInstrument(instrument - 1);
+ note = lastnote;
+ } else
+ UniPTEffect(0xc,
+ mh->samples[instrument -
+ 1].volume & 0x7f);
+ }
+ } else {
+ /* Fasttracker handling */
+ 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);
+
+ /* Volume slide, up has priority */
+ if ((effect == 0xa) && (effdat & 0xf) && (effdat & 0xf0))
+ effdat &= 0xf0;
+
+ /* Handle ``heavy'' volumes correctly */
+ if ((effect == 0xc) && (effdat > 0x40))
+ effdat = 0x40;
+
+ /* An isolated 100, 200 or 300 effect should be ignored (no
+ "standalone" porta memory in mod files). However, a sequence such
+ as 1XX, 100, 100, 100 is fine. */
+ if ((!effdat) && ((effect == 1)||(effect == 2)||(effect ==3)) &&
+ (lasteffect < 0x10) && (effect != lasteffect))
+ effect = 0;
+
+ UniPTEffect(effect, effdat);
+ if (effect == 8)
+ of.flags |= UF_PANNING;
+
+ return effect;
+}
+
+static UBYTE *ConvertTrack(MODNOTE *n, int numchn)
+{
+ int t;
+ UBYTE lasteffect = 0x10; /* non existant effect */
+
+ UniReset();
+ for (t = 0; t < 64; t++) {
+ lasteffect = ConvertNote(n,lasteffect);
+ UniNewline();
+ n += numchn;
+ }
+ return UniDup();
+}
+
+/* Loads all patterns of a modfile and converts them into the 3 byte format. */
+static int ML_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 *)MikMod_calloc(64U * of.numchn, sizeof(MODNOTE))))
+ return 0;
+
+ if (trekker && of.numchn == 8) {
+ /* Startrekker module dual pattern */
+ for (t = 0; t < of.numpat; t++) {
+ for (s = 0; s < (64U * 4); s++) {
+ patbuf[s].a = _mm_read_UBYTE(modreader);
+ patbuf[s].b = _mm_read_UBYTE(modreader);
+ patbuf[s].c = _mm_read_UBYTE(modreader);
+ patbuf[s].d = _mm_read_UBYTE(modreader);
+ }
+ for (s = 0; s < 4; s++)
+ if (!(of.tracks[tracks++] = ConvertTrack(patbuf + s, 4)))
+ return 0;
+ for (s = 0; s < (64U * 4); s++) {
+ patbuf[s].a = _mm_read_UBYTE(modreader);
+ patbuf[s].b = _mm_read_UBYTE(modreader);
+ patbuf[s].c = _mm_read_UBYTE(modreader);
+ patbuf[s].d = _mm_read_UBYTE(modreader);
+ }
+ for (s = 0; s < 4; s++)
+ if (!(of.tracks[tracks++] = ConvertTrack(patbuf + s, 4)))
+ return 0;
+ }
+ } else {
+ /* Generic module pattern */
+ for (t = 0; t < of.numpat; t++) {
+ /* Load the pattern into the temp buffer and convert it */
+ for (s = 0; s < (64U * of.numchn); s++) {
+ patbuf[s].a = _mm_read_UBYTE(modreader);
+ patbuf[s].b = _mm_read_UBYTE(modreader);
+ patbuf[s].c = _mm_read_UBYTE(modreader);
+ patbuf[s].d = _mm_read_UBYTE(modreader);
+ }
+ for (s = 0; s < of.numchn; s++)
+ if (!(of.tracks[tracks++] = ConvertTrack(patbuf + s, of.numchn)))
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static int MOD_Load(int curious)
+{
+ int t, scan;
+ SAMPLE *q;
+ MSAMPINFO *s;
+ CHAR *descr;
+
+ /* try to read module header */
+ _mm_read_string((CHAR *)mh->songname, 20, modreader);
+ mh->songname[20] = 0; /* just in case */
+
+ for (t = 0; t < 31; t++) {
+ s = &mh->samples[t];
+ _mm_read_string(s->samplename, 22, modreader);
+ s->samplename[22] = 0; /* just in case */
+ s->length = _mm_read_M_UWORD(modreader);
+ s->finetune = _mm_read_UBYTE(modreader);
+ s->volume = _mm_read_UBYTE(modreader);
+ s->reppos = _mm_read_M_UWORD(modreader);
+ s->replen = _mm_read_M_UWORD(modreader);
+ }
+
+ mh->songlength = _mm_read_UBYTE(modreader);
+
+ /* this fixes mods which declare more than 128 positions.
+ * eg: beatwave.mod */
+ if (mh->songlength > 128) { mh->songlength = 128; }
+
+ mh->magic1 = _mm_read_UBYTE(modreader);
+ _mm_read_UBYTES(mh->positions, 128, modreader);
+ _mm_read_UBYTES(mh->magic2, 4, modreader);
+
+ if (_mm_eof(modreader)) {
+ _mm_errno = MMERR_LOADING_HEADER;
+ return 0;
+ }
+
+ /* set module variables */
+ of.initspeed = 6;
+ of.inittempo = 125;
+ if (!(MOD_CheckType(mh->magic2, &of.numchn, &descr))) {
+ _mm_errno = MMERR_NOT_A_MODULE;
+ return 0;
+ }
+ if (trekker && of.numchn == 8)
+ for (t = 0; t < 128; t++)
+ /* if module pretends to be FLT8, yet the order table
+ contains odd numbers, chances are it's a lying FLT4... */
+ if (mh->positions[t] & 1) {
+ of.numchn = 4;
+ break;
+ }
+ if (trekker && of.numchn == 8)
+ for (t = 0; t < 128; t++)
+ mh->positions[t] >>= 1;
+
+ of.songname = DupStr(mh->songname, 21, 1);
+ 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 = 31;
+ 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, 1);
+ /* init the sampleinfo variables and convert the size pointers */
+ q->speed = finetune[s->finetune & 0xf];
+ q->volume = s->volume & 0x7f;
+ q->loopstart = (ULONG)s->reppos << 1;
+ q->loopend = q->loopstart + ((ULONG)s->replen << 1);
+ q->length = (ULONG)s->length << 1;
+ q->flags = SF_SIGNED;
+ /* Imago Orpheus creates MODs with 16 bit samples, check */
+ if ((modtype == 2) && (s->volume & 0x80)) {
+ q->flags |= SF_16BITS;
+ descr = orpheus;
+ }
+ if (s->replen > 2)
+ q->flags |= SF_LOOP;
+
+ s++;
+ q++;
+ }
+
+ of.modtype = StrDup(descr);
+
+ if (!ML_LoadPatterns())
+ return 0;
+
+ return 1;
+}
+
+static CHAR *MOD_LoadTitle(void)
+{
+ CHAR s[21];
+
+ _mm_fseek(modreader, 0, SEEK_SET);
+ if (!_mm_read_UBYTES(s, 20, modreader))
+ return NULL;
+ s[20] = 0; /* just in case */
+
+ return (DupStr(s, 21, 1));
+}
+
+/*========== Loader information */
+
+MIKMODAPI MLOADER load_mod = {
+ NULL,
+ "Standard module",
+ "MOD (31 instruments)",
+ MOD_Init,
+ MOD_Test,
+ MOD_Load,
+ MOD_Cleanup,
+ MOD_LoadTitle
+};
+
+/* ex:set ts=4: */
diff --git a/apps/plugins/mikmod/load_mtm.c b/apps/plugins/mikmod/load_mtm.c
new file mode 100644
index 0000000000..abd1da41f5
--- /dev/null
+++ b/apps/plugins/mikmod/load_mtm.c
@@ -0,0 +1,285 @@
+/* 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_mtm.c,v 1.3 2005/04/07 19:57:38 realtech Exp $
+
+ MTM 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 */
+
+typedef struct MTMHEADER {
+ UBYTE id[3]; /* MTM file marker */
+ UBYTE version; /* upper major, lower nibble minor version number */
+ CHAR songname[20]; /* ASCIIZ songname */
+ UWORD numtracks; /* number of tracks saved */
+ UBYTE lastpattern; /* last pattern number saved */
+ UBYTE lastorder; /* last order number to play (songlength-1) */
+ UWORD commentsize; /* length of comment field */
+ UBYTE numsamples; /* number of samples saved */
+ UBYTE attribute; /* attribute byte (unused) */
+ UBYTE beatspertrack;
+ UBYTE numchannels; /* number of channels used */
+ UBYTE panpos[32]; /* voice pan positions */
+} MTMHEADER;
+
+typedef struct MTMSAMPLE {
+ CHAR samplename[22];
+ ULONG length;
+ ULONG reppos;
+ ULONG repend;
+ UBYTE finetune;
+ UBYTE volume;
+ UBYTE attribute;
+} MTMSAMPLE;
+
+typedef struct MTMNOTE {
+ UBYTE a,b,c;
+} MTMNOTE;
+
+/*========== Loader variables */
+
+static MTMHEADER *mh = NULL;
+static MTMNOTE *mtmtrk = NULL;
+static UWORD pat[32];
+
+static CHAR MTM_Version[] = "MTM";
+
+/*========== Loader code */
+
+int MTM_Test(void)
+{
+ UBYTE id[3];
+
+ if(!_mm_read_UBYTES(id,3,modreader)) return 0;
+ if(!memcmp(id,"MTM",3)) return 1;
+ return 0;
+}
+
+int MTM_Init(void)
+{
+ if(!(mtmtrk=(MTMNOTE*)MikMod_calloc(64,sizeof(MTMNOTE)))) return 0;
+ if(!(mh=(MTMHEADER*)MikMod_malloc(sizeof(MTMHEADER)))) return 0;
+
+ return 1;
+}
+
+void MTM_Cleanup(void)
+{
+ MikMod_free(mtmtrk);
+ MikMod_free(mh);
+}
+
+static UBYTE* MTM_Convert(void)
+{
+ int t;
+ UBYTE a,b,inst,note,eff,dat;
+
+ UniReset();
+ for(t=0;t<64;t++) {
+ a=mtmtrk[t].a;
+ b=mtmtrk[t].b;
+ inst=((a&0x3)<<4)|(b>>4);
+ note=a>>2;
+ eff=b&0xf;
+ dat=mtmtrk[t].c;
+
+ if(inst) UniInstrument(inst-1);
+ if(note) UniNote(note+2*OCTAVE);
+
+ /* MTM bug workaround : when the effect is volslide, slide-up *always*
+ overrides slide-down. */
+ if(eff==0xa && (dat&0xf0)) dat&=0xf0;
+
+ /* Convert pattern jump from Dec to Hex */
+ if(eff==0xd)
+ dat=(((dat&0xf0)>>4)*10)+(dat&0xf);
+ UniPTEffect(eff,dat);
+ UniNewline();
+ }
+ return UniDup();
+}
+
+int MTM_Load(int curious)
+{
+ int t,u;
+ MTMSAMPLE s;
+ SAMPLE *q;
+
+ /* try to read module header */
+ _mm_read_UBYTES(mh->id,3,modreader);
+ mh->version =_mm_read_UBYTE(modreader);
+ _mm_read_string(mh->songname,20,modreader);
+ mh->numtracks =_mm_read_I_UWORD(modreader);
+ mh->lastpattern =_mm_read_UBYTE(modreader);
+ mh->lastorder =_mm_read_UBYTE(modreader);
+ mh->commentsize =_mm_read_I_UWORD(modreader);
+ mh->numsamples =_mm_read_UBYTE(modreader);
+ mh->attribute =_mm_read_UBYTE(modreader);
+ mh->beatspertrack=_mm_read_UBYTE(modreader);
+ mh->numchannels =_mm_read_UBYTE(modreader);
+ _mm_read_UBYTES(mh->panpos,32,modreader);
+
+ if(_mm_eof(modreader)) {
+ _mm_errno = MMERR_LOADING_HEADER;
+ return 0;
+ }
+
+ /* set module variables */
+ of.initspeed = 6;
+ of.inittempo = 125;
+ of.modtype = StrDup(MTM_Version);
+ of.numchn = mh->numchannels;
+ of.numtrk = mh->numtracks+1; /* get number of channels */
+ of.songname = DupStr(mh->songname,20,1); /* make a cstr of songname */
+ of.numpos = mh->lastorder+1; /* copy the songlength */
+ of.numpat = mh->lastpattern+1;
+ of.reppos = 0;
+ of.flags |= UF_PANNING;
+ for(t=0;t<32;t++) of.panning[t]=mh->panpos[t]<< 4;
+ of.numins=of.numsmp=mh->numsamples;
+
+ if(!AllocSamples()) return 0;
+ q=of.samples;
+ for(t=0;t<of.numins;t++) {
+ /* try to read sample info */
+ _mm_read_string(s.samplename,22,modreader);
+ s.length =_mm_read_I_ULONG(modreader);
+ s.reppos =_mm_read_I_ULONG(modreader);
+ s.repend =_mm_read_I_ULONG(modreader);
+ s.finetune =_mm_read_UBYTE(modreader);
+ s.volume =_mm_read_UBYTE(modreader);
+ s.attribute =_mm_read_UBYTE(modreader);
+
+ if(_mm_eof(modreader)) {
+ _mm_errno = MMERR_LOADING_SAMPLEINFO;
+ return 0;
+ }
+
+ q->samplename = DupStr(s.samplename,22,1);
+ q->seekpos = 0;
+ q->speed = finetune[s.finetune];
+ q->length = s.length;
+ q->loopstart = s.reppos;
+ q->loopend = s.repend;
+ q->volume = s.volume;
+ if((s.repend-s.reppos)>2) q->flags |= SF_LOOP;
+
+ if(s.attribute&1) {
+ /* If the sample is 16-bits, convert the length and replen
+ byte-values into sample-values */
+ q->flags|=SF_16BITS;
+ q->length>>=1;
+ q->loopstart>>=1;
+ q->loopend>>=1;
+ }
+ q++;
+ }
+
+ if(!AllocPositions(of.numpos)) return 0;
+ for(t=0;t<of.numpos;t++)
+ of.positions[t]=_mm_read_UBYTE(modreader);
+ for(;t<128;t++) _mm_read_UBYTE(modreader);
+ if(_mm_eof(modreader)) {
+ _mm_errno = MMERR_LOADING_HEADER;
+ return 0;
+ }
+
+ if(!AllocTracks()) return 0;
+ if(!AllocPatterns()) return 0;
+
+ of.tracks[0]=MTM_Convert(); /* track 0 is empty */
+ for(t=1;t<of.numtrk;t++) {
+ int s;
+
+ for(s=0;s<64;s++) {
+ mtmtrk[s].a=_mm_read_UBYTE(modreader);
+ mtmtrk[s].b=_mm_read_UBYTE(modreader);
+ mtmtrk[s].c=_mm_read_UBYTE(modreader);
+ }
+
+ if(_mm_eof(modreader)) {
+ _mm_errno = MMERR_LOADING_TRACK;
+ return 0;
+ }
+
+ if(!(of.tracks[t]=MTM_Convert())) return 0;
+ }
+
+ for(t=0;t<of.numpat;t++) {
+ _mm_read_I_UWORDS(pat,32,modreader);
+ for(u=0;u<of.numchn;u++)
+ of.patterns[((long)t*of.numchn)+u]=pat[u];
+ }
+
+ /* read comment field */
+ if(mh->commentsize)
+ if(!ReadLinedComment(mh->commentsize, 40)) return 0;
+
+ return 1;
+}
+
+CHAR *MTM_LoadTitle(void)
+{
+ CHAR s[20];
+
+ _mm_fseek(modreader,4,SEEK_SET);
+ if(!_mm_read_UBYTES(s,20,modreader)) return NULL;
+
+ return(DupStr(s,20,1));
+}
+
+/*========== Loader information */
+
+MIKMODAPI MLOADER load_mtm={
+ NULL,
+ "MTM",
+ "MTM (MultiTracker Module editor)",
+ MTM_Init,
+ MTM_Test,
+ MTM_Load,
+ MTM_Cleanup,
+ MTM_LoadTitle
+};
+
+/* ex:set ts=4: */
diff --git a/apps/plugins/mikmod/load_okt.c b/apps/plugins/mikmod/load_okt.c
new file mode 100644
index 0000000000..c4420e5738
--- /dev/null
+++ b/apps/plugins/mikmod/load_okt.c
@@ -0,0 +1,460 @@
+/* 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_okt.c,v 1.3 2005/04/07 19:57:38 realtech Exp $
+
+ Oktalyzer (OKT) module loader
+
+==============================================================================*/
+
+/*
+ Written by UFO <ufo303@poczta.onet.pl>
+ based on the file description compiled by Harald Zappe
+ <zappe@gaea.sietec.de>
+
+*/
+
+#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 blocks */
+
+/* sample information */
+typedef struct OKTSAMPLE {
+ CHAR sampname[20];
+ ULONG len;
+ UWORD loopbeg;
+ UWORD looplen;
+ UBYTE volume;
+} OKTSAMPLE;
+
+typedef struct OKTNOTE {
+ UBYTE note, ins, eff, dat;
+} OKTNOTE;
+
+/*========== Loader variables */
+
+static OKTNOTE *okttrk = NULL;
+
+/*========== Loader code */
+
+int OKT_Test(void)
+{
+ CHAR id[8];
+
+ if (!_mm_read_UBYTES(id, 8, modreader))
+ return 0;
+ if (!memcmp(id, "OKTASONG", 8))
+ return 1;
+
+ return 0;
+}
+
+/* Pattern analysis routine.
+ Effects not implemented (yet) : (in decimal)
+ 11 Arpeggio 4: Change note every 50Hz tick between N,H,N,L
+ 12 Arpeggio 5: Change note every 50Hz tick between H,H,N
+ N = normal note being played in this channel (1-36)
+ L = normal note number minus upper four bits of 'data'.
+ H = normal note number plus lower four bits of 'data'.
+ 13 Decrease note number by 'data' once per tick.
+ 17 Increase note number by 'data' once per tick.
+ 21 Decrease note number by 'data' once per line.
+ 30 Increase note number by 'data' once per line.
+*/
+static UBYTE *OKT_ConvertTrack(UBYTE patrows)
+{
+ int t;
+ UBYTE ins, note, eff, dat;
+
+ UniReset();
+ for (t = 0; t < patrows; t++) {
+ note = okttrk[t].note;
+ ins = okttrk[t].ins;
+ eff = okttrk[t].eff;
+ dat = okttrk[t].dat;
+
+ if (note) {
+ UniNote(note + 3 * OCTAVE - 1);
+ UniInstrument(ins);
+ }
+
+ if (eff)
+ switch (eff) {
+ case 1: /* Porta Up */
+ UniPTEffect(0x1, dat);
+ break;
+ case 2: /* Portamento Down */
+ UniPTEffect(0x2, dat);
+ break;
+ /* case 9: what is this? */
+ case 10: /* Arpeggio 3 */
+ case 11: /* Arpeggio 4 */
+ case 12: /* Arpeggio 5 */
+ UniWriteByte(UNI_OKTARP);
+ UniWriteByte(eff + 3 - 10);
+ UniWriteByte(dat);
+ break;
+ case 15: /* Amiga filter toggle, ignored */
+ break;
+ case 25: /* Pattern Jump */
+ dat = (dat >> 4) * 10 + (dat & 0x0f);
+ UniPTEffect(0xb, dat);
+ break;
+ case 27: /* Release - similar to Keyoff */
+ UniWriteByte(UNI_KEYOFF);
+ break;
+ case 28: /* Set Tempo */
+ UniPTEffect(0xf, dat & 0x0f);
+ break;
+ case 31: /* volume Control */
+ if (dat <= 0x40)
+ UniPTEffect(0xc, dat);
+ else if (dat <= 0x50)
+ UniEffect(UNI_XMEFFECTA, (dat - 0x40)); /* fast fade out */
+ else if (dat <= 0x60)
+ UniEffect(UNI_XMEFFECTA, (dat - 0x50) << 4); /* fast fade in */
+ else if (dat <= 0x70)
+ UniEffect(UNI_XMEFFECTEB, (dat - 0x60)); /* slow fade out */
+ else if (dat <= 0x80)
+ UniEffect(UNI_XMEFFECTEA, (dat - 0x70)); /* slow fade in */
+ break;
+#ifdef MIKMOD_DEBUG
+ default:
+ fprintf(stderr, "\rUnimplemented effect (%02d,%02x)\n",
+ eff, dat);
+#endif
+ }
+
+ UniNewline();
+ }
+ return UniDup();
+}
+
+/* Read "channel modes" i.e. channel number and panning information */
+static void OKT_doCMOD(void)
+{
+ /* amiga channel panning table */
+ UBYTE amigapan[4] = { 0x00, 0xff, 0xff, 0x00 };
+ int t;
+
+ of.numchn = 0;
+ of.flags |= UF_PANNING;
+
+ for (t = 0; t < 4; t++)
+ if (_mm_read_M_UWORD(modreader)) {
+ /* two channels tied to the same Amiga hardware voice */
+ of.panning[of.numchn++] = amigapan[t];
+ of.panning[of.numchn++] = amigapan[t];
+ } else
+ /* one channel tied to the Amiga hardware voice */
+ of.panning[of.numchn++] = amigapan[t];
+}
+
+/* Read sample information */
+static int OKT_doSAMP(int len)
+{
+ int t;
+ SAMPLE *q;
+ OKTSAMPLE s;
+
+ of.numins = of.numsmp = (len / 0x20);
+ if (!AllocSamples())
+ return 0;
+
+ for (t = 0, q = of.samples; t < of.numins; t++, q++) {
+ _mm_read_UBYTES(s.sampname, 20, modreader);
+ s.len = _mm_read_M_ULONG(modreader);
+ s.loopbeg = _mm_read_M_UWORD(modreader) * 2;
+ s.looplen = _mm_read_M_UWORD(modreader) * 2;
+ _mm_read_UBYTE(modreader);
+ s.volume = _mm_read_UBYTE(modreader);
+ _mm_read_M_UWORD(modreader);
+
+ if (_mm_eof(modreader)) {
+ _mm_errno = MMERR_LOADING_SAMPLEINFO;
+ return 0;
+ }
+
+ if (!s.len)
+ q->seekpos = q->length = q->loopstart = q->loopend = q->flags = 0;
+ else {
+ s.len--;
+ /* sanity checks */
+ if (s.loopbeg > s.len)
+ s.loopbeg = s.len;
+ if (s.loopbeg + s.looplen > s.len)
+ s.looplen = s.len - s.loopbeg;
+ if (s.looplen < 2)
+ s.looplen = 0;
+
+ q->length = s.len;
+ q->loopstart = s.loopbeg;
+ q->loopend = s.looplen + q->loopstart;
+ q->volume = s.volume;
+ q->flags = SF_SIGNED;
+
+ if (s.looplen)
+ q->flags |= SF_LOOP;
+ }
+ q->samplename = DupStr(s.sampname, 20, 1);
+ q->speed = 8287;
+ }
+ return 1;
+}
+
+/* Read speed information */
+static void OKT_doSPEE(void)
+{
+ int tempo = _mm_read_M_UWORD(modreader);
+
+ of.initspeed = tempo;
+}
+
+/* Read song length information */
+static void OKT_doSLEN(void)
+{
+ of.numpat = _mm_read_M_UWORD(modreader);
+}
+
+/* Read pattern length information */
+static void OKT_doPLEN(void)
+{
+ of.numpos = _mm_read_M_UWORD(modreader);
+}
+
+/* Read order table */
+static int OKT_doPATT(void)
+{
+ int t;
+
+ if (!of.numpos || !AllocPositions(of.numpos))
+ return 0;
+
+ for (t = 0; t < 128; t++)
+ if (t < of.numpos)
+ of.positions[t] = _mm_read_UBYTE(modreader);
+ else
+ break;
+
+ return 1;
+}
+
+static int OKT_doPBOD(int patnum)
+{
+ char *patbuf;
+ int rows, i;
+ int u;
+
+ if (!patnum) {
+ of.numtrk = of.numpat * of.numchn;
+
+ if (!AllocTracks() || !AllocPatterns())
+ return 0;
+ }
+
+ /* Read pattern */
+ of.pattrows[patnum] = rows = _mm_read_M_UWORD(modreader);
+
+ if (!(okttrk = (OKTNOTE *) MikMod_calloc(rows, sizeof(OKTNOTE))) ||
+ !(patbuf = (char *)MikMod_calloc(rows * of.numchn, sizeof(OKTNOTE))))
+ return 0;
+ _mm_read_UBYTES(patbuf, rows * of.numchn * sizeof(OKTNOTE), modreader);
+ if (_mm_eof(modreader)) {
+ _mm_errno = MMERR_LOADING_PATTERN;
+ return 0;
+ }
+
+ for (i = 0; i < of.numchn; i++) {
+ for (u = 0; u < rows; u++) {
+ okttrk[u].note = patbuf[(u * of.numchn + i) * sizeof(OKTNOTE)];
+ okttrk[u].ins = patbuf[(u * of.numchn + i) * sizeof(OKTNOTE) + 1];
+ okttrk[u].eff = patbuf[(u * of.numchn + i) * sizeof(OKTNOTE) + 2];
+ okttrk[u].dat = patbuf[(u * of.numchn + i) * sizeof(OKTNOTE) + 3];
+ }
+
+ if (!(of.tracks[patnum * of.numchn + i] = OKT_ConvertTrack(rows)))
+ return 0;
+ }
+ MikMod_free(patbuf);
+ MikMod_free(okttrk);
+ return 1;
+}
+
+static void OKT_doSBOD(int insnum)
+{
+ of.samples[insnum].seekpos = _mm_ftell(modreader);
+}
+
+int OKT_Load(int curious)
+{
+ UBYTE id[4];
+ ULONG len;
+ ULONG fp;
+ int seen_cmod = 0, seen_samp = 0, seen_slen = 0, seen_plen = 0, seen_patt
+ = 0, seen_spee = 0;
+ int patnum = 0, insnum = 0;
+
+ /* skip OKTALYZER header */
+ _mm_fseek(modreader, 8, SEEK_SET);
+ of.songname = StrDup("");
+
+ of.modtype = StrDup("Amiga Oktalyzer");
+ of.numpos = of.reppos = 0;
+
+ /* default values */
+ of.initspeed = 6;
+ of.inittempo = 125;
+
+ while (1) {
+ /* read block header */
+ _mm_read_UBYTES(id, 4, modreader);
+ len = _mm_read_M_ULONG(modreader);
+
+ if (_mm_eof(modreader))
+ break;
+ fp = _mm_ftell(modreader);
+
+ if (!memcmp(id, "CMOD", 4)) {
+ if (!seen_cmod) {
+ OKT_doCMOD();
+ seen_cmod = 1;
+ } else {
+ _mm_errno = MMERR_LOADING_HEADER;
+ return 0;
+ }
+ } else if (!memcmp(id, "SAMP", 4)) {
+ if (!seen_samp && OKT_doSAMP(len))
+ seen_samp = 1;
+ else {
+ _mm_errno = MMERR_LOADING_HEADER;
+ return 0;
+ }
+ } else if (!memcmp(id, "SPEE", 4)) {
+ if (!seen_spee) {
+ OKT_doSPEE();
+ seen_spee = 1;
+ } else {
+ _mm_errno = MMERR_LOADING_HEADER;
+ return 0;
+ }
+ } else if (!memcmp(id, "SLEN", 4)) {
+ if (!seen_slen) {
+ OKT_doSLEN();
+ seen_slen = 1;
+ } else {
+ _mm_errno = MMERR_LOADING_HEADER;
+ return 0;
+ }
+ } else if (!memcmp(id, "PLEN", 4)) {
+ if (!seen_plen) {
+ OKT_doPLEN();
+ seen_plen = 1;
+ } else {
+ _mm_errno = MMERR_LOADING_HEADER;
+ return 0;
+ }
+ } else if (!memcmp(id, "PATT", 4)) {
+ if (!seen_plen) {
+ _mm_errno = MMERR_LOADING_HEADER;
+ return 0;
+ }
+ if (!seen_patt && OKT_doPATT())
+ seen_patt = 1;
+ else {
+ _mm_errno = MMERR_LOADING_HEADER;
+ return 0;
+ }
+ } else if (!memcmp(id,"PBOD", 4)) {
+ /* need to know numpat and numchn */
+ if (!seen_slen || !seen_cmod || (patnum >= of.numpat)) {
+ _mm_errno = MMERR_LOADING_HEADER;
+ return 0;
+ }
+ if (!OKT_doPBOD(patnum++)) {
+ _mm_errno = MMERR_LOADING_PATTERN;
+ return 0;
+ }
+ } else if (!memcmp(id,"SBOD",4)) {
+ /* need to know numsmp */
+ if (!seen_samp) {
+ _mm_errno = MMERR_LOADING_HEADER;
+ return 0;
+ }
+ while ((insnum < of.numins) && !of.samples[insnum].length)
+ insnum++;
+ if (insnum >= of.numins) {
+ _mm_errno = MMERR_LOADING_HEADER;
+ return 0;
+ }
+ OKT_doSBOD(insnum++);
+ }
+
+ /* goto next block start position */
+ _mm_fseek(modreader, fp + len, SEEK_SET);
+ }
+
+ if (!seen_cmod || !seen_samp || !seen_patt ||
+ !seen_slen || !seen_plen || (patnum != of.numpat)) {
+ _mm_errno = MMERR_LOADING_HEADER;
+ return 0;
+ }
+
+ return 1;
+}
+
+CHAR *OKT_LoadTitle(void)
+{
+ return StrDup("");
+}
+
+/*========== Loader information */
+
+MIKMODAPI MLOADER load_okt = {
+ NULL,
+ "OKT",
+ "OKT (Amiga Oktalyzer)",
+ NULL,
+ OKT_Test,
+ OKT_Load,
+ NULL,
+ OKT_LoadTitle
+};
+
+/* ex:set ts=4: */
diff --git a/apps/plugins/mikmod/load_s3m.c b/apps/plugins/mikmod/load_s3m.c
new file mode 100644
index 0000000000..4ecb5bdd1f
--- /dev/null
+++ b/apps/plugins/mikmod/load_s3m.c
@@ -0,0 +1,470 @@
+/* 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_s3m.c,v 1.3 2005/04/07 19:57:38 realtech Exp $
+
+ Screamtracker (S3M) 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 */
+
+/* header */
+typedef struct S3MHEADER {
+ CHAR songname[28];
+ UBYTE t1a;
+ UBYTE type;
+ UBYTE unused1[2];
+ UWORD ordnum;
+ UWORD insnum;
+ UWORD patnum;
+ UWORD flags;
+ UWORD tracker;
+ UWORD fileformat;
+ CHAR scrm[4];
+ UBYTE mastervol;
+ UBYTE initspeed;
+ UBYTE inittempo;
+ UBYTE mastermult;
+ UBYTE ultraclick;
+ UBYTE pantable;
+ UBYTE unused2[8];
+ UWORD special;
+ UBYTE channels[32];
+} S3MHEADER;
+
+/* sample information */
+typedef struct S3MSAMPLE {
+ UBYTE type;
+ CHAR filename[12];
+ UBYTE memsegh;
+ UWORD memsegl;
+ ULONG length;
+ ULONG loopbeg;
+ ULONG loopend;
+ UBYTE volume;
+ UBYTE dsk;
+ UBYTE pack;
+ UBYTE flags;
+ ULONG c2spd;
+ UBYTE unused[12];
+ CHAR sampname[28];
+ CHAR scrs[4];
+} S3MSAMPLE;
+
+typedef struct S3MNOTE {
+ UBYTE note,ins,vol,cmd,inf;
+} S3MNOTE;
+
+/*========== Loader variables */
+
+static S3MNOTE *s3mbuf = NULL; /* pointer to a complete S3M pattern */
+static S3MHEADER *mh = NULL;
+static UWORD *paraptr = NULL; /* parapointer array (see S3M docs) */
+static unsigned int tracker; /* tracker id */
+
+/* tracker identifiers */
+#define NUMTRACKERS 4
+static CHAR* S3M_Version[] = {
+ "Screamtracker x.xx",
+ "Imago Orpheus x.xx (S3M format)",
+ "Impulse Tracker x.xx (S3M format)",
+ "Unknown tracker x.xx (S3M format)",
+ "Impulse Tracker 2.14p3 (S3M format)",
+ "Impulse Tracker 2.14p4 (S3M format)"
+};
+/* version number position in above array */
+static int numeric[NUMTRACKERS]={14,14,16,16};
+
+/*========== Loader code */
+
+int S3M_Test(void)
+{
+ UBYTE id[4];
+
+ _mm_fseek(modreader,0x2c,SEEK_SET);
+ if(!_mm_read_UBYTES(id,4,modreader)) return 0;
+ if(!memcmp(id,"SCRM",4)) return 1;
+ return 0;
+}
+
+int S3M_Init(void)
+{
+ if(!(s3mbuf=(S3MNOTE*)MikMod_malloc(32*64*sizeof(S3MNOTE)))) return 0;
+ if(!(mh=(S3MHEADER*)MikMod_malloc(sizeof(S3MHEADER)))) return 0;
+ if(!(poslookup=(UBYTE*)MikMod_malloc(sizeof(UBYTE)*256))) return 0;
+ memset(poslookup,-1,256);
+
+ return 1;
+}
+
+void S3M_Cleanup(void)
+{
+ MikMod_free(s3mbuf);
+ MikMod_free(paraptr);
+ MikMod_free(poslookup);
+ MikMod_free(mh);
+ MikMod_free(origpositions);
+}
+
+/* Because so many s3m files have 16 channels as the set number used, but really
+ only use far less (usually 8 to 12 still), I had to make this function, which
+ determines the number of channels that are actually USED by a pattern.
+
+ For every channel that's used, it sets the appropriate array entry of the
+ global variable 'remap'
+
+ NOTE: You must first seek to the file location of the pattern before calling
+ this procedure.
+
+ Returns 1 on fail. */
+static int S3M_GetNumChannels(void)
+{
+ int row=0,flag,ch;
+
+ while(row<64) {
+ flag=_mm_read_UBYTE(modreader);
+
+ if(_mm_eof(modreader)) {
+ _mm_errno = MMERR_LOADING_PATTERN;
+ return 1;
+ }
+
+ if(flag) {
+ ch=flag&31;
+ if(mh->channels[ch]<32) remap[ch] = 0;
+ if(flag&32) {_mm_read_UBYTE(modreader);_mm_read_UBYTE(modreader);}
+ if(flag&64) _mm_read_UBYTE(modreader);
+ if(flag&128){_mm_read_UBYTE(modreader);_mm_read_UBYTE(modreader);}
+ } else row++;
+ }
+ return 0;
+}
+
+static int S3M_ReadPattern(void)
+{
+ int row=0,flag,ch;
+ S3MNOTE *n,dummy;
+
+ /* clear pattern data */
+ memset(s3mbuf,255,32*64*sizeof(S3MNOTE));
+
+ while(row<64) {
+ flag=_mm_read_UBYTE(modreader);
+
+ if(_mm_eof(modreader)) {
+ _mm_errno = MMERR_LOADING_PATTERN;
+ return 0;
+ }
+
+ if(flag) {
+ ch=remap[flag&31];
+
+ if(ch!=-1)
+ n=&s3mbuf[(64U*ch)+row];
+ else
+ n=&dummy;
+
+ if(flag&32) {
+ n->note=_mm_read_UBYTE(modreader);
+ n->ins=_mm_read_UBYTE(modreader);
+ }
+ if(flag&64) {
+ n->vol=_mm_read_UBYTE(modreader);
+ if (n->vol>64) n->vol=64;
+ }
+ if(flag&128) {
+ n->cmd=_mm_read_UBYTE(modreader);
+ n->inf=_mm_read_UBYTE(modreader);
+ }
+ } else row++;
+ }
+ return 1;
+}
+
+static UBYTE* S3M_ConvertTrack(S3MNOTE* tr)
+{
+ int t;
+
+ UniReset();
+ for(t=0;t<64;t++) {
+ UBYTE note,ins,vol;
+
+ note=tr[t].note;
+ ins=tr[t].ins;
+ vol=tr[t].vol;
+
+ if((ins)&&(ins!=255)) UniInstrument(ins-1);
+ if(note!=255) {
+ if(note==254) {
+ UniPTEffect(0xc,0); /* note cut command */
+ vol=255;
+ } else
+ UniNote(((note>>4)*OCTAVE)+(note&0xf)); /* normal note */
+ }
+ if(vol<255) UniPTEffect(0xc,vol);
+
+ S3MIT_ProcessCmd(tr[t].cmd,tr[t].inf,
+ tracker == 1 ? S3MIT_OLDSTYLE | S3MIT_SCREAM : S3MIT_OLDSTYLE);
+ UniNewline();
+ }
+ return UniDup();
+}
+
+int S3M_Load(int curious)
+{
+ int t,u,track = 0;
+ SAMPLE *q;
+ UBYTE pan[32];
+
+ /* try to read module header */
+ _mm_read_string(mh->songname,28,modreader);
+ mh->t1a =_mm_read_UBYTE(modreader);
+ mh->type =_mm_read_UBYTE(modreader);
+ _mm_read_UBYTES(mh->unused1,2,modreader);
+ mh->ordnum =_mm_read_I_UWORD(modreader);
+ mh->insnum =_mm_read_I_UWORD(modreader);
+ mh->patnum =_mm_read_I_UWORD(modreader);
+ mh->flags =_mm_read_I_UWORD(modreader);
+ mh->tracker =_mm_read_I_UWORD(modreader);
+ mh->fileformat =_mm_read_I_UWORD(modreader);
+ _mm_read_string(mh->scrm,4,modreader);
+ mh->mastervol =_mm_read_UBYTE(modreader);
+ mh->initspeed =_mm_read_UBYTE(modreader);
+ mh->inittempo =_mm_read_UBYTE(modreader);
+ mh->mastermult =_mm_read_UBYTE(modreader);
+ mh->ultraclick =_mm_read_UBYTE(modreader);
+ mh->pantable =_mm_read_UBYTE(modreader);
+ _mm_read_UBYTES(mh->unused2,8,modreader);
+ mh->special =_mm_read_I_UWORD(modreader);
+ _mm_read_UBYTES(mh->channels,32,modreader);
+
+ if(_mm_eof(modreader)) {
+ _mm_errno = MMERR_LOADING_HEADER;
+ return 0;
+ }
+
+ /* then we can decide the module type */
+ tracker=mh->tracker>>12;
+ if((!tracker)||(tracker>=NUMTRACKERS))
+ tracker=NUMTRACKERS-1; /* unknown tracker */
+ else {
+ if(mh->tracker>=0x3217)
+ tracker=NUMTRACKERS+1; /* IT 2.14p4 */
+ else if(mh->tracker>=0x3216)
+ tracker=NUMTRACKERS; /* IT 2.14p3 */
+ else tracker--;
+ }
+ of.modtype = StrDup(S3M_Version[tracker]);
+ if(tracker<NUMTRACKERS) {
+ of.modtype[numeric[tracker]] = ((mh->tracker>>8) &0xf)+'0';
+ of.modtype[numeric[tracker]+2] = ((mh->tracker>>4)&0xf)+'0';
+ of.modtype[numeric[tracker]+3] = ((mh->tracker)&0xf)+'0';
+ }
+ /* set module variables */
+ of.songname = DupStr(mh->songname,28,0);
+ of.numpat = mh->patnum;
+ of.reppos = 0;
+ of.numins = of.numsmp = mh->insnum;
+ of.initspeed = mh->initspeed;
+ of.inittempo = mh->inittempo;
+ of.initvolume = mh->mastervol<<1;
+ of.flags |= UF_ARPMEM | UF_PANNING;
+ if((mh->tracker==0x1300)||(mh->flags&64))
+ of.flags|=UF_S3MSLIDES;
+ of.bpmlimit = 32;
+
+ /* read the order data */
+ if(!AllocPositions(mh->ordnum)) return 0;
+ if(!(origpositions=MikMod_calloc(mh->ordnum,sizeof(UWORD)))) return 0;
+
+ for(t=0;t<mh->ordnum;t++) {
+ origpositions[t]=_mm_read_UBYTE(modreader);
+ if((origpositions[t]>=mh->patnum)&&(origpositions[t]<254))
+ origpositions[t]=255/*mh->patnum-1*/;
+ }
+
+ if(_mm_eof(modreader)) {
+ _mm_errno = MMERR_LOADING_HEADER;
+ return 0;
+ }
+
+ poslookupcnt=mh->ordnum;
+ S3MIT_CreateOrders(curious);
+
+ if(!(paraptr=(UWORD*)MikMod_malloc((of.numins+of.numpat)*sizeof(UWORD))))
+ return 0;
+
+ /* read the instrument+pattern parapointers */
+ _mm_read_I_UWORDS(paraptr,of.numins+of.numpat,modreader);
+
+ if(mh->pantable==252) {
+ /* read the panning table (ST 3.2 addition. See below for further
+ portions of channel panning [past reampper]). */
+ _mm_read_UBYTES(pan,32,modreader);
+ }
+
+ if(_mm_eof(modreader)) {
+ _mm_errno = MMERR_LOADING_HEADER;
+ return 0;
+ }
+
+ /* load samples */
+ if(!AllocSamples()) return 0;
+ q = of.samples;
+ for(t=0;t<of.numins;t++) {
+ S3MSAMPLE s;
+
+ /* seek to instrument position */
+ _mm_fseek(modreader,((long)paraptr[t])<<4,SEEK_SET);
+ /* and load sample info */
+ s.type =_mm_read_UBYTE(modreader);
+ _mm_read_string(s.filename,12,modreader);
+ s.memsegh =_mm_read_UBYTE(modreader);
+ s.memsegl =_mm_read_I_UWORD(modreader);
+ s.length =_mm_read_I_ULONG(modreader);
+ s.loopbeg =_mm_read_I_ULONG(modreader);
+ s.loopend =_mm_read_I_ULONG(modreader);
+ s.volume =_mm_read_UBYTE(modreader);
+ s.dsk =_mm_read_UBYTE(modreader);
+ s.pack =_mm_read_UBYTE(modreader);
+ s.flags =_mm_read_UBYTE(modreader);
+ s.c2spd =_mm_read_I_ULONG(modreader);
+ _mm_read_UBYTES(s.unused,12,modreader);
+ _mm_read_string(s.sampname,28,modreader);
+ _mm_read_string(s.scrs,4,modreader);
+
+ /* ScreamTracker imposes a 64000 bytes (not 64k !) limit */
+ if (s.length > 64000)
+ s.length = 64000;
+
+ if(_mm_eof(modreader)) {
+ _mm_errno = MMERR_LOADING_SAMPLEINFO;
+ return 0;
+ }
+
+ q->samplename = DupStr(s.sampname,28,0);
+ q->speed = s.c2spd;
+ q->length = s.length;
+ q->loopstart = s.loopbeg;
+ q->loopend = s.loopend;
+ q->volume = s.volume;
+ q->seekpos = (((long)s.memsegh)<<16|s.memsegl)<<4;
+
+ if(s.flags&1) q->flags |= SF_LOOP;
+ if(s.flags&4) q->flags |= SF_16BITS;
+ if(mh->fileformat==1) q->flags |= SF_SIGNED;
+
+ /* don't load sample if it doesn't have the SCRS tag */
+ if(memcmp(s.scrs,"SCRS",4)) q->length = 0;
+
+ q++;
+ }
+
+ /* determine the number of channels actually used. */
+ of.numchn = 0;
+ memset(remap,-1,32*sizeof(UBYTE));
+ for(t=0;t<of.numpat;t++) {
+ /* seek to pattern position (+2 skip pattern length) */
+ _mm_fseek(modreader,(long)((paraptr[of.numins+t])<<4)+2,SEEK_SET);
+ if(S3M_GetNumChannels()) return 0;
+ }
+
+ /* build the remap array */
+ for(t=0;t<32;t++)
+ if(!remap[t])
+ remap[t]=of.numchn++;
+
+ /* set panning positions after building remap chart! */
+ for(t=0;t<32;t++)
+ if((mh->channels[t]<32)&&(remap[t]!=-1)) {
+ if(mh->channels[t]<8)
+ of.panning[remap[t]]=0x30;
+ else
+ of.panning[remap[t]]=0xc0;
+ }
+ if(mh->pantable==252)
+ /* set panning positions according to panning table (new for st3.2) */
+ for(t=0;t<32;t++)
+ if((pan[t]&0x20)&&(mh->channels[t]<32)&&(remap[t]!=-1))
+ of.panning[remap[t]]=(pan[t]&0xf)<<4;
+
+ /* load pattern info */
+ of.numtrk=of.numpat*of.numchn;
+ if(!AllocTracks()) return 0;
+ if(!AllocPatterns()) return 0;
+
+ for(t=0;t<of.numpat;t++) {
+ /* seek to pattern position (+2 skip pattern length) */
+ _mm_fseek(modreader,(((long)paraptr[of.numins+t])<<4)+2,SEEK_SET);
+ if(!S3M_ReadPattern()) return 0;
+ for(u=0;u<of.numchn;u++)
+ if(!(of.tracks[track++]=S3M_ConvertTrack(&s3mbuf[u*64]))) return 0;
+ }
+
+ return 1;
+}
+
+CHAR *S3M_LoadTitle(void)
+{
+ CHAR s[28];
+
+ _mm_fseek(modreader,0,SEEK_SET);
+ if(!_mm_read_UBYTES(s,28,modreader)) return NULL;
+
+ return(DupStr(s,28,0));
+}
+
+/*========== Loader information */
+
+MIKMODAPI MLOADER load_s3m={
+ NULL,
+ "S3M",
+ "S3M (Scream Tracker 3)",
+ S3M_Init,
+ S3M_Test,
+ S3M_Load,
+ S3M_Cleanup,
+ S3M_LoadTitle
+};
+
+/* ex:set ts=4: */
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 <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 */
+
+/* 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;t<STM_NTRACKERS;t++)
+ if(!memcmp(str,STM_Signatures[t],8))
+ return 1;
+
+ return 0;
+}
+
+int STM_Init(void)
+{
+ if(!(mh=(STMHEADER*)MikMod_malloc(sizeof(STMHEADER)))) return 0;
+ if(!(stmbuf=(STMNOTE*)MikMod_calloc(64U*4,sizeof(STMNOTE)))) return 0;
+
+ return 1;
+}
+
+static void STM_Cleanup(void)
+{
+ MikMod_free(mh);
+ MikMod_free(stmbuf);
+}
+
+static void STM_ConvertNote(STMNOTE *n)
+{
+ UBYTE note,ins,vol,cmd,inf;
+
+ /* extract the various information from the 4 bytes that make up a note */
+ note = n->note;
+ 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;t<of.numpat;t++) {
+ for(s=0;s<(64U*of.numchn);s++) {
+ stmbuf[s].note = _mm_read_UBYTE(modreader);
+ stmbuf[s].insvol = _mm_read_UBYTE(modreader);
+ stmbuf[s].volcmd = _mm_read_UBYTE(modreader);
+ stmbuf[s].cmdinf = _mm_read_UBYTE(modreader);
+ }
+
+ if(_mm_eof(modreader)) {
+ _mm_errno = MMERR_LOADING_PATTERN;
+ return 0;
+ }
+
+ for(s=0;s<of.numchn;s++)
+ if(!(of.tracks[tracks++]=STM_ConvertTrack(stmbuf+s))) return 0;
+ }
+ return 1;
+}
+
+int STM_Load(int curious)
+{
+ int t;
+ ULONG MikMod_ISA; /* We must generate our own ISA, it's not stored in stm */
+ SAMPLE *q;
+
+ /* try to read stm header */
+ _mm_read_string(mh->songname,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;t<STM_NTRACKERS;t++)
+ if(!memcmp(mh->trackername,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]<mh->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;t<of.numsmp;t++,q++) {
+ /* load sample info */
+ q->samplename = 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: */
diff --git a/apps/plugins/mikmod/load_stx.c b/apps/plugins/mikmod/load_stx.c
new file mode 100644
index 0000000000..ac6e51f4c7
--- /dev/null
+++ b/apps/plugins/mikmod/load_stx.c
@@ -0,0 +1,439 @@
+/* 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_stx.c,v 1.3 2005/04/07 19:57:38 realtech Exp $
+
+ STMIK 0.2 (STX) module loader
+
+==============================================================================*/
+
+/*
+
+ Written by Claudio Matsuoka <claudio@helllabs.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
+
+/*========== Module structure */
+
+/* header */
+typedef struct STXHEADER {
+ CHAR songname[20];
+ CHAR trackername[8];
+ UWORD patsize;
+ UWORD unknown1;
+ UWORD patptr;
+ UWORD insptr;
+ UWORD chnptr; /* not sure */
+ UWORD unknown2;
+ UWORD unknown3;
+ UBYTE mastermult;
+ UBYTE initspeed;
+ UWORD unknown4;
+ UWORD unknown5;
+ UWORD patnum;
+ UWORD insnum;
+ UWORD ordnum;
+ UWORD unknown6;
+ UWORD unknown7;
+ UWORD unknown8;
+ CHAR scrm[4];
+} STXHEADER;
+
+/* sample information */
+typedef struct STXSAMPLE {
+ UBYTE type;
+ CHAR filename[12];
+ UBYTE memsegh;
+ UWORD memsegl;
+ ULONG length;
+ ULONG loopbeg;
+ ULONG loopend;
+ UBYTE volume;
+ UBYTE dsk;
+ UBYTE pack;
+ UBYTE flags;
+ ULONG c2spd;
+ UBYTE unused[12];
+ CHAR sampname[28];
+ CHAR scrs[4];
+} STXSAMPLE;
+
+typedef struct STXNOTE {
+ UBYTE note,ins,vol,cmd,inf;
+} STXNOTE;
+
+/*========== Loader variables */
+
+static STXNOTE *stxbuf = NULL; /* pointer to a complete STX pattern */
+static STXHEADER *mh = NULL;
+static UWORD *paraptr = NULL; /* parapointer array (see STX docs) */
+
+/*========== Loader code */
+
+static int STX_Test(void)
+{
+ UBYTE id[8];
+ int t;
+
+ _mm_fseek(modreader,0x3C,SEEK_SET);
+ if(!_mm_read_UBYTES(id,4,modreader)) return 0;
+ if(memcmp(id,"SCRM",4)) return 0;
+
+ _mm_fseek(modreader,0x14,SEEK_SET);
+ if(!_mm_read_UBYTES(id,8,modreader)) return 0;
+
+ for(t=0;t<STM_NTRACKERS;t++)
+ if(!memcmp(id,STM_Signatures[t],8)) return 1;
+
+ return 0;
+}
+
+static int STX_Init(void)
+{
+ if(!(stxbuf=(STXNOTE*)MikMod_malloc(4*64*sizeof(STXNOTE)))) return 0;
+ if(!(mh=(STXHEADER*)MikMod_malloc(sizeof(STXHEADER)))) return 0;
+ if(!(poslookup=(UBYTE*)MikMod_malloc(sizeof(UBYTE)*256))) return 0;
+ memset(poslookup,-1,256);
+
+ return 1;
+}
+
+static void STX_Cleanup(void)
+{
+ MikMod_free(stxbuf);
+ MikMod_free(paraptr);
+ MikMod_free(poslookup);
+ MikMod_free(mh);
+}
+
+static int STX_ReadPattern(void)
+{
+ int row=0,flag,ch;
+ STXNOTE *n,dummy;
+
+ /* clear pattern data */
+ memset(stxbuf,255,4*64*sizeof(STXNOTE));
+
+ while(row<64) {
+ flag=_mm_read_UBYTE(modreader);
+
+ if(_mm_eof(modreader)) {
+ _mm_errno = MMERR_LOADING_PATTERN;
+ return 0;
+ }
+
+ if(flag) {
+ ch=flag&31;
+
+ if((ch>=0)&&(ch<4))
+ n=&stxbuf[(64U*ch)+row];
+ else
+ n=&dummy;
+
+ if(flag&32) {
+ n->note=_mm_read_UBYTE(modreader);
+ n->ins=_mm_read_UBYTE(modreader);
+ }
+ if(flag&64) {
+ n->vol=_mm_read_UBYTE(modreader);
+ if(n->vol>64) n->vol=64;
+ }
+ if(flag&128) {
+ n->cmd=_mm_read_UBYTE(modreader);
+ n->inf=_mm_read_UBYTE(modreader);
+ }
+ } else row++;
+ }
+ return 1;
+}
+
+static UBYTE* STX_ConvertTrack(STXNOTE* tr)
+{
+ int t;
+
+ UniReset();
+ for(t=0;t<64;t++) {
+ UBYTE note,ins,vol,cmd,inf;
+
+ note=tr[t].note;
+ ins=tr[t].ins;
+ vol=tr[t].vol;
+ cmd=tr[t].cmd;
+ inf=tr[t].inf;
+
+ if((ins)&&(ins!=255)) UniInstrument(ins-1);
+ if((note)&&(note!=255)) {
+ if(note==254) {
+ UniPTEffect(0xc,0); /* note cut command */
+ vol=255;
+ } else UniNote(24+((note>>4)*OCTAVE)+(note&0xf)); /* normal note */
+ }
+
+ if(vol<255) 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;
+ }
+ UniNewline();
+ }
+ return UniDup();
+}
+
+static int STX_Load(int curious)
+{
+ int t,u,track = 0;
+ int version = 0;
+ SAMPLE *q;
+
+ /* try to read module header */
+ _mm_read_string(mh->songname,20,modreader);
+ _mm_read_string(mh->trackername,8,modreader);
+ mh->patsize =_mm_read_I_UWORD(modreader);
+ mh->unknown1 =_mm_read_I_UWORD(modreader);
+ mh->patptr =_mm_read_I_UWORD(modreader);
+ mh->insptr =_mm_read_I_UWORD(modreader);
+ mh->chnptr =_mm_read_I_UWORD(modreader);
+ mh->unknown2 =_mm_read_I_UWORD(modreader);
+ mh->unknown3 =_mm_read_I_UWORD(modreader);
+ mh->mastermult =_mm_read_UBYTE(modreader);
+ mh->initspeed =_mm_read_UBYTE(modreader)>>4;
+ mh->unknown4 =_mm_read_I_UWORD(modreader);
+ mh->unknown5 =_mm_read_I_UWORD(modreader);
+ mh->patnum =_mm_read_I_UWORD(modreader);
+ mh->insnum =_mm_read_I_UWORD(modreader);
+ mh->ordnum =_mm_read_I_UWORD(modreader);
+ mh->unknown6 =_mm_read_I_UWORD(modreader);
+ mh->unknown7 =_mm_read_I_UWORD(modreader);
+ mh->unknown8 =_mm_read_I_UWORD(modreader);
+ _mm_read_string(mh->scrm,4,modreader);
+
+ if(_mm_eof(modreader)) {
+ _mm_errno = MMERR_LOADING_HEADER;
+ return 0;
+ }
+
+ /* set module variables */
+ of.songname = DupStr(mh->songname,20,1);
+ of.numpat = mh->patnum;
+ of.reppos = 0;
+ of.numins = of.numsmp = mh->insnum;
+ of.initspeed = mh->initspeed;
+ of.inittempo = 125;
+ of.numchn = 4;
+ of.flags |= UF_S3MSLIDES;
+ of.bpmlimit = 32;
+
+ if(!(paraptr=(UWORD*)MikMod_malloc((of.numins+of.numpat)*sizeof(UWORD))))
+ return 0;
+
+ /* read the instrument+pattern parapointers */
+ _mm_fseek(modreader,mh->insptr<<4,SEEK_SET);
+ _mm_read_I_UWORDS(paraptr,of.numins,modreader);
+ _mm_fseek(modreader,mh->patptr<<4,SEEK_SET);
+ _mm_read_I_UWORDS(paraptr+of.numins,of.numpat,modreader);
+
+ /* check module version */
+ _mm_fseek(modreader,paraptr[of.numins]<<4,SEEK_SET);
+ version=_mm_read_I_UWORD(modreader);
+ if(version==mh->patsize) {
+ version = 0x10;
+ of.modtype = StrDup("STMIK 0.2 (STM2STX 1.0)");
+ } else {
+ version = 0x11;
+ of.modtype = StrDup("STMIK 0.2 (STM2STX 1.1)");
+ }
+
+ /* read the order data */
+ _mm_fseek(modreader,(mh->chnptr<<4)+32,SEEK_SET);
+ if(!AllocPositions(mh->ordnum)) return 0;
+ for(t=0;t<mh->ordnum;t++) {
+ of.positions[t]=_mm_read_UBYTE(modreader);
+ _mm_fseek(modreader,4,SEEK_CUR);
+ }
+
+ of.numpos=0;poslookupcnt=mh->ordnum;
+ for(t=0;t<mh->ordnum;t++) {
+ int order=of.positions[t];
+ if(order==255) order=LAST_PATTERN;
+ of.positions[of.numpos]=order;
+ poslookup[t]=of.numpos; /* bug fix for freaky S3Ms */
+ if(of.positions[t]<254) of.numpos++;
+ else
+ /* special end of song pattern */
+ if((order==LAST_PATTERN)&&(!curious)) break;
+ }
+
+ if(_mm_eof(modreader)) {
+ _mm_errno = MMERR_LOADING_HEADER;
+ return 0;
+ }
+
+ /* load samples */
+ if(!AllocSamples()) return 0;
+ for(q=of.samples,t=0;t<of.numins;t++,q++) {
+ STXSAMPLE s;
+
+ /* seek to instrument position */
+ _mm_fseek(modreader,((long)paraptr[t])<<4,SEEK_SET);
+ /* and load sample info */
+ s.type =_mm_read_UBYTE(modreader);
+ _mm_read_string(s.filename,12,modreader);
+ s.memsegh =_mm_read_UBYTE(modreader);
+ s.memsegl =_mm_read_I_UWORD(modreader);
+ s.length =_mm_read_I_ULONG(modreader);
+ s.loopbeg =_mm_read_I_ULONG(modreader);
+ s.loopend =_mm_read_I_ULONG(modreader);
+ s.volume =_mm_read_UBYTE(modreader);
+ s.dsk =_mm_read_UBYTE(modreader);
+ s.pack =_mm_read_UBYTE(modreader);
+ s.flags =_mm_read_UBYTE(modreader);
+ s.c2spd =_mm_read_I_ULONG(modreader);
+ _mm_read_UBYTES(s.unused,12,modreader);
+ _mm_read_string(s.sampname,28,modreader);
+ _mm_read_string(s.scrs,4,modreader);
+
+ if(_mm_eof(modreader)) {
+ _mm_errno = MMERR_LOADING_SAMPLEINFO;
+ return 0;
+ }
+
+ q->samplename = DupStr(s.sampname,28,1);
+ q->speed = (s.c2spd * 8363) / 8448;
+ q->length = s.length;
+ q->loopstart = s.loopbeg;
+ q->loopend = s.loopend;
+ q->volume = s.volume;
+ q->seekpos = (((long)s.memsegh)<<16|s.memsegl)<<4;
+ q->flags |= SF_SIGNED;
+
+ if(s.flags&1) q->flags |= SF_LOOP;
+ if(s.flags&4) q->flags |= SF_16BITS;
+ }
+
+ /* load pattern info */
+ of.numtrk=of.numpat*of.numchn;
+ if(!AllocTracks()) return 0;
+ if(!AllocPatterns()) return 0;
+
+ for(t=0;t<of.numpat;t++) {
+ /* seek to pattern position (+2 skip pattern length) */
+ _mm_fseek(modreader,(((long)paraptr[of.numins+t])<<4)+
+ (version==0x10?2:0),SEEK_SET);
+ if(!STX_ReadPattern()) return 0;
+ for(u=0;u<of.numchn;u++)
+ if(!(of.tracks[track++]=STX_ConvertTrack(&stxbuf[u*64]))) return 0;
+ }
+
+ return 1;
+}
+
+static CHAR *STX_LoadTitle(void)
+{
+ CHAR s[28];
+
+ _mm_fseek(modreader,0,SEEK_SET);
+ if(!_mm_read_UBYTES(s,20,modreader)) return NULL;
+
+ return(DupStr(s,28,1));
+}
+
+/*========== Loader information */
+
+MIKMODAPI MLOADER load_stx={
+ NULL,
+ "STX",
+ "STX (Scream Tracker Music Interface Kit)",
+ STX_Init,
+ STX_Test,
+ STX_Load,
+ STX_Cleanup,
+ STX_LoadTitle
+};
+
+/* ex:set ts=4: */
diff --git a/apps/plugins/mikmod/load_ult.c b/apps/plugins/mikmod/load_ult.c
new file mode 100644
index 0000000000..aca2407a4a
--- /dev/null
+++ b/apps/plugins/mikmod/load_ult.c
@@ -0,0 +1,339 @@
+/* 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_ult.c,v 1.3 2010/01/12 03:30:32 realtech Exp $
+
+ Ultratracker (ULT) 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 */
+
+/* header */
+typedef struct ULTHEADER {
+ CHAR id[16];
+ CHAR songtitle[32];
+ UBYTE reserved;
+} ULTHEADER;
+
+/* sample information */
+typedef struct ULTSAMPLE {
+ CHAR samplename[32];
+ CHAR dosname[12];
+ SLONG loopstart;
+ SLONG loopend;
+ SLONG sizestart;
+ SLONG sizeend;
+ UBYTE volume;
+ UBYTE flags;
+ UWORD speed;
+ SWORD finetune;
+} ULTSAMPLE;
+
+typedef struct ULTEVENT {
+ UBYTE note,sample,eff,dat1,dat2;
+} ULTEVENT;
+
+/*========== Loader variables */
+
+#define ULTS_16BITS 4
+#define ULTS_LOOP 8
+#define ULTS_REVERSE 16
+
+#define ULT_VERSION_LEN 18
+static CHAR ULT_Version[ULT_VERSION_LEN]="Ultra Tracker v1.x";
+
+static ULTEVENT ev;
+
+/*========== Loader code */
+
+int ULT_Test(void)
+{
+ CHAR id[16];
+
+ if(!_mm_read_string(id,15,modreader)) return 0;
+ if(strncmp(id,"MAS_UTrack_V00",14)) return 0;
+ if((id[14]<'1')||(id[14]>'4')) return 0;
+ return 1;
+}
+
+int ULT_Init(void)
+{
+ return 1;
+}
+
+void ULT_Cleanup(void)
+{
+}
+
+static UBYTE ReadUltEvent(ULTEVENT* event)
+{
+ UBYTE flag,rep=1;
+
+ flag = _mm_read_UBYTE(modreader);
+ if(flag==0xfc) {
+ rep = _mm_read_UBYTE(modreader);
+ event->note =_mm_read_UBYTE(modreader);
+ } else
+ event->note = flag;
+
+ event->sample =_mm_read_UBYTE(modreader);
+ event->eff =_mm_read_UBYTE(modreader);
+ event->dat1 =_mm_read_UBYTE(modreader);
+ event->dat2 =_mm_read_UBYTE(modreader);
+
+ return rep;
+}
+
+int ULT_Load(int curious)
+{
+ int t,u,tracks=0;
+ SAMPLE *q;
+ ULTSAMPLE s;
+ ULTHEADER mh;
+ UBYTE nos,noc,rbnop;
+
+ /* try to read module header */
+ _mm_read_string(mh.id,15,modreader);
+ _mm_read_string(mh.songtitle,32,modreader);
+ mh.reserved=_mm_read_UBYTE(modreader);
+
+ if(_mm_eof(modreader)) {
+ _mm_errno = MMERR_LOADING_HEADER;
+ return 0;
+ }
+
+ ULT_Version[ULT_VERSION_LEN-1]='3'+(mh.id[14]-'1');
+ of.modtype = DupStr(ULT_Version,ULT_VERSION_LEN,1);
+ of.initspeed = 6;
+ of.inittempo = 125;
+ of.reppos = 0;
+
+ /* read songtext */
+ if ((mh.id[14]>'1')&&(mh.reserved))
+ if(!ReadLinedComment(mh.reserved * 32, 32)) return 0;
+
+ nos=_mm_read_UBYTE(modreader);
+ if(_mm_eof(modreader)) {
+ _mm_errno = MMERR_LOADING_HEADER;
+ return 0;
+ }
+
+ of.songname=DupStr(mh.songtitle,32,1);
+ of.numins=of.numsmp=nos;
+
+ if(!AllocSamples()) return 0;
+ q = of.samples;
+ for(t=0;t<nos;t++) {
+ /* try to read sample info */
+ _mm_read_string(s.samplename,32,modreader);
+ _mm_read_string(s.dosname,12,modreader);
+ s.loopstart =_mm_read_I_ULONG(modreader);
+ s.loopend =_mm_read_I_ULONG(modreader);
+ s.sizestart =_mm_read_I_ULONG(modreader);
+ s.sizeend =_mm_read_I_ULONG(modreader);
+ s.volume =_mm_read_UBYTE(modreader);
+ s.flags =_mm_read_UBYTE(modreader);
+ s.speed =(mh.id[14]>='4')?_mm_read_I_UWORD(modreader):8363;
+ s.finetune =_mm_read_I_SWORD(modreader);
+
+ if(_mm_eof(modreader)) {
+ _mm_errno = MMERR_LOADING_SAMPLEINFO;
+ return 0;
+ }
+
+ q->samplename=DupStr(s.samplename,32,1);
+ /* The correct formula for the coefficient would be
+ pow(2,(double)s.finetume/OCTAVE/32768), but to avoid floating point
+ here, we'll use a first order approximation here.
+ 1/567290 == Ln(2)/OCTAVE/32768 */
+ q->speed=s.speed+s.speed*(((SLONG)s.speed*(SLONG)s.finetune)/567290);
+ q->length = s.sizeend-s.sizestart;
+ q->volume = s.volume>>2;
+ q->loopstart = s.loopstart;
+ q->loopend = s.loopend;
+ q->flags = SF_SIGNED;
+ if(s.flags&ULTS_LOOP) q->flags|=SF_LOOP;
+ if(s.flags&ULTS_16BITS) {
+ s.sizeend+=(s.sizeend-s.sizestart);
+ s.sizestart<<=1;
+ q->flags|=SF_16BITS;
+ q->loopstart>>=1;
+ q->loopend>>=1;
+ }
+ q++;
+ }
+
+ if(!AllocPositions(256)) return 0;
+ for(t=0;t<256;t++)
+ of.positions[t]=_mm_read_UBYTE(modreader);
+ for(t=0;t<256;t++)
+ if(of.positions[t]==255) {
+ of.positions[t]=LAST_PATTERN;
+ break;
+ }
+ of.numpos=t;
+
+ noc=_mm_read_UBYTE(modreader);
+ rbnop=_mm_read_UBYTE(modreader);
+
+ of.numchn=++noc;
+ of.numpat=++rbnop;
+ of.numtrk=of.numchn*of.numpat;
+ if(!AllocTracks()) return 0;
+ if(!AllocPatterns()) return 0;
+ for(u=0;u<of.numchn;u++)
+ for(t=0;t<of.numpat;t++)
+ of.patterns[(t*of.numchn)+u]=tracks++;
+
+ // SA37775
+ if (of.numchn>=UF_MAXCHAN)
+ of.numchn=UF_MAXCHAN - 1;
+
+ /* read pan position table for v1.5 and higher */
+ if(mh.id[14]>='3') {
+ for(t=0;t<of.numchn;t++) of.panning[t]=_mm_read_UBYTE(modreader)<<4;
+ of.flags |= UF_PANNING;
+ }
+
+ for(t=0;t<of.numtrk;t++) {
+ int rep,row=0;
+
+ UniReset();
+ while(row<64) {
+ rep=ReadUltEvent(&ev);
+
+ if(_mm_eof(modreader)) {
+ _mm_errno = MMERR_LOADING_TRACK;
+ return 0;
+ }
+
+ while(rep--) {
+ UBYTE eff;
+ int offset;
+
+ if(ev.sample) UniInstrument(ev.sample-1);
+ if(ev.note) UniNote(ev.note+2*OCTAVE-1);
+
+ /* first effect - various fixes by Alexander Kerkhove and
+ Thomas Neumann */
+ eff = ev.eff>>4;
+ switch(eff) {
+ case 0x3: /* tone portamento */
+ UniEffect(UNI_ITEFFECTG,ev.dat2);
+ break;
+ case 0x5:
+ break;
+ case 0x9: /* sample offset */
+ offset=(ev.dat2<<8)|((ev.eff&0xf)==9?ev.dat1:0);
+ UniEffect(UNI_ULTEFFECT9,offset);
+ break;
+ case 0xb: /* panning */
+ UniPTEffect(8,ev.dat2*0xf);
+ of.flags |= UF_PANNING;
+ break;
+ case 0xc: /* volume */
+ UniPTEffect(eff,ev.dat2>>2);
+ break;
+ default:
+ UniPTEffect(eff,ev.dat2);
+ break;
+ }
+
+ /* second effect */
+ eff=ev.eff&0xf;
+ switch(eff) {
+ case 0x3: /* tone portamento */
+ UniEffect(UNI_ITEFFECTG,ev.dat1);
+ break;
+ case 0x5:
+ break;
+ case 0x9: /* sample offset */
+ if((ev.eff>>4)!=9)
+ UniEffect(UNI_ULTEFFECT9,((UWORD)ev.dat1)<<8);
+ break;
+ case 0xb: /* panning */
+ UniPTEffect(8,ev.dat1*0xf);
+ of.flags |= UF_PANNING;
+ break;
+ case 0xc: /* volume */
+ UniPTEffect(eff,ev.dat1>>2);
+ break;
+ default:
+ UniPTEffect(eff,ev.dat1);
+ break;
+ }
+
+ UniNewline();
+ row++;
+ }
+ }
+ if(!(of.tracks[t]=UniDup())) return 0;
+ }
+ return 1;
+}
+
+CHAR *ULT_LoadTitle(void)
+{
+ CHAR s[32];
+
+ _mm_fseek(modreader,15,SEEK_SET);
+ if(!_mm_read_UBYTES(s,32,modreader)) return NULL;
+
+ return(DupStr(s,32,1));
+}
+
+/*========== Loader information */
+
+MIKMODAPI MLOADER load_ult={
+ NULL,
+ "ULT",
+ "ULT (UltraTracker)",
+ ULT_Init,
+ ULT_Test,
+ ULT_Load,
+ ULT_Cleanup,
+ ULT_LoadTitle
+};
+
+
+/* ex:set ts=4: */
diff --git a/apps/plugins/mikmod/load_uni.c b/apps/plugins/mikmod/load_uni.c
new file mode 100644
index 0000000000..3140336b94
--- /dev/null
+++ b/apps/plugins/mikmod/load_uni.c
@@ -0,0 +1,717 @@
+/* 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_uni.c,v 1.3 2005/04/07 19:57:38 realtech Exp $
+
+ UNIMOD (libmikmod's and APlayer's internal module format) 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 */
+
+typedef struct UNIHEADER {
+ CHAR id[4];
+ UBYTE numchn;
+ UWORD numpos;
+ UWORD reppos;
+ UWORD numpat;
+ UWORD numtrk;
+ UWORD numins;
+ UWORD numsmp;
+ UBYTE initspeed;
+ UBYTE inittempo;
+ UBYTE initvolume;
+ UWORD flags;
+ UBYTE numvoices;
+ UWORD bpmlimit;
+
+ UBYTE positions[256];
+ UBYTE panning[32];
+} UNIHEADER;
+
+typedef struct UNISMP05 {
+ UWORD c2spd;
+ UWORD transpose;
+ UBYTE volume;
+ UBYTE panning;
+ ULONG length;
+ ULONG loopstart;
+ ULONG loopend;
+ UWORD flags;
+ CHAR* samplename;
+ UBYTE vibtype;
+ UBYTE vibsweep;
+ UBYTE vibdepth;
+ UBYTE vibrate;
+} UNISMP05;
+
+/*========== Loader variables */
+
+static UWORD universion;
+static UNIHEADER mh;
+
+#define UNI_SMPINCR 64
+static UNISMP05 *wh=NULL,*s=NULL;
+
+/*========== Loader code */
+
+static char* readstring(void)
+{
+ char *s=NULL;
+ UWORD len;
+
+ len=_mm_read_I_UWORD(modreader);
+ if(len) {
+ s=MikMod_malloc(len+1);
+ _mm_read_UBYTES(s,len,modreader);
+ s[len]=0;
+ }
+ return s;
+}
+
+int UNI_Test(void)
+{
+ char id[6];
+
+ if(!_mm_read_UBYTES(id,6,modreader)) return 0;
+
+ /* UNIMod created by MikCvt */
+ if(!(memcmp(id,"UN0",3))) {
+ if((id[3]>='4')&&(id[3]<='6')) return 1;
+ }
+ /* UNIMod created by APlayer */
+ if(!(memcmp(id,"APUN\01",5))) {
+ if((id[5]>=1)&&(id[5]<=6)) return 1;
+ }
+ return 0;
+}
+
+int UNI_Init(void)
+{
+ return 1;
+}
+
+void UNI_Cleanup(void)
+{
+ MikMod_free(wh);
+ s=NULL;
+}
+
+static UBYTE* readtrack(void)
+{
+ UBYTE *t;
+ UWORD len;
+ int cur=0,chunk;
+
+ if(universion>=6)
+ len=_mm_read_M_UWORD(modreader);
+ else
+ len=_mm_read_I_UWORD(modreader);
+
+ if(!len) return NULL;
+ if(!(t=MikMod_malloc(len))) return NULL;
+ _mm_read_UBYTES(t,len,modreader);
+
+ /* Check if the track is correct */
+ while(1) {
+ chunk=t[cur++];
+ if(!chunk) break;
+ chunk=(chunk&0x1f)-1;
+ while(chunk>0) {
+ int opcode,oplen;
+
+ if(cur>=len) {
+ MikMod_free(t);
+ return NULL;
+ }
+ opcode=t[cur];
+
+ /* Remap opcodes */
+ if (universion <= 5) {
+ if (opcode > 29) {
+ MikMod_free(t);
+ return NULL;
+ }
+ switch (opcode) {
+ /* UNI_NOTE .. UNI_S3MEFFECTQ are the same */
+ case 25:
+ opcode = UNI_S3MEFFECTT;
+ break;
+ case 26:
+ opcode = UNI_XMEFFECTA;
+ break;
+ case 27:
+ opcode = UNI_XMEFFECTG;
+ break;
+ case 28:
+ opcode = UNI_XMEFFECTH;
+ break;
+ case 29:
+ opcode = UNI_XMEFFECTP;
+ break;
+ }
+ } else {
+ /* APlayer < 1.05 does not have XMEFFECT6 */
+ if (opcode >= UNI_XMEFFECT6 && universion < 0x105)
+ opcode++;
+ /* APlayer < 1.03 does not have ITEFFECTT */
+ if (opcode >= UNI_ITEFFECTT && universion < 0x103)
+ opcode++;
+ /* APlayer < 1.02 does not have ITEFFECTZ */
+ if (opcode >= UNI_ITEFFECTZ && universion < 0x102)
+ opcode++;
+ }
+
+ if((!opcode)||(opcode>=UNI_LAST)) {
+ MikMod_free(t);
+ return NULL;
+ }
+ t[cur]=opcode;
+ oplen=unioperands[opcode]+1;
+ cur+=oplen;
+ chunk-=oplen;
+ }
+ if((chunk<0)||(cur>=len)) {
+ MikMod_free(t);
+ return NULL;
+ }
+ }
+ return t;
+}
+
+static int loadsmp6(void)
+{
+ int t;
+ SAMPLE *s;
+
+ s=of.samples;
+ for(t=0;t<of.numsmp;t++,s++) {
+ int flags;
+
+ flags = _mm_read_M_UWORD(modreader);
+ s->flags=0;
+ if(flags&0x0004) s->flags|=SF_STEREO;
+ if(flags&0x0002) s->flags|=SF_SIGNED;
+ if(flags&0x0001) s->flags|=SF_16BITS;
+ /* convert flags */
+ if(universion>=0x104) {
+ if(flags&0x2000) s->flags|=SF_UST_LOOP;
+ if(flags&0x1000) s->flags|=SF_OWNPAN;
+ if(flags&0x0800) s->flags|=SF_SUSTAIN;
+ if(flags&0x0400) s->flags|=SF_REVERSE;
+ if(flags&0x0200) s->flags|=SF_BIDI;
+ if(flags&0x0100) s->flags|=SF_LOOP;
+ if(flags&0x0020) s->flags|=SF_ITPACKED;
+ if(flags&0x0010) s->flags|=SF_DELTA;
+ if(flags&0x0008) s->flags|=SF_BIG_ENDIAN;
+ } else if(universion>=0x102) {
+ if(flags&0x0800) s->flags|=SF_UST_LOOP;
+ if(flags&0x0400) s->flags|=SF_OWNPAN;
+ if(flags&0x0200) s->flags|=SF_SUSTAIN;
+ if(flags&0x0100) s->flags|=SF_REVERSE;
+ if(flags&0x0080) s->flags|=SF_BIDI;
+ if(flags&0x0040) s->flags|=SF_LOOP;
+ if(flags&0x0020) s->flags|=SF_ITPACKED;
+ if(flags&0x0010) s->flags|=SF_DELTA;
+ if(flags&0x0008) s->flags|=SF_BIG_ENDIAN;
+ } else {
+ if(flags&0x400) s->flags|=SF_UST_LOOP;
+ if(flags&0x200) s->flags|=SF_OWNPAN;
+ if(flags&0x100) s->flags|=SF_REVERSE;
+ if(flags&0x080) s->flags|=SF_SUSTAIN;
+ if(flags&0x040) s->flags|=SF_BIDI;
+ if(flags&0x020) s->flags|=SF_LOOP;
+ if(flags&0x010) s->flags|=SF_BIG_ENDIAN;
+ if(flags&0x008) s->flags|=SF_DELTA;
+ }
+
+ s->speed = _mm_read_M_ULONG(modreader);
+ s->volume = _mm_read_UBYTE(modreader);
+ s->panning = _mm_read_M_UWORD(modreader);
+ s->length = _mm_read_M_ULONG(modreader);
+ s->loopstart = _mm_read_M_ULONG(modreader);
+ s->loopend = _mm_read_M_ULONG(modreader);
+ s->susbegin = _mm_read_M_ULONG(modreader);
+ s->susend = _mm_read_M_ULONG(modreader);
+ s->globvol = _mm_read_UBYTE(modreader);
+ s->vibflags = _mm_read_UBYTE(modreader);
+ s->vibtype = _mm_read_UBYTE(modreader);
+ s->vibsweep = _mm_read_UBYTE(modreader);
+ s->vibdepth = _mm_read_UBYTE(modreader);
+ s->vibrate = _mm_read_UBYTE(modreader);
+
+ s->samplename=readstring();
+
+ if(_mm_eof(modreader)) {
+ _mm_errno = MMERR_LOADING_SAMPLEINFO;
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static int loadinstr6(void)
+{
+ int t,w;
+ INSTRUMENT *i;
+
+ i=of.instruments;
+ for(t=0;t<of.numins;t++,i++) {
+ i->flags = _mm_read_UBYTE(modreader);
+ i->nnatype = _mm_read_UBYTE(modreader);
+ i->dca = _mm_read_UBYTE(modreader);
+ i->dct = _mm_read_UBYTE(modreader);
+ i->globvol = _mm_read_UBYTE(modreader);
+ i->panning = _mm_read_M_UWORD(modreader);
+ i->pitpansep = _mm_read_UBYTE(modreader);
+ i->pitpancenter = _mm_read_UBYTE(modreader);
+ i->rvolvar = _mm_read_UBYTE(modreader);
+ i->rpanvar = _mm_read_UBYTE(modreader);
+ i->volfade = _mm_read_M_UWORD(modreader);
+
+#if defined __STDC__ || defined _MSC_VER || defined MPW_C
+#define UNI_LoadEnvelope6(name) \
+ i-> name##flg=_mm_read_UBYTE(modreader); \
+ i-> name##pts=_mm_read_UBYTE(modreader); \
+ i-> name##susbeg=_mm_read_UBYTE(modreader); \
+ i-> name##susend=_mm_read_UBYTE(modreader); \
+ i-> name##beg=_mm_read_UBYTE(modreader); \
+ i-> name##end=_mm_read_UBYTE(modreader); \
+ for(w=0;w<(universion>=0x100?32:i-> name##pts);w++) { \
+ i-> name##env[w].pos=_mm_read_M_SWORD(modreader); \
+ i-> name##env[w].val=_mm_read_M_SWORD(modreader); \
+ }
+#else
+#define UNI_LoadEnvelope6(name) \
+ i-> name/**/flg=_mm_read_UBYTE(modreader); \
+ i-> name/**/pts=_mm_read_UBYTE(modreader); \
+ i-> name/**/susbeg=_mm_read_UBYTE(modreader); \
+ i-> name/**/susend=_mm_read_UBYTE(modreader); \
+ i-> name/**/beg=_mm_read_UBYTE(modreader); \
+ i-> name/**/end=_mm_read_UBYTE(modreader); \
+ for (w=0;w<(universion>=0x100?32:i-> name/**/pts);w++) { \
+ i-> name/**/env[w].pos=_mm_read_M_SWORD(modreader); \
+ i-> name/**/env[w].val=_mm_read_M_SWORD(modreader); \
+ }
+#endif
+
+ UNI_LoadEnvelope6(vol);
+ UNI_LoadEnvelope6(pan);
+ UNI_LoadEnvelope6(pit);
+#undef UNI_LoadEnvelope6
+
+ if(universion>=0x103)
+ _mm_read_M_UWORDS(i->samplenumber,120,modreader);
+ else
+ for(w=0;w<120;w++)
+ i->samplenumber[w]=_mm_read_UBYTE(modreader);
+ _mm_read_UBYTES(i->samplenote,120,modreader);
+
+ i->insname=readstring();
+
+ if(_mm_eof(modreader)) {
+ _mm_errno = MMERR_LOADING_SAMPLEINFO;
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static int loadinstr5(void)
+{
+ INSTRUMENT *i;
+ int t;
+ UWORD wavcnt=0;
+ UBYTE vibtype,vibsweep,vibdepth,vibrate;
+
+ i=of.instruments;
+ for(of.numsmp=t=0;t<of.numins;t++,i++) {
+ int u,numsmp;
+
+ numsmp=_mm_read_UBYTE(modreader);
+
+ memset(i->samplenumber,0xff,INSTNOTES*sizeof(UWORD));
+ for(u=0;u<96;u++)
+ i->samplenumber[u]=of.numsmp+_mm_read_UBYTE(modreader);
+
+#if defined __STDC__ || defined _MSC_VER || defined MPW_C
+#define UNI_LoadEnvelope5(name) \
+ i-> name##flg=_mm_read_UBYTE(modreader); \
+ i-> name##pts=_mm_read_UBYTE(modreader); \
+ i-> name##susbeg=_mm_read_UBYTE(modreader); \
+ i-> name##susend=i-> name##susbeg; \
+ i-> name##beg=_mm_read_UBYTE(modreader); \
+ i-> name##end=_mm_read_UBYTE(modreader); \
+ for(u=0;u<12;u++) { \
+ i-> name##env[u].pos=_mm_read_I_SWORD(modreader); \
+ i-> name##env[u].val=_mm_read_I_SWORD(modreader); \
+ }
+#else
+#define UNI_LoadEnvelope5(name) \
+ i-> name/**/flg=_mm_read_UBYTE(modreader); \
+ i-> name/**/pts=_mm_read_UBYTE(modreader); \
+ i-> name/**/susbeg=_mm_read_UBYTE(modreader); \
+ i-> name/**/susend=i-> name/**/susbeg; \
+ i-> name/**/beg=_mm_read_UBYTE(modreader); \
+ i-> name/**/end=_mm_read_UBYTE(modreader); \
+ for(u=0;u<12;u++) { \
+ i-> name/**/env[u].pos=_mm_read_I_SWORD(modreader); \
+ i-> name/**/env[u].val=_mm_read_I_SWORD(modreader); \
+ }
+#endif
+
+ UNI_LoadEnvelope5(vol);
+ UNI_LoadEnvelope5(pan);
+#undef UNI_LoadEnvelope5
+
+ vibtype =_mm_read_UBYTE(modreader);
+ vibsweep =_mm_read_UBYTE(modreader);
+ vibdepth =_mm_read_UBYTE(modreader);
+ vibrate =_mm_read_UBYTE(modreader);
+
+ i->volfade=_mm_read_I_UWORD(modreader);
+ i->insname=readstring();
+
+ for(u=0;u<numsmp;u++,s++,of.numsmp++) {
+ /* Allocate more room for sample information if necessary */
+ if(of.numsmp+u==wavcnt) {
+ wavcnt+=UNI_SMPINCR;
+ if(!(wh=MikMod_realloc(wh,wavcnt*sizeof(UNISMP05)))) {
+ _mm_errno=MMERR_OUT_OF_MEMORY;
+ return 0;
+ }
+ s=wh+(wavcnt-UNI_SMPINCR);
+ }
+
+ s->c2spd =_mm_read_I_UWORD(modreader);
+ s->transpose=_mm_read_SBYTE(modreader);
+ s->volume =_mm_read_UBYTE(modreader);
+ s->panning =_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->flags =_mm_read_I_UWORD(modreader);
+ s->samplename=readstring();
+
+ s->vibtype =vibtype;
+ s->vibsweep=vibsweep;
+ s->vibdepth=vibdepth;
+ s->vibrate =vibrate;
+
+ if(_mm_eof(modreader)) {
+ MikMod_free(wh);wh=NULL;
+ _mm_errno=MMERR_LOADING_SAMPLEINFO;
+ return 0;
+ }
+ }
+ }
+
+ /* sanity check */
+ if(!of.numsmp) {
+ if(wh) { MikMod_free(wh);wh=NULL; }
+ _mm_errno=MMERR_LOADING_SAMPLEINFO;
+ return 0;
+ }
+ return 1;
+}
+
+static int loadsmp5(void)
+{
+ int t,u;
+ SAMPLE *q;
+ INSTRUMENT *d;
+
+ q=of.samples;s=wh;
+ for(u=0;u<of.numsmp;u++,q++,s++) {
+ q->samplename=s->samplename;
+
+ q->length =s->length;
+ q->loopstart=s->loopstart;
+ q->loopend =s->loopend;
+ q->volume =s->volume;
+ q->speed =s->c2spd;
+ q->panning =s->panning;
+ q->vibtype =s->vibtype;
+ q->vibsweep =s->vibsweep;
+ q->vibdepth =s->vibdepth;
+ q->vibrate =s->vibrate;
+
+ /* convert flags */
+ q->flags=0;
+ if(s->flags&128) q->flags|=SF_REVERSE;
+ if(s->flags& 64) q->flags|=SF_SUSTAIN;
+ if(s->flags& 32) q->flags|=SF_BIDI;
+ if(s->flags& 16) q->flags|=SF_LOOP;
+ if(s->flags& 8) q->flags|=SF_BIG_ENDIAN;
+ if(s->flags& 4) q->flags|=SF_DELTA;
+ if(s->flags& 2) q->flags|=SF_SIGNED;
+ if(s->flags& 1) q->flags|=SF_16BITS;
+ }
+
+ d=of.instruments;s=wh;
+ for(u=0;u<of.numins;u++,d++)
+ for(t=0;t<INSTNOTES;t++)
+ d->samplenote[t]=(d->samplenumber[t]>=of.numsmp)?
+ 255:(t+s[d->samplenumber[t]].transpose);
+
+ MikMod_free(wh);wh=NULL;
+
+ return 1;
+}
+
+int UNI_Load(int curious)
+{
+ int t;
+ char *modtype,*oldtype=NULL;
+ INSTRUMENT *d;
+ SAMPLE *q;
+
+ /* read module header */
+ _mm_read_UBYTES(mh.id,4,modreader);
+ if(mh.id[3]!='N')
+ universion=mh.id[3]-'0';
+ else
+ universion=0x100;
+
+ if(universion>=6) {
+ if (universion==6)
+ _mm_read_UBYTE(modreader);
+ else
+ universion=_mm_read_M_UWORD(modreader);
+
+ mh.flags =_mm_read_M_UWORD(modreader);
+ mh.numchn =_mm_read_UBYTE(modreader);
+ mh.numvoices =_mm_read_UBYTE(modreader);
+ mh.numpos =_mm_read_M_UWORD(modreader);
+ mh.numpat =_mm_read_M_UWORD(modreader);
+ mh.numtrk =_mm_read_M_UWORD(modreader);
+ mh.numins =_mm_read_M_UWORD(modreader);
+ mh.numsmp =_mm_read_M_UWORD(modreader);
+ mh.reppos =_mm_read_M_UWORD(modreader);
+ mh.initspeed =_mm_read_UBYTE(modreader);
+ mh.inittempo =_mm_read_UBYTE(modreader);
+ mh.initvolume=_mm_read_UBYTE(modreader);
+ /* I expect this to show up soon in APlayer 1.06 format */
+ if (universion >= 0x106)
+ mh.bpmlimit=_mm_read_M_UWORD(modreader);
+ else
+ mh.bpmlimit=32;
+
+ mh.flags &= UF_XMPERIODS | UF_LINEAR | UF_INST | UF_NNA;
+ mh.flags |= UF_PANNING;
+ } else {
+ mh.numchn =_mm_read_UBYTE(modreader);
+ mh.numpos =_mm_read_I_UWORD(modreader);
+ mh.reppos =(universion==5)?_mm_read_I_UWORD(modreader):0;
+ mh.numpat =_mm_read_I_UWORD(modreader);
+ mh.numtrk =_mm_read_I_UWORD(modreader);
+ mh.numins =_mm_read_I_UWORD(modreader);
+ mh.initspeed =_mm_read_UBYTE(modreader);
+ mh.inittempo =_mm_read_UBYTE(modreader);
+ _mm_read_UBYTES(mh.positions,256,modreader);
+ _mm_read_UBYTES(mh.panning,32,modreader);
+ mh.flags =_mm_read_UBYTE(modreader);
+ mh.bpmlimit =32;
+
+ mh.flags &= UF_XMPERIODS | UF_LINEAR;
+ mh.flags |= UF_INST | UF_NOWRAP | UF_PANNING;
+ }
+
+ /* set module parameters */
+ of.flags =mh.flags;
+ of.numchn =mh.numchn;
+ of.numpos =mh.numpos;
+ of.numpat =mh.numpat;
+ of.numtrk =mh.numtrk;
+ of.numins =mh.numins;
+ of.reppos =mh.reppos;
+ of.initspeed =mh.initspeed;
+ of.inittempo =mh.inittempo;
+ if(mh.bpmlimit)
+ of.bpmlimit=mh.bpmlimit;
+ else
+ /* be bug-compatible with older releases */
+ of.bpmlimit=32;
+
+ of.songname=readstring();
+ if(universion<0x102)
+ oldtype=readstring();
+ if(oldtype) {
+ size_t len=strlen(oldtype)+20;
+ if(!(modtype=MikMod_malloc(len))) return 0;
+#ifdef HAVE_SNPRINTF
+ snprintf(modtype,len,"%s (was %s)",(universion>=0x100)?"APlayer":"MikCvt2",oldtype);
+#else
+ sprintf(modtype,"%s (was %s)",(universion>=0x100)?"APlayer":"MikCvt2",oldtype);
+#endif
+ } else {
+ if(!(modtype=MikMod_malloc(10))) return 0;
+#ifdef HAVE_SNPRINTF
+ snprintf(modtype,10,"%s",(universion>=0x100)?"APlayer":"MikCvt3");
+#else
+ sprintf(modtype,"%s",(universion>=0x100)?"APlayer":"MikCvt3");
+#endif
+ }
+ of.modtype=StrDup(modtype);
+ MikMod_free(modtype);MikMod_free(oldtype);
+ of.comment=readstring();
+
+ if(universion>=6) {
+ of.numvoices=mh.numvoices;
+ of.initvolume=mh.initvolume;
+ }
+
+ if(_mm_eof(modreader)) {
+ _mm_errno=MMERR_LOADING_HEADER;
+ return 0;
+ }
+
+ /* positions */
+ if(!AllocPositions(of.numpos)) return 0;
+ if(universion>=6) {
+ if(universion>=0x100)
+ _mm_read_M_UWORDS(of.positions,of.numpos,modreader);
+ else
+ for(t=0;t<of.numpos;t++) of.positions[t]=_mm_read_UBYTE(modreader);
+ _mm_read_M_UWORDS(of.panning,of.numchn,modreader);
+ _mm_read_UBYTES(of.chanvol,of.numchn,modreader);
+ } else {
+ if((mh.numpos>256)||(mh.numchn>32)) {
+ _mm_errno=MMERR_LOADING_HEADER;
+ return 0;
+ }
+ for(t=0;t<of.numpos;t++) of.positions[t]=mh.positions[t];
+ for(t=0;t<of.numchn;t++) of.panning[t]=mh.panning[t];
+ }
+ /* convert the ``end of song'' pattern code if necessary */
+ if(universion<0x106)
+ for(t=0;t<of.numpos;t++)
+ if(of.positions[t]==255) of.positions[t]=LAST_PATTERN;
+
+ /* instruments and samples */
+ if(universion>=6) {
+ of.numsmp=mh.numsmp;
+ if(!AllocSamples()) return 0;
+ if(!loadsmp6()) return 0;
+
+ if(of.flags&UF_INST) {
+ if(!AllocInstruments()) return 0;
+ if(!loadinstr6()) return 0;
+ }
+ } else {
+ if(!AllocInstruments()) return 0;
+ if(!loadinstr5()) return 0;
+ if(!AllocSamples()) {
+ if(wh) { MikMod_free(wh);wh=NULL; }
+ return 0;
+ }
+ if(!loadsmp5()) return 0;
+
+ /* check if the original file had no instruments */
+ if(of.numsmp==of.numins) {
+ for(t=0,d=of.instruments;t<of.numins;t++,d++) {
+ int u;
+
+ if((d->volpts)||(d->panpts)||(d->globvol!=64)) break;
+ for(u=0;u<96;u++)
+ if((d->samplenumber[u]!=t)||(d->samplenote[u]!=u)) break;
+ if(u!=96) break;
+ }
+ if(t==of.numins) {
+ of.flags&=~UF_INST;
+ of.flags&=~UF_NOWRAP;
+ for(t=0,d=of.instruments,q=of.samples;t<of.numins;t++,d++,q++) {
+ q->samplename=d->insname;
+ d->insname=NULL;
+ }
+ }
+ }
+ }
+
+ /* patterns */
+ if(!AllocPatterns()) return 0;
+ if(universion>=6) {
+ _mm_read_M_UWORDS(of.pattrows,of.numpat,modreader);
+ _mm_read_M_UWORDS(of.patterns,of.numpat*of.numchn,modreader);
+ } else {
+ _mm_read_I_UWORDS(of.pattrows,of.numpat,modreader);
+ _mm_read_I_UWORDS(of.patterns,of.numpat*of.numchn,modreader);
+ }
+
+ /* tracks */
+ if(!AllocTracks()) return 0;
+ for(t=0;t<of.numtrk;t++)
+ if(!(of.tracks[t]=readtrack())) {
+ _mm_errno=MMERR_LOADING_TRACK;
+ return 0;
+ }
+
+ return 1;
+}
+
+CHAR *UNI_LoadTitle(void)
+{
+ UBYTE ver;
+ int posit[3]={304,306,26};
+
+ _mm_fseek(modreader,3,SEEK_SET);
+ ver=_mm_read_UBYTE(modreader);
+ if(ver=='N') ver='6';
+
+ _mm_fseek(modreader,posit[ver-'4'],SEEK_SET);
+ return readstring();
+}
+
+/*========== Loader information */
+
+MIKMODAPI MLOADER load_uni={
+ NULL,
+ "UNI",
+ "APUN (APlayer) and UNI (MikMod)",
+ UNI_Init,
+ UNI_Test,
+ UNI_Load,
+ UNI_Cleanup,
+ UNI_LoadTitle
+};
+
+/* ex:set ts=4: */
diff --git a/apps/plugins/mikmod/load_xm.c b/apps/plugins/mikmod/load_xm.c
new file mode 100644
index 0000000000..54a95aa2e6
--- /dev/null
+++ b/apps/plugins/mikmod/load_xm.c
@@ -0,0 +1,829 @@
+/* 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_xm.c,v 1.5 2008/02/29 18:49:03 denis111 Exp $
+
+ Fasttracker (XM) 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 */
+
+typedef struct XMHEADER {
+ CHAR id[17]; /* ID text: 'Extended module: ' */
+ CHAR songname[21]; /* Module name */
+ CHAR trackername[20]; /* Tracker name */
+ UWORD version; /* Version number */
+ ULONG headersize; /* Header size */
+ UWORD songlength; /* Song length (in patten order table) */
+ UWORD restart; /* Restart position */
+ UWORD numchn; /* Number of channels (2,4,6,8,10,...,32) */
+ UWORD numpat; /* Number of patterns (max 256) */
+ UWORD numins; /* Number of instruments (max 128) */
+ UWORD flags;
+ UWORD tempo; /* Default tempo */
+ UWORD bpm; /* Default BPM */
+ UBYTE orders[256]; /* Pattern order table */
+} XMHEADER;
+
+typedef struct XMINSTHEADER {
+ ULONG size; /* Instrument size */
+ CHAR name[22]; /* Instrument name */
+ UBYTE type; /* Instrument type (always 0) */
+ UWORD numsmp; /* Number of samples in instrument */
+ ULONG ssize;
+} XMINSTHEADER;
+
+#define XMENVCNT (12*2)
+#define XMNOTECNT (8*OCTAVE)
+typedef struct XMPATCHHEADER {
+ UBYTE what[XMNOTECNT]; /* Sample number for all notes */
+ UWORD volenv[XMENVCNT]; /* Points for volume envelope */
+ UWORD panenv[XMENVCNT]; /* Points for panning envelope */
+ UBYTE volpts; /* Number of volume points */
+ UBYTE panpts; /* Number of panning points */
+ UBYTE volsus; /* Volume sustain point */
+ UBYTE volbeg; /* Volume loop start point */
+ UBYTE volend; /* Volume loop end point */
+ UBYTE pansus; /* Panning sustain point */
+ UBYTE panbeg; /* Panning loop start point */
+ UBYTE panend; /* Panning loop end point */
+ UBYTE volflg; /* Volume type: bit 0: On; 1: Sustain; 2: Loop */
+ UBYTE panflg; /* Panning type: bit 0: On; 1: Sustain; 2: Loop */
+ UBYTE vibflg; /* Vibrato type */
+ UBYTE vibsweep; /* Vibrato sweep */
+ UBYTE vibdepth; /* Vibrato depth */
+ UBYTE vibrate; /* Vibrato rate */
+ UWORD volfade; /* Volume fadeout */
+} XMPATCHHEADER;
+
+typedef struct XMWAVHEADER {
+ ULONG length; /* Sample length */
+ ULONG loopstart; /* Sample loop start */
+ ULONG looplength; /* Sample loop length */
+ UBYTE volume; /* Volume */
+ SBYTE finetune; /* Finetune (signed byte -128..+127) */
+ UBYTE type; /* Loop type */
+ UBYTE panning; /* Panning (0-255) */
+ SBYTE relnote; /* Relative note number (signed byte) */
+ UBYTE reserved;
+ CHAR samplename[22]; /* Sample name */
+ UBYTE vibtype; /* Vibrato type */
+ UBYTE vibsweep; /* Vibrato sweep */
+ UBYTE vibdepth; /* Vibrato depth */
+ UBYTE vibrate; /* Vibrato rate */
+} XMWAVHEADER;
+
+typedef struct XMPATHEADER {
+ ULONG size; /* Pattern header length */
+ UBYTE packing; /* Packing type (always 0) */
+ UWORD numrows; /* Number of rows in pattern (1..256) */
+ SWORD packsize; /* Packed patterndata size */
+} XMPATHEADER;
+
+typedef struct XMNOTE {
+ UBYTE note,ins,vol,eff,dat;
+} XMNOTE;
+
+/*========== Loader variables */
+
+static XMNOTE *xmpat=NULL;
+static XMHEADER *mh=NULL;
+
+/* increment unit for sample array MikMod_reallocation */
+#define XM_SMPINCR 64
+static ULONG *nextwav=NULL;
+static XMWAVHEADER *wh=NULL,*s=NULL;
+
+/*========== Loader code */
+
+int XM_Test(void)
+{
+ UBYTE id[38];
+
+ if(!_mm_read_UBYTES(id,38,modreader)) return 0;
+ if(memcmp(id,"Extended Module: ",17)) return 0;
+ if(id[37]==0x1a) return 1;
+ return 0;
+}
+
+int XM_Init(void)
+{
+ if(!(mh=(XMHEADER *)MikMod_malloc(sizeof(XMHEADER)))) return 0;
+ return 1;
+}
+
+void XM_Cleanup(void)
+{
+ MikMod_free(mh);
+}
+
+static int XM_ReadNote(XMNOTE* n)
+{
+ UBYTE cmp,result=1;
+
+ memset(n,0,sizeof(XMNOTE));
+ cmp=_mm_read_UBYTE(modreader);
+
+ if(cmp&0x80) {
+ if(cmp&1) { result++;n->note = _mm_read_UBYTE(modreader); }
+ if(cmp&2) { result++;n->ins = _mm_read_UBYTE(modreader); }
+ if(cmp&4) { result++;n->vol = _mm_read_UBYTE(modreader); }
+ if(cmp&8) { result++;n->eff = _mm_read_UBYTE(modreader); }
+ if(cmp&16) { result++;n->dat = _mm_read_UBYTE(modreader); }
+ } else {
+ n->note = cmp;
+ n->ins = _mm_read_UBYTE(modreader);
+ n->vol = _mm_read_UBYTE(modreader);
+ n->eff = _mm_read_UBYTE(modreader);
+ n->dat = _mm_read_UBYTE(modreader);
+ result += 4;
+ }
+ return result;
+}
+
+static UBYTE* XM_Convert(XMNOTE* xmtrack,UWORD rows)
+{
+ int t;
+ UBYTE note,ins,vol,eff,dat;
+
+ UniReset();
+ for(t=0;t<rows;t++) {
+ note = xmtrack->note;
+ ins = xmtrack->ins;
+ vol = xmtrack->vol;
+ eff = xmtrack->eff;
+ dat = xmtrack->dat;
+
+ if(note) {
+ if(note>XMNOTECNT)
+ UniEffect(UNI_KEYFADE,0);
+ else
+ UniNote(note-1);
+ }
+ if(ins) UniInstrument(ins-1);
+
+ switch(vol>>4) {
+ case 0x6: /* volslide down */
+ if(vol&0xf) UniEffect(UNI_XMEFFECTA,vol&0xf);
+ break;
+ case 0x7: /* volslide up */
+ if(vol&0xf) UniEffect(UNI_XMEFFECTA,vol<<4);
+ break;
+
+ /* volume-row fine volume slide is compatible with protracker
+ EBx and EAx effects i.e. a zero nibble means DO NOT SLIDE, as
+ opposed to 'take the last sliding value'. */
+ case 0x8: /* finevol down */
+ UniPTEffect(0xe,0xb0|(vol&0xf));
+ break;
+ case 0x9: /* finevol up */
+ UniPTEffect(0xe,0xa0|(vol&0xf));
+ break;
+ case 0xa: /* set vibrato speed */
+ UniEffect(UNI_XMEFFECT4,vol<<4);
+ break;
+ case 0xb: /* vibrato */
+ UniEffect(UNI_XMEFFECT4,vol&0xf);
+ break;
+ case 0xc: /* set panning */
+ UniPTEffect(0x8,vol<<4);
+ break;
+ case 0xd: /* panning slide left (only slide when data not zero) */
+ if(vol&0xf) UniEffect(UNI_XMEFFECTP,vol&0xf);
+ break;
+ case 0xe: /* panning slide right (only slide when data not zero) */
+ if(vol&0xf) UniEffect(UNI_XMEFFECTP,vol<<4);
+ break;
+ case 0xf: /* tone porta */
+ UniPTEffect(0x3,vol<<4);
+ break;
+ default:
+ if((vol>=0x10)&&(vol<=0x50))
+ UniPTEffect(0xc,vol-0x10);
+ }
+
+ switch(eff) {
+ case 0x4:
+ UniEffect(UNI_XMEFFECT4,dat);
+ break;
+ case 0x6:
+ UniEffect(UNI_XMEFFECT6,dat);
+ break;
+ case 0xa:
+ UniEffect(UNI_XMEFFECTA,dat);
+ break;
+ case 0xe: /* Extended effects */
+ switch(dat>>4) {
+ case 0x1: /* XM fine porta up */
+ UniEffect(UNI_XMEFFECTE1,dat&0xf);
+ break;
+ case 0x2: /* XM fine porta down */
+ UniEffect(UNI_XMEFFECTE2,dat&0xf);
+ break;
+ case 0xa: /* XM fine volume up */
+ UniEffect(UNI_XMEFFECTEA,dat&0xf);
+ break;
+ case 0xb: /* XM fine volume down */
+ UniEffect(UNI_XMEFFECTEB,dat&0xf);
+ break;
+ default:
+ UniPTEffect(eff,dat);
+ }
+ break;
+ case 'G'-55: /* G - set global volume */
+ UniEffect(UNI_XMEFFECTG,dat>64?128:dat<<1);
+ break;
+ case 'H'-55: /* H - global volume slide */
+ UniEffect(UNI_XMEFFECTH,dat);
+ break;
+ case 'K'-55: /* K - keyOff and KeyFade */
+ UniEffect(UNI_KEYFADE,dat);
+ break;
+ case 'L'-55: /* L - set envelope position */
+ UniEffect(UNI_XMEFFECTL,dat);
+ break;
+ case 'P'-55: /* P - panning slide */
+ UniEffect(UNI_XMEFFECTP,dat);
+ break;
+ case 'R'-55: /* R - multi retrig note */
+ UniEffect(UNI_S3MEFFECTQ,dat);
+ break;
+ case 'T'-55: /* T - Tremor */
+ UniEffect(UNI_S3MEFFECTI,dat);
+ break;
+ case 'X'-55:
+ switch(dat>>4) {
+ case 1: /* X1 - Extra Fine Porta up */
+ UniEffect(UNI_XMEFFECTX1,dat&0xf);
+ break;
+ case 2: /* X2 - Extra Fine Porta down */
+ UniEffect(UNI_XMEFFECTX2,dat&0xf);
+ break;
+ }
+ break;
+ default:
+ if(eff<=0xf) {
+ /* the pattern jump destination is written in decimal,
+ but it seems some poor tracker software writes them
+ in hexadecimal... (sigh) */
+ if (eff==0xd)
+ /* don't change anything if we're sure it's in hexa */
+ if ((((dat&0xf0)>>4)<=9)&&((dat&0xf)<=9))
+ /* otherwise, convert from dec to hex */
+ dat=(((dat&0xf0)>>4)*10)+(dat&0xf);
+ UniPTEffect(eff,dat);
+ }
+ break;
+ }
+ UniNewline();
+ xmtrack++;
+ }
+ return UniDup();
+}
+
+static int LoadPatterns(int dummypat)
+{
+ int t,u,v,numtrk;
+
+ if(!AllocTracks()) return 0;
+ if(!AllocPatterns()) return 0;
+
+ numtrk=0;
+ for(t=0;t<mh->numpat;t++) {
+ XMPATHEADER ph;
+
+ ph.size =_mm_read_I_ULONG(modreader);
+ if (ph.size<(mh->version==0x0102?8:9)) {
+ _mm_errno=MMERR_LOADING_PATTERN;
+ return 0;
+ }
+ ph.packing =_mm_read_UBYTE(modreader);
+ if(ph.packing) {
+ _mm_errno=MMERR_LOADING_PATTERN;
+ return 0;
+ }
+ if(mh->version==0x0102)
+ ph.numrows =_mm_read_UBYTE(modreader)+1;
+ else
+ ph.numrows =_mm_read_I_UWORD(modreader);
+ ph.packsize =_mm_read_I_UWORD(modreader);
+
+ ph.size-=(mh->version==0x0102?8:9);
+ if(ph.size)
+ _mm_fseek(modreader,ph.size,SEEK_CUR);
+
+ of.pattrows[t]=ph.numrows;
+
+ if(ph.numrows) {
+ if(!(xmpat=(XMNOTE*)MikMod_calloc(ph.numrows*of.numchn,sizeof(XMNOTE))))
+ return 0;
+
+ /* when packsize is 0, don't try to load a pattern.. it's empty. */
+ if(ph.packsize)
+ for(u=0;u<ph.numrows;u++)
+ for(v=0;v<of.numchn;v++) {
+ if(!ph.packsize) break;
+
+ ph.packsize-=XM_ReadNote(&xmpat[(v*ph.numrows)+u]);
+ if(ph.packsize<0) {
+ MikMod_free(xmpat);xmpat=NULL;
+ _mm_errno=MMERR_LOADING_PATTERN;
+ return 0;
+ }
+ }
+
+ if(ph.packsize) {
+ _mm_fseek(modreader,ph.packsize,SEEK_CUR);
+ }
+
+ if(_mm_eof(modreader)) {
+ MikMod_free(xmpat);xmpat=NULL;
+ _mm_errno=MMERR_LOADING_PATTERN;
+ return 0;
+ }
+
+ for(v=0;v<of.numchn;v++)
+ of.tracks[numtrk++]=XM_Convert(&xmpat[v*ph.numrows],ph.numrows);
+
+ MikMod_free(xmpat);xmpat=NULL;
+ } else {
+ for(v=0;v<of.numchn;v++)
+ of.tracks[numtrk++]=XM_Convert(NULL,ph.numrows);
+ }
+ }
+
+ if(dummypat) {
+ of.pattrows[t]=64;
+ if(!(xmpat=(XMNOTE*)MikMod_calloc(64*of.numchn,sizeof(XMNOTE)))) return 0;
+ for(v=0;v<of.numchn;v++)
+ of.tracks[numtrk++]=XM_Convert(&xmpat[v*64],64);
+ MikMod_free(xmpat);xmpat=NULL;
+ }
+
+ return 1;
+}
+
+static void FixEnvelope(ENVPT *cur, int pts)
+{
+ int u, old, tmp;
+ ENVPT *prev;
+
+ /* Some broken XM editing program will only save the low byte
+ of the position value. Try to compensate by adding the
+ missing high byte. */
+
+ prev = cur++;
+ old = prev->pos;
+
+ for (u = 1; u < pts; u++, prev++, cur++) {
+ if (cur->pos < prev->pos) {
+ if (cur->pos < 0x100) {
+ if (cur->pos > old) /* same hex century */
+ tmp = cur->pos + (prev->pos - old);
+ else
+ tmp = cur->pos | ((prev->pos + 0x100) & 0xff00);
+ old = cur->pos;
+ cur->pos = tmp;
+#ifdef MIKMOD_DEBUG
+ fprintf(stderr, "\rbroken envelope position(%d/%d), %d %d -> %d\n",
+ u, pts, prev->pos, old, cur->pos);
+#endif
+ } else {
+#ifdef MIKMOD_DEBUG
+ /* different brokenness style... fix unknown */
+ fprintf(stderr, "\rbroken envelope position(%d/%d), %d %d\n",
+ u, pts, old, cur->pos);
+#endif
+ old = cur->pos;
+ }
+ } else
+ old = cur->pos;
+ }
+}
+
+static int LoadInstruments(void)
+{
+ int t,u, ck;
+ INSTRUMENT *d;
+ ULONG next=0;
+ UWORD wavcnt=0;
+
+ if(!AllocInstruments()) return 0;
+ d=of.instruments;
+ for(t=0;t<of.numins;t++,d++) {
+ XMINSTHEADER ih;
+ long headend;
+
+ memset(d->samplenumber,0xff,INSTNOTES*sizeof(UWORD));
+
+ /* read instrument header */
+ headend = _mm_ftell(modreader);
+ ih.size = _mm_read_I_ULONG(modreader);
+ headend += ih.size;
+ ck = _mm_ftell(modreader);
+ _mm_fseek(modreader,0,SEEK_END);
+ if ((headend<0) || (_mm_ftell(modreader)<headend) || (headend<ck)) {
+ _mm_fseek(modreader,ck,SEEK_SET);
+ break;
+ }
+ _mm_fseek(modreader,ck,SEEK_SET);
+ _mm_read_string(ih.name, 22, modreader);
+ ih.type = _mm_read_UBYTE(modreader);
+ ih.numsmp = _mm_read_I_UWORD(modreader);
+
+ d->insname = DupStr(ih.name,22,1);
+
+ if((SWORD)ih.size>29) {
+ ih.ssize = _mm_read_I_ULONG(modreader);
+ if(((SWORD)ih.numsmp>0)&&(ih.numsmp<=XMNOTECNT)) {
+ XMPATCHHEADER pth;
+ int p;
+
+ _mm_read_UBYTES (pth.what,XMNOTECNT,modreader);
+ _mm_read_I_UWORDS (pth.volenv, XMENVCNT, modreader);
+ _mm_read_I_UWORDS (pth.panenv, XMENVCNT, modreader);
+ pth.volpts = _mm_read_UBYTE(modreader);
+ pth.panpts = _mm_read_UBYTE(modreader);
+ pth.volsus = _mm_read_UBYTE(modreader);
+ pth.volbeg = _mm_read_UBYTE(modreader);
+ pth.volend = _mm_read_UBYTE(modreader);
+ pth.pansus = _mm_read_UBYTE(modreader);
+ pth.panbeg = _mm_read_UBYTE(modreader);
+ pth.panend = _mm_read_UBYTE(modreader);
+ pth.volflg = _mm_read_UBYTE(modreader);
+ pth.panflg = _mm_read_UBYTE(modreader);
+ pth.vibflg = _mm_read_UBYTE(modreader);
+ pth.vibsweep = _mm_read_UBYTE(modreader);
+ pth.vibdepth = _mm_read_UBYTE(modreader);
+ pth.vibrate = _mm_read_UBYTE(modreader);
+ pth.volfade = _mm_read_I_UWORD(modreader);
+
+ /* read the remainder of the header
+ (2 bytes for 1.03, 22 for 1.04) */
+ if (headend>=_mm_ftell(modreader)) for(u=headend-_mm_ftell(modreader);u;u--) _mm_read_UBYTE(modreader);
+
+ /* we can't trust the envelope point count here, as some
+ modules have incorrect values (K_OSPACE.XM reports 32 volume
+ points, for example). */
+ if(pth.volpts>XMENVCNT/2) pth.volpts=XMENVCNT/2;
+ if(pth.panpts>XMENVCNT/2) pth.panpts=XMENVCNT/2;
+
+ if((_mm_eof(modreader))||(pth.volpts>XMENVCNT/2)||(pth.panpts>XMENVCNT/2)) {
+ if(nextwav) { MikMod_free(nextwav);nextwav=NULL; }
+ if(wh) { MikMod_free(wh);wh=NULL; }
+ _mm_errno = MMERR_LOADING_SAMPLEINFO;
+ return 0;
+ }
+
+ for(u=0;u<XMNOTECNT;u++)
+ d->samplenumber[u]=pth.what[u]+of.numsmp;
+ d->volfade = pth.volfade;
+
+#if defined __STDC__ || defined _MSC_VER || defined MPW_C
+#define XM_ProcessEnvelope(name) \
+ for (u = 0; u < (XMENVCNT >> 1); u++) { \
+ d-> name##env[u].pos = pth. name##env[u << 1]; \
+ d-> name##env[u].val = pth. name##env[(u << 1)+ 1]; \
+ } \
+ if (pth. name##flg&1) d-> name##flg|=EF_ON; \
+ if (pth. name##flg&2) d-> name##flg|=EF_SUSTAIN; \
+ if (pth. name##flg&4) d-> name##flg|=EF_LOOP; \
+ d-> name##susbeg=d-> name##susend=pth. name##sus; \
+ d-> name##beg=pth. name##beg; \
+ d-> name##end=pth. name##end; \
+ d-> name##pts=pth. name##pts; \
+ \
+ /* scale envelope */ \
+ for (p=0;p<XMENVCNT/2;p++) \
+ d-> name##env[p].val<<=2; \
+ \
+ if ((d-> name##flg&EF_ON)&&(d-> name##pts<2)) \
+ d-> name##flg&=~EF_ON
+#else
+#define XM_ProcessEnvelope(name) \
+ for (u = 0; u < (XMENVCNT >> 1); u++) { \
+ d-> name/**/env[u].pos = pth. name/**/env[u << 1]; \
+ d-> name/**/env[u].val = pth. name/**/env[(u << 1)+ 1]; \
+ } \
+ if (pth. name/**/flg&1) d-> name/**/flg|=EF_ON; \
+ if (pth. name/**/flg&2) d-> name/**/flg|=EF_SUSTAIN; \
+ if (pth. name/**/flg&4) d-> name/**/flg|=EF_LOOP; \
+ d-> name/**/susbeg=d-> name/**/susend= \
+ pth. name/**/sus; \
+ d-> name/**/beg=pth. name/**/beg; \
+ d-> name/**/end=pth. name/**/end; \
+ d-> name/**/pts=pth. name/**/pts; \
+ \
+ /* scale envelope */ \
+ for (p=0;p<XMENVCNT/2;p++) \
+ d-> name/**/env[p].val<<=2; \
+ \
+ if ((d-> name/**/flg&EF_ON)&&(d-> name/**/pts<2)) \
+ d-> name/**/flg&=~EF_ON
+#endif
+
+ XM_ProcessEnvelope(vol);
+ XM_ProcessEnvelope(pan);
+#undef XM_ProcessEnvelope
+
+ if (d->volflg & EF_ON)
+ FixEnvelope(d->volenv, d->volpts);
+ if (d->panflg & EF_ON)
+ FixEnvelope(d->panenv, d->panpts);
+
+ /* Samples are stored outside the instrument struct now, so we
+ have to load them all into a temp area, count the of.numsmp
+ along the way and then do an AllocSamples() and move
+ everything over */
+ if(mh->version>0x0103) next = 0;
+ for(u=0;u<ih.numsmp;u++,s++) {
+ /* Allocate more room for sample information if necessary */
+ if(of.numsmp+u==wavcnt) {
+ wavcnt+=XM_SMPINCR;
+ if(!(nextwav=MikMod_realloc(nextwav,wavcnt*sizeof(ULONG)))){
+ if(wh) { MikMod_free(wh);wh=NULL; }
+ _mm_errno = MMERR_OUT_OF_MEMORY;
+ return 0;
+ }
+ if(!(wh=MikMod_realloc(wh,wavcnt*sizeof(XMWAVHEADER)))) {
+ MikMod_free(nextwav);nextwav=NULL;
+ _mm_errno = MMERR_OUT_OF_MEMORY;
+ return 0;
+ }
+ s=wh+(wavcnt-XM_SMPINCR);
+ }
+
+ s->length =_mm_read_I_ULONG (modreader);
+ s->loopstart =_mm_read_I_ULONG (modreader);
+ s->looplength =_mm_read_I_ULONG (modreader);
+ s->volume =_mm_read_UBYTE (modreader);
+ s->finetune =_mm_read_SBYTE (modreader);
+ s->type =_mm_read_UBYTE (modreader);
+ s->panning =_mm_read_UBYTE (modreader);
+ s->relnote =_mm_read_SBYTE (modreader);
+ s->vibtype = pth.vibflg;
+ s->vibsweep = pth.vibsweep;
+ s->vibdepth = pth.vibdepth*4;
+ s->vibrate = pth.vibrate;
+ s->reserved =_mm_read_UBYTE (modreader);
+ _mm_read_string(s->samplename, 22, modreader);
+
+ nextwav[of.numsmp+u]=next;
+ next+=s->length;
+
+ if(_mm_eof(modreader)) {
+ MikMod_free(nextwav);MikMod_free(wh);
+ nextwav=NULL;wh=NULL;
+ _mm_errno = MMERR_LOADING_SAMPLEINFO;
+ return 0;
+ }
+ }
+
+ if(mh->version>0x0103) {
+ for(u=0;u<ih.numsmp;u++)
+ nextwav[of.numsmp++]+=_mm_ftell(modreader);
+ _mm_fseek(modreader,next,SEEK_CUR);
+ } else
+ of.numsmp+=ih.numsmp;
+ } else {
+ /* read the remainder of the header */
+ ck = _mm_ftell(modreader);
+ _mm_fseek(modreader,0,SEEK_END);
+ if ((headend<0) || (_mm_ftell(modreader)<headend) || (headend<ck)) {
+ _mm_fseek(modreader,ck,SEEK_SET);
+ break;
+ }
+ _mm_fseek(modreader,ck,SEEK_SET);
+ for(u=headend-_mm_ftell(modreader);u;u--) _mm_read_UBYTE(modreader);
+
+ if(_mm_eof(modreader)) {
+ MikMod_free(nextwav);MikMod_free(wh);
+ nextwav=NULL;wh=NULL;
+ _mm_errno = MMERR_LOADING_SAMPLEINFO;
+ return 0;
+ }
+ }
+ }
+ }
+
+ /* sanity check */
+ if(!of.numsmp) {
+ if(nextwav) { MikMod_free(nextwav);nextwav=NULL; }
+ if(wh) { MikMod_free(wh);wh=NULL; }
+ _mm_errno = MMERR_LOADING_SAMPLEINFO;
+ return 0;
+ }
+
+ return 1;
+}
+
+int XM_Load(int curious)
+{
+ INSTRUMENT *d;
+ SAMPLE *q;
+ int t,u;
+ int dummypat=0;
+ char tracker[21],modtype[60];
+
+ /* try to read module header */
+ _mm_read_string(mh->id,17,modreader);
+ _mm_read_string(mh->songname,21,modreader);
+ _mm_read_string(mh->trackername,20,modreader);
+ mh->version =_mm_read_I_UWORD(modreader);
+ if((mh->version<0x102)||(mh->version>0x104)) {
+ _mm_errno=MMERR_NOT_A_MODULE;
+ return 0;
+ }
+ mh->headersize =_mm_read_I_ULONG(modreader);
+ mh->songlength =_mm_read_I_UWORD(modreader);
+ mh->restart =_mm_read_I_UWORD(modreader);
+ mh->numchn =_mm_read_I_UWORD(modreader);
+ mh->numpat =_mm_read_I_UWORD(modreader);
+ mh->numins =_mm_read_I_UWORD(modreader);
+ mh->flags =_mm_read_I_UWORD(modreader);
+ mh->tempo =_mm_read_I_UWORD(modreader);
+ mh->bpm =_mm_read_I_UWORD(modreader);
+ if(!mh->bpm) {
+ _mm_errno=MMERR_NOT_A_MODULE;
+ return 0;
+ }
+ _mm_read_UBYTES(mh->orders,mh->headersize-20,modreader);
+
+ if(_mm_eof(modreader)) {
+ _mm_errno = MMERR_LOADING_HEADER;
+ return 0;
+ }
+
+ /* set module variables */
+ of.initspeed = mh->tempo;
+ of.inittempo = mh->bpm;
+ strncpy(tracker,mh->trackername,20);tracker[20]=0;
+ for(t=20;(tracker[t]<=' ')&&(t>=0);t--) tracker[t]=0;
+
+ /* some modules have the tracker name empty */
+ if (!tracker[0])
+ strcpy(tracker,"Unknown tracker");
+
+#ifdef HAVE_SNPRINTF
+ snprintf(modtype,60,"%s (XM format %d.%02d)",
+ tracker,mh->version>>8,mh->version&0xff);
+#else
+ sprintf(modtype,"%s (XM format %d.%02d)",
+ tracker,mh->version>>8,mh->version&0xff);
+#endif
+ of.modtype = StrDup(modtype);
+ of.numchn = mh->numchn;
+ of.numpat = mh->numpat;
+ of.numtrk = (UWORD)of.numpat*of.numchn; /* get number of channels */
+ of.songname = DupStr(mh->songname,20,1);
+ of.numpos = mh->songlength; /* copy the songlength */
+ of.reppos = mh->restart<mh->songlength?mh->restart:0;
+ of.numins = mh->numins;
+ of.flags |= UF_XMPERIODS | UF_INST | UF_NOWRAP | UF_FT2QUIRKS |
+ UF_PANNING;
+ if(mh->flags&1) of.flags |= UF_LINEAR;
+ of.bpmlimit = 32;
+
+ memset(of.chanvol,64,of.numchn); /* store channel volumes */
+
+ if(!AllocPositions(of.numpos+1)) return 0;
+ for(t=0;t<of.numpos;t++)
+ of.positions[t]=mh->orders[t];
+
+ /* We have to check for any pattern numbers in the order list greater than
+ the number of patterns total. If one or more is found, we set it equal to
+ the pattern total and make a dummy pattern to workaround the problem */
+ for(t=0;t<of.numpos;t++) {
+ if(of.positions[t]>=of.numpat) {
+ of.positions[t]=of.numpat;
+ dummypat=1;
+ }
+ }
+ if(dummypat) {
+ of.numpat++;of.numtrk+=of.numchn;
+ }
+
+ if(mh->version<0x0104) {
+ if(!LoadInstruments()) return 0;
+ if(!LoadPatterns(dummypat)) return 0;
+ for(t=0;t<of.numsmp;t++)
+ nextwav[t]+=_mm_ftell(modreader);
+ } else {
+ if(!LoadPatterns(dummypat)) return 0;
+ if(!LoadInstruments()) return 0;
+ }
+
+ if(!AllocSamples()) {
+ MikMod_free(nextwav);MikMod_free(wh);
+ nextwav=NULL;wh=NULL;
+ return 0;
+ }
+ q = of.samples;
+ s = wh;
+ for(u=0;u<of.numsmp;u++,q++,s++) {
+ q->samplename = DupStr(s->samplename,22,1);
+ q->length = s->length;
+ q->loopstart = s->loopstart;
+ q->loopend = s->loopstart+s->looplength;
+ q->volume = s->volume;
+ q->speed = s->finetune+128;
+ q->panning = s->panning;
+ q->seekpos = nextwav[u];
+ q->vibtype = s->vibtype;
+ q->vibsweep = s->vibsweep;
+ q->vibdepth = s->vibdepth;
+ q->vibrate = s->vibrate;
+
+ if(s->type & 0x10) {
+ q->length >>= 1;
+ q->loopstart >>= 1;
+ q->loopend >>= 1;
+ }
+
+ q->flags|=SF_OWNPAN|SF_DELTA|SF_SIGNED;
+ if(s->type&0x3) q->flags|=SF_LOOP;
+ if(s->type&0x2) q->flags|=SF_BIDI;
+ if(s->type&0x10) q->flags|=SF_16BITS;
+ }
+
+ d=of.instruments;
+ s=wh;
+ for(u=0;u<of.numins;u++,d++)
+ for(t=0;t<XMNOTECNT;t++) {
+ if (d->samplenumber[t]>=of.numsmp)
+ d->samplenote[t]=255;
+ else {
+ int note=t+s[d->samplenumber[t]].relnote;
+ d->samplenote[t]=(note<0)?0:note;
+ }
+ }
+
+ MikMod_free(wh);MikMod_free(nextwav);
+ wh=NULL;nextwav=NULL;
+ return 1;
+}
+
+CHAR *XM_LoadTitle(void)
+{
+ CHAR s[21];
+
+ _mm_fseek(modreader,17,SEEK_SET);
+ if(!_mm_read_UBYTES(s,21,modreader)) return NULL;
+
+ return(DupStr(s,21,1));
+}
+
+/*========== Loader information */
+
+MIKMODAPI MLOADER load_xm={
+ NULL,
+ "XM",
+ "XM (FastTracker 2)",
+ XM_Init,
+ XM_Test,
+ XM_Load,
+ XM_Cleanup,
+ XM_LoadTitle
+};
+
+/* ex:set ts=4: */
diff --git a/apps/plugins/mikmod/mdreg.c b/apps/plugins/mikmod/mdreg.c
new file mode 100644
index 0000000000..8385e15ff5
--- /dev/null
+++ b/apps/plugins/mikmod/mdreg.c
@@ -0,0 +1,131 @@
+/* MikMod sound library
+ (c) 1998, 1999 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: mdreg.c,v 1.2 2005/03/30 19:11:13 realtech Exp $
+
+ Routine for registering all drivers in libmikmod for the current platform.
+
+==============================================================================*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "mikmod_internals.h"
+
+void _mm_registeralldrivers(void)
+{
+#if 0
+
+ /* Register network drivers */
+#ifdef DRV_AF
+ _mm_registerdriver(&drv_AF);
+#endif
+#ifdef DRV_ESD
+ _mm_registerdriver(&drv_esd);
+#endif
+#ifdef DRV_NAS
+ _mm_registerdriver(&drv_nas);
+#endif
+
+ /* Register hardware drivers - hardware mixing */
+#ifdef DRV_ULTRA
+ _mm_registerdriver(&drv_ultra);
+#endif
+
+ /* Register hardware drivers - software mixing */
+#ifdef DRV_AIX
+ _mm_registerdriver(&drv_aix);
+#endif
+#ifdef DRV_ALSA
+ _mm_registerdriver(&drv_alsa);
+#endif
+#ifdef DRV_HP
+ _mm_registerdriver(&drv_hp);
+#endif
+#ifdef DRV_OSS
+ _mm_registerdriver(&drv_oss);
+#endif
+#ifdef DRV_SGI
+ _mm_registerdriver(&drv_sgi);
+#endif
+#ifdef DRV_SUN
+ _mm_registerdriver(&drv_sun);
+#endif
+#ifdef DRV_DART
+ _mm_registerdriver(&drv_dart);
+#endif
+#ifdef DRV_OS2
+ _mm_registerdriver(&drv_os2);
+#endif
+#ifdef DRV_DS
+ _mm_registerdriver(&drv_ds);
+#endif
+#ifdef DRV_WIN
+ _mm_registerdriver(&drv_win);
+#endif
+#ifdef DRV_MAC
+ _mm_registerdriver(&drv_mac);
+#endif
+#ifdef DRV_OSX
+ _mm_registerdriver(&drv_osx);
+#endif
+#ifdef DRV_GP32
+ _mm_registerdriver(&drv_gp32);
+#endif
+
+ /* dos drivers */
+#ifdef DRV_WSS
+ /* wss first, since some cards emulate sb */
+ _mm_registerdriver(&drv_wss);
+#endif
+#ifdef DRV_SB
+ _mm_registerdriver(&drv_sb);
+#endif
+
+ /* Register disk writers */
+ _mm_registerdriver(&drv_raw);
+ _mm_registerdriver(&drv_wav);
+#ifdef DRV_AIFF
+ _mm_registerdriver(&drv_aiff);
+#endif
+
+ /* Register other drivers */
+#ifdef DRV_PIPE
+ _mm_registerdriver(&drv_pipe);
+#endif
+#ifndef macintosh
+ _mm_registerdriver(&drv_stdout);
+#endif
+
+#endif
+ _mm_registerdriver(&drv_nos);
+}
+
+void MikMod_RegisterAllDrivers(void)
+{
+ MUTEX_LOCK(lists);
+ _mm_registeralldrivers();
+ MUTEX_UNLOCK(lists);
+}
+
+/* ex:set ts=4: */
diff --git a/apps/plugins/mikmod/mdriver.c b/apps/plugins/mikmod/mdriver.c
new file mode 100644
index 0000000000..e11d32539b
--- /dev/null
+++ b/apps/plugins/mikmod/mdriver.c
@@ -0,0 +1,965 @@
+/* MikMod sound library
+ (c) 1998, 1999, 2000, 2001 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: mdriver.c,v 1.4 2007/12/03 20:59:05 denis111 Exp $
+
+ These routines are used to access the available soundcard drivers.
+
+==============================================================================*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#if 0
+#if defined unix || (defined __APPLE__ && defined __MACH__)
+#include <pwd.h>
+#include <sys/stat.h>
+#endif
+#endif
+
+#include <string.h>
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+
+#include "mikmod_internals.h"
+
+#ifdef SUNOS
+extern int fprintf(FILE *, const char *, ...);
+#endif
+
+static MDRIVER *firstdriver=NULL;
+MIKMODAPI MDRIVER *md_driver=NULL;
+extern MODULE *pf; /* modfile being played */
+
+/* Initial global settings */
+MIKMODAPI UWORD md_device = 0; /* autodetect */
+MIKMODAPI UWORD md_mixfreq = 44100;
+MIKMODAPI UWORD md_mode = DMODE_STEREO | DMODE_16BITS |
+ DMODE_SURROUND |DMODE_SOFT_MUSIC |
+ DMODE_SOFT_SNDFX;
+MIKMODAPI UBYTE md_pansep = 128; /* 128 == 100% (full left/right) */
+MIKMODAPI UBYTE md_reverb = 0; /* no reverb */
+MIKMODAPI UBYTE md_volume = 128; /* global sound volume (0-128) */
+MIKMODAPI UBYTE md_musicvolume = 128; /* volume of song */
+MIKMODAPI UBYTE md_sndfxvolume = 128; /* volume of sound effects */
+ UWORD md_bpm = 125; /* tempo */
+
+/* Do not modify the numchn variables yourself! use MD_SetVoices() */
+ UBYTE md_numchn=0,md_sngchn=0,md_sfxchn=0;
+ UBYTE md_hardchn=0,md_softchn=0;
+
+ void (*md_player)(void) = Player_HandleTick;
+static volatile int isplaying=0, initialized = 0;
+static UBYTE *sfxinfo;
+static int sfxpool;
+
+static SAMPLE **md_sample = NULL;
+
+/* Previous driver in use */
+static SWORD olddevice = -1;
+
+/* Limits the number of hardware voices to the specified amount.
+ This function should only be used by the low-level drivers. */
+static void LimitHardVoices(int limit)
+{
+ int t=0;
+
+ if (!(md_mode & DMODE_SOFT_SNDFX) && (md_sfxchn>limit)) md_sfxchn=limit;
+ if (!(md_mode & DMODE_SOFT_MUSIC) && (md_sngchn>limit)) md_sngchn=limit;
+
+ if (!(md_mode & DMODE_SOFT_SNDFX))
+ md_hardchn=md_sfxchn;
+ else
+ md_hardchn=0;
+
+ if (!(md_mode & DMODE_SOFT_MUSIC)) md_hardchn += md_sngchn;
+
+ while (md_hardchn>limit) {
+ if (++t & 1) {
+ if (!(md_mode & DMODE_SOFT_SNDFX) && (md_sfxchn>4)) md_sfxchn--;
+ } else {
+ if (!(md_mode & DMODE_SOFT_MUSIC) && (md_sngchn>8)) md_sngchn--;
+ }
+
+ if (!(md_mode & DMODE_SOFT_SNDFX))
+ md_hardchn=md_sfxchn;
+ else
+ md_hardchn=0;
+
+ if (!(md_mode & DMODE_SOFT_MUSIC))
+ md_hardchn+=md_sngchn;
+ }
+ md_numchn=md_hardchn+md_softchn;
+}
+
+/* Limits the number of hardware voices to the specified amount.
+ This function should only be used by the low-level drivers. */
+static void LimitSoftVoices(int limit)
+{
+ int t=0;
+
+ if ((md_mode & DMODE_SOFT_SNDFX) && (md_sfxchn>limit)) md_sfxchn=limit;
+ if ((md_mode & DMODE_SOFT_MUSIC) && (md_sngchn>limit)) md_sngchn=limit;
+
+ if (md_mode & DMODE_SOFT_SNDFX)
+ md_softchn=md_sfxchn;
+ else
+ md_softchn=0;
+
+ if (md_mode & DMODE_SOFT_MUSIC) md_softchn+=md_sngchn;
+
+ while (md_softchn>limit) {
+ if (++t & 1) {
+ if ((md_mode & DMODE_SOFT_SNDFX) && (md_sfxchn>4)) md_sfxchn--;
+ } else {
+ if ((md_mode & DMODE_SOFT_MUSIC) && (md_sngchn>8)) md_sngchn--;
+ }
+
+ if (!(md_mode & DMODE_SOFT_SNDFX))
+ md_softchn=md_sfxchn;
+ else
+ md_softchn=0;
+
+ if (!(md_mode & DMODE_SOFT_MUSIC))
+ md_softchn+=md_sngchn;
+ }
+ md_numchn=md_hardchn+md_softchn;
+}
+
+/* Note: 'type' indicates whether the returned value should be for music or for
+ sound effects. */
+ULONG MD_SampleSpace(int type)
+{
+ if(type==MD_MUSIC)
+ type=(md_mode & DMODE_SOFT_MUSIC)?MD_SOFTWARE:MD_HARDWARE;
+ else if(type==MD_SNDFX)
+ type=(md_mode & DMODE_SOFT_SNDFX)?MD_SOFTWARE:MD_HARDWARE;
+
+ return md_driver->FreeSampleSpace(type);
+}
+
+ULONG MD_SampleLength(int type,SAMPLE* s)
+{
+ if(type==MD_MUSIC)
+ type=(md_mode & DMODE_SOFT_MUSIC)?MD_SOFTWARE:MD_HARDWARE;
+ else
+ if(type==MD_SNDFX)
+ type=(md_mode & DMODE_SOFT_SNDFX)?MD_SOFTWARE:MD_HARDWARE;
+
+ return md_driver->RealSampleLength(type,s);
+}
+
+MIKMODAPI CHAR* MikMod_InfoDriver(void)
+{
+ int t;
+ size_t len=0;
+ MDRIVER *l;
+ CHAR *list=NULL;
+
+ MUTEX_LOCK(lists);
+ /* compute size of buffer */
+ for(l=firstdriver;l;l=l->next)
+ len+=4+(l->next?1:0)+strlen(l->Version);
+
+ if(len)
+ if((list=MikMod_malloc(len*sizeof(CHAR)))) {
+ list[0]=0;
+ /* list all registered device drivers : */
+ for(t=1,l=firstdriver;l;l=l->next,t++)
+ sprintf(list,(l->next)?"%s%2d %s\n":"%s%2d %s",
+ list,t,l->Version);
+ }
+ MUTEX_UNLOCK(lists);
+ return list;
+}
+
+void _mm_registerdriver(struct MDRIVER* drv)
+{
+ MDRIVER *cruise = firstdriver;
+
+ /* don't register a MISSING() driver */
+ if ((drv->Name) && (drv->Version)) {
+ if (cruise) {
+ if ( cruise == drv )
+ return;
+ while(cruise->next) {
+ cruise = cruise->next;
+ if ( cruise == drv )
+ return;
+ }
+ cruise->next = drv;
+ } else
+ firstdriver = drv;
+ }
+}
+
+MIKMODAPI void MikMod_RegisterDriver(struct MDRIVER* drv)
+{
+ /* if we try to register an invalid driver, or an already registered driver,
+ ignore this attempt */
+ if ((!drv)||(drv->next)||(!drv->Name))
+ return;
+
+ MUTEX_LOCK(lists);
+ _mm_registerdriver(drv);
+ MUTEX_UNLOCK(lists);
+}
+
+MIKMODAPI int MikMod_DriverFromAlias(CHAR *alias)
+{
+ int rank=1;
+ MDRIVER *cruise;
+
+ MUTEX_LOCK(lists);
+ cruise=firstdriver;
+ while(cruise) {
+ if (cruise->Alias) {
+ if (!(strcasecmp(alias,cruise->Alias))) break;
+ rank++;
+ }
+ cruise=cruise->next;
+ }
+ if(!cruise) rank=0;
+ MUTEX_UNLOCK(lists);
+
+ return rank;
+}
+
+MIKMODAPI MDRIVER *MikMod_DriverByOrdinal(int ordinal)
+{
+ MDRIVER *cruise;
+
+ /* Allow only driver ordinals > 0 */
+ if (!ordinal)
+ return 0;
+
+ MUTEX_LOCK(lists);
+ cruise = firstdriver;
+ while (cruise && --ordinal)
+ cruise = cruise->next;
+ MUTEX_UNLOCK(lists);
+ return cruise;
+}
+
+SWORD MD_SampleLoad(SAMPLOAD* s, int type)
+{
+ SWORD result;
+
+ if(type==MD_MUSIC)
+ type=(md_mode & DMODE_SOFT_MUSIC)?MD_SOFTWARE:MD_HARDWARE;
+ else if(type==MD_SNDFX)
+ type=(md_mode & DMODE_SOFT_SNDFX)?MD_SOFTWARE:MD_HARDWARE;
+
+ SL_Init(s);
+ result=md_driver->SampleLoad(s,type);
+ SL_Exit(s);
+
+ return result;
+}
+
+void MD_SampleUnload(SWORD handle)
+{
+ md_driver->SampleUnload(handle);
+}
+
+MIKMODAPI MikMod_player_t MikMod_RegisterPlayer(MikMod_player_t player)
+{
+ MikMod_player_t result;
+
+ MUTEX_LOCK(vars);
+ result=md_player;
+ md_player=player;
+ MUTEX_UNLOCK(vars);
+
+ return result;
+}
+
+MIKMODAPI void MikMod_Update(void)
+{
+ MUTEX_LOCK(vars);
+ if(isplaying) {
+ if((!pf)||(!pf->forbid))
+ md_driver->Update();
+ else {
+ if (md_driver->Pause)
+ md_driver->Pause();
+ }
+ }
+ MUTEX_UNLOCK(vars);
+}
+
+void Voice_SetVolume_internal(SBYTE voice,UWORD vol)
+{
+ ULONG tmp;
+
+ if((voice<0)||(voice>=md_numchn)) return;
+
+ /* range checks */
+ if(md_musicvolume>128) md_musicvolume=128;
+ if(md_sndfxvolume>128) md_sndfxvolume=128;
+ if(md_volume>128) md_volume=128;
+
+ tmp=(ULONG)vol*(ULONG)md_volume*
+ ((voice<md_sngchn)?(ULONG)md_musicvolume:(ULONG)md_sndfxvolume);
+ md_driver->VoiceSetVolume(voice,tmp/16384UL);
+}
+
+MIKMODAPI void Voice_SetVolume(SBYTE voice,UWORD vol)
+{
+ MUTEX_LOCK(vars);
+ Voice_SetVolume_internal(voice,vol);
+ MUTEX_UNLOCK(vars);
+}
+
+MIKMODAPI UWORD Voice_GetVolume(SBYTE voice)
+{
+ UWORD result=0;
+
+ MUTEX_LOCK(vars);
+ if((voice>=0)&&(voice<md_numchn))
+ result=md_driver->VoiceGetVolume(voice);
+ MUTEX_UNLOCK(vars);
+
+ return result;
+}
+
+void Voice_SetFrequency_internal(SBYTE voice,ULONG frq)
+{
+ if((voice<0)||(voice>=md_numchn)) return;
+ if((md_sample[voice])&&(md_sample[voice]->divfactor))
+ frq/=md_sample[voice]->divfactor;
+ md_driver->VoiceSetFrequency(voice,frq);
+}
+
+MIKMODAPI void Voice_SetFrequency(SBYTE voice,ULONG frq)
+{
+ MUTEX_LOCK(vars);
+ Voice_SetFrequency_internal(voice,frq);
+ MUTEX_UNLOCK(vars);
+}
+
+MIKMODAPI ULONG Voice_GetFrequency(SBYTE voice)
+{
+ ULONG result=0;
+
+ MUTEX_LOCK(vars);
+ if((voice>=0)&&(voice<md_numchn))
+ result=md_driver->VoiceGetFrequency(voice);
+ MUTEX_UNLOCK(vars);
+
+ return result;
+}
+
+void Voice_SetPanning_internal(SBYTE voice,ULONG pan)
+{
+ if((voice<0)||(voice>=md_numchn)) return;
+ if(pan!=PAN_SURROUND) {
+ if(md_pansep>128) md_pansep=128;
+ if(md_mode & DMODE_REVERSE) pan=255-pan;
+ pan = (((SWORD)(pan-128)*md_pansep)/128)+128;
+ }
+ md_driver->VoiceSetPanning(voice, pan);
+}
+
+MIKMODAPI void Voice_SetPanning(SBYTE voice,ULONG pan)
+{
+#ifdef MIKMOD_DEBUG
+ if((pan!=PAN_SURROUND)&&((pan<0)||(pan>255)))
+ fprintf(stderr,"\rVoice_SetPanning called with pan=%ld\n",(long)pan);
+#endif
+
+ MUTEX_LOCK(vars);
+ Voice_SetPanning_internal(voice,pan);
+ MUTEX_UNLOCK(vars);
+}
+
+MIKMODAPI ULONG Voice_GetPanning(SBYTE voice)
+{
+ ULONG result=PAN_CENTER;
+
+ MUTEX_LOCK(vars);
+ if((voice>=0)&&(voice<md_numchn))
+ result=md_driver->VoiceGetPanning(voice);
+ MUTEX_UNLOCK(vars);
+
+ return result;
+}
+
+void Voice_Play_internal(SBYTE voice,SAMPLE* s,ULONG start)
+{
+ ULONG repend;
+
+ if((voice<0)||(voice>=md_numchn)) return;
+
+ md_sample[voice]=s;
+ repend=s->loopend;
+
+ if(s->flags&SF_LOOP)
+ /* repend can't be bigger than size */
+ if(repend>s->length) repend=s->length;
+
+ md_driver->VoicePlay(voice,s->handle,start,s->length,s->loopstart,repend,s->flags);
+}
+
+MIKMODAPI void Voice_Play(SBYTE voice,SAMPLE* s,ULONG start)
+{
+ if(start>s->length) return;
+
+ MUTEX_LOCK(vars);
+ Voice_Play_internal(voice,s,start);
+ MUTEX_UNLOCK(vars);
+}
+
+void Voice_Stop_internal(SBYTE voice)
+{
+ if((voice<0)||(voice>=md_numchn)) return;
+ if(voice>=md_sngchn)
+ /* It is a sound effects channel, so flag the voice as non-critical! */
+ sfxinfo[voice-md_sngchn]=0;
+ md_driver->VoiceStop(voice);
+}
+
+MIKMODAPI void Voice_Stop(SBYTE voice)
+{
+ MUTEX_LOCK(vars);
+ Voice_Stop_internal(voice);
+ MUTEX_UNLOCK(vars);
+}
+
+int Voice_Stopped_internal(SBYTE voice)
+{
+ if((voice<0)||(voice>=md_numchn)) return 0;
+ return(md_driver->VoiceStopped(voice));
+}
+
+MIKMODAPI int Voice_Stopped(SBYTE voice)
+{
+ int result;
+
+ MUTEX_LOCK(vars);
+ result=Voice_Stopped_internal(voice);
+ MUTEX_UNLOCK(vars);
+
+ return result;
+}
+
+MIKMODAPI SLONG Voice_GetPosition(SBYTE voice)
+{
+ SLONG result=0;
+
+ MUTEX_LOCK(vars);
+ if((voice>=0)&&(voice<md_numchn)) {
+ if (md_driver->VoiceGetPosition)
+ result=(md_driver->VoiceGetPosition(voice));
+ else
+ result=-1;
+ }
+ MUTEX_UNLOCK(vars);
+
+ return result;
+}
+
+MIKMODAPI ULONG Voice_RealVolume(SBYTE voice)
+{
+ ULONG result=0;
+
+ MUTEX_LOCK(vars);
+ if((voice>=0)&&(voice<md_numchn)&& md_driver->VoiceRealVolume)
+ result=(md_driver->VoiceRealVolume(voice));
+ MUTEX_UNLOCK(vars);
+
+ return result;
+}
+
+extern MikMod_callback_t vc_callback;
+
+MIKMODAPI void VC_SetCallback(MikMod_callback_t callback)
+{
+ vc_callback = callback;
+}
+
+static int _mm_init(CHAR *cmdline)
+{
+ UWORD t;
+
+ _mm_critical = 1;
+
+ /* if md_device==0, try to find a device number */
+ if(!md_device) {
+ cmdline=NULL;
+
+ for(t=1,md_driver=firstdriver;md_driver;md_driver=md_driver->next,t++)
+ if(md_driver->IsPresent()) break;
+
+ if(!md_driver) {
+ _mm_errno = MMERR_DETECTING_DEVICE;
+ if(_mm_errorhandler) _mm_errorhandler();
+ md_driver = &drv_nos;
+ return 1;
+ }
+
+ md_device = t;
+ } else {
+ /* if n>0, use that driver */
+ for(t=1,md_driver=firstdriver;(md_driver)&&(t!=md_device);md_driver=md_driver->next)
+ t++;
+
+ if(!md_driver) {
+ _mm_errno = MMERR_INVALID_DEVICE;
+ if(_mm_errorhandler) _mm_errorhandler();
+ md_driver = &drv_nos;
+ return 1;
+ }
+
+ /* arguments here might be necessary for the presence check to succeed */
+ if(cmdline&&(md_driver->CommandLine))
+ md_driver->CommandLine(cmdline);
+
+ if(!md_driver->IsPresent()) {
+ _mm_errno = MMERR_DETECTING_DEVICE;
+ if(_mm_errorhandler) _mm_errorhandler();
+ md_driver = &drv_nos;
+ return 1;
+ }
+ }
+
+ olddevice = md_device;
+ if(md_driver->Init()) {
+ MikMod_Exit_internal();
+ if(_mm_errorhandler) _mm_errorhandler();
+ return 1;
+ }
+
+ initialized=1;
+ _mm_critical=0;
+
+ return 0;
+}
+
+MIKMODAPI int MikMod_Init(CHAR *cmdline)
+{
+ int result;
+
+ MUTEX_LOCK(vars);
+ MUTEX_LOCK(lists);
+ result=_mm_init(cmdline);
+ MUTEX_UNLOCK(lists);
+ MUTEX_UNLOCK(vars);
+
+ return result;
+}
+
+void MikMod_Exit_internal(void)
+{
+ MikMod_DisableOutput_internal();
+ md_driver->Exit();
+ md_numchn = md_sfxchn = md_sngchn = 0;
+ md_driver = &drv_nos;
+
+ if(sfxinfo) MikMod_free(sfxinfo);
+ if(md_sample) MikMod_free(md_sample);
+ md_sample = NULL;
+ sfxinfo = NULL;
+
+ initialized = 0;
+}
+
+MIKMODAPI void MikMod_Exit(void)
+{
+ MUTEX_LOCK(vars);
+ MUTEX_LOCK(lists);
+ MikMod_Exit_internal();
+ MUTEX_UNLOCK(lists);
+ MUTEX_UNLOCK(vars);
+}
+
+/* Reset the driver using the new global variable settings.
+ If the driver has not been initialized, it will be now. */
+static int _mm_reset(CHAR *cmdline)
+{
+ int wasplaying = 0;
+
+ if(!initialized) return _mm_init(cmdline);
+
+ if (isplaying) {
+ wasplaying = 1;
+ md_driver->PlayStop();
+ }
+
+ if((!md_driver->Reset)||(md_device != olddevice)) {
+ /* md_driver->Reset was NULL, or md_device was changed, so do a full
+ reset of the driver. */
+ md_driver->Exit();
+ if(_mm_init(cmdline)) {
+ MikMod_Exit_internal();
+ if(_mm_errno)
+ if(_mm_errorhandler) _mm_errorhandler();
+ return 1;
+ }
+ } else {
+ if(md_driver->Reset()) {
+ MikMod_Exit_internal();
+ if(_mm_errno)
+ if(_mm_errorhandler) _mm_errorhandler();
+ return 1;
+ }
+ }
+
+ if (wasplaying) md_driver->PlayStart();
+ return 0;
+}
+
+MIKMODAPI int MikMod_Reset(CHAR *cmdline)
+{
+ int result;
+
+ MUTEX_LOCK(vars);
+ MUTEX_LOCK(lists);
+ result=_mm_reset(cmdline);
+ MUTEX_UNLOCK(lists);
+ MUTEX_UNLOCK(vars);
+
+ return result;
+}
+
+/* If either parameter is -1, the current set value will be retained. */
+int MikMod_SetNumVoices_internal(int music, int sfx)
+{
+ int resume = 0;
+ int t, oldchn = 0;
+
+ if((!music)&&(!sfx)) return 1;
+ _mm_critical = 1;
+ if(isplaying) {
+ MikMod_DisableOutput_internal();
+ oldchn = md_numchn;
+ resume = 1;
+ }
+
+ if(sfxinfo) MikMod_free(sfxinfo);
+ if(md_sample) MikMod_free(md_sample);
+ md_sample = NULL;
+ sfxinfo = NULL;
+
+ if(music!=-1) md_sngchn = music;
+ if(sfx!=-1) md_sfxchn = sfx;
+ md_numchn = md_sngchn + md_sfxchn;
+
+ LimitHardVoices(md_driver->HardVoiceLimit);
+ LimitSoftVoices(md_driver->SoftVoiceLimit);
+
+ if(md_driver->SetNumVoices()) {
+ MikMod_Exit_internal();
+ if(_mm_errno)
+ if(_mm_errorhandler!=NULL) _mm_errorhandler();
+ md_numchn = md_softchn = md_hardchn = md_sfxchn = md_sngchn = 0;
+ return 1;
+ }
+
+ if(md_sngchn+md_sfxchn)
+ md_sample=(SAMPLE**)MikMod_calloc(md_sngchn+md_sfxchn,sizeof(SAMPLE*));
+ if(md_sfxchn)
+ sfxinfo = (UBYTE *)MikMod_calloc(md_sfxchn,sizeof(UBYTE));
+
+ /* make sure the player doesn't start with garbage */
+ for(t=oldchn;t<md_numchn;t++) Voice_Stop_internal(t);
+
+ sfxpool = 0;
+ if(resume) MikMod_EnableOutput_internal();
+ _mm_critical = 0;
+
+ return 0;
+}
+
+MIKMODAPI int MikMod_SetNumVoices(int music, int sfx)
+{
+ int result;
+
+ MUTEX_LOCK(vars);
+ result=MikMod_SetNumVoices_internal(music,sfx);
+ MUTEX_UNLOCK(vars);
+
+ return result;
+}
+
+int MikMod_EnableOutput_internal(void)
+{
+ _mm_critical = 1;
+ if(!isplaying) {
+ if(md_driver->PlayStart()) return 1;
+ isplaying = 1;
+ }
+ _mm_critical = 0;
+ return 0;
+}
+
+MIKMODAPI int MikMod_EnableOutput(void)
+{
+ int result;
+
+ MUTEX_LOCK(vars);
+ result=MikMod_EnableOutput_internal();
+ MUTEX_UNLOCK(vars);
+
+ return result;
+}
+
+void MikMod_DisableOutput_internal(void)
+{
+ if(isplaying && md_driver) {
+ isplaying = 0;
+ md_driver->PlayStop();
+ }
+}
+
+MIKMODAPI void MikMod_DisableOutput(void)
+{
+ MUTEX_LOCK(vars);
+ MikMod_DisableOutput_internal();
+ MUTEX_UNLOCK(vars);
+}
+
+int MikMod_Active_internal(void)
+{
+ return isplaying;
+}
+
+MIKMODAPI int MikMod_Active(void)
+{
+ int result;
+
+ MUTEX_LOCK(vars);
+ result=MikMod_Active_internal();
+ MUTEX_UNLOCK(vars);
+
+ return result;
+}
+
+/* Plays a sound effects sample. Picks a voice from the number of voices
+ allocated for use as sound effects (loops through voices, skipping all active
+ criticals).
+
+ Returns the voice that the sound is being played on. */
+SBYTE Sample_Play_internal(SAMPLE *s,ULONG start,UBYTE flags)
+{
+ int orig=sfxpool;/* for cases where all channels are critical */
+ int c;
+
+ if(!md_sfxchn) return -1;
+ if(s->volume>64) s->volume = 64;
+
+ /* check the first location after sfxpool */
+ do {
+ if(sfxinfo[sfxpool]&SFX_CRITICAL) {
+ if(md_driver->VoiceStopped(c=sfxpool+md_sngchn)) {
+ sfxinfo[sfxpool]=flags;
+ Voice_Play_internal(c,s,start);
+ md_driver->VoiceSetVolume(c,s->volume<<2);
+ Voice_SetPanning_internal(c,s->panning);
+ md_driver->VoiceSetFrequency(c,s->speed);
+ sfxpool++;
+ if(sfxpool>=md_sfxchn) sfxpool=0;
+ return c;
+ }
+ } else {
+ sfxinfo[sfxpool]=flags;
+ Voice_Play_internal(c=sfxpool+md_sngchn,s,start);
+ md_driver->VoiceSetVolume(c,s->volume<<2);
+ Voice_SetPanning_internal(c,s->panning);
+ md_driver->VoiceSetFrequency(c,s->speed);
+ sfxpool++;
+ if(sfxpool>=md_sfxchn) sfxpool=0;
+ return c;
+ }
+
+ sfxpool++;
+ if(sfxpool>=md_sfxchn) sfxpool = 0;
+ } while(sfxpool!=orig);
+
+ return -1;
+}
+
+MIKMODAPI SBYTE Sample_Play(SAMPLE *s,ULONG start,UBYTE flags)
+{
+ SBYTE result;
+
+ MUTEX_LOCK(vars);
+ result=Sample_Play_internal(s,start,flags);
+ MUTEX_UNLOCK(vars);
+
+ return result;
+}
+
+MIKMODAPI long MikMod_GetVersion(void)
+{
+ return LIBMIKMOD_VERSION;
+}
+
+/*========== MT-safe stuff */
+
+#ifdef HAVE_PTHREAD
+#define INIT_MUTEX(name) \
+ pthread_mutex_t _mm_mutex_##name=PTHREAD_MUTEX_INITIALIZER
+#elif defined(__OS2__)||defined(__EMX__)
+#define INIT_MUTEX(name) \
+ HMTX _mm_mutex_##name
+#elif defined(WIN32)
+#define INIT_MUTEX(name) \
+ HANDLE _mm_mutex_##name
+#else
+#define INIT_MUTEX(name) \
+ void *_mm_mutex_##name = NULL
+#endif
+
+INIT_MUTEX(vars);
+INIT_MUTEX(lists);
+
+MIKMODAPI int MikMod_InitThreads(void)
+{
+ static int firstcall=1;
+ static int result=0;
+
+ if (firstcall) {
+ firstcall=0;
+#ifdef HAVE_PTHREAD
+ result=1;
+#elif defined(__OS2__)||defined(__EMX__)
+ if(DosCreateMutexSem((PSZ)NULL,&_mm_mutex_lists,0,0) ||
+ DosCreateMutexSem((PSZ)NULL,&_mm_mutex_vars,0,0)) {
+ _mm_mutex_lists=_mm_mutex_vars=(HMTX)NULL;
+ result=0;
+ } else
+ result=1;
+#elif defined(WIN32)
+ if((!(_mm_mutex_lists=CreateMutex(NULL,FALSE,"libmikmod(lists)")))||
+ (!(_mm_mutex_vars=CreateMutex(NULL,FALSE,"libmikmod(vars)"))))
+ result=0;
+ else
+ result=1;
+#endif
+ }
+ return result;
+}
+
+MIKMODAPI void MikMod_Unlock(void)
+{
+ MUTEX_UNLOCK(lists);
+ MUTEX_UNLOCK(vars);
+}
+
+MIKMODAPI void MikMod_Lock(void)
+{
+ MUTEX_LOCK(vars);
+ MUTEX_LOCK(lists);
+}
+
+/*========== Parameter extraction helper */
+
+CHAR *MD_GetAtom(CHAR *atomname,CHAR *cmdline,int implicit)
+{
+ CHAR *ret=NULL;
+
+ if(cmdline) {
+ CHAR *buf=strstr(cmdline,atomname);
+
+ if((buf)&&((buf==cmdline)||(*(buf-1)==','))) {
+ CHAR *ptr=buf+strlen(atomname);
+
+ if(*ptr=='=') {
+ for(buf=++ptr;(*ptr)&&((*ptr)!=',');ptr++);
+ ret=MikMod_malloc((1+ptr-buf)*sizeof(CHAR));
+ if(ret)
+ strncpy(ret,buf,ptr-buf);
+ } else if((*ptr==',')||(!*ptr)) {
+ if(implicit) {
+ ret=MikMod_malloc((1+ptr-buf)*sizeof(CHAR));
+ if(ret)
+ strncpy(ret,buf,ptr-buf);
+ }
+ }
+ }
+ }
+ return ret;
+}
+
+#if 0
+#if defined unix || (defined __APPLE__ && defined __MACH__)
+
+/*========== Posix helper functions */
+
+/* Check if the file is a regular or nonexistant file (or a link to a such a
+ file), and that, should the calling program be setuid, the access rights are
+ reasonable. Returns 1 if it is safe to rewrite the file, 0 otherwise.
+ The goal is to prevent a setuid root libmikmod application from overriding
+ files like /etc/passwd with digital sound... */
+int MD_Access(CHAR *filename)
+{
+ struct stat buf;
+
+ if(!stat(filename,&buf)) {
+ /* not a regular file ? */
+ if(!S_ISREG(buf.st_mode)) return 0;
+ /* more than one hard link to the file ? */
+ if(buf.st_nlink>1) return 0;
+ /* check access rights with the real user and group id */
+ if(getuid()==buf.st_uid) {
+ if(!(buf.st_mode&S_IWUSR)) return 0;
+ } else if(getgid()==buf.st_gid) {
+ if(!(buf.st_mode&S_IWGRP)) return 0;
+ } else
+ if(!(buf.st_mode&S_IWOTH)) return 0;
+ }
+
+ return 1;
+}
+
+/* Drop all root privileges we might have */
+int MD_DropPrivileges(void)
+{
+ if(!geteuid()) {
+ if(getuid()) {
+ /* we are setuid root -> drop setuid to become the real user */
+ if(setuid(getuid())) return 1;
+ } else {
+ /* we are run as root -> drop all and become user 'nobody' */
+ struct passwd *nobody;
+ int uid;
+
+ if(!(nobody=getpwnam("nobody"))) return 1; /* no such user ? */
+ uid=nobody->pw_uid;
+ if (!uid) /* user 'nobody' has root privileges ? weird... */
+ return 1;
+ if (setuid(uid)) return 1;
+ }
+ }
+ return 0;
+}
+
+#endif
+#endif
+/* ex:set ts=4: */
diff --git a/apps/plugins/mikmod/mikmod.c b/apps/plugins/mikmod/mikmod.c
new file mode 100644
index 0000000000..fe1768376e
--- /dev/null
+++ b/apps/plugins/mikmod/mikmod.c
@@ -0,0 +1,943 @@
+#define NO_MMSUPP_DEFINES
+
+#include "plugin.h"
+#include "lib/configfile.h"
+#include "mikmod.h"
+
+
+#undef SYNC
+#ifdef SIMULATOR
+#define SYNC
+#elif NUM_CORES > 1
+#define USETHREADS
+#endif
+
+#define MAX_CHARS LCD_WIDTH/6
+#define MAX_LINES LCD_HEIGHT/8
+#define LINE_LENGTH 80
+
+#define DIR_PREV 1
+#define DIR_NEXT -1
+#define DIR_NONE 0
+
+#define PLUGIN_NEWSONG 10
+
+/* Persistent configuration */
+#define MIKMOD_CONFIGFILE "mikmod.cfg"
+#define MIKMOD_SETTINGS_MINVERSION 1
+#define MIKMOD_SETTINGS_VERSION 1
+
+#ifdef USETHREADS
+#define EV_EXIT 9999
+#define THREAD_STACK_SIZE DEFAULT_STACK_SIZE + 0x200
+static unsigned int thread_id;
+static struct event_queue thread_q;
+/* use long for aligning */
+unsigned long thread_stack[THREAD_STACK_SIZE/sizeof(long)];
+#endif
+
+/* the current full file name */
+static char np_file[MAX_PATH];
+static int curfile = 0, direction = DIR_NEXT, entries = 0;
+
+/* list of the mod files */
+static char **file_pt;
+
+
+/* The MP3 audio buffer which we will use as heap memory */
+static unsigned char* audio_buffer;
+/* amount of bytes left in audio_buffer */
+static size_t audio_buffer_free;
+
+
+/* The rockbox plugin interface */
+MEM_FUNCTION_WRAPPERS;
+
+bool quit;
+int playingtime IBSS_ATTR;
+MODULE *module IBSS_ATTR;
+char gmbuf[BUF_SIZE*NBUF];
+
+
+int textlines;
+int vscroll = 0;
+int hscroll = 0;
+bool screenupdated = false;
+
+enum {
+ DISPLAY_INFO = 0,
+ DISPLAY_SAMPLE,
+ DISPLAY_INST,
+ DISPLAY_COMMENTS,
+} display;
+
+
+/*
+* strncat wrapper
+*/
+char* mmsupp_strncat(char *s1, const char *s2, size_t n)
+{
+ char *s = s1;
+ /* Loop over the data in s1. */
+ while (*s != '\0')
+ s++;
+ /* s now points to s1's trailing null character, now copy
+ up to n bytes from s2 into s1 stopping if a null character
+ is encountered in s2.
+ It is not safe to use strncpy here since it copies EXACTLY n
+ characters, NULL padding if necessary. */
+ while (n != 0 && (*s = *s2++) != '\0')
+ {
+ n--;
+ s++;
+ }
+ if (*s != '\0')
+ *s = '\0';
+ return s1;
+}
+
+/*
+* sprintf wrapper
+*/
+int mmsupp_sprintf(char *buf, const char *fmt, ... )
+{
+ bool ok;
+ va_list ap;
+
+ va_start(ap, fmt);
+ ok = rb->vsnprintf(buf, LINE_LENGTH, fmt, ap);
+ va_end(ap);
+
+ return ok;
+}
+
+/*
+* printf wrapper
+*/
+void mmsupp_printf(const char *fmt, ...)
+{
+ static int p_xtpt = 0;
+ char p_buf[LINE_LENGTH];
+ bool ok;
+ va_list ap;
+
+ va_start(ap, fmt);
+ ok = rb->vsnprintf(p_buf, sizeof(p_buf), fmt, ap);
+ va_end(ap);
+
+ int i=0;
+
+ /* Device LCDs display newlines funny. */
+ for(i=0; p_buf[i]!=0; i++)
+ if(p_buf[i] == '\n')
+ p_buf[i] = ' ';
+
+ rb->lcd_putsxy(1, p_xtpt, (unsigned char *)p_buf);
+ rb->lcd_update();
+
+ p_xtpt += 8;
+ if(p_xtpt > LCD_HEIGHT-8)
+ {
+ p_xtpt = 0;
+ rb->lcd_clear_display();
+ }
+}
+
+
+/************************* File Access ***************************/
+
+/* support function for qsort() */
+static int compare(const void* p1, const void* p2)
+{
+ return rb->strcasecmp(*((char **)p1), *((char **)p2));
+}
+
+bool mod_ext(const char ext[])
+{
+ if(!ext)
+ return false;
+ if(!rb->strcasecmp(ext,".669") ||
+ !rb->strcasecmp(ext,".amf") ||
+ !rb->strcasecmp(ext,".asy") ||
+ !rb->strcasecmp(ext,".dsm") ||
+ !rb->strcasecmp(ext,".far") ||
+ !rb->strcasecmp(ext,".gdm") ||
+ !rb->strcasecmp(ext,".gt2") ||
+ !rb->strcasecmp(ext,".imf") ||
+ !rb->strcasecmp(ext,".it") ||
+ !rb->strcasecmp(ext,".m15") ||
+ !rb->strcasecmp(ext,".med") ||
+ !rb->strcasecmp(ext,".mod") ||
+ !rb->strcasecmp(ext,".mtm") ||
+ !rb->strcasecmp(ext,".okt") ||
+ !rb->strcasecmp(ext,".s3m") ||
+ !rb->strcasecmp(ext,".stm") ||
+ !rb->strcasecmp(ext,".stx") ||
+ !rb->strcasecmp(ext,".ult") ||
+ !rb->strcasecmp(ext,".uni") ||
+ !rb->strcasecmp(ext,".xm") )
+ return true;
+ else
+ return false;
+}
+
+/*Read directory contents for scrolling. */
+void get_mod_list(void)
+{
+ struct tree_context *tree = rb->tree_get_context();
+ struct entry *dircache = tree->dircache;
+ int i;
+ char *pname;
+
+ file_pt = (char **) audio_buffer;
+
+ /* Remove path and leave only the name.*/
+ pname = rb->strrchr(np_file,'/');
+ pname++;
+
+ for (i = 0; i < tree->filesindir && audio_buffer_free > sizeof(char**); i++)
+ {
+ if (!(dircache[i].attr & ATTR_DIRECTORY)
+ && mod_ext(rb->strrchr(dircache[i].name,'.')))
+ {
+ file_pt[entries] = dircache[i].name;
+ /* Set Selected File. */
+ if (!rb->strcmp(file_pt[entries], pname))
+ curfile = entries;
+ entries++;
+
+ audio_buffer += (sizeof(char**));
+ audio_buffer_free -= (sizeof(char**));
+ }
+ }
+}
+
+int change_filename(int direct)
+{
+ bool file_erased = (file_pt[curfile] == NULL);
+ direction = direct;
+
+ curfile += (direct == DIR_PREV? entries - 1: 1);
+ if (curfile >= entries)
+ curfile -= entries;
+
+ if (file_erased)
+ {
+ /* remove 'erased' file names from list. */
+ int count, i;
+ for (count = i = 0; i < entries; i++)
+ {
+ if (curfile == i)
+ curfile = count;
+ if (file_pt[i] != NULL)
+ file_pt[count++] = file_pt[i];
+ }
+ entries = count;
+ }
+
+ if (entries == 0)
+ {
+ rb->splash(HZ, "No supported files");
+ return PLUGIN_ERROR;
+ }
+
+ rb->strcpy(rb->strrchr(np_file, '/')+1, file_pt[curfile]);
+
+ return PLUGIN_NEWSONG;
+}
+
+/*****************************************************************************
+* Playback
+*/
+
+bool swap = false;
+bool lastswap = true;
+
+static inline void synthbuf(void)
+{
+ char *outptr;
+
+#ifndef SYNC
+ if (lastswap == swap) return;
+ lastswap = swap;
+
+ outptr = (swap ? gmbuf : gmbuf + BUF_SIZE);
+#else
+ outptr = gmbuf;
+#endif
+
+ VC_WriteBytes(outptr, BUF_SIZE);
+}
+
+void get_more(unsigned char** start, size_t* size)
+{
+#ifndef SYNC
+ if (lastswap != swap)
+ {
+ //printf("Buffer miss!");
+ }
+
+#else
+ synthbuf();
+#endif
+
+ *size = BUF_SIZE;
+#ifndef SYNC
+ *start = (unsigned char*)((swap ? gmbuf : gmbuf + BUF_SIZE));
+ swap = !swap;
+#else
+ *start = (unsigned char*)(gmbuf);
+#endif
+}
+
+void showinfo()
+{
+ char statustext[LINE_LENGTH];
+
+ if (!module)
+ {
+ return;
+ }
+
+ rb->lcd_clear_display();
+
+ playingtime = (int)(module->sngtime >> 10);
+ sprintf(statustext, "Name: %s", module->songname);
+ rb->lcd_putsxy(1, 1, statustext);
+ sprintf(statustext, "Type: %s", module->modtype);
+ rb->lcd_putsxy(1, 11, statustext);
+
+ sprintf(statustext, "Samples: %d", module->numsmp);
+ rb->lcd_putsxy(1, 21, statustext);
+
+ if ( module->flags & UF_INST )
+ {
+ sprintf(statustext, "Instruments: %d", module->numins);
+ rb->lcd_putsxy(1, 31, statustext);
+ }
+
+ sprintf(statustext, "pat: %03d/%03d %2.2X",
+ module->sngpos, module->numpos - 1, module->patpos);
+ rb->lcd_putsxy(1, 51, statustext);
+
+ sprintf(statustext, "spd: %d/%d",
+ module->sngspd, module->bpm);
+ rb->lcd_putsxy(1, 61, statustext);
+
+ sprintf(statustext, "vol: %ddB", rb->global_settings->volume);
+ rb->lcd_putsxy(1, 71, statustext);
+
+ sprintf(statustext, "time: %d:%02d",
+ (playingtime / 60) % 60, playingtime % 60);
+ rb->lcd_putsxy(1, 81, statustext);
+
+ if (module->flags & UF_NNA)
+ {
+ sprintf(statustext, "chn: %d/%d+%d->%d",
+ module->realchn, module->numchn,
+ module->totalchn - module->realchn,
+ module->totalchn);
+ }
+ else
+ {
+ sprintf(statustext, "chn: %d/%d",
+ module->realchn, module->numchn);
+ }
+ rb->lcd_putsxy(0, 91, statustext);
+
+ rb->lcd_update();
+}
+
+void showsamples()
+{
+ int i, j;
+ char statustext[LINE_LENGTH];
+
+ if ( screenupdated )
+ {
+ return;
+ }
+ rb->lcd_clear_display();
+ for( i=0; i<MAX_LINES && i+vscroll<module->numsmp; i++ )
+ {
+ sprintf(statustext, "%02d %s", i+vscroll+1, module->samples[i+vscroll].samplename);
+ rb->lcd_putsxy(1, 1+(8*i), statustext);
+ }
+ rb->lcd_update();
+ screenupdated = true;
+}
+
+void showinstruments()
+{
+ int i, j;
+ char statustext[LINE_LENGTH];
+
+ if ( screenupdated )
+ {
+ return;
+ }
+ rb->lcd_clear_display();
+ for( i=0; i<MAX_LINES && i+vscroll<module->numins; i++ )
+ {
+ sprintf(statustext, "%02d %s", i+vscroll+1, module->instruments[i+vscroll].insname);
+ rb->lcd_putsxy(1, 1+(8*i), statustext);
+ }
+ rb->lcd_update();
+ screenupdated = true;
+}
+
+void showcomments()
+{
+ int i, j=0, k=0, l;
+ char statustext[LINE_LENGTH];
+
+ if ( screenupdated )
+ {
+ return;
+ }
+ rb->lcd_clear_display();
+
+ for(i=0; module->comment[i]!='\0'; i++)
+ {
+ if(module->comment[i] != '\n')
+ {
+ statustext[j] = module->comment[i];
+ j++;
+ }
+
+ if(module->comment[i] == '\n' || j>LINE_LENGTH-1)
+ {
+ rb->lcd_putsxy(1-(6*hscroll), 1+(8*k)-(8*vscroll), statustext);
+ for( l=0; l<LINE_LENGTH; l++ )
+ {
+ statustext[l] = 0;
+ }
+ k++;
+ j=0;
+ }
+ }
+ if (j>0)
+ {
+ rb->lcd_putsxy(1-(6*hscroll), 1+(8*k)-(8*vscroll), statustext);
+ }
+
+ rb->lcd_update();
+ screenupdated = true;
+}
+
+int changedisplay()
+{
+ display = (display+1) % 4;
+
+ if (display == DISPLAY_SAMPLE)
+ {
+ textlines = module->numsmp;
+ }
+
+ if (display == DISPLAY_INST)
+ {
+ if ( module->flags & UF_INST )
+ {
+ textlines = module->numins;
+ }
+ else
+ {
+ display = DISPLAY_COMMENTS;
+ }
+ }
+
+ if (display == DISPLAY_COMMENTS)
+ {
+ if (module->comment)
+ {
+ textlines = 100;
+ }
+ else
+ {
+ display = DISPLAY_INFO;
+ }
+ }
+ screenupdated = false;
+ vscroll = 0;
+ hscroll = 0;
+}
+
+struct mikmod_settings
+{
+ int pansep;
+ int reverb;
+ bool interp;
+ bool reverse;
+ bool surround;
+ bool boost;
+};
+
+static struct mikmod_settings settings =
+{
+ 128,
+ 0,
+ 0,
+ 0,
+ 1,
+ 1
+};
+
+static struct mikmod_settings old_settings;
+
+static struct configdata config[] =
+{
+ { TYPE_INT, 0, 128, { .int_p = &settings.pansep }, "Panning Separation", NULL},
+ { TYPE_INT, 0, 15, { .int_p = &settings.reverb }, "Reverberation", NULL},
+ { TYPE_BOOL, 0, 1, { .bool_p = &settings.interp }, "Interpolation", NULL},
+ { TYPE_BOOL, 0, 1, { .bool_p = &settings.reverse }, "Reverse Channels", NULL},
+ { TYPE_BOOL, 0, 1, { .bool_p = &settings.surround }, "Surround", NULL},
+ { TYPE_BOOL, 0, 1, { .bool_p = &settings.boost }, "CPU Boost", NULL},
+};
+
+void applysettings()
+{
+ md_pansep = settings.pansep;
+ md_reverb = settings.reverb;
+ md_mode = DMODE_STEREO | DMODE_16BITS | DMODE_SOFT_MUSIC | DMODE_SOFT_SNDFX;
+ if ( settings.interp )
+ {
+ md_mode |= DMODE_INTERP;
+ }
+ if ( settings.reverse )
+ {
+ md_mode |= DMODE_REVERSE;
+ }
+ if ( settings.surround )
+ {
+ md_mode |= DMODE_SURROUND;
+ }
+#ifdef HAVE_ADJUSTABLE_CPU_FREQ
+ if ( Player_Active() )
+ {
+ rb->cpu_boost(settings.boost);
+ }
+#endif
+}
+
+/**
+ Shows the settings menu
+ */
+int settings_menu(void)
+{
+ int selection = 0;
+ bool old_val;
+
+ MENUITEM_STRINGLIST(settings_menu, "Mikmod Settings", NULL, "Panning Separation",
+ "Reverberation", "Interpolation", "Reverse Channels", "Surround",
+#ifdef HAVE_ADJUSTABLE_CPU_FREQ
+ "CPU Boost"
+#endif
+ );
+
+ do
+ {
+ selection=rb->do_menu(&settings_menu,&selection, NULL, false);
+ switch(selection)
+ {
+ case 0:
+ rb->set_int("Panning Separation", "", 1,
+ &(settings.pansep),
+ NULL, 8, 0, 128, NULL );
+ applysettings();
+ break;
+
+ case 1:
+ rb->set_int("Reverberation", "", 1,
+ &(settings.reverb),
+ NULL, 1, 0, 15, NULL );
+ applysettings();
+ break;
+
+ case 2:
+ rb->set_bool("Interpolation", &(settings.interp));
+ applysettings();
+ break;
+
+ case 3:
+ rb->set_bool("Reverse Channels", &(settings.reverse));
+ applysettings();
+ break;
+
+ case 4:
+ rb->set_bool("Surround", &(settings.surround));
+ applysettings();
+ break;
+
+ case 5:
+ rb->set_bool("CPU Boost", &(settings.boost));
+ applysettings();
+ break;
+
+ case MENU_ATTACHED_USB:
+ return PLUGIN_USB_CONNECTED;
+ }
+ } while ( selection >= 0 );
+ return 0;
+}
+
+/**
+ Show the main menu
+ */
+int main_menu(void)
+{
+ int selection = 0;
+ int result;
+
+ MENUITEM_STRINGLIST(main_menu,"Mikmod Main Menu",NULL,
+ "Settings", "Return", "Quit");
+ while (1)
+ {
+ switch (rb->do_menu(&main_menu,&selection, NULL, false))
+ {
+ case 0:
+ result = settings_menu();
+ if ( result != 0 ) return result;
+ break;
+
+ case 1:
+ return 0;
+
+ case 2:
+ return -1;
+
+ case MENU_ATTACHED_USB:
+ return PLUGIN_USB_CONNECTED;
+
+ default:
+ return 0;
+ }
+ }
+}
+
+#ifdef USETHREADS
+/* double buffering thread */
+void thread(void)
+{
+ struct queue_event ev;
+
+ while (1)
+ {
+ synthbuf();
+ rb->queue_wait_w_tmo(&thread_q, &ev, HZ/20);
+ switch (ev.id) {
+ case EV_EXIT:
+ return;
+ }
+ }
+}
+#endif
+
+void mm_errorhandler(void)
+{
+ rb->splashf(HZ, "%s", MikMod_strerror(MikMod_errno));
+ quit = true;
+}
+
+int playfile(char* filename)
+{
+ int vol = 0;
+ int button;
+ int retval = PLUGIN_OK;
+ bool changingpos = false;
+ int menureturn;
+
+ playingtime = 0;
+
+ rb->splashf(HZ, "Loading %s", filename);
+
+ module = Player_Load(filename, 64, 0);
+
+ if (!module)
+ {
+ rb->splashf(HZ, "%s", MikMod_strerror(MikMod_errno));
+ retval = PLUGIN_ERROR;
+ quit = true;
+ }
+ else
+ {
+ display = DISPLAY_INFO;
+ Player_Start(module);
+ rb->pcm_play_data(&get_more, NULL, 0);
+ }
+
+#ifdef HAVE_ADJUSTABLE_CPU_FREQ
+ if ( settings.boost )
+ rb->cpu_boost(true);
+#endif
+#ifdef USETHREADS
+ rb->queue_init(&thread_q, true);
+ if ((thread_id = rb->create_thread(thread, thread_stack,
+ sizeof(thread_stack), 0, "render buffering thread"
+ IF_PRIO(, PRIORITY_PLAYBACK)
+ IF_COP(, CPU))) == 0)
+ {
+ rb->splash(HZ, "Cannot create thread!");
+ return PLUGIN_ERROR;
+ }
+#endif
+
+ while (!quit && Player_Active() && retval == PLUGIN_OK)
+ {
+#if !defined(SYNC) && !defined(USETHREADS)
+ synthbuf();
+#endif
+ switch (display)
+ {
+ case DISPLAY_SAMPLE:
+ showsamples();
+ break;
+ case DISPLAY_INST:
+ showinstruments();
+ break;
+ case DISPLAY_COMMENTS:
+ showcomments();
+ break;
+ default:
+ showinfo();
+ }
+
+ rb->yield();
+
+ /* Prevent idle poweroff */
+ rb->reset_poweroff_timer();
+
+ button = rb->get_action(CONTEXT_WPS, TIMEOUT_NOBLOCK);
+ switch (button)
+ {
+ case ACTION_WPS_VOLUP:
+ if ( display != DISPLAY_INFO )
+ {
+ if ( textlines-vscroll >= MAX_LINES )
+ {
+ vscroll++;
+ screenupdated = false;
+ }
+ break;
+ }
+ vol = rb->global_settings->volume;
+ if (vol < rb->sound_max(SOUND_VOLUME))
+ {
+ vol++;
+ rb->sound_set(SOUND_VOLUME, vol);
+ rb->global_settings->volume = vol;
+ }
+ break;
+
+ case ACTION_WPS_VOLDOWN:
+ if ( display != DISPLAY_INFO )
+ {
+ if ( vscroll > 0 )
+ {
+ vscroll--;
+ screenupdated = false;
+ }
+ break;
+ }
+ vol = rb->global_settings->volume;
+ if (vol > rb->sound_min(SOUND_VOLUME))
+ {
+ vol--;
+ rb->sound_set(SOUND_VOLUME, vol);
+ rb->global_settings->volume = vol;
+ }
+ break;
+
+ case ACTION_WPS_SKIPPREV:
+ if(entries>1 && !changingpos)
+ {
+ if ((int)(module->sngtime >> 10) > 2)
+ {
+ Player_SetPosition(0);
+ module->sngtime = 0;
+ }
+ else {
+ retval = change_filename(DIR_PREV);
+ }
+ }
+ else
+ {
+ changingpos = false;
+ }
+ break;
+ case ACTION_WPS_SEEKBACK:
+ if ( display != DISPLAY_INFO )
+ {
+ if ( hscroll > 0 )
+ {
+ hscroll--;
+ screenupdated = false;
+ }
+ break;
+ }
+ Player_PrevPosition();
+ changingpos = true;
+ break;
+
+ case ACTION_WPS_SKIPNEXT:
+ if(entries>1 && !changingpos)
+ {
+ retval = change_filename(DIR_NEXT);
+ }
+ else
+ {
+ changingpos = false;
+ }
+ break;
+ case ACTION_WPS_SEEKFWD:
+ if ( display != DISPLAY_INFO )
+ {
+ hscroll++;
+ screenupdated = false;
+ break;
+ }
+ Player_NextPosition();
+ changingpos = true;
+ break;
+
+ case ACTION_WPS_PLAY:
+ if(!Player_Paused())
+ {
+ rb->pcm_play_stop();
+ }
+ else
+ {
+ rb->pcm_play_data(&get_more, NULL, 0);
+ }
+ Player_TogglePause();
+ break;
+
+ case ACTION_WPS_BROWSE:
+ changedisplay();
+ break;
+
+ case ACTION_WPS_MENU:
+ menureturn = main_menu();
+ if ( menureturn != 0 )
+ {
+ quit = true;
+ if ( menureturn == PLUGIN_USB_CONNECTED )
+ {
+ retval = menureturn;
+ }
+ }
+ rb->lcd_setfont(0);
+ screenupdated = false;
+ break;
+
+ case ACTION_WPS_STOP:
+ quit = true;
+ break;
+
+ default:
+ if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
+ {
+ quit = true;
+ retval = PLUGIN_USB_CONNECTED;
+ }
+ }
+ }
+
+#ifdef USETHREADS
+ rb->queue_post(&thread_q, EV_EXIT, 0);
+ rb->thread_wait(thread_id);
+ rb->queue_delete(&thread_q);
+#endif
+#ifdef HAVE_ADJUSTABLE_CPU_FREQ
+ if ( settings.boost )
+ rb->cpu_boost(false);
+#endif
+
+ Player_Stop();
+ Player_Free(module);
+
+ memset(gmbuf, '\0', sizeof(gmbuf));
+
+ if ( retval == PLUGIN_OK && entries > 1 && !quit )
+ {
+ retval = change_filename(DIR_NEXT);
+ }
+
+ return retval;
+}
+
+/*
+* Plugin entry point
+*
+*/
+enum plugin_status plugin_start(const void* parameter)
+{
+ enum plugin_status retval;
+
+ if (parameter == NULL)
+ {
+ rb->splash(HZ*2, " Play .mod, .it, .s3m, .xm file ");
+ return PLUGIN_OK;
+ }
+
+ rb->lcd_setfont(0);
+
+ rb->pcm_play_stop();
+#if INPUT_SRC_CAPS != 0
+ /* Select playback */
+ rb->audio_set_input_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK);
+ rb->audio_set_output_source(AUDIO_SRC_PLAYBACK);
+#endif
+ rb->pcm_set_frequency(SAMPLE_RATE);
+
+ audio_buffer = rb->plugin_get_audio_buffer((size_t *)&audio_buffer_free);
+
+ rb->strcpy(np_file, parameter);
+ get_mod_list();
+ if(!entries) {
+ return PLUGIN_ERROR;
+ }
+
+ //add_pool(audio_buffer, audio_buffer_free);
+ init_memory_pool(audio_buffer_free, audio_buffer);
+
+ MikMod_RegisterDriver(&drv_nos);
+ MikMod_RegisterAllLoaders();
+ MikMod_RegisterErrorHandler(mm_errorhandler);
+
+ md_mixfreq = SAMPLE_RATE;
+
+ configfile_load(MIKMOD_CONFIGFILE, config,
+ ARRAYLEN(config), MIKMOD_SETTINGS_MINVERSION);
+ rb->memcpy(&old_settings, &settings, sizeof (settings));
+ applysettings();
+
+ if (MikMod_Init(""))
+ {
+ rb->splashf(HZ, "%s", MikMod_strerror(MikMod_errno));
+ return PLUGIN_ERROR;
+ }
+
+ do
+ {
+ retval = playfile(np_file);
+ } while (retval == PLUGIN_NEWSONG);
+
+ MikMod_Exit();
+
+ rb->pcm_play_stop();
+ rb->pcm_set_frequency(HW_SAMPR_DEFAULT);
+
+ if (retval == PLUGIN_OK)
+ {
+ rb->splash(0, "Saving Settings");
+ if (rb->memcmp(&settings, &old_settings, sizeof (settings)))
+ {
+ configfile_save(MIKMOD_CONFIGFILE, config,
+ ARRAYLEN(config), MIKMOD_SETTINGS_MINVERSION);
+ }
+ }
+
+ destroy_memory_pool(audio_buffer);
+
+ return retval;
+}
diff --git a/apps/plugins/mikmod/mikmod.h b/apps/plugins/mikmod/mikmod.h
new file mode 100644
index 0000000000..a1c201f6d2
--- /dev/null
+++ b/apps/plugins/mikmod/mikmod.h
@@ -0,0 +1,783 @@
+/* MikMod sound library
+ (c) 1998, 1999, 2000 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: mikmod.h.in,v 1.3 2005/03/30 19:09:21 realtech Exp $
+
+ MikMod sound library include file
+
+==============================================================================*/
+
+#ifndef _MIKMOD_H_
+#define _MIKMOD_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "mikmod_supp.h"
+
+/*
+ * ========== Compiler magic for shared libraries
+ */
+
+#if defined WIN32 && defined _DLL
+#ifdef DLL_EXPORTS
+#define MIKMODAPI __declspec(dllexport)
+#else
+#define MIKMODAPI __declspec(dllimport)
+#endif
+#else
+#define MIKMODAPI
+#endif
+
+/*
+ * ========== Library version
+ */
+
+#define LIBMIKMOD_VERSION_MAJOR 3L
+#define LIBMIKMOD_VERSION_MINOR 2L
+#define LIBMIKMOD_REVISION 0L
+
+#define LIBMIKMOD_VERSION \
+ ((LIBMIKMOD_VERSION_MAJOR<<16)| \
+ (LIBMIKMOD_VERSION_MINOR<< 8)| \
+ (LIBMIKMOD_REVISION))
+
+MIKMODAPI extern long MikMod_GetVersion(void);
+
+/*
+ * ========== Platform independent-type definitions
+ */
+#if 0
+#ifdef WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <io.h>
+#include <mmsystem.h>
+#endif
+
+#if defined(__OS2__)||defined(__EMX__)
+#define INCL_DOSSEMAPHORES
+#include <os2.h>
+#else
+typedef char CHAR;
+#endif
+#endif
+
+typedef char CHAR;
+
+
+#if defined(__arch64__) || defined(__alpha) || defined(__x86_64) || defined(__powerpc64__)
+/* 64 bit architectures */
+
+typedef signed char SBYTE; /* 1 byte, signed */
+typedef unsigned char UBYTE; /* 1 byte, unsigned */
+typedef signed short SWORD; /* 2 bytes, signed */
+typedef unsigned short UWORD; /* 2 bytes, unsigned */
+typedef signed int SLONG; /* 4 bytes, signed */
+typedef unsigned int ULONG; /* 4 bytes, unsigned */
+//typedef int BOOL; /* 0=false, <>0 true */
+
+#else
+/* 32 bit architectures */
+
+typedef signed char SBYTE; /* 1 byte, signed */
+typedef unsigned char UBYTE; /* 1 byte, unsigned */
+typedef signed short SWORD; /* 2 bytes, signed */
+typedef unsigned short UWORD; /* 2 bytes, unsigned */
+typedef signed long SLONG; /* 4 bytes, signed */
+#if !defined(__OS2__)&&!defined(__EMX__)&&!defined(WIN32)
+typedef unsigned long ULONG; /* 4 bytes, unsigned */
+//typedef int BOOL; /* 0=false, <>0 true */
+#endif
+#endif
+
+/*
+ * ========== Error codes
+ */
+
+enum {
+ MMERR_OPENING_FILE = 1,
+ MMERR_OUT_OF_MEMORY,
+ MMERR_DYNAMIC_LINKING,
+
+ MMERR_SAMPLE_TOO_BIG,
+ MMERR_OUT_OF_HANDLES,
+ MMERR_UNKNOWN_WAVE_TYPE,
+
+ MMERR_LOADING_PATTERN,
+ MMERR_LOADING_TRACK,
+ MMERR_LOADING_HEADER,
+ MMERR_LOADING_SAMPLEINFO,
+ MMERR_NOT_A_MODULE,
+ MMERR_NOT_A_STREAM,
+ MMERR_MED_SYNTHSAMPLES,
+ MMERR_ITPACK_INVALID_DATA,
+
+ MMERR_DETECTING_DEVICE,
+ MMERR_INVALID_DEVICE,
+ MMERR_INITIALIZING_MIXER,
+ MMERR_OPENING_AUDIO,
+ MMERR_8BIT_ONLY,
+ MMERR_16BIT_ONLY,
+ MMERR_STEREO_ONLY,
+ MMERR_ULAW,
+ MMERR_NON_BLOCK,
+
+ MMERR_AF_AUDIO_PORT,
+
+ MMERR_AIX_CONFIG_INIT,
+ MMERR_AIX_CONFIG_CONTROL,
+ MMERR_AIX_CONFIG_START,
+
+ MMERR_GUS_SETTINGS,
+ MMERR_GUS_RESET,
+ MMERR_GUS_TIMER,
+
+ MMERR_HP_SETSAMPLESIZE,
+ MMERR_HP_SETSPEED,
+ MMERR_HP_CHANNELS,
+ MMERR_HP_AUDIO_OUTPUT,
+ MMERR_HP_AUDIO_DESC,
+ MMERR_HP_BUFFERSIZE,
+
+ MMERR_OSS_SETFRAGMENT,
+ MMERR_OSS_SETSAMPLESIZE,
+ MMERR_OSS_SETSTEREO,
+ MMERR_OSS_SETSPEED,
+
+ MMERR_SGI_SPEED,
+ MMERR_SGI_16BIT,
+ MMERR_SGI_8BIT,
+ MMERR_SGI_STEREO,
+ MMERR_SGI_MONO,
+
+ MMERR_SUN_INIT,
+
+ MMERR_OS2_MIXSETUP,
+ MMERR_OS2_SEMAPHORE,
+ MMERR_OS2_TIMER,
+ MMERR_OS2_THREAD,
+
+ MMERR_DS_PRIORITY,
+ MMERR_DS_BUFFER,
+ MMERR_DS_FORMAT,
+ MMERR_DS_NOTIFY,
+ MMERR_DS_EVENT,
+ MMERR_DS_THREAD,
+ MMERR_DS_UPDATE,
+
+ MMERR_WINMM_HANDLE,
+ MMERR_WINMM_ALLOCATED,
+ MMERR_WINMM_DEVICEID,
+ MMERR_WINMM_FORMAT,
+ MMERR_WINMM_UNKNOWN,
+
+ MMERR_MAC_SPEED,
+ MMERR_MAC_START,
+
+ MMERR_OSX_UNKNOWN_DEVICE,
+ MMERR_OSX_BAD_PROPERTY,
+ MMERR_OSX_UNSUPPORTED_FORMAT,
+ MMERR_OSX_SET_STEREO,
+ MMERR_OSX_BUFFER_ALLOC,
+ MMERR_OSX_ADD_IO_PROC,
+ MMERR_OSX_DEVICE_START,
+ MMERR_OSX_PTHREAD,
+
+ MMERR_DOSWSS_STARTDMA,
+ MMERR_DOSSB_STARTDMA,
+
+ MMERR_MAX
+};
+
+/*
+ * ========== Error handling
+ */
+
+typedef void (MikMod_handler)(void);
+typedef MikMod_handler *MikMod_handler_t;
+
+MIKMODAPI extern int MikMod_errno;
+MIKMODAPI extern int MikMod_critical;
+MIKMODAPI extern char *MikMod_strerror(int);
+
+MIKMODAPI extern MikMod_handler_t MikMod_RegisterErrorHandler(MikMod_handler_t);
+
+/*
+ * ========== Library initialization and core functions
+ */
+
+struct MDRIVER;
+
+MIKMODAPI extern void MikMod_RegisterAllDrivers(void);
+
+MIKMODAPI extern CHAR* MikMod_InfoDriver(void);
+MIKMODAPI extern void MikMod_RegisterDriver(struct MDRIVER*);
+MIKMODAPI extern int MikMod_DriverFromAlias(CHAR*);
+MIKMODAPI extern struct MDRIVER *MikMod_DriverByOrdinal(int);
+
+MIKMODAPI extern int MikMod_Init(CHAR*);
+MIKMODAPI extern void MikMod_Exit(void);
+MIKMODAPI extern int MikMod_Reset(CHAR*);
+MIKMODAPI extern int MikMod_SetNumVoices(int,int);
+MIKMODAPI extern int MikMod_Active(void);
+MIKMODAPI extern int MikMod_EnableOutput(void);
+MIKMODAPI extern void MikMod_DisableOutput(void);
+MIKMODAPI extern void MikMod_Update(void);
+
+MIKMODAPI extern int MikMod_InitThreads(void);
+MIKMODAPI extern void MikMod_Lock(void);
+MIKMODAPI extern void MikMod_Unlock(void);
+
+MIKMODAPI extern void* MikMod_malloc(size_t);
+MIKMODAPI extern void* MikMod_realloc(void *, size_t);
+MIKMODAPI extern void* MikMod_calloc(size_t,size_t);
+MIKMODAPI extern void MikMod_free(void*);
+
+/*
+ * ========== Reader, Writer
+ */
+
+typedef struct MREADER {
+ int (*Seek)(struct MREADER*,long,int);
+ long (*Tell)(struct MREADER*);
+ int (*Read)(struct MREADER*,void*,size_t);
+ int (*Get)(struct MREADER*);
+ int (*Eof)(struct MREADER*);
+ long iobase;
+ long prev_iobase;
+} MREADER;
+
+typedef struct MWRITER {
+ int (*Seek)(struct MWRITER*,long,int);
+ long (*Tell)(struct MWRITER*);
+ int (*Write)(struct MWRITER*,void*,size_t);
+ int (*Put)(struct MWRITER*,int);
+} MWRITER;
+
+/*
+ * ========== Samples
+ */
+
+/* Sample playback should not be interrupted */
+#define SFX_CRITICAL 1
+
+/* Sample format [loading and in-memory] flags: */
+#define SF_16BITS 0x0001
+#define SF_STEREO 0x0002
+#define SF_SIGNED 0x0004
+#define SF_BIG_ENDIAN 0x0008
+#define SF_DELTA 0x0010
+#define SF_ITPACKED 0x0020
+
+#define SF_FORMATMASK 0x003F
+
+/* General Playback flags */
+
+#define SF_LOOP 0x0100
+#define SF_BIDI 0x0200
+#define SF_REVERSE 0x0400
+#define SF_SUSTAIN 0x0800
+
+#define SF_PLAYBACKMASK 0x0C00
+
+/* Module-only Playback Flags */
+
+#define SF_OWNPAN 0x1000
+#define SF_UST_LOOP 0x2000
+
+#define SF_EXTRAPLAYBACKMASK 0x3000
+
+/* Panning constants */
+#define PAN_LEFT 0
+#define PAN_HALFLEFT 64
+#define PAN_CENTER 128
+#define PAN_HALFRIGHT 192
+#define PAN_RIGHT 255
+#define PAN_SURROUND 512 /* panning value for Dolby Surround */
+
+typedef struct SAMPLE {
+ SWORD panning; /* panning (0-255 or PAN_SURROUND) */
+ ULONG speed; /* Base playing speed/frequency of note */
+ UBYTE volume; /* volume 0-64 */
+ UWORD inflags; /* sample format on disk */
+ UWORD flags; /* sample format in memory */
+ ULONG length; /* length of sample (in samples!) */
+ ULONG loopstart; /* repeat position (relative to start, in samples) */
+ ULONG loopend; /* repeat end */
+ ULONG susbegin; /* sustain loop begin (in samples) \ Not Supported */
+ ULONG susend; /* sustain loop end / Yet! */
+
+ /* Variables used by the module player only! (ignored for sound effects) */
+ UBYTE globvol; /* global volume */
+ UBYTE vibflags; /* autovibrato flag stuffs */
+ UBYTE vibtype; /* Vibratos moved from INSTRUMENT to SAMPLE */
+ UBYTE vibsweep;
+ UBYTE vibdepth;
+ UBYTE vibrate;
+ CHAR* samplename; /* name of the sample */
+
+ /* Values used internally only */
+ UWORD avibpos; /* autovibrato pos [player use] */
+ UBYTE divfactor; /* for sample scaling, maintains proper period slides */
+ ULONG seekpos; /* seek position in file */
+ SWORD handle; /* sample handle used by individual drivers */
+ void (*onfree)(void *ctx); /* called from Sample_Free if not NULL */
+ void *ctx; /* context passed to previous function*/
+} SAMPLE;
+
+/* Sample functions */
+
+MIKMODAPI extern SAMPLE *Sample_LoadRaw(CHAR *,ULONG rate, ULONG channel, ULONG flags);
+MIKMODAPI extern SAMPLE *Sample_LoadRawFP(int fp,ULONG rate,ULONG channel, ULONG flags);
+MIKMODAPI extern SAMPLE *Sample_LoadRawMem(const char *buf, int len, ULONG rate, ULONG channel, ULONG flags);
+MIKMODAPI extern SAMPLE *Sample_LoadRawGeneric(MREADER*reader,ULONG rate, ULONG channel, ULONG flags);
+
+MIKMODAPI extern SAMPLE *Sample_Load(CHAR*);
+MIKMODAPI extern SAMPLE *Sample_LoadFP(int);
+MIKMODAPI extern SAMPLE *Sample_LoadMem(const char *buf, int len);
+MIKMODAPI extern SAMPLE *Sample_LoadGeneric(MREADER*);
+MIKMODAPI extern void Sample_Free(SAMPLE*);
+MIKMODAPI extern SBYTE Sample_Play(SAMPLE*,ULONG,UBYTE);
+
+MIKMODAPI extern void Voice_SetVolume(SBYTE,UWORD);
+MIKMODAPI extern UWORD Voice_GetVolume(SBYTE);
+MIKMODAPI extern void Voice_SetFrequency(SBYTE,ULONG);
+MIKMODAPI extern ULONG Voice_GetFrequency(SBYTE);
+MIKMODAPI extern void Voice_SetPanning(SBYTE,ULONG);
+MIKMODAPI extern ULONG Voice_GetPanning(SBYTE);
+MIKMODAPI extern void Voice_Play(SBYTE,SAMPLE*,ULONG);
+MIKMODAPI extern void Voice_Stop(SBYTE);
+MIKMODAPI extern int Voice_Stopped(SBYTE);
+MIKMODAPI extern SLONG Voice_GetPosition(SBYTE);
+MIKMODAPI extern ULONG Voice_RealVolume(SBYTE);
+
+/*
+ * ========== Internal module representation (UniMod)
+ */
+
+/*
+ Instrument definition - for information only, the only field which may be
+ of use in user programs is the name field
+*/
+
+/* Instrument note count */
+#define INSTNOTES 120
+
+/* Envelope point */
+typedef struct ENVPT {
+ SWORD pos;
+ SWORD val;
+} ENVPT;
+
+/* Envelope point count */
+#define ENVPOINTS 32
+
+/* Instrument structure */
+typedef struct INSTRUMENT {
+ CHAR* insname;
+
+ UBYTE flags;
+ UWORD samplenumber[INSTNOTES];
+ UBYTE samplenote[INSTNOTES];
+
+ UBYTE nnatype;
+ UBYTE dca; /* duplicate check action */
+ UBYTE dct; /* duplicate check type */
+ UBYTE globvol;
+ UWORD volfade;
+ SWORD panning; /* instrument-based panning var */
+
+ UBYTE pitpansep; /* pitch pan separation (0 to 255) */
+ UBYTE pitpancenter; /* pitch pan center (0 to 119) */
+ UBYTE rvolvar; /* random volume varations (0 - 100%) */
+ UBYTE rpanvar; /* random panning varations (0 - 100%) */
+
+ /* volume envelope */
+ UBYTE volflg; /* bit 0: on 1: sustain 2: loop */
+ UBYTE volpts;
+ UBYTE volsusbeg;
+ UBYTE volsusend;
+ UBYTE volbeg;
+ UBYTE volend;
+ ENVPT volenv[ENVPOINTS];
+ /* panning envelope */
+ UBYTE panflg; /* bit 0: on 1: sustain 2: loop */
+ UBYTE panpts;
+ UBYTE pansusbeg;
+ UBYTE pansusend;
+ UBYTE panbeg;
+ UBYTE panend;
+ ENVPT panenv[ENVPOINTS];
+ /* pitch envelope */
+ UBYTE pitflg; /* bit 0: on 1: sustain 2: loop */
+ UBYTE pitpts;
+ UBYTE pitsusbeg;
+ UBYTE pitsusend;
+ UBYTE pitbeg;
+ UBYTE pitend;
+ ENVPT pitenv[ENVPOINTS];
+} INSTRUMENT;
+
+struct MP_CONTROL;
+struct MP_VOICE;
+
+/*
+ Module definition
+*/
+
+/* maximum master channels supported */
+#define UF_MAXCHAN 64
+
+/* Module flags */
+#define UF_XMPERIODS 0x0001 /* XM periods / finetuning */
+#define UF_LINEAR 0x0002 /* LINEAR periods (UF_XMPERIODS must be set) */
+#define UF_INST 0x0004 /* Instruments are used */
+#define UF_NNA 0x0008 /* IT: NNA used, set numvoices rather
+ than numchn */
+#define UF_S3MSLIDES 0x0010 /* uses old S3M volume slides */
+#define UF_BGSLIDES 0x0020 /* continue volume slides in the background */
+#define UF_HIGHBPM 0x0040 /* MED: can use >255 bpm */
+#define UF_NOWRAP 0x0080 /* XM-type (i.e. illogical) pattern break
+ semantics */
+#define UF_ARPMEM 0x0100 /* IT: need arpeggio memory */
+#define UF_FT2QUIRKS 0x0200 /* emulate some FT2 replay quirks */
+#define UF_PANNING 0x0400 /* module uses panning effects or have
+ non-tracker default initial panning */
+
+typedef struct MODULE {
+ /* general module information */
+ CHAR* songname; /* name of the song */
+ CHAR* modtype; /* string type of module loaded */
+ CHAR* comment; /* module comments */
+
+ UWORD flags; /* See module flags above */
+ UBYTE numchn; /* number of module channels */
+ UBYTE numvoices; /* max # voices used for full NNA playback */
+ UWORD numpos; /* number of positions in this song */
+ UWORD numpat; /* number of patterns in this song */
+ UWORD numins; /* number of instruments */
+ UWORD numsmp; /* number of samples */
+struct INSTRUMENT* instruments; /* all instruments */
+struct SAMPLE* samples; /* all samples */
+ UBYTE realchn; /* real number of channels used */
+ UBYTE totalchn; /* total number of channels used (incl NNAs) */
+
+ /* playback settings */
+ UWORD reppos; /* restart position */
+ UBYTE initspeed; /* initial song speed */
+ UWORD inittempo; /* initial song tempo */
+ UBYTE initvolume; /* initial global volume (0 - 128) */
+ UWORD panning[UF_MAXCHAN]; /* panning positions */
+ UBYTE chanvol[UF_MAXCHAN]; /* channel positions */
+ UWORD bpm; /* current beats-per-minute speed */
+ UWORD sngspd; /* current song speed */
+ SWORD volume; /* song volume (0-128) (or user volume) */
+
+ int extspd; /* extended speed flag (default enabled) */
+ int panflag; /* panning flag (default enabled) */
+ int wrap; /* wrap module ? (default disabled) */
+ int loop; /* allow module to loop ? (default enabled) */
+ int fadeout; /* volume fade out during last pattern */
+
+ UWORD patpos; /* current row number */
+ SWORD sngpos; /* current song position */
+ ULONG sngtime; /* current song time in 2^-10 seconds */
+
+ SWORD relspd; /* relative speed factor */
+
+ /* internal module representation */
+ UWORD numtrk; /* number of tracks */
+ UBYTE** tracks; /* array of numtrk pointers to tracks */
+ UWORD* patterns; /* array of Patterns */
+ UWORD* pattrows; /* array of number of rows for each pattern */
+ UWORD* positions; /* all positions */
+
+ int forbid; /* if true, no player update! */
+ UWORD numrow; /* number of rows on current pattern */
+ UWORD vbtick; /* tick counter (counts from 0 to sngspd) */
+ UWORD sngremainder;/* used for song time computation */
+
+struct MP_CONTROL* control; /* Effects Channel info (size pf->numchn) */
+struct MP_VOICE* voice; /* Audio Voice information (size md_numchn) */
+
+ UBYTE globalslide; /* global volume slide rate */
+ UBYTE pat_repcrazy;/* module has just looped to position -1 */
+ UWORD patbrk; /* position where to start a new pattern */
+ UBYTE patdly; /* patterndelay counter (command memory) */
+ UBYTE patdly2; /* patterndelay counter (real one) */
+ SWORD posjmp; /* flag to indicate a jump is needed... */
+ UWORD bpmlimit; /* threshold to detect bpm or speed values */
+} MODULE;
+
+
+/* This structure is used to query current playing voices status */
+typedef struct VOICEINFO {
+ INSTRUMENT* i; /* Current channel instrument */
+ SAMPLE* s; /* Current channel sample */
+ SWORD panning; /* panning position */
+ SBYTE volume; /* channel's "global" volume (0..64) */
+ UWORD period; /* period to play the sample at */
+ UBYTE kick; /* if true = sample has been restarted */
+} VOICEINFO;
+
+/*
+ * ========== Module loaders
+ */
+
+struct MLOADER;
+
+MIKMODAPI extern CHAR* MikMod_InfoLoader(void);
+MIKMODAPI extern void MikMod_RegisterAllLoaders(void);
+MIKMODAPI extern void MikMod_RegisterLoader(struct MLOADER*);
+
+MIKMODAPI extern struct MLOADER load_669; /* 669 and Extended-669 (by Tran/Renaissance) */
+MIKMODAPI extern struct MLOADER load_amf; /* DMP Advanced Module Format (by Otto Chrons) */
+MIKMODAPI extern struct MLOADER load_asy; /* ASYLUM Music Format 1.0 */
+MIKMODAPI extern struct MLOADER load_dsm; /* DSIK internal module format */
+MIKMODAPI extern struct MLOADER load_far; /* Farandole Composer (by Daniel Potter) */
+MIKMODAPI extern struct MLOADER load_gdm; /* General DigiMusic (by Edward Schlunder) */
+MIKMODAPI extern struct MLOADER load_gt2; /* Graoumf tracker */
+MIKMODAPI extern struct MLOADER load_it; /* Impulse Tracker (by Jeffrey Lim) */
+MIKMODAPI extern struct MLOADER load_imf; /* Imago Orpheus (by Lutz Roeder) */
+MIKMODAPI extern struct MLOADER load_med; /* Amiga MED modules (by Teijo Kinnunen) */
+MIKMODAPI extern struct MLOADER load_m15; /* Soundtracker 15-instrument */
+MIKMODAPI extern struct MLOADER load_mod; /* Standard 31-instrument Module loader */
+MIKMODAPI extern struct MLOADER load_mtm; /* Multi-Tracker Module (by Renaissance) */
+MIKMODAPI extern struct MLOADER load_okt; /* Amiga Oktalyzer */
+MIKMODAPI extern struct MLOADER load_stm; /* ScreamTracker 2 (by Future Crew) */
+MIKMODAPI extern struct MLOADER load_stx; /* STMIK 0.2 (by Future Crew) */
+MIKMODAPI extern struct MLOADER load_s3m; /* ScreamTracker 3 (by Future Crew) */
+MIKMODAPI extern struct MLOADER load_ult; /* UltraTracker (by MAS) */
+MIKMODAPI extern struct MLOADER load_uni; /* MikMod and APlayer internal module format */
+MIKMODAPI extern struct MLOADER load_xm; /* FastTracker 2 (by Triton) */
+
+/*
+ * ========== Module player
+ */
+
+MIKMODAPI extern MODULE* Player_Load(CHAR*,int,int);
+MIKMODAPI extern MODULE* Player_LoadFP(int,int,int);
+MIKMODAPI extern MODULE* Player_LoadMem(const char *buffer,int len,int maxchan,int curious);
+MIKMODAPI extern MODULE* Player_LoadGeneric(MREADER*,int,int);
+MIKMODAPI extern CHAR* Player_LoadTitle(CHAR*);
+MIKMODAPI extern CHAR* Player_LoadTitleFP(int);
+MIKMODAPI extern CHAR* Player_LoadTitleMem(const char *buffer,int len);
+MIKMODAPI extern CHAR* Player_LoadTitleGeneric(MREADER*);
+
+MIKMODAPI extern void Player_Free(MODULE*);
+MIKMODAPI extern void Player_Start(MODULE*);
+MIKMODAPI extern int Player_Active(void);
+MIKMODAPI extern void Player_Stop(void);
+MIKMODAPI extern void Player_TogglePause(void);
+MIKMODAPI extern int Player_Paused(void);
+MIKMODAPI extern void Player_NextPosition(void);
+MIKMODAPI extern void Player_PrevPosition(void);
+MIKMODAPI extern void Player_SetPosition(UWORD);
+MIKMODAPI extern int Player_Muted(UBYTE);
+MIKMODAPI extern void Player_SetVolume(SWORD);
+MIKMODAPI extern MODULE* Player_GetModule(void);
+MIKMODAPI extern void Player_SetSpeed(UWORD);
+MIKMODAPI extern void Player_SetTempo(UWORD);
+MIKMODAPI extern void Player_Unmute(SLONG,...);
+MIKMODAPI extern void Player_Mute(SLONG,...);
+MIKMODAPI extern void Player_ToggleMute(SLONG,...);
+MIKMODAPI extern int Player_GetChannelVoice(UBYTE);
+MIKMODAPI extern UWORD Player_GetChannelPeriod(UBYTE);
+MIKMODAPI extern int Player_QueryVoices(UWORD numvoices, VOICEINFO *vinfo);
+MIKMODAPI extern int Player_GetRow(void);
+MIKMODAPI extern int Player_GetOrder(void);
+
+typedef void (*MikMod_player_t)(void);
+typedef void (*MikMod_callback_t)(unsigned char *data, size_t len);
+
+MIKMODAPI extern MikMod_player_t MikMod_RegisterPlayer(MikMod_player_t);
+
+#define MUTE_EXCLUSIVE 32000
+#define MUTE_INCLUSIVE 32001
+
+/*
+ * ========== Drivers
+ */
+
+enum {
+ MD_MUSIC = 0,
+ MD_SNDFX
+};
+
+enum {
+ MD_HARDWARE = 0,
+ MD_SOFTWARE
+};
+
+/* Mixing flags */
+
+/* These ones take effect only after MikMod_Init or MikMod_Reset */
+#define DMODE_16BITS 0x0001 /* enable 16 bit output */
+#define DMODE_STEREO 0x0002 /* enable stereo output */
+#define DMODE_SOFT_SNDFX 0x0004 /* Process sound effects via software mixer */
+#define DMODE_SOFT_MUSIC 0x0008 /* Process music via software mixer */
+#define DMODE_HQMIXER 0x0010 /* Use high-quality (slower) software mixer */
+#define DMODE_FLOAT 0x0020 /* enable float output */
+/* These take effect immediately. */
+#define DMODE_SURROUND 0x0100 /* enable surround sound */
+#define DMODE_INTERP 0x0200 /* enable interpolation */
+#define DMODE_REVERSE 0x0400 /* reverse stereo */
+#define DMODE_SIMDMIXER 0x0800 /* enable SIMD mixing */
+#define DMODE_NOISEREDUCTION 0x1000 /* Low pass filtering */
+
+struct SAMPLOAD;
+typedef struct MDRIVER {
+struct MDRIVER* next;
+ CHAR* Name;
+ CHAR* Version;
+
+ UBYTE HardVoiceLimit; /* Limit of hardware mixer voices */
+ UBYTE SoftVoiceLimit; /* Limit of software mixer voices */
+
+ CHAR *Alias;
+ CHAR *CmdLineHelp;
+
+ void (*CommandLine) (CHAR*);
+ int (*IsPresent) (void);
+ SWORD (*SampleLoad) (struct SAMPLOAD*,int);
+ void (*SampleUnload) (SWORD);
+ ULONG (*FreeSampleSpace) (int);
+ ULONG (*RealSampleLength) (int,struct SAMPLE*);
+ int (*Init) (void);
+ void (*Exit) (void);
+ int (*Reset) (void);
+ int (*SetNumVoices) (void);
+ int (*PlayStart) (void);
+ void (*PlayStop) (void);
+ void (*Update) (void);
+ void (*Pause) (void);
+ void (*VoiceSetVolume) (UBYTE,UWORD);
+ UWORD (*VoiceGetVolume) (UBYTE);
+ void (*VoiceSetFrequency)(UBYTE,ULONG);
+ ULONG (*VoiceGetFrequency)(UBYTE);
+ void (*VoiceSetPanning) (UBYTE,ULONG);
+ ULONG (*VoiceGetPanning) (UBYTE);
+ void (*VoicePlay) (UBYTE,SWORD,ULONG,ULONG,ULONG,ULONG,UWORD);
+ void (*VoiceStop) (UBYTE);
+ int (*VoiceStopped) (UBYTE);
+ SLONG (*VoiceGetPosition) (UBYTE);
+ ULONG (*VoiceRealVolume) (UBYTE);
+} MDRIVER;
+
+/* These variables can be changed at ANY time and results will be immediate */
+MIKMODAPI extern UBYTE md_volume; /* global sound volume (0-128) */
+MIKMODAPI extern UBYTE md_musicvolume; /* volume of song */
+MIKMODAPI extern UBYTE md_sndfxvolume; /* volume of sound effects */
+MIKMODAPI extern UBYTE md_reverb; /* 0 = none; 15 = chaos */
+MIKMODAPI extern UBYTE md_pansep; /* 0 = mono; 128 == 100% (full left/right) */
+
+/* The variables below can be changed at any time, but changes will not be
+ implemented until MikMod_Reset is called. A call to MikMod_Reset may result
+ in a skip or pop in audio (depending on the soundcard driver and the settings
+ changed). */
+MIKMODAPI extern UWORD md_device; /* device */
+MIKMODAPI extern UWORD md_mixfreq; /* mixing frequency */
+MIKMODAPI extern UWORD md_mode; /* mode. See DMODE_? flags above */
+
+/* The following variable should not be changed! */
+MIKMODAPI extern MDRIVER* md_driver; /* Current driver in use. */
+
+/* Known drivers list */
+
+MIKMODAPI extern struct MDRIVER drv_nos; /* no sound */
+#if 0
+MIKMODAPI extern struct MDRIVER drv_pipe; /* piped output */
+MIKMODAPI extern struct MDRIVER drv_raw; /* raw file disk writer [music.raw] */
+MIKMODAPI extern struct MDRIVER drv_stdout; /* output to stdout */
+MIKMODAPI extern struct MDRIVER drv_wav; /* RIFF WAVE file disk writer [music.wav] */
+MIKMODAPI extern struct MDRIVER drv_aiff; /* AIFF file disk writer [music.aiff] */
+
+MIKMODAPI extern struct MDRIVER drv_ultra; /* Linux Ultrasound driver */
+MIKMODAPI extern struct MDRIVER drv_sam9407; /* Linux sam9407 driver */
+
+MIKMODAPI extern struct MDRIVER drv_AF; /* Dec Alpha AudioFile */
+MIKMODAPI extern struct MDRIVER drv_aix; /* AIX audio device */
+MIKMODAPI extern struct MDRIVER drv_alsa; /* Advanced Linux Sound Architecture (ALSA) */
+MIKMODAPI extern struct MDRIVER drv_esd; /* Enlightened sound daemon (EsounD) */
+MIKMODAPI extern struct MDRIVER drv_hp; /* HP-UX audio device */
+MIKMODAPI extern struct MDRIVER drv_nas; /* Network Audio System (NAS) */
+MIKMODAPI extern struct MDRIVER drv_oss; /* OpenSound System (Linux,FreeBSD...) */
+MIKMODAPI extern struct MDRIVER drv_sgi; /* SGI audio library */
+MIKMODAPI extern struct MDRIVER drv_sun; /* Sun/NetBSD/OpenBSD audio device */
+
+MIKMODAPI extern struct MDRIVER drv_dart; /* OS/2 Direct Audio RealTime */
+MIKMODAPI extern struct MDRIVER drv_os2; /* OS/2 MMPM/2 */
+
+MIKMODAPI extern struct MDRIVER drv_ds; /* Win32 DirectSound driver */
+MIKMODAPI extern struct MDRIVER drv_win; /* Win32 multimedia API driver */
+
+MIKMODAPI extern struct MDRIVER drv_mac; /* Macintosh Sound Manager driver */
+MIKMODAPI extern struct MDRIVER drv_osx; /* MacOS X CoreAudio Driver */
+
+MIKMODAPI extern struct MDRIVER drv_gp32; /* GP32 Sound driver */
+
+MIKMODAPI extern struct MDRIVER drv_wss; /* DOS WSS driver */
+MIKMODAPI extern struct MDRIVER drv_sb; /* DOS SB driver */
+#endif
+/*========== Virtual channel mixer interface (for user-supplied drivers only) */
+
+MIKMODAPI extern int VC_Init(void);
+MIKMODAPI extern void VC_Exit(void);
+MIKMODAPI extern void VC_SetCallback(MikMod_callback_t callback);
+MIKMODAPI extern int VC_SetNumVoices(void);
+MIKMODAPI extern ULONG VC_SampleSpace(int);
+MIKMODAPI extern ULONG VC_SampleLength(int,SAMPLE*);
+
+MIKMODAPI extern int VC_PlayStart(void);
+MIKMODAPI extern void VC_PlayStop(void);
+
+MIKMODAPI extern SWORD VC_SampleLoad(struct SAMPLOAD*,int);
+MIKMODAPI extern void VC_SampleUnload(SWORD);
+
+MIKMODAPI extern ULONG VC_WriteBytes(SBYTE*,ULONG);
+MIKMODAPI extern ULONG VC_SilenceBytes(SBYTE*,ULONG);
+
+MIKMODAPI extern void VC_VoiceSetVolume(UBYTE,UWORD);
+MIKMODAPI extern UWORD VC_VoiceGetVolume(UBYTE);
+MIKMODAPI extern void VC_VoiceSetFrequency(UBYTE,ULONG);
+MIKMODAPI extern ULONG VC_VoiceGetFrequency(UBYTE);
+MIKMODAPI extern void VC_VoiceSetPanning(UBYTE,ULONG);
+MIKMODAPI extern ULONG VC_VoiceGetPanning(UBYTE);
+MIKMODAPI extern void VC_VoicePlay(UBYTE,SWORD,ULONG,ULONG,ULONG,ULONG,UWORD);
+
+MIKMODAPI extern void VC_VoiceStop(UBYTE);
+MIKMODAPI extern int VC_VoiceStopped(UBYTE);
+MIKMODAPI extern SLONG VC_VoiceGetPosition(UBYTE);
+MIKMODAPI extern ULONG VC_VoiceRealVolume(UBYTE);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/* ex:set ts=4: */
diff --git a/apps/plugins/mikmod/mikmod.make b/apps/plugins/mikmod/mikmod.make
new file mode 100644
index 0000000000..112c25dda1
--- /dev/null
+++ b/apps/plugins/mikmod/mikmod.make
@@ -0,0 +1,33 @@
+# __________ __ ___.
+# Open \______ \ ____ ____ | | _\_ |__ _______ ___
+# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+# \/ \/ \/ \/ \/
+# $Id: Makefile 19082 2008-11-10 23:54:24Z zagor $
+#
+
+MIKMODSRCDIR := $(APPSDIR)/plugins/mikmod
+MIKMODBUILDDIR := $(BUILDDIR)/apps/plugins/mikmod
+
+ROCKS += $(MIKMODBUILDDIR)/mikmod.rock
+
+MIKMOD_SRC := $(call preprocess, $(MIKMODSRCDIR)/SOURCES)
+MIKMOD_OBJ := $(call c2obj, $(MIKMOD_SRC))
+
+# add source files to OTHER_SRC to get automatic dependencies
+OTHER_SRC += $(MIKMOD_SRC)
+
+MIKMODCFLAGS = $(PLUGINFLAGS) -I$(MIKMODSRCDIR) -w
+ifeq ($(CPU),coldfire)
+ MIKMODCFLAGS += -O0
+else
+ MIKMODCFLAGS += -O2
+endif
+
+$(MIKMODBUILDDIR)/mikmod.rock: $(MIKMOD_OBJ) $(CODECDIR)/libtlsf.a
+
+# new rule needed to use extra compile flags
+$(MIKMODBUILDDIR)/%.o: $(MIKMODSRCDIR)/%.c
+ $(SILENT)mkdir -p $(dir $@)
+ $(call PRINTS,CC $(subst $(ROOTDIR)/,,$<))$(CC) $(MIKMODCFLAGS) -c $< -o $@
diff --git a/apps/plugins/mikmod/mikmod_internals.h b/apps/plugins/mikmod/mikmod_internals.h
new file mode 100644
index 0000000000..284dd85936
--- /dev/null
+++ b/apps/plugins/mikmod/mikmod_internals.h
@@ -0,0 +1,806 @@
+/* MikMod sound library
+ (c) 1998, 1999, 2005 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: mikmod_internals.h,v 1.7 2010/01/12 03:30:31 realtech Exp $
+
+ MikMod sound library internal definitions
+
+==============================================================================*/
+
+#ifndef _MIKMOD_INTERNALS_H
+#define _MIKMOD_INTERNALS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdarg.h>
+#if 0
+#if defined(__OS2__)||defined(__EMX__)||defined(WIN32)
+#define strcasecmp(s,t) stricmp(s,t)
+#endif
+#endif
+
+#include "mikmod.h"
+
+/*========== More type definitions */
+
+/* SLONGLONG: 64bit, signed */
+#if defined (__arch64__) || defined(__alpha) || defined (__x64_64) || defined (_LP64) || defined (__powerpc64__)
+typedef long SLONGLONG;
+#define NATIVE_64BIT_INT
+#if 0
+#elif defined(__WATCOMC__)
+typedef __int64 SLONGLONG;
+#elif defined(WIN32) && !defined(__MWERKS__)
+typedef LONGLONG SLONGLONG;
+#elif macintosh && !TYPE_LONGLONG
+#include <Types.h>
+typedef SInt64 SLONGLONG;
+#endif
+#else
+typedef long long SLONGLONG;
+#endif
+
+/*========== Error handling */
+
+#define _mm_errno MikMod_errno
+#define _mm_critical MikMod_critical
+extern MikMod_handler_t _mm_errorhandler;
+
+/*========== MT stuff */
+
+#ifdef HAVE_PTHREAD
+#include <pthread.h>
+#define DECLARE_MUTEX(name) \
+ extern pthread_mutex_t _mm_mutex_##name
+#define MUTEX_LOCK(name) \
+ pthread_mutex_lock(&_mm_mutex_##name)
+#define MUTEX_UNLOCK(name) \
+ pthread_mutex_unlock(&_mm_mutex_##name)
+#elif defined(__OS2__)||defined(__EMX__)
+#define DECLARE_MUTEX(name) \
+ extern HMTX _mm_mutex_##name
+#define MUTEX_LOCK(name) \
+ if(_mm_mutex_##name) \
+ DosRequestMutexSem(_mm_mutex_##name,SEM_INDEFINITE_WAIT)
+#define MUTEX_UNLOCK(name) \
+ if(_mm_mutex_##name) \
+ DosReleaseMutexSem(_mm_mutex_##name)
+#elif defined(WIN32)
+#include <windows.h>
+#define DECLARE_MUTEX(name) \
+ extern HANDLE _mm_mutex_##name
+#define MUTEX_LOCK(name) \
+ if(_mm_mutex_##name) \
+ WaitForSingleObject(_mm_mutex_##name,INFINITE)
+#define MUTEX_UNLOCK(name) \
+ if(_mm_mutex_##name) \
+ ReleaseMutex(_mm_mutex_##name)
+#else
+#define DECLARE_MUTEX(name) \
+ extern void *_mm_mutex_##name
+#define MUTEX_LOCK(name)
+#define MUTEX_UNLOCK(name)
+#endif
+
+DECLARE_MUTEX(lists);
+DECLARE_MUTEX(vars);
+
+/*========== Portable file I/O */
+
+extern MREADER* _mm_new_mem_reader(const void *buffer, int len);
+extern void _mm_delete_mem_reader(MREADER *reader);
+
+extern MREADER* _mm_new_file_reader(int fp);
+extern void _mm_delete_file_reader(MREADER*);
+
+extern MWRITER* _mm_new_file_writer(int fp);
+extern void _mm_delete_file_writer(MWRITER*);
+
+extern int _mm_FileExists(CHAR *fname);
+
+#define _mm_write_SBYTE(x,y) y->Put(y,(int)x)
+#define _mm_write_UBYTE(x,y) y->Put(y,(int)x)
+
+#define _mm_read_SBYTE(x) (SBYTE)x->Get(x)
+#define _mm_read_UBYTE(x) (UBYTE)x->Get(x)
+
+#define _mm_write_SBYTES(x,y,z) z->Write(z,(void *)x,y)
+#define _mm_write_UBYTES(x,y,z) z->Write(z,(void *)x,y)
+#define _mm_read_SBYTES(x,y,z) z->Read(z,(void *)x,y)
+#define _mm_read_UBYTES(x,y,z) z->Read(z,(void *)x,y)
+
+#define _mm_fseek(x,y,z) x->Seek(x,y,z)
+#define _mm_ftell(x) x->Tell(x)
+#define _mm_rewind(x) _mm_fseek(x,0,SEEK_SET)
+
+#define _mm_eof(x) x->Eof(x)
+
+extern void _mm_iobase_setcur(MREADER*);
+extern void _mm_iobase_revert(MREADER*);
+extern int _mm_fopen(CHAR*,CHAR*);
+extern int _mm_fclose(int);
+extern void _mm_write_string(CHAR*,MWRITER*);
+extern int _mm_read_string (CHAR*,int,MREADER*);
+
+extern SWORD _mm_read_M_SWORD(MREADER*);
+extern SWORD _mm_read_I_SWORD(MREADER*);
+extern UWORD _mm_read_M_UWORD(MREADER*);
+extern UWORD _mm_read_I_UWORD(MREADER*);
+
+extern SLONG _mm_read_M_SLONG(MREADER*);
+extern SLONG _mm_read_I_SLONG(MREADER*);
+extern ULONG _mm_read_M_ULONG(MREADER*);
+extern ULONG _mm_read_I_ULONG(MREADER*);
+
+extern int _mm_read_M_SWORDS(SWORD*,int,MREADER*);
+extern int _mm_read_I_SWORDS(SWORD*,int,MREADER*);
+extern int _mm_read_M_UWORDS(UWORD*,int,MREADER*);
+extern int _mm_read_I_UWORDS(UWORD*,int,MREADER*);
+
+extern int _mm_read_M_SLONGS(SLONG*,int,MREADER*);
+extern int _mm_read_I_SLONGS(SLONG*,int,MREADER*);
+extern int _mm_read_M_ULONGS(ULONG*,int,MREADER*);
+extern int _mm_read_I_ULONGS(ULONG*,int,MREADER*);
+
+extern void _mm_write_M_SWORD(SWORD,MWRITER*);
+extern void _mm_write_I_SWORD(SWORD,MWRITER*);
+extern void _mm_write_M_UWORD(UWORD,MWRITER*);
+extern void _mm_write_I_UWORD(UWORD,MWRITER*);
+
+extern void _mm_write_M_SLONG(SLONG,MWRITER*);
+extern void _mm_write_I_SLONG(SLONG,MWRITER*);
+extern void _mm_write_M_ULONG(ULONG,MWRITER*);
+extern void _mm_write_I_ULONG(ULONG,MWRITER*);
+
+extern void _mm_write_M_SWORDS(SWORD*,int,MWRITER*);
+extern void _mm_write_I_SWORDS(SWORD*,int,MWRITER*);
+extern void _mm_write_M_UWORDS(UWORD*,int,MWRITER*);
+extern void _mm_write_I_UWORDS(UWORD*,int,MWRITER*);
+
+extern void _mm_write_M_SLONGS(SLONG*,int,MWRITER*);
+extern void _mm_write_I_SLONGS(SLONG*,int,MWRITER*);
+extern void _mm_write_M_ULONGS(ULONG*,int,MWRITER*);
+extern void _mm_write_I_ULONGS(ULONG*,int,MWRITER*);
+
+/*========== Samples */
+
+/* This is a handle of sorts attached to any sample registered with
+ SL_RegisterSample. Generally, this only need be used or changed by the
+ loaders and drivers of mikmod. */
+typedef struct SAMPLOAD {
+ struct SAMPLOAD *next;
+
+ ULONG length; /* length of sample (in samples!) */
+ ULONG loopstart; /* repeat position (relative to start, in samples) */
+ ULONG loopend; /* repeat end */
+ UWORD infmt,outfmt;
+ int scalefactor;
+ SAMPLE* sample;
+ MREADER* reader;
+} SAMPLOAD;
+
+/*========== Sample and waves loading interface */
+
+extern void SL_HalveSample(SAMPLOAD*,int);
+extern void SL_Sample8to16(SAMPLOAD*);
+extern void SL_Sample16to8(SAMPLOAD*);
+extern void SL_SampleSigned(SAMPLOAD*);
+extern void SL_SampleUnsigned(SAMPLOAD*);
+extern int SL_LoadSamples(void);
+extern SAMPLOAD* SL_RegisterSample(SAMPLE*,int,MREADER*);
+extern int SL_Load(void*,SAMPLOAD*,ULONG);
+extern int SL_Init(SAMPLOAD*);
+extern void SL_Exit(SAMPLOAD*);
+
+/*========== Internal module representation (UniMod) interface */
+
+/* number of notes in an octave */
+#define OCTAVE 12
+
+extern void UniSetRow(UBYTE*);
+extern UBYTE UniGetByte(void);
+extern UWORD UniGetWord(void);
+extern UBYTE* UniFindRow(UBYTE*,UWORD);
+extern void UniSkipOpcode(void);
+extern void UniReset(void);
+extern void UniWriteByte(UBYTE);
+extern void UniWriteWord(UWORD);
+extern void UniNewline(void);
+extern UBYTE* UniDup(void);
+extern int UniInit(void);
+extern void UniCleanup(void);
+extern void UniEffect(UWORD,UWORD);
+#define UniInstrument(x) UniEffect(UNI_INSTRUMENT,x)
+#define UniNote(x) UniEffect(UNI_NOTE,x)
+extern void UniPTEffect(UBYTE,UBYTE);
+extern void UniVolEffect(UWORD,UBYTE);
+
+/*========== Module Commands */
+
+enum {
+ /* Simple note */
+ UNI_NOTE = 1,
+ /* Instrument change */
+ UNI_INSTRUMENT,
+ /* Protracker effects */
+ UNI_PTEFFECT0, /* arpeggio */
+ UNI_PTEFFECT1, /* porta up */
+ UNI_PTEFFECT2, /* porta down */
+ UNI_PTEFFECT3, /* porta to note */
+ UNI_PTEFFECT4, /* vibrato */
+ UNI_PTEFFECT5, /* dual effect 3+A */
+ UNI_PTEFFECT6, /* dual effect 4+A */
+ UNI_PTEFFECT7, /* tremolo */
+ UNI_PTEFFECT8, /* pan */
+ UNI_PTEFFECT9, /* sample offset */
+ UNI_PTEFFECTA, /* volume slide */
+ UNI_PTEFFECTB, /* pattern jump */
+ UNI_PTEFFECTC, /* set volume */
+ UNI_PTEFFECTD, /* pattern break */
+ UNI_PTEFFECTE, /* extended effects */
+ UNI_PTEFFECTF, /* set speed */
+ /* Scream Tracker effects */
+ UNI_S3MEFFECTA, /* set speed */
+ UNI_S3MEFFECTD, /* volume slide */
+ UNI_S3MEFFECTE, /* porta down */
+ UNI_S3MEFFECTF, /* porta up */
+ UNI_S3MEFFECTI, /* tremor */
+ UNI_S3MEFFECTQ, /* retrig */
+ UNI_S3MEFFECTR, /* tremolo */
+ UNI_S3MEFFECTT, /* set tempo */
+ UNI_S3MEFFECTU, /* fine vibrato */
+ UNI_KEYOFF, /* note off */
+ /* Fast Tracker effects */
+ UNI_KEYFADE, /* note fade */
+ UNI_VOLEFFECTS, /* volume column effects */
+ UNI_XMEFFECT4, /* vibrato */
+ UNI_XMEFFECT6, /* dual effect 4+A */
+ UNI_XMEFFECTA, /* volume slide */
+ UNI_XMEFFECTE1, /* fine porta up */
+ UNI_XMEFFECTE2, /* fine porta down */
+ UNI_XMEFFECTEA, /* fine volume slide up */
+ UNI_XMEFFECTEB, /* fine volume slide down */
+ UNI_XMEFFECTG, /* set global volume */
+ UNI_XMEFFECTH, /* global volume slide */
+ UNI_XMEFFECTL, /* set envelope position */
+ UNI_XMEFFECTP, /* pan slide */
+ UNI_XMEFFECTX1, /* extra fine porta up */
+ UNI_XMEFFECTX2, /* extra fine porta down */
+ /* Impulse Tracker effects */
+ UNI_ITEFFECTG, /* porta to note */
+ UNI_ITEFFECTH, /* vibrato */
+ UNI_ITEFFECTI, /* tremor (xy not incremented) */
+ UNI_ITEFFECTM, /* set channel volume */
+ UNI_ITEFFECTN, /* slide / fineslide channel volume */
+ UNI_ITEFFECTP, /* slide / fineslide channel panning */
+ UNI_ITEFFECTT, /* slide tempo */
+ UNI_ITEFFECTU, /* fine vibrato */
+ UNI_ITEFFECTW, /* slide / fineslide global volume */
+ UNI_ITEFFECTY, /* panbrello */
+ UNI_ITEFFECTZ, /* resonant filters */
+ UNI_ITEFFECTS0,
+ /* UltraTracker effects */
+ UNI_ULTEFFECT9, /* Sample fine offset */
+ /* OctaMED effects */
+ UNI_MEDSPEED,
+ UNI_MEDEFFECTF1, /* play note twice */
+ UNI_MEDEFFECTF2, /* delay note */
+ UNI_MEDEFFECTF3, /* play note three times */
+ /* Oktalyzer effects */
+ UNI_OKTARP, /* arpeggio */
+
+ UNI_LAST
+};
+
+extern UWORD unioperands[UNI_LAST];
+
+/* IT / S3M Extended SS effects: */
+enum {
+ SS_GLISSANDO = 1,
+ SS_FINETUNE,
+ SS_VIBWAVE,
+ SS_TREMWAVE,
+ SS_PANWAVE,
+ SS_FRAMEDELAY,
+ SS_S7EFFECTS,
+ SS_PANNING,
+ SS_SURROUND,
+ SS_HIOFFSET,
+ SS_PATLOOP,
+ SS_NOTECUT,
+ SS_NOTEDELAY,
+ SS_PATDELAY
+};
+
+/* IT Volume column effects */
+enum {
+ VOL_VOLUME = 1,
+ VOL_PANNING,
+ VOL_VOLSLIDE,
+ VOL_PITCHSLIDEDN,
+ VOL_PITCHSLIDEUP,
+ VOL_PORTAMENTO,
+ VOL_VIBRATO
+};
+
+/* IT resonant filter information */
+
+#define UF_MAXMACRO 0x10
+#define UF_MAXFILTER 0x100
+
+#define FILT_CUT 0x80
+#define FILT_RESONANT 0x81
+
+typedef struct FILTER {
+ UBYTE filter,inf;
+} FILTER;
+
+/*========== Instruments */
+
+/* Instrument format flags */
+#define IF_OWNPAN 1
+#define IF_PITCHPAN 2
+
+/* Envelope flags: */
+#define EF_ON 1
+#define EF_SUSTAIN 2
+#define EF_LOOP 4
+#define EF_VOLENV 8
+
+/* New Note Action Flags */
+#define NNA_CUT 0
+#define NNA_CONTINUE 1
+#define NNA_OFF 2
+#define NNA_FADE 3
+
+#define NNA_MASK 3
+
+#define DCT_OFF 0
+#define DCT_NOTE 1
+#define DCT_SAMPLE 2
+#define DCT_INST 3
+
+#define DCA_CUT 0
+#define DCA_OFF 1
+#define DCA_FADE 2
+
+#define KEY_KICK 0
+#define KEY_OFF 1
+#define KEY_FADE 2
+#define KEY_KILL (KEY_OFF|KEY_FADE)
+
+#define KICK_ABSENT 0
+#define KICK_NOTE 1
+#define KICK_KEYOFF 2
+#define KICK_ENV 4
+
+#define AV_IT 1 /* IT vs. XM vibrato info */
+
+/*========== Playing */
+
+#define POS_NONE (-2) /* no loop position defined */
+
+#define LAST_PATTERN (UWORD)(-1) /* special ``end of song'' pattern */
+
+typedef struct ENVPR {
+ UBYTE flg; /* envelope flag */
+ UBYTE pts; /* number of envelope points */
+ UBYTE susbeg; /* envelope sustain index begin */
+ UBYTE susend; /* envelope sustain index end */
+ UBYTE beg; /* envelope loop begin */
+ UBYTE end; /* envelope loop end */
+ SWORD p; /* current envelope counter */
+ UWORD a; /* envelope index a */
+ UWORD b; /* envelope index b */
+ ENVPT* env; /* envelope points */
+} ENVPR;
+
+typedef struct MP_CHANNEL {
+ INSTRUMENT* i;
+ SAMPLE* s;
+ UBYTE sample; /* which sample number */
+ UBYTE note; /* the audible note as heard, direct rep of period */
+ SWORD outvolume; /* output volume (vol + sampcol + instvol) */
+ SBYTE chanvol; /* channel's "global" volume */
+ UWORD fadevol; /* fading volume rate */
+ SWORD panning; /* panning position */
+ UBYTE kick; /* if true = sample has to be restarted */
+ UBYTE kick_flag; /* kick has been true */
+ UWORD period; /* period to play the sample at */
+ UBYTE nna; /* New note action type + master/slave flags */
+
+ UBYTE volflg; /* volume envelope settings */
+ UBYTE panflg; /* panning envelope settings */
+ UBYTE pitflg; /* pitch envelope settings */
+
+ UBYTE keyoff; /* if true = fade out and stuff */
+ SWORD handle; /* which sample-handle */
+ UBYTE notedelay; /* (used for note delay) */
+ SLONG start; /* The starting byte index in the sample */
+} MP_CHANNEL;
+
+typedef struct MP_CONTROL {
+ struct MP_CHANNEL main;
+
+ struct MP_VOICE *slave; /* Audio Slave of current effects control channel */
+
+ UBYTE slavechn; /* Audio Slave of current effects control channel */
+ UBYTE muted; /* if set, channel not played */
+ UWORD ultoffset; /* fine sample offset memory */
+ UBYTE anote; /* the note that indexes the audible */
+ UBYTE oldnote;
+ SWORD ownper;
+ SWORD ownvol;
+ UBYTE dca; /* duplicate check action */
+ UBYTE dct; /* duplicate check type */
+ UBYTE* row; /* row currently playing on this channel */
+ SBYTE retrig; /* retrig value (0 means don't retrig) */
+ ULONG speed; /* what finetune to use */
+ SWORD volume; /* amiga volume (0 t/m 64) to play the sample at */
+
+ SWORD tmpvolume; /* tmp volume */
+ UWORD tmpperiod; /* tmp period */
+ UWORD wantedperiod; /* period to slide to (with effect 3 or 5) */
+
+ UBYTE arpmem; /* arpeggio command memory */
+ UBYTE pansspd; /* panslide speed */
+ UWORD slidespeed;
+ UWORD portspeed; /* noteslide speed (toneportamento) */
+
+ UBYTE s3mtremor; /* s3m tremor (effect I) counter */
+ UBYTE s3mtronof; /* s3m tremor ontime/offtime */
+ UBYTE s3mvolslide; /* last used volslide */
+ SBYTE sliding;
+ UBYTE s3mrtgspeed; /* last used retrig speed */
+ UBYTE s3mrtgslide; /* last used retrig slide */
+
+ UBYTE glissando; /* glissando (0 means off) */
+ UBYTE wavecontrol;
+
+ SBYTE vibpos; /* current vibrato position */
+ UBYTE vibspd; /* "" speed */
+ UBYTE vibdepth; /* "" depth */
+
+ SBYTE trmpos; /* current tremolo position */
+ UBYTE trmspd; /* "" speed */
+ UBYTE trmdepth; /* "" depth */
+
+ UBYTE fslideupspd;
+ UBYTE fslidednspd;
+ UBYTE fportupspd; /* fx E1 (extra fine portamento up) data */
+ UBYTE fportdnspd; /* fx E2 (extra fine portamento dn) data */
+ UBYTE ffportupspd; /* fx X1 (extra fine portamento up) data */
+ UBYTE ffportdnspd; /* fx X2 (extra fine portamento dn) data */
+
+ ULONG hioffset; /* last used high order of sample offset */
+ UWORD soffset; /* last used low order of sample-offset (effect 9) */
+
+ UBYTE sseffect; /* last used Sxx effect */
+ UBYTE ssdata; /* last used Sxx data info */
+ UBYTE chanvolslide; /* last used channel volume slide */
+
+ UBYTE panbwave; /* current panbrello waveform */
+ UBYTE panbpos; /* current panbrello position */
+ SBYTE panbspd; /* "" speed */
+ UBYTE panbdepth; /* "" depth */
+
+ UWORD newsamp; /* set to 1 upon a sample / inst change */
+ UBYTE voleffect; /* Volume Column Effect Memory as used by IT */
+ UBYTE voldata; /* Volume Column Data Memory */
+
+ SWORD pat_reppos; /* patternloop position */
+ UWORD pat_repcnt; /* times to loop */
+} MP_CONTROL;
+
+/* Used by NNA only player (audio control. AUDTMP is used for full effects
+ control). */
+typedef struct MP_VOICE {
+ struct MP_CHANNEL main;
+
+ ENVPR venv;
+ ENVPR penv;
+ ENVPR cenv;
+
+ UWORD avibpos; /* autovibrato pos */
+ UWORD aswppos; /* autovibrato sweep pos */
+
+ ULONG totalvol; /* total volume of channel (before global mixings) */
+
+ int mflag;
+ SWORD masterchn;
+ UWORD masterperiod;
+
+ MP_CONTROL* master; /* index of "master" effects channel */
+} MP_VOICE;
+
+/*========== Loaders */
+
+typedef struct MLOADER {
+struct MLOADER* next;
+ CHAR* type;
+ CHAR* version;
+ int (*Init)(void);
+ int (*Test)(void);
+ int (*Load)(int);
+ void (*Cleanup)(void);
+ CHAR* (*LoadTitle)(void);
+} MLOADER;
+
+/* internal loader variables */
+extern MREADER* modreader;
+extern UWORD finetune[16];
+extern MODULE of; /* static unimod loading space */
+extern UWORD npertab[7*OCTAVE]; /* used by the original MOD loaders */
+
+extern SBYTE remap[UF_MAXCHAN]; /* for removing empty channels */
+extern UBYTE* poslookup; /* lookup table for pattern jumps after
+ blank pattern removal */
+extern UWORD poslookupcnt;
+extern UWORD* origpositions;
+
+extern int filters; /* resonant filters in use */
+extern UBYTE activemacro; /* active midi macro number for Sxx */
+extern UBYTE filtermacros[UF_MAXMACRO]; /* midi macro settings */
+extern FILTER filtersettings[UF_MAXFILTER]; /* computed filter settings */
+
+extern int* noteindex;
+
+/*========== Internal loader interface */
+
+extern int ReadComment(UWORD);
+extern int ReadLinedComment(UWORD,UWORD);
+extern int AllocPositions(int);
+extern int AllocPatterns(void);
+extern int AllocTracks(void);
+extern int AllocInstruments(void);
+extern int AllocSamples(void);
+extern CHAR* DupStr(CHAR*,UWORD,int);
+extern CHAR* StrDup(CHAR *s);
+
+/* loader utility functions */
+extern int* AllocLinear(void);
+extern void FreeLinear(void);
+extern int speed_to_finetune(ULONG,int);
+extern void S3MIT_ProcessCmd(UBYTE,UBYTE,unsigned int);
+extern void S3MIT_CreateOrders(int);
+
+/* flags for S3MIT_ProcessCmd */
+#define S3MIT_OLDSTYLE 1 /* behave as old scream tracker */
+#define S3MIT_IT 2 /* behave as impulse tracker */
+#define S3MIT_SCREAM 4 /* enforce scream tracker specific limits */
+
+/* used to convert c4spd to linear XM periods (IT and IMF loaders). */
+extern UWORD getlinearperiod(UWORD,ULONG);
+extern ULONG getfrequency(UWORD,ULONG);
+
+/* loader shared data */
+#define STM_NTRACKERS 3
+extern CHAR *STM_Signatures[STM_NTRACKERS];
+
+/*========== Player interface */
+
+extern int Player_Init(MODULE*);
+extern void Player_Exit(MODULE*);
+extern void Player_HandleTick(void);
+
+/*========== Drivers */
+
+/* max. number of handles a driver has to provide. (not strict) */
+#define MAXSAMPLEHANDLES 384
+
+/* These variables can be changed at ANY time and results will be immediate */
+extern UWORD md_bpm; /* current song / hardware BPM rate */
+
+/* Variables below can be changed via MD_SetNumVoices at any time. However, a
+ call to MD_SetNumVoicess while the driver is active will cause the sound to
+ skip slightly. */
+extern UBYTE md_numchn; /* number of song + sound effects voices */
+extern UBYTE md_sngchn; /* number of song voices */
+extern UBYTE md_sfxchn; /* number of sound effects voices */
+extern UBYTE md_hardchn; /* number of hardware mixed voices */
+extern UBYTE md_softchn; /* number of software mixed voices */
+
+/* This is for use by the hardware drivers only. It points to the registered
+ tickhandler function. */
+extern void (*md_player)(void);
+
+extern SWORD MD_SampleLoad(SAMPLOAD*,int);
+extern void MD_SampleUnload(SWORD);
+extern ULONG MD_SampleSpace(int);
+extern ULONG MD_SampleLength(int,SAMPLE*);
+
+/* uLaw conversion */
+extern void unsignedtoulaw(char *,int);
+
+/* Parameter extraction helper */
+extern CHAR *MD_GetAtom(CHAR*,CHAR*,int);
+
+/* Internal software mixer stuff */
+extern void VC_SetupPointers(void);
+extern int VC1_Init(void);
+extern int VC2_Init(void);
+
+#if defined(unix) || defined(__APPLE__) && defined(__MACH__)
+/* POSIX helper functions */
+extern int MD_Access(CHAR *);
+extern int MD_DropPrivileges(void);
+#endif
+
+/* Macro to define a missing driver, yet allowing binaries to dynamically link
+ with the library without missing symbol errors */
+#define MISSING(a) MDRIVER a = { NULL, NULL, NULL, 0, 0 }
+
+/*========== Prototypes for non-MT safe versions of some public functions */
+
+extern void _mm_registerdriver(struct MDRIVER*);
+extern void _mm_registerloader(struct MLOADER*);
+extern int MikMod_Active_internal(void);
+extern void MikMod_DisableOutput_internal(void);
+extern int MikMod_EnableOutput_internal(void);
+extern void MikMod_Exit_internal(void);
+extern int MikMod_SetNumVoices_internal(int,int);
+extern void Player_Exit_internal(MODULE*);
+extern void Player_Stop_internal(void);
+extern int Player_Paused_internal(void);
+extern void Sample_Free_internal(SAMPLE*);
+extern void Voice_Play_internal(SBYTE,SAMPLE*,ULONG);
+extern void Voice_SetFrequency_internal(SBYTE,ULONG);
+extern void Voice_SetPanning_internal(SBYTE,ULONG);
+extern void Voice_SetVolume_internal(SBYTE,UWORD);
+extern void Voice_Stop_internal(SBYTE);
+extern int Voice_Stopped_internal(SBYTE);
+
+#ifdef __cplusplus
+}
+#endif
+
+/*========== SIMD mixing routines */
+#undef HAVE_ALTIVEC
+#undef HAVE_SSE2
+
+#if defined(__APPLE__) && !defined (__i386__)
+
+#if defined __VEC__ && !(defined(__GNUC__) && (__GNUC__ < 3))
+#define HAVE_ALTIVEC
+#endif // __VEC__
+
+#elif defined WIN32 || defined __WIN64 || (defined __APPLE__ && defined (__i386__) && defined __VEC__)
+
+// FIXME: emmintrin.h requires VC6 processor pack or VC2003+
+#define HAVE_SSE2
+
+/* Fixes couples warnings */
+#ifdef _MSC_VER
+#pragma warning(disable:4761)
+#pragma warning(disable:4391)
+#pragma warning(disable:4244)
+#endif
+#endif
+// TODO: Test for GCC Linux
+
+/*========== SIMD mixing helper functions =============*/
+
+#define IS_ALIGNED_16(ptr) (!(((int)(ptr)) & 15))
+
+/* Altivec helper function */
+#if defined HAVE_ALTIVEC
+
+#define simd_m128i vector signed int
+#define simd_m128 vector float
+
+#ifdef __GNUC__
+#include <ppc_intrinsics.h>
+#endif
+
+// Helper functions
+
+// Set single float across the four values
+static inline vector float vec_mul( const vector float a, const vector float b)
+{
+ return vec_madd(a, b, (const vector float)(0.f));
+}
+
+// Set single float across the four values
+static inline vector float vec_load_ps1(const float *pF )
+{
+ vector float data = vec_lde(0, pF);
+ return vec_splat(vec_perm(data, data, vec_lvsl(0, pF)), 0);
+}
+
+// Set vector to 0
+static inline const vector float vec_setzero()
+{
+ return (const vector float) (0.);
+}
+
+static inline vector signed char vec_set1_8(unsigned char splatchar)
+{
+ vector unsigned char splatmap = vec_lvsl(0, &splatchar);
+ vector unsigned char result = vec_lde(0, &splatchar);
+ splatmap = vec_splat(splatmap, 0);
+ return (vector signed char)vec_perm(result, result, splatmap);
+}
+
+#define PERM_A0 0x00,0x01,0x02,0x03
+#define PERM_A1 0x04,0x05,0x06,0x07
+#define PERM_A2 0x08,0x09,0x0A,0x0B
+#define PERM_A3 0x0C,0x0D,0x0E,0x0F
+#define PERM_B0 0x10,0x11,0x12,0x13
+#define PERM_B1 0x14,0x15,0x16,0x17
+#define PERM_B2 0x18,0x19,0x1A,0x1B
+#define PERM_B3 0x1C,0x1D,0x1E,0x1F
+
+// Equivalent to _mm_unpacklo_epi32
+static inline vector signed int vec_unpacklo(vector signed int a, vector signed int b)
+{
+ return vec_perm(a, b, (vector unsigned char)(PERM_A0,PERM_A1,PERM_B0,PERM_B1));
+}
+
+// Equivalent to _mm_srli_si128(a, 8) (without the zeroing in high part).
+static inline vector signed int vec_hiqq(vector signed int a)
+{
+ vector signed int b = vec_splat_s32(0);
+ return vec_perm(a, b, (vector unsigned char)(PERM_A2,PERM_A3,PERM_B2,PERM_B3));
+}
+
+// vec_sra is max +15. We have to do in two times ...
+#define EXTRACT_SAMPLE_SIMD_F(srce, var, size, mul) var = vec_mul(vec_ctf(vec_sra(vec_ld(0, (vector signed int*)(srce)), vec_splat_u32(BITSHIFT-size)),0), mul);
+#define EXTRACT_SAMPLE_SIMD_0(srce, var) var = vec_sra(vec_sra(vec_ld(0, (vector signed int*)(srce)), vec_splat_u32(15)), vec_splat_u32(BITSHIFT+16-15-0));
+#define EXTRACT_SAMPLE_SIMD_8(srce, var) var = vec_sra(vec_sra(vec_ld(0, (vector signed int*)(srce)), vec_splat_u32(15)), vec_splat_u32(BITSHIFT+16-15-8));
+#define EXTRACT_SAMPLE_SIMD_16(srce, var) var = vec_sra(vec_ld(0, (vector signed int*)(srce)), vec_splat_u32(BITSHIFT+16-16));
+#define PUT_SAMPLE_SIMD_W(dste, v1, v2) vec_st(vec_packs(v1, v2), 0, dste);
+#define PUT_SAMPLE_SIMD_B(dste, v1, v2, v3, v4) vec_st(vec_add(vec_packs((vector signed short)vec_packs(v1, v2), (vector signed short)vec_packs(v3, v4)), vec_set1_8(128)), 0, dste);
+#define PUT_SAMPLE_SIMD_F(dste, v1) vec_st(v1, 0, dste);
+#define LOAD_PS1_SIMD(ptr) vec_load_ps1(ptr)
+
+#elif defined HAVE_SSE2
+
+/* SSE2 helper function */
+
+#include <emmintrin.h>
+
+static __inline __m128i mm_hiqq(const __m128i a)
+{
+ return _mm_srli_si128(a, 8); // get the 64bit upper part. new 64bit upper is undefined (zeroed is fine).
+}
+
+/* 128-bit mixing macros */
+#define EXTRACT_SAMPLE_SIMD(srce, var, size) var = _mm_srai_epi32(_mm_load_si128((__m128i*)(srce)), BITSHIFT+16-size);
+#define EXTRACT_SAMPLE_SIMD_F(srce, var, size, mul) var = _mm_mul_ps(_mm_cvtepi32_ps(_mm_srai_epi32(_mm_load_si128((__m128i*)(srce)), BITSHIFT-size)), mul);
+#define EXTRACT_SAMPLE_SIMD_0(srce, var) EXTRACT_SAMPLE_SIMD(srce, var, 0)
+#define EXTRACT_SAMPLE_SIMD_8(srce, var) EXTRACT_SAMPLE_SIMD(srce, var, 8)
+#define EXTRACT_SAMPLE_SIMD_16(srce, var) EXTRACT_SAMPLE_SIMD(srce, var, 16)
+#define PUT_SAMPLE_SIMD_W(dste, v1, v2) _mm_store_si128((__m128i*)(dste), _mm_packs_epi32(v1, v2));
+#define PUT_SAMPLE_SIMD_B(dste, v1, v2, v3, v4) _mm_store_si128((__m128i*)(dste), _mm_add_epi8(_mm_packs_epi16(_mm_packs_epi32(v1, v2), _mm_packs_epi32(v3, v4)), _mm_set1_epi8(128)));
+#define PUT_SAMPLE_SIMD_F(dste, v1) _mm_store_ps((float*)(dste), v1);
+#define LOAD_PS1_SIMD(ptr) _mm_load_ps1(ptr)
+#define simd_m128i __m128i
+#define simd_m128 __m128
+
+#endif
+
+
+#endif
+
+/* ex:set ts=4: */
diff --git a/apps/plugins/mikmod/mikmod_supp.h b/apps/plugins/mikmod/mikmod_supp.h
new file mode 100644
index 0000000000..55963bf5d4
--- /dev/null
+++ b/apps/plugins/mikmod/mikmod_supp.h
@@ -0,0 +1,79 @@
+#include <string.h>
+#include "plugin.h"
+#include "inttypes.h"
+#include "codecs/lib/tlsf/src/tlsf.h"
+
+#ifndef MIKMOD_SUPP_H
+#define MIKMOD_SUPP_H
+
+#undef WIN32
+
+#ifndef NO_MMSUPP_DEFINES
+#define snprintf(...) rb->snprintf(__VA_ARGS__)
+#define fdprintf(...) rb->fdprintf(__VA_ARGS__)
+#define vsnprintf(...) rb->vsnprintf(__VA_ARGS__)
+
+#define srand(a) rb->srand(a)
+#define rand() rb->rand()
+#define qsort(a,b,c,d) rb->qsort(a,b,c,d)
+#define atoi(a) rb->atoi(a)
+
+#define strlen(a) rb->strlen(a)
+#define strcpy(a,b) rb->strcpy(a,b)
+#define strcat(a,b) rb->strcat(a,b)
+#define strncmp(a,b,c) rb->strncmp(a,b,c)
+#define strcasecmp(a,b) rb->strcasecmp(a,b)
+
+#undef open
+#define open(a,b) rb->open(a,b)
+#undef lseek
+#define lseek(a,b,c) rb->lseek(a,b,c)
+#undef close
+#define close(a) rb->close(a)
+#undef read
+#define read(a,b,c) rb->read(a,b,c)
+#undef write
+#define write(a,b,c) rb->write(a,b,c)
+#undef filesize
+#define filesize(a) rb->filesize(a)
+#endif
+
+#define malloc(x) tlsf_malloc(x)
+#define free(x) tlsf_free(x)
+#define realloc(x,y) tlsf_realloc(x,y)
+#define calloc(x,y) tlsf_calloc(x,y)
+
+#define strncat mmsupp_strncat
+#define printf mmsupp_printf
+#define sprintf mmsupp_sprintf
+
+#define fprintf(...)
+
+char* mmsupp_strncat(char *s1, const char *s2, size_t n);
+void mmsupp_printf(const char *fmt, ...);
+int mmsupp_sprintf(char *buf, const char *fmt, ... );
+
+extern const struct plugin_api * rb;
+
+
+#ifdef SIMULATOR
+#define SAMPLE_RATE SAMPR_44 /* Simulator requires 44100Hz */
+#else
+#if (HW_SAMPR_CAPS & SAMPR_CAP_22) /* use 22050Hz if we can */
+#define SAMPLE_RATE SAMPR_22 /* 22050 */
+#else
+#define SAMPLE_RATE SAMPR_44 /* 44100 */
+#endif
+#endif
+
+#define BUF_SIZE 4096*8
+#define NBUF 2
+
+/* LibMikMod defines */
+#define HAVE_SNPRINTF 1
+
+#ifndef INT_MAX
+#define INT_MAX 2147483647
+#endif
+
+#endif
diff --git a/apps/plugins/mikmod/mloader.c b/apps/plugins/mikmod/mloader.c
new file mode 100644
index 0000000000..7bce40578e
--- /dev/null
+++ b/apps/plugins/mikmod/mloader.c
@@ -0,0 +1,615 @@
+/* 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: mloader.c,v 1.3 2005/04/07 19:57:39 realtech Exp $
+
+ These routines are used to access the available module loaders
+
+==============================================================================*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+#include <string.h>
+
+#include "mikmod_internals.h"
+
+#ifdef SUNOS
+extern int fprintf(FILE *, const char *, ...);
+#endif
+
+MREADER *modreader;
+MODULE of;
+
+static MLOADER *firstloader=NULL;
+
+UWORD finetune[16]={
+ 8363,8413,8463,8529,8581,8651,8723,8757,
+ 7895,7941,7985,8046,8107,8169,8232,8280
+};
+
+MIKMODAPI CHAR* MikMod_InfoLoader(void)
+{
+ int len=0;
+ MLOADER *l;
+ CHAR *list=NULL;
+
+ MUTEX_LOCK(lists);
+ /* compute size of buffer */
+ for(l=firstloader;l;l=l->next) len+=1+(l->next?1:0)+strlen(l->version);
+
+ if(len)
+ if((list=MikMod_malloc(len*sizeof(CHAR)))) {
+ list[0]=0;
+ /* list all registered module loders */
+ for(l=firstloader;l;l=l->next)
+ sprintf(list,(l->next)?"%s%s\n":"%s%s",list,l->version);
+ }
+ MUTEX_UNLOCK(lists);
+ return list;
+}
+
+void _mm_registerloader(MLOADER* ldr)
+{
+ MLOADER *cruise=firstloader;
+
+ if(cruise) {
+ while(cruise->next) cruise = cruise->next;
+ cruise->next=ldr;
+ } else
+ firstloader=ldr;
+}
+
+MIKMODAPI void MikMod_RegisterLoader(struct MLOADER* ldr)
+{
+ /* if we try to register an invalid loader, or an already registered loader,
+ ignore this attempt */
+ if ((!ldr)||(ldr->next))
+ return;
+
+ MUTEX_LOCK(lists);
+ _mm_registerloader(ldr);
+ MUTEX_UNLOCK(lists);
+}
+
+int ReadComment(UWORD len)
+{
+ if(len) {
+ int i;
+
+ if(!(of.comment=(CHAR*)MikMod_malloc(len+1))) return 0;
+ _mm_read_UBYTES(of.comment,len,modreader);
+
+ /* translate IT linefeeds */
+ for(i=0;i<len;i++)
+ if(of.comment[i]=='\r') of.comment[i]='\n';
+
+ of.comment[len]=0; /* just in case */
+ }
+ if(!of.comment[0]) {
+ MikMod_free(of.comment);
+ of.comment=NULL;
+ }
+ return 1;
+}
+
+int ReadLinedComment(UWORD len,UWORD linelen)
+{
+ CHAR *tempcomment,*line,*storage;
+ UWORD total=0,t,lines;
+ int i;
+
+ lines = (len + linelen - 1) / linelen;
+ if (len) {
+ if(!(tempcomment=(CHAR*)MikMod_malloc(len+1))) return 0;
+ if(!(storage=(CHAR*)MikMod_malloc(linelen+1))) {
+ MikMod_free(tempcomment);
+ return 0;
+ }
+ memset(tempcomment, ' ', len);
+ _mm_read_UBYTES(tempcomment,len,modreader);
+
+ /* compute message length */
+ for(line=tempcomment,total=t=0;t<lines;t++,line+=linelen) {
+ for(i=linelen;(i>=0)&&(line[i]==' ');i--) line[i]=0;
+ for(i=0;i<linelen;i++) if (!line[i]) break;
+ total+=1+i;
+ }
+
+ if(total>lines) {
+ if(!(of.comment=(CHAR*)MikMod_malloc(total+1))) {
+ MikMod_free(storage);
+ MikMod_free(tempcomment);
+ return 0;
+ }
+
+ /* convert message */
+ for(line=tempcomment,t=0;t<lines;t++,line+=linelen) {
+ for(i=0;i<linelen;i++) if(!(storage[i]=line[i])) break;
+ storage[i]=0; /* if (i==linelen) */
+ strcat(of.comment,storage);strcat(of.comment,"\r");
+ }
+ MikMod_free(storage);
+ MikMod_free(tempcomment);
+ }
+ }
+ return 1;
+}
+
+int AllocPositions(int total)
+{
+ if(!total) {
+ _mm_errno=MMERR_NOT_A_MODULE;
+ return 0;
+ }
+ if(!(of.positions=MikMod_calloc(total,sizeof(UWORD)))) return 0;
+ return 1;
+}
+
+int AllocPatterns(void)
+{
+ int s,t,tracks = 0;
+
+ if((!of.numpat)||(!of.numchn)) {
+ _mm_errno=MMERR_NOT_A_MODULE;
+ return 0;
+ }
+ /* Allocate track sequencing array */
+ if(!(of.patterns=(UWORD*)MikMod_calloc((ULONG)(of.numpat+1)*of.numchn,sizeof(UWORD)))) return 0;
+ if(!(of.pattrows=(UWORD*)MikMod_calloc(of.numpat+1,sizeof(UWORD)))) return 0;
+
+ for(t=0;t<=of.numpat;t++) {
+ of.pattrows[t]=64;
+ for(s=0;s<of.numchn;s++)
+ of.patterns[(t*of.numchn)+s]=tracks++;
+ }
+
+ return 1;
+}
+
+int AllocTracks(void)
+{
+ if(!of.numtrk) {
+ _mm_errno=MMERR_NOT_A_MODULE;
+ return 0;
+ }
+ if(!(of.tracks=(UBYTE **)MikMod_calloc(of.numtrk,sizeof(UBYTE *)))) return 0;
+ return 1;
+}
+
+int AllocInstruments(void)
+{
+ int t,n;
+
+ if(!of.numins) {
+ _mm_errno=MMERR_NOT_A_MODULE;
+ return 0;
+ }
+ if(!(of.instruments=(INSTRUMENT*)MikMod_calloc(of.numins,sizeof(INSTRUMENT))))
+ return 0;
+
+ for(t=0;t<of.numins;t++) {
+ for(n=0;n<INSTNOTES;n++) {
+ /* Init note / sample lookup table */
+ of.instruments[t].samplenote[n] = n;
+ of.instruments[t].samplenumber[n] = t;
+ }
+ of.instruments[t].globvol = 64;
+ }
+ return 1;
+}
+
+int AllocSamples(void)
+{
+ UWORD u;
+
+ if(!of.numsmp) {
+ _mm_errno=MMERR_NOT_A_MODULE;
+ return 0;
+ }
+ if(!(of.samples=(SAMPLE*)MikMod_calloc(of.numsmp,sizeof(SAMPLE)))) return 0;
+
+ for(u=0;u<of.numsmp;u++) {
+ of.samples[u].panning = 128; /* center */
+ of.samples[u].handle = -1;
+ of.samples[u].globvol = 64;
+ of.samples[u].volume = 64;
+ }
+ return 1;
+}
+
+static int ML_LoadSamples(void)
+{
+ SAMPLE *s;
+ int u;
+
+ for(u=of.numsmp,s=of.samples;u;u--,s++)
+ if(s->length) SL_RegisterSample(s,MD_MUSIC,modreader);
+
+ return 1;
+}
+
+/* Creates a CSTR out of a character buffer of 'len' bytes, but strips any
+ terminating non-printing characters like 0, spaces etc. */
+CHAR *DupStr(CHAR* s,UWORD len,int strict)
+{
+ UWORD t;
+ CHAR *d=NULL;
+
+ /* Scan for last printing char in buffer [includes high ascii up to 254] */
+ while(len) {
+ if(s[len-1]>0x20) break;
+ len--;
+ }
+
+ /* Scan forward for possible NULL character */
+ if(strict) {
+ for(t=0;t<len;t++) if (!s[t]) break;
+ if (t<len) len=t;
+ }
+
+ /* When the buffer wasn't completely empty, allocate a cstring and copy the
+ buffer into that string, except for any control-chars */
+ if((d=(CHAR*)MikMod_malloc(sizeof(CHAR)*(len+1)))) {
+ for(t=0;t<len;t++) d[t]=(s[t]<32)?'.':s[t];
+ d[len]=0;
+ }
+ return d;
+}
+
+CHAR *StrDup(CHAR *s)
+{
+ size_t l = strlen(s) + 1;
+ CHAR *d = MikMod_malloc(l);
+ strcpy(d, s);
+ return d;
+}
+
+static void ML_XFreeSample(SAMPLE *s)
+{
+ if(s->handle>=0)
+ MD_SampleUnload(s->handle);
+ if(s->samplename) MikMod_free(s->samplename);
+}
+
+static void ML_XFreeInstrument(INSTRUMENT *i)
+{
+ if(i->insname) MikMod_free(i->insname);
+}
+
+static void ML_FreeEx(MODULE *mf)
+{
+ UWORD t;
+
+ if(mf->songname) MikMod_free(mf->songname);
+ if(mf->comment) MikMod_free(mf->comment);
+
+ if(mf->modtype) MikMod_free(mf->modtype);
+ if(mf->positions) MikMod_free(mf->positions);
+ if(mf->patterns) MikMod_free(mf->patterns);
+ if(mf->pattrows) MikMod_free(mf->pattrows);
+
+ if(mf->tracks) {
+ for(t=0;t<mf->numtrk;t++)
+ if(mf->tracks[t]) MikMod_free(mf->tracks[t]);
+ MikMod_free(mf->tracks);
+ }
+ if(mf->instruments) {
+ for(t=0;t<mf->numins;t++)
+ ML_XFreeInstrument(&mf->instruments[t]);
+ MikMod_free(mf->instruments);
+ }
+ if(mf->samples) {
+ for(t=0;t<mf->numsmp;t++)
+ if(mf->samples[t].length) ML_XFreeSample(&mf->samples[t]);
+ MikMod_free(mf->samples);
+ }
+ memset(mf,0,sizeof(MODULE));
+ if(mf!=&of) MikMod_free(mf);
+}
+
+static MODULE *ML_AllocUniMod(void)
+{
+ MODULE *mf;
+
+ return (mf=MikMod_malloc(sizeof(MODULE)));
+}
+
+void Player_Free_internal(MODULE *mf)
+{
+ if(mf) {
+ Player_Exit_internal(mf);
+ ML_FreeEx(mf);
+ }
+}
+
+MIKMODAPI void Player_Free(MODULE *mf)
+{
+ MUTEX_LOCK(vars);
+ Player_Free_internal(mf);
+ MUTEX_UNLOCK(vars);
+}
+
+static CHAR* Player_LoadTitle_internal(MREADER *reader)
+{
+ MLOADER *l;
+
+ modreader=reader;
+ _mm_errno = 0;
+ _mm_critical = 0;
+ _mm_iobase_setcur(modreader);
+
+ /* Try to find a loader that recognizes the module */
+ for(l=firstloader;l;l=l->next) {
+ _mm_rewind(modreader);
+ if(l->Test()) break;
+ }
+
+ if(!l) {
+ _mm_errno = MMERR_NOT_A_MODULE;
+ if(_mm_errorhandler) _mm_errorhandler();
+ return NULL;
+ }
+
+ return l->LoadTitle();
+}
+
+MIKMODAPI CHAR* Player_LoadTitleFP(int fp)
+{
+ CHAR* result=NULL;
+ MREADER* reader;
+
+ if(fp && (reader=_mm_new_file_reader(fp))) {
+ MUTEX_LOCK(lists);
+ result=Player_LoadTitle_internal(reader);
+ MUTEX_UNLOCK(lists);
+ _mm_delete_file_reader(reader);
+ }
+ return result;
+}
+
+MIKMODAPI CHAR* Player_LoadTitleMem(const char *buffer,int len)
+{
+ CHAR *result=NULL;
+ MREADER* reader;
+
+ if ((reader=_mm_new_mem_reader(buffer,len)))
+ {
+ MUTEX_LOCK(lists);
+ result=Player_LoadTitle_internal(reader);
+ MUTEX_UNLOCK(lists);
+ _mm_delete_mem_reader(reader);
+ }
+
+
+ return result;
+}
+
+MIKMODAPI CHAR* Player_LoadTitleGeneric(MREADER *reader)
+{
+ CHAR *result=NULL;
+
+ if (reader) {
+ MUTEX_LOCK(lists);
+ result=Player_LoadTitle_internal(reader);
+ MUTEX_UNLOCK(lists);
+ }
+ return result;
+}
+
+MIKMODAPI CHAR* Player_LoadTitle(CHAR* filename)
+{
+ CHAR* result=NULL;
+ int fp;
+ MREADER* reader;
+
+ if((fp=_mm_fopen(filename,"rb"))) {
+ if((reader=_mm_new_file_reader(fp))) {
+ MUTEX_LOCK(lists);
+ result=Player_LoadTitle_internal(reader);
+ MUTEX_UNLOCK(lists);
+ _mm_delete_file_reader(reader);
+ }
+ _mm_fclose(fp);
+ }
+ return result;
+}
+
+/* Loads a module given an reader */
+MODULE* Player_LoadGeneric_internal(MREADER *reader,int maxchan,int curious)
+{
+ int t;
+ MLOADER *l;
+ int ok;
+ MODULE *mf;
+
+ modreader = reader;
+ _mm_errno = 0;
+ _mm_critical = 0;
+ _mm_iobase_setcur(modreader);
+
+ /* Try to find a loader that recognizes the module */
+ for(l=firstloader;l;l=l->next) {
+ _mm_rewind(modreader);
+ if(l->Test()) break;
+ }
+
+ if(!l) {
+ _mm_errno = MMERR_NOT_A_MODULE;
+ if(_mm_errorhandler) _mm_errorhandler();
+ _mm_rewind(modreader);_mm_iobase_revert(modreader);
+ return NULL;
+ }
+
+ /* init unitrk routines */
+ if(!UniInit()) {
+ if(_mm_errorhandler) _mm_errorhandler();
+ _mm_rewind(modreader);_mm_iobase_revert(modreader);
+ return NULL;
+ }
+
+ /* init the module structure with vanilla settings */
+ memset(&of,0,sizeof(MODULE));
+ of.bpmlimit = 33;
+ of.initvolume = 128;
+ for (t = 0; t < UF_MAXCHAN; t++) of.chanvol[t] = 64;
+ for (t = 0; t < UF_MAXCHAN; t++)
+ of.panning[t] = ((t + 1) & 2) ? PAN_RIGHT : PAN_LEFT;
+
+ /* init module loader and load the header / patterns */
+ if (!l->Init || l->Init()) {
+ _mm_rewind(modreader);
+ ok = l->Load(curious);
+ if (ok) {
+ /* propagate inflags=flags for in-module samples */
+ for (t = 0; t < of.numsmp; t++)
+ if (of.samples[t].inflags == 0)
+ of.samples[t].inflags = of.samples[t].flags;
+ }
+ } else
+ ok = 0;
+
+ /* free loader and unitrk allocations */
+ if (l->Cleanup) l->Cleanup();
+ UniCleanup();
+
+ if(!ok) {
+ ML_FreeEx(&of);
+ if(_mm_errorhandler) _mm_errorhandler();
+ _mm_rewind(modreader);_mm_iobase_revert(modreader);
+ return NULL;
+ }
+
+ if(!ML_LoadSamples()) {
+ ML_FreeEx(&of);
+ if(_mm_errorhandler) _mm_errorhandler();
+ _mm_rewind(modreader);_mm_iobase_revert(modreader);
+ return NULL;
+ }
+
+ if(!(mf=ML_AllocUniMod())) {
+ ML_FreeEx(&of);
+ _mm_rewind(modreader);_mm_iobase_revert(modreader);
+ if(_mm_errorhandler) _mm_errorhandler();
+ return NULL;
+ }
+
+ /* If the module doesn't have any specific panning, create a
+ MOD-like panning, with the channels half-separated. */
+ if (!(of.flags & UF_PANNING))
+ for (t = 0; t < of.numchn; t++)
+ of.panning[t] = ((t + 1) & 2) ? PAN_HALFRIGHT : PAN_HALFLEFT;
+
+ /* Copy the static MODULE contents into the dynamic MODULE struct. */
+ memcpy(mf,&of,sizeof(MODULE));
+
+ if(maxchan>0) {
+ if(!(mf->flags&UF_NNA)&&(mf->numchn<maxchan))
+ maxchan = mf->numchn;
+ else
+ if((mf->numvoices)&&(mf->numvoices<maxchan))
+ maxchan = mf->numvoices;
+
+ if(maxchan<mf->numchn) mf->flags |= UF_NNA;
+
+ if(MikMod_SetNumVoices_internal(maxchan,-1)) {
+ _mm_iobase_revert(modreader);
+ Player_Free(mf);
+ return NULL;
+ }
+ }
+ if(SL_LoadSamples()) {
+ _mm_iobase_revert(modreader);
+ Player_Free_internal(mf);
+ return NULL;
+ }
+ if(Player_Init(mf)) {
+ _mm_iobase_revert(modreader);
+ Player_Free_internal(mf);
+ mf=NULL;
+ }
+ _mm_iobase_revert(modreader);
+ return mf;
+}
+
+MIKMODAPI MODULE* Player_LoadGeneric(MREADER *reader,int maxchan,int curious)
+{
+ MODULE* result;
+
+ MUTEX_LOCK(vars);
+ MUTEX_LOCK(lists);
+ result=Player_LoadGeneric_internal(reader,maxchan,curious);
+ MUTEX_UNLOCK(lists);
+ MUTEX_UNLOCK(vars);
+
+ return result;
+}
+
+MIKMODAPI MODULE* Player_LoadMem(const char *buffer,int len,int maxchan,int curious)
+{
+ MODULE* result=NULL;
+ MREADER* reader;
+
+ if ((reader=_mm_new_mem_reader(buffer, len))) {
+ result=Player_LoadGeneric(reader,maxchan,curious);
+ _mm_delete_mem_reader(reader);
+ }
+ return result;
+}
+
+/* Loads a module given a file pointer.
+ File is loaded from the current file seek position. */
+MIKMODAPI MODULE* Player_LoadFP(int fp,int maxchan,int curious)
+{
+ MODULE* result=NULL;
+ struct MREADER* reader=_mm_new_file_reader (fp);
+
+ if (reader) {
+ result=Player_LoadGeneric(reader,maxchan,curious);
+ _mm_delete_file_reader(reader);
+ }
+ return result;
+}
+
+/* Open a module via its filename. The loader will initialize the specified
+ song-player 'player'. */
+MIKMODAPI MODULE* Player_Load(CHAR* filename,int maxchan,int curious)
+{
+ int fp;
+ MODULE *mf=NULL;
+
+ if((fp=_mm_fopen(filename,"rb"))) {
+ mf=Player_LoadFP(fp,maxchan,curious);
+ _mm_fclose(fp);
+ }
+ return mf;
+}
+
+/* ex:set ts=4: */
diff --git a/apps/plugins/mikmod/mlreg.c b/apps/plugins/mikmod/mlreg.c
new file mode 100644
index 0000000000..e57e82553b
--- /dev/null
+++ b/apps/plugins/mikmod/mlreg.c
@@ -0,0 +1,66 @@
+/* MikMod sound library
+ (c) 1998, 1999 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: mlreg.c,v 1.2 2005/03/30 19:11:34 realtech Exp $
+
+ Routine for registering all loaders in libmikmod for the current platform.
+
+==============================================================================*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "mikmod_internals.h"
+
+void MikMod_RegisterAllLoaders_internal(void)
+{
+ _mm_registerloader(&load_669);
+ _mm_registerloader(&load_amf);
+ _mm_registerloader(&load_asy);
+ _mm_registerloader(&load_dsm);
+ _mm_registerloader(&load_far);
+ _mm_registerloader(&load_gdm);
+ _mm_registerloader(&load_gt2);
+ _mm_registerloader(&load_it);
+ _mm_registerloader(&load_imf);
+ _mm_registerloader(&load_mod);
+ _mm_registerloader(&load_med);
+ _mm_registerloader(&load_mtm);
+ _mm_registerloader(&load_okt);
+ _mm_registerloader(&load_s3m);
+ _mm_registerloader(&load_stm);
+ _mm_registerloader(&load_stx);
+ _mm_registerloader(&load_ult);
+ _mm_registerloader(&load_uni);
+ _mm_registerloader(&load_xm);
+
+ _mm_registerloader(&load_m15);
+}
+
+void MikMod_RegisterAllLoaders(void)
+{
+ MUTEX_LOCK(lists);
+ MikMod_RegisterAllLoaders_internal();
+ MUTEX_UNLOCK(lists);
+}
+/* ex:set ts=4: */
diff --git a/apps/plugins/mikmod/mlutil.c b/apps/plugins/mikmod/mlutil.c
new file mode 100644
index 0000000000..6d3a05f45d
--- /dev/null
+++ b/apps/plugins/mikmod/mlutil.c
@@ -0,0 +1,336 @@
+/* MikMod sound library
+ (c) 1998, 1999, 2000, 2001 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: mlutil.c,v 1.3 2007/12/06 17:43:10 denis111 Exp $
+
+ Utility functions for the module loader
+
+==============================================================================*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+#include <string.h>
+
+#include "mikmod_internals.h"
+
+#ifdef SUNOS
+extern int fprintf(FILE *, const char *, ...);
+#endif
+
+/*========== Shared tracker identifiers */
+
+CHAR *STM_Signatures[STM_NTRACKERS] = {
+ "!Scream!",
+ "BMOD2STM",
+ "WUZAMOD!"
+};
+
+CHAR *STM_Version[STM_NTRACKERS] = {
+ "Screamtracker 2",
+ "Converted by MOD2STM (STM format)",
+ "Wuzamod (STM format)"
+};
+
+/*========== Shared loader variables */
+
+SBYTE remap[UF_MAXCHAN]; /* for removing empty channels */
+UBYTE* poslookup=NULL; /* lookup table for pattern jumps after blank
+ pattern removal */
+UWORD poslookupcnt;
+UWORD* origpositions=NULL;
+
+int filters; /* resonant filters in use */
+UBYTE activemacro; /* active midi macro number for Sxx,xx<80h */
+UBYTE filtermacros[UF_MAXMACRO]; /* midi macro settings */
+FILTER filtersettings[UF_MAXFILTER]; /* computed filter settings */
+
+/*========== Linear periods stuff */
+
+int* noteindex=NULL; /* remap value for linear period modules */
+static int noteindexcount=0;
+
+int *AllocLinear(void)
+{
+ if(of.numsmp>noteindexcount) {
+ noteindexcount=of.numsmp;
+ noteindex=MikMod_realloc(noteindex,noteindexcount*sizeof(int));
+ }
+ return noteindex;
+}
+
+void FreeLinear(void)
+{
+ if(noteindex) {
+ MikMod_free(noteindex);
+ noteindex=NULL;
+ }
+ noteindexcount=0;
+}
+
+int speed_to_finetune(ULONG speed,int sample)
+{
+ int ctmp=0,tmp,note=1,finetune=0;
+
+ speed>>=1;
+ while((tmp=getfrequency(of.flags,getlinearperiod(note<<1,0)))<speed) {
+ ctmp=tmp;
+ note++;
+ }
+
+ if(tmp!=speed) {
+ if((tmp-speed)<(speed-ctmp))
+ while(tmp>speed)
+ tmp=getfrequency(of.flags,getlinearperiod(note<<1,--finetune));
+ else {
+ note--;
+ while(ctmp<speed)
+ ctmp=getfrequency(of.flags,getlinearperiod(note<<1,++finetune));
+ }
+ }
+
+ noteindex[sample]=note-4*OCTAVE;
+ return finetune;
+}
+
+/*========== Order stuff */
+
+/* handles S3M and IT orders */
+void S3MIT_CreateOrders(int curious)
+{
+ int t;
+
+ of.numpos = 0;
+ memset(of.positions,0,poslookupcnt*sizeof(UWORD));
+ memset(poslookup,-1,256);
+ for(t=0;t<poslookupcnt;t++) {
+ int order=origpositions[t];
+ if(order==255) order=LAST_PATTERN;
+ of.positions[of.numpos]=order;
+ poslookup[t]=of.numpos; /* bug fix for freaky S3Ms / ITs */
+ if(origpositions[t]<254) of.numpos++;
+ else
+ /* end of song special order */
+ if((order==LAST_PATTERN)&&(!(curious--))) break;
+ }
+}
+
+/*========== Effect stuff */
+
+/* handles S3M and IT effects */
+void S3MIT_ProcessCmd(UBYTE cmd,UBYTE inf,unsigned int flags)
+{
+ UBYTE hi,lo;
+
+ lo=inf&0xf;
+ hi=inf>>4;
+
+ /* process S3M / IT specific command structure */
+
+ if(cmd!=255) {
+ switch(cmd) {
+ case 1: /* Axx set speed to xx */
+ UniEffect(UNI_S3MEFFECTA,inf);
+ break;
+ case 2: /* Bxx position jump */
+ if (inf<poslookupcnt) {
+ /* switch to curious mode if necessary, for example
+ sympex.it, deep joy.it */
+ if(((SBYTE)poslookup[inf]<0)&&(origpositions[inf]!=255))
+ S3MIT_CreateOrders(1);
+
+ if(!((SBYTE)poslookup[inf]<0))
+ UniPTEffect(0xb,poslookup[inf]);
+ }
+ break;
+ case 3: /* Cxx patternbreak to row xx */
+ if ((flags & S3MIT_OLDSTYLE) && !(flags & S3MIT_IT))
+ UniPTEffect(0xd,(inf>>4)*10+(inf&0xf));
+ else
+ UniPTEffect(0xd,inf);
+ 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 */
+ if (flags & S3MIT_OLDSTYLE)
+ UniPTEffect(0x3,inf);
+ else
+ UniEffect(UNI_ITEFFECTG,inf);
+ break;
+ case 8: /* Hxy vibrato */
+ if (flags & S3MIT_OLDSTYLE)
+ UniPTEffect(0x4,inf);
+ else
+ UniEffect(UNI_ITEFFECTH,inf);
+ break;
+ case 9: /* Ixy tremor, ontime x, offtime y */
+ if (flags & S3MIT_OLDSTYLE)
+ UniEffect(UNI_S3MEFFECTI,inf);
+ else
+ UniEffect(UNI_ITEFFECTI,inf);
+ break;
+ case 0xa: /* Jxy arpeggio */
+ UniPTEffect(0x0,inf);
+ break;
+ case 0xb: /* Kxy Dual command H00 & Dxy */
+ if (flags & S3MIT_OLDSTYLE)
+ UniPTEffect(0x4,0);
+ else
+ UniEffect(UNI_ITEFFECTH,0);
+ UniEffect(UNI_S3MEFFECTD,inf);
+ break;
+ case 0xc: /* Lxy Dual command G00 & Dxy */
+ if (flags & S3MIT_OLDSTYLE)
+ UniPTEffect(0x3,0);
+ else
+ UniEffect(UNI_ITEFFECTG,0);
+ UniEffect(UNI_S3MEFFECTD,inf);
+ break;
+ case 0xd: /* Mxx Set Channel Volume */
+ UniEffect(UNI_ITEFFECTM,inf);
+ break;
+ case 0xe: /* Nxy Slide Channel Volume */
+ UniEffect(UNI_ITEFFECTN,inf);
+ break;
+ case 0xf: /* Oxx set sampleoffset xx00h */
+ UniPTEffect(0x9,inf);
+ break;
+ case 0x10: /* Pxy Slide Panning Commands */
+ UniEffect(UNI_ITEFFECTP,inf);
+ break;
+ case 0x11: /* Qxy Retrig (+volumeslide) */
+ UniWriteByte(UNI_S3MEFFECTQ);
+ if(inf && !lo && !(flags & S3MIT_OLDSTYLE))
+ UniWriteByte(1);
+ else
+ UniWriteByte(inf);
+ break;
+ case 0x12: /* Rxy tremolo speed x, depth y */
+ UniEffect(UNI_S3MEFFECTR,inf);
+ break;
+ case 0x13: /* Sxx special commands */
+ if (inf>=0xf0) {
+ /* change resonant filter settings if necessary */
+ if((filters)&&((inf&0xf)!=activemacro)) {
+ activemacro=inf&0xf;
+ for(inf=0;inf<0x80;inf++)
+ filtersettings[inf].filter=filtermacros[activemacro];
+ }
+ } else {
+ /* Scream Tracker does not have samples larger than
+ 64 Kb, thus doesn't need the SAx effect */
+ if ((flags & S3MIT_SCREAM) && ((inf & 0xf0) == 0xa0))
+ break;
+
+ UniEffect(UNI_ITEFFECTS0,inf);
+ }
+ break;
+ case 0x14: /* Txx tempo */
+ if(inf>=0x20)
+ UniEffect(UNI_S3MEFFECTT,inf);
+ else {
+ if(!(flags & S3MIT_OLDSTYLE))
+ /* IT Tempo slide */
+ UniEffect(UNI_ITEFFECTT,inf);
+ }
+ break;
+ case 0x15: /* Uxy Fine Vibrato speed x, depth y */
+ if(flags & S3MIT_OLDSTYLE)
+ UniEffect(UNI_S3MEFFECTU,inf);
+ else
+ UniEffect(UNI_ITEFFECTU,inf);
+ break;
+ case 0x16: /* Vxx Set Global Volume */
+ UniEffect(UNI_XMEFFECTG,inf);
+ break;
+ case 0x17: /* Wxy Global Volume Slide */
+ UniEffect(UNI_ITEFFECTW,inf);
+ break;
+ case 0x18: /* Xxx amiga command 8xx */
+ if(flags & S3MIT_OLDSTYLE) {
+ if(inf>128)
+ UniEffect(UNI_ITEFFECTS0,0x91); /* surround */
+ else
+ UniPTEffect(0x8,(inf==128)?255:(inf<<1));
+ } else
+ UniPTEffect(0x8,inf);
+ break;
+ case 0x19: /* Yxy Panbrello speed x, depth y */
+ UniEffect(UNI_ITEFFECTY,inf);
+ break;
+ case 0x1a: /* Zxx midi/resonant filters */
+ if(filtersettings[inf].filter) {
+ UniWriteByte(UNI_ITEFFECTZ);
+ UniWriteByte(filtersettings[inf].filter);
+ UniWriteByte(filtersettings[inf].inf);
+ }
+ break;
+ }
+ }
+}
+
+/*========== Unitrk stuff */
+
+/* Generic effect writing routine */
+void UniEffect(UWORD eff,UWORD dat)
+{
+ if((!eff)||(eff>=UNI_LAST)) return;
+
+ UniWriteByte(eff);
+ if(unioperands[eff]==2)
+ UniWriteWord(dat);
+ else
+ UniWriteByte(dat);
+}
+
+/* Appends UNI_PTEFFECTX opcode to the unitrk stream. */
+void UniPTEffect(UBYTE eff, UBYTE dat)
+{
+#ifdef MIKMOD_DEBUG
+ if (eff>=0x10)
+ fprintf(stderr,"UniPTEffect called with incorrect eff value %d\n",eff);
+ else
+#endif
+ if((eff)||(dat)||(of.flags&UF_ARPMEM)) UniEffect(UNI_PTEFFECT0+eff,dat);
+}
+
+/* Appends UNI_VOLEFFECT + effect/dat to unistream. */
+void UniVolEffect(UWORD eff,UBYTE dat)
+{
+ if((eff)||(dat)) { /* don't write empty effect */
+ UniWriteByte(UNI_VOLEFFECTS);
+ UniWriteByte(eff);UniWriteByte(dat);
+ }
+}
+
+/* ex:set ts=4: */
diff --git a/apps/plugins/mikmod/mmalloc.c b/apps/plugins/mikmod/mmalloc.c
new file mode 100644
index 0000000000..7d505dff93
--- /dev/null
+++ b/apps/plugins/mikmod/mmalloc.c
@@ -0,0 +1,179 @@
+/* MikMod sound library
+ (c) 1998, 1999 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: mmalloc.c,v 1.3 2007/12/03 20:42:58 denis111 Exp $
+
+ Dynamic memory routines
+
+==============================================================================*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "mikmod_internals.h"
+
+#define ALIGN_STRIDE 16
+
+static void * align_pointer(char *ptr, size_t stride)
+{
+ char *pptr = ptr + sizeof(void*);
+ char *fptr;
+ size_t err = ((size_t)pptr)&(stride-1);
+ if (err)
+ fptr = pptr + (stride - err);
+ else
+ fptr = pptr;
+ *(size_t*)(fptr - sizeof(void*)) = (size_t)ptr;
+ return fptr;
+}
+
+static void *get_pointer(void *data)
+{
+ unsigned char *_pptr = (unsigned char*)data - sizeof(void*);
+ size_t _ptr = *(size_t*)_pptr;
+ return (void*)_ptr;
+}
+
+
+void* MikMod_realloc(void *data, size_t size)
+{
+ return realloc(data, size);
+
+#if 0
+ if (data)
+ {
+#if defined __MACH__
+ void *d = realloc(data, size);
+ if (d)
+ {
+ return d;
+ }
+ return 0;
+#elif (defined _WIN32 || defined _WIN64) && !defined(_WIN32_WCE)
+ return _aligned_realloc(data, size, ALIGN_STRIDE);
+#else
+ unsigned char *newPtr = (unsigned char *)realloc(get_pointer(data), size + ALIGN_STRIDE + sizeof(void*));
+ return align_pointer(newPtr, ALIGN_STRIDE);
+#endif
+ }
+ return MikMod_malloc(size);
+#endif
+}
+
+
+/* Same as malloc, but sets error variable _mm_error when fails. Returns a 16-byte aligned pointer */
+void* MikMod_malloc(size_t size)
+{
+ void *d;
+ if(!(d=calloc(1,size))) {
+ _mm_errno = MMERR_OUT_OF_MEMORY;
+ if(_mm_errorhandler) _mm_errorhandler();
+ }
+ return d;
+
+#if 0
+#if defined __MACH__
+ void *d = calloc(1, size);
+ if (d)
+ {
+ return d;
+ }
+ return 0;
+#elif (defined _WIN32 || defined _WIN64) && !defined(_WIN32_WCE)
+ void * d = _aligned_malloc(size, ALIGN_STRIDE);
+ if (d)
+ {
+ ZeroMemory(d, size);
+ return d;
+ }
+ return 0;
+#else
+ void *d = calloc(1, size + ALIGN_STRIDE + sizeof(void*));
+
+ if(!d) {
+ _mm_errno = MMERR_OUT_OF_MEMORY;
+ if(_mm_errorhandler) _mm_errorhandler();
+ }
+ return align_pointer(d, ALIGN_STRIDE);
+#endif
+#endif
+}
+
+/* Same as calloc, but sets error variable _mm_error when fails */
+void* MikMod_calloc(size_t nitems,size_t size)
+{
+ void *d;
+
+ if(!(d=calloc(nitems,size))) {
+ _mm_errno = MMERR_OUT_OF_MEMORY;
+ if(_mm_errorhandler) _mm_errorhandler();
+ }
+ return d;
+
+#if 0
+#if defined __MACH__
+ void *d = calloc(nitems, size);
+ if (d)
+ {
+ return d;
+ }
+ return 0;
+#elif (defined _WIN32 || defined _WIN64) && !defined(_WIN32_WCE)
+ void * d = _aligned_malloc(size * nitems, ALIGN_STRIDE);
+ if (d)
+ {
+ ZeroMemory(d, size * nitems);
+ return d;
+ }
+ return 0;
+#else
+ void *d = calloc(nitems, size + ALIGN_STRIDE + sizeof(void*));
+
+ if(!d) {
+ _mm_errno = MMERR_OUT_OF_MEMORY;
+ if(_mm_errorhandler) _mm_errorhandler();
+ }
+ return align_pointer(d, ALIGN_STRIDE);
+#endif
+#endif
+}
+
+void MikMod_free(void *data)
+{
+ free(data);
+
+#if 0
+ if (data)
+ {
+#if defined __MACH__
+ free(data);
+#elif (defined _WIN32 || defined _WIN64) && !defined(_WIN32_WCE)
+ _aligned_free(data);
+#else
+ free(get_pointer(data));
+#endif
+ }
+#endif
+}
+
+/* ex:set ts=4: */
diff --git a/apps/plugins/mikmod/mmerror.c b/apps/plugins/mikmod/mmerror.c
new file mode 100644
index 0000000000..bd703f6c26
--- /dev/null
+++ b/apps/plugins/mikmod/mmerror.c
@@ -0,0 +1,213 @@
+/* MikMod sound library
+ (c) 1998, 1999, 2000 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: mmerror.c,v 1.2 2005/03/30 19:10:41 realtech Exp $
+
+ Error handling functions.
+ Register an error handler with _mm_RegisterErrorHandler() and you're all set.
+
+==============================================================================*/
+
+/*
+
+ The global variables _mm_errno, and _mm_critical are set before the error
+ handler in called. See below for the values of these variables.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "mikmod_internals.h"
+
+CHAR *_mm_errmsg[MMERR_MAX+1] =
+{
+/* No error */
+
+ "No error",
+
+/* Generic errors */
+
+ "Could not open requested file",
+ "Out of memory",
+ "Dynamic linking failed",
+
+/* Sample errors */
+
+ "Out of memory to load sample",
+ "Out of sample handles to load sample",
+ "Sample format not recognized",
+
+/* Module errors */
+
+ "Failure loading module pattern",
+ "Failure loading module track",
+ "Failure loading module header",
+ "Failure loading sampleinfo",
+ "Module format not recognized",
+ "Module sample format not recognized",
+ "Synthsounds not supported in MED files",
+ "Compressed sample is invalid",
+
+/* Driver errors: */
+
+ "Sound device not detected",
+ "Device number out of range",
+ "Software mixer failure",
+ "Could not open sound device",
+ "This driver supports 8 bit linear output only",
+ "This driver supports 16 bit linear output only",
+ "This driver supports stereo output only",
+ "This driver supports uLaw output (8 bit mono, 8 kHz) only",
+ "Unable to set non-blocking mode for audio device",
+
+/* AudioFile driver errors */
+
+ "Cannot find suitable AudioFile audio port",
+
+/* AIX driver errors */
+
+ "Configuration (init step) of audio device failed",
+ "Configuration (control step) of audio device failed",
+ "Configuration (start step) of audio device failed",
+
+/* ALSA driver errors */
+
+/* EsounD driver errors */
+
+/* Ultrasound driver errors */
+
+ "Ultrasound driver only works in 16 bit stereo 44 KHz",
+ "Ultrasound card could not be reset",
+ "Could not start Ultrasound timer",
+
+/* HP driver errors */
+
+ "Unable to select 16bit-linear sample format",
+ "Could not select requested sample-rate",
+ "Could not select requested number of channels",
+ "Unable to select audio output",
+ "Unable to get audio description",
+ "Could not set transmission buffer size",
+
+/* Open Sound System driver errors */
+
+ "Could not set fragment size",
+ "Could not set sample size",
+ "Could not set mono/stereo setting",
+ "Could not set sample rate",
+
+/* SGI driver errors */
+
+ "Unsupported sample rate",
+ "Hardware does not support 16 bit sound",
+ "Hardware does not support 8 bit sound",
+ "Hardware does not support stereo sound",
+ "Hardware does not support mono sound",
+
+/* Sun driver errors */
+
+ "Sound device initialization failed",
+
+/* OS/2 drivers errors */
+
+ "Could not set mixing parameters",
+ "Could not create playback semaphores",
+ "Could not create playback timer",
+ "Could not create playback thread",
+
+/* DirectSound driver errors */
+
+ "Could not set playback priority",
+ "Could not create playback buffers",
+ "Could not set playback format",
+ "Could not register callback",
+ "Could not register event",
+ "Could not create playback thread",
+ "Could not initialize playback thread",
+
+/* Windows Multimedia API driver errors */
+
+ "Invalid device handle",
+ "The resource is already allocated",
+ "Invalid device identifier",
+ "Unsupported output format",
+ "Unknown error",
+
+/* Macintosh driver errors */
+
+ "Unsupported sample rate",
+ "Could not start playback",
+
+/* MacOS X/Darwin driver errors */
+
+ "Unknown device",
+ "Bad property",
+ "Could not set playback format",
+ "Could not set mono/stereo setting",
+ "Could not create playback buffers",
+ "Could not create playback thread",
+ "Could not start audio device",
+ "Could not create buffer thread",
+
+/* DOS driver errors */
+
+ "WSS_STARTDMA",
+ "SB_STARTDMA",
+
+/* Invalid error */
+
+ "Invalid error code"
+};
+
+MIKMODAPI char *MikMod_strerror(int code)
+{
+ if ((code<0)||(code>MMERR_MAX)) code=MMERR_MAX+1;
+ return _mm_errmsg[code];
+}
+
+/* User installed error callback */
+MikMod_handler_t _mm_errorhandler = NULL;
+MIKMODAPI int _mm_errno = 0;
+MIKMODAPI int _mm_critical = 0;
+
+MikMod_handler_t _mm_registererrorhandler(MikMod_handler_t proc)
+{
+ MikMod_handler_t oldproc=_mm_errorhandler;
+
+ _mm_errorhandler = proc;
+ return oldproc;
+}
+
+MIKMODAPI MikMod_handler_t MikMod_RegisterErrorHandler(MikMod_handler_t proc)
+{
+ MikMod_handler_t result;
+
+ MUTEX_LOCK(vars);
+ result=_mm_registererrorhandler(proc);
+ MUTEX_UNLOCK(vars);
+
+ return result;
+}
+
+/* ex:set ts=4: */
diff --git a/apps/plugins/mikmod/mmio.c b/apps/plugins/mikmod/mmio.c
new file mode 100644
index 0000000000..344833e632
--- /dev/null
+++ b/apps/plugins/mikmod/mmio.c
@@ -0,0 +1,517 @@
+/* MikMod sound library
+ (c) 1998, 1999, 2000 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: mmio.c,v 1.3 2005/03/30 19:10:58 realtech Exp $
+
+ Portable file I/O routines
+
+==============================================================================*/
+
+/*
+
+ The way this module works:
+
+ - _mm_fopen will call the errorhandler [see mmerror.c] in addition to
+ setting _mm_errno on exit.
+ - _mm_iobase is for internal use. It is used by Player_LoadFP to
+ ensure that it works properly with wad files.
+ - _mm_read_I_* and _mm_read_M_* differ : the first is for reading data
+ written by a little endian (intel) machine, and the second is for reading
+ big endian (Mac, RISC, Alpha) machine data.
+ - _mm_write functions work the same as the _mm_read functions.
+ - _mm_read_string is for reading binary strings. It is basically the same
+ as an fread of bytes.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#include "mikmod.h"
+#include "mikmod_internals.h"
+
+#ifdef SUNOS
+extern int fclose(FILE *);
+extern int fgetc(FILE *);
+extern int fputc(int, FILE *);
+extern size_t fread(void *, size_t, size_t, FILE *);
+extern int fseek(FILE *, long, int);
+extern size_t fwrite(const void *, size_t, size_t, FILE *);
+#endif
+
+#define COPY_BUFSIZE 1024
+
+/* some prototypes */
+static int _mm_MemReader_Eof(MREADER* reader);
+static int _mm_MemReader_Read(MREADER* reader,void* ptr,size_t size);
+static int _mm_MemReader_Get(MREADER* reader);
+static int _mm_MemReader_Seek(MREADER* reader,long offset,int whence);
+static long _mm_MemReader_Tell(MREADER* reader);
+
+//static long _mm_iobase=0,temp_iobase=0;
+
+int _mm_fopen(CHAR* fname,CHAR* attrib)
+{
+ int fp;
+
+ //if(!(fp=fopen(fname,attrib))) {
+ // _mm_errno = MMERR_OPENING_FILE;
+ // if(_mm_errorhandler) _mm_errorhandler();
+ //}
+ fp = open(fname, O_RDONLY);
+ if( fp < 0 ) {
+ _mm_errno = MMERR_OPENING_FILE;
+ if(_mm_errorhandler) _mm_errorhandler();
+ }
+ return fp;
+}
+
+int _mm_FileExists(CHAR* fname)
+{
+ int fp;
+
+ //if(!(fp=fopen(fname,"r"))) return 0;
+ //fclose(fp);
+ fp = open(fname, O_RDONLY);
+ if ( fp < 0 ) return 0;
+ close(fp);
+
+ return 1;
+}
+
+int _mm_fclose(int fp)
+{
+ //return fclose(fp);
+ return close(fp);
+}
+
+/* Sets the current file-position as the new iobase */
+void _mm_iobase_setcur(MREADER* reader)
+{
+ reader->prev_iobase=reader->iobase; /* store old value in case of revert */
+ reader->iobase=reader->Tell(reader);
+}
+
+/* Reverts to the last known iobase value. */
+void _mm_iobase_revert(MREADER* reader)
+{
+ reader->iobase=reader->prev_iobase;
+}
+
+/*========== File Reader */
+
+typedef struct MFILEREADER {
+ MREADER core;
+ int file;
+} MFILEREADER;
+
+static int _mm_FileReader_Eof(MREADER* reader)
+{
+ //return feof(((MFILEREADER*)reader)->file);
+ int size = filesize(((MFILEREADER*)reader)->file);
+ int offset = lseek(((MFILEREADER*)reader)->file, 0, SEEK_CUR);
+ return offset < 0;
+ return (size <= 0 || offset < 0 || offset >= size) ? 1 : 0;
+}
+
+static int _mm_FileReader_Read(MREADER* reader,void* ptr,size_t size)
+{
+ //return !!fread(ptr,size,1,((MFILEREADER*)reader)->file);
+ return read(((MFILEREADER*)reader)->file, ptr, size);
+}
+
+static int _mm_FileReader_Get(MREADER* reader)
+{
+ //return fgetc(((MFILEREADER*)reader)->file);
+ unsigned char c;
+ if ( read(((MFILEREADER*)reader)->file, &c, 1) )
+ return c;
+ else
+ return EOF;
+}
+
+static int _mm_FileReader_Seek(MREADER* reader,long offset,int whence)
+{
+ //return fseek(((MFILEREADER*)reader)->file,
+ // (whence==SEEK_SET)?offset+reader->iobase:offset,whence);
+ return lseek(((MFILEREADER*)reader)->file,
+ (whence==SEEK_SET)?offset+reader->iobase:offset,whence);
+}
+
+static long _mm_FileReader_Tell(MREADER* reader)
+{
+ //return ftell(((MFILEREADER*)reader)->file)-reader->iobase;
+ return lseek( (((MFILEREADER*)reader)->file)-reader->iobase, 0, SEEK_CUR );
+}
+
+MREADER *_mm_new_file_reader(int fp)
+{
+ MFILEREADER* reader=(MFILEREADER*)MikMod_malloc(sizeof(MFILEREADER));
+ if (reader) {
+ reader->core.Eof =&_mm_FileReader_Eof;
+ reader->core.Read=&_mm_FileReader_Read;
+ reader->core.Get =&_mm_FileReader_Get;
+ reader->core.Seek=&_mm_FileReader_Seek;
+ reader->core.Tell=&_mm_FileReader_Tell;
+ reader->file=fp;
+ }
+ return (MREADER*)reader;
+}
+
+void _mm_delete_file_reader (MREADER* reader)
+{
+ if(reader) MikMod_free(reader);
+}
+
+/*========== File Writer */
+
+typedef struct MFILEWRITER {
+ MWRITER core;
+ int file;
+} MFILEWRITER;
+
+static int _mm_FileWriter_Seek(MWRITER* writer,long offset,int whence)
+{
+ //return fseek(((MFILEWRITER*)writer)->file,offset,whence);
+ return lseek(((MFILEREADER*)writer)->file,offset,whence);
+}
+
+static long _mm_FileWriter_Tell(MWRITER* writer)
+{
+ //return ftell(((MFILEWRITER*)writer)->file);
+ return lseek(((MFILEWRITER*)writer)->file, 0, SEEK_CUR);
+}
+
+static int _mm_FileWriter_Write(MWRITER* writer,void* ptr,size_t size)
+{
+ //return (fwrite(ptr,size,1,((MFILEWRITER*)writer)->file)==size);
+ return (write(ptr,size,((MFILEWRITER*)writer)->file)==size);
+}
+
+static int _mm_FileWriter_Put(MWRITER* writer,int value)
+{
+ //return fputc(value,((MFILEWRITER*)writer)->file);
+ return 1; // TODO
+}
+
+MWRITER *_mm_new_file_writer(int fp)
+{
+ MFILEWRITER* writer=(MFILEWRITER*)MikMod_malloc(sizeof(MFILEWRITER));
+ if (writer) {
+ writer->core.Seek =&_mm_FileWriter_Seek;
+ writer->core.Tell =&_mm_FileWriter_Tell;
+ writer->core.Write=&_mm_FileWriter_Write;
+ writer->core.Put =&_mm_FileWriter_Put;
+ writer->file=fp;
+ }
+ return (MWRITER*) writer;
+}
+
+void _mm_delete_file_writer (MWRITER* writer)
+{
+ if(writer) MikMod_free (writer);
+}
+
+/*========== Memory Reader */
+
+
+typedef struct MMEMREADER {
+ MREADER core;
+ const void *buffer;
+ long len;
+ long pos;
+} MMEMREADER;
+
+void _mm_delete_mem_reader(MREADER* reader)
+{
+ if (reader) { MikMod_free(reader); }
+}
+
+MREADER *_mm_new_mem_reader(const void *buffer, int len)
+{
+ MMEMREADER* reader=(MMEMREADER*)MikMod_malloc(sizeof(MMEMREADER));
+ if (reader)
+ {
+ reader->core.Eof =&_mm_MemReader_Eof;
+ reader->core.Read=&_mm_MemReader_Read;
+ reader->core.Get =&_mm_MemReader_Get;
+ reader->core.Seek=&_mm_MemReader_Seek;
+ reader->core.Tell=&_mm_MemReader_Tell;
+ reader->buffer = buffer;
+ reader->len = len;
+ reader->pos = 0;
+ }
+ return (MREADER*)reader;
+}
+
+static int _mm_MemReader_Eof(MREADER* reader)
+{
+ if (!reader) { return 1; }
+ if ( ((MMEMREADER*)reader)->pos > ((MMEMREADER*)reader)->len ) {
+ return 1;
+ }
+ return 0;
+}
+
+static int _mm_MemReader_Read(MREADER* reader,void* ptr,size_t size)
+{
+ unsigned char *d=ptr;
+ const unsigned char *s;
+
+ if (!reader) { return 0; }
+
+ if (reader->Eof(reader)) { return 0; }
+
+ s = ((MMEMREADER*)reader)->buffer;
+ s += ((MMEMREADER*)reader)->pos;
+
+ if ( ((MMEMREADER*)reader)->pos + size > ((MMEMREADER*)reader)->len)
+ {
+ ((MMEMREADER*)reader)->pos = ((MMEMREADER*)reader)->len;
+ return 0; /* not enough remaining bytes */
+ }
+
+ ((MMEMREADER*)reader)->pos += (long)size;
+
+ while (size--)
+ {
+ *d = *s;
+ s++;
+ d++;
+ }
+
+ return 1;
+}
+
+static int _mm_MemReader_Get(MREADER* reader)
+{
+ int pos;
+
+ if (reader->Eof(reader)) { return 0; }
+
+ pos = ((MMEMREADER*)reader)->pos;
+ ((MMEMREADER*)reader)->pos++;
+
+ return ((unsigned char*)(((MMEMREADER*)reader)->buffer))[pos];
+}
+
+static int _mm_MemReader_Seek(MREADER* reader,long offset,int whence)
+{
+ if (!reader) { return -1; }
+
+ switch(whence)
+ {
+ case SEEK_CUR:
+ ((MMEMREADER*)reader)->pos += offset;
+ break;
+ case SEEK_SET:
+ ((MMEMREADER*)reader)->pos = offset;
+ break;
+ case SEEK_END:
+ ((MMEMREADER*)reader)->pos = ((MMEMREADER*)reader)->len - offset - 1;
+ break;
+ }
+ if ( ((MMEMREADER*)reader)->pos < 0) { ((MMEMREADER*)reader)->pos = 0; }
+ if ( ((MMEMREADER*)reader)->pos > ((MMEMREADER*)reader)->len ) {
+ ((MMEMREADER*)reader)->pos = ((MMEMREADER*)reader)->len;
+ }
+ return 0;
+}
+
+static long _mm_MemReader_Tell(MREADER* reader)
+{
+ if (reader) {
+ return ((MMEMREADER*)reader)->pos;
+ }
+ return 0;
+}
+
+/*========== Write functions */
+
+void _mm_write_string(CHAR* data,MWRITER* writer)
+{
+ if(data)
+ _mm_write_UBYTES(data,strlen(data),writer);
+}
+
+void _mm_write_M_UWORD(UWORD data,MWRITER* writer)
+{
+ _mm_write_UBYTE(data>>8,writer);
+ _mm_write_UBYTE(data&0xff,writer);
+}
+
+void _mm_write_I_UWORD(UWORD data,MWRITER* writer)
+{
+ _mm_write_UBYTE(data&0xff,writer);
+ _mm_write_UBYTE(data>>8,writer);
+}
+
+void _mm_write_M_ULONG(ULONG data,MWRITER* writer)
+{
+ _mm_write_M_UWORD(data>>16,writer);
+ _mm_write_M_UWORD(data&0xffff,writer);
+}
+
+void _mm_write_I_ULONG(ULONG data,MWRITER* writer)
+{
+ _mm_write_I_UWORD(data&0xffff,writer);
+ _mm_write_I_UWORD(data>>16,writer);
+}
+
+void _mm_write_M_SWORD(SWORD data,MWRITER* writer)
+{
+ _mm_write_M_UWORD((UWORD)data,writer);
+}
+
+void _mm_write_I_SWORD(SWORD data,MWRITER* writer)
+{
+ _mm_write_I_UWORD((UWORD)data,writer);
+}
+
+void _mm_write_M_SLONG(SLONG data,MWRITER* writer)
+{
+ _mm_write_M_ULONG((ULONG)data,writer);
+}
+
+void _mm_write_I_SLONG(SLONG data,MWRITER* writer)
+{
+ _mm_write_I_ULONG((ULONG)data,writer);
+}
+
+#if defined __STDC__ || defined _MSC_VER || defined MPW_C
+#define DEFINE_MULTIPLE_WRITE_FUNCTION(type_name,type) \
+void _mm_write_##type_name##S (type *buffer,int number,MWRITER* writer) \
+{ \
+ while(number-->0) \
+ _mm_write_##type_name(*(buffer++),writer); \
+}
+#else
+#define DEFINE_MULTIPLE_WRITE_FUNCTION(type_name,type) \
+void _mm_write_/**/type_name/**/S (type *buffer,int number,MWRITER* writer) \
+{ \
+ while(number-->0) \
+ _mm_write_/**/type_name(*(buffer++),writer); \
+}
+#endif
+
+DEFINE_MULTIPLE_WRITE_FUNCTION(M_SWORD,SWORD)
+DEFINE_MULTIPLE_WRITE_FUNCTION(M_UWORD,UWORD)
+DEFINE_MULTIPLE_WRITE_FUNCTION(I_SWORD,SWORD)
+DEFINE_MULTIPLE_WRITE_FUNCTION(I_UWORD,UWORD)
+
+DEFINE_MULTIPLE_WRITE_FUNCTION(M_SLONG,SLONG)
+DEFINE_MULTIPLE_WRITE_FUNCTION(M_ULONG,ULONG)
+DEFINE_MULTIPLE_WRITE_FUNCTION(I_SLONG,SLONG)
+DEFINE_MULTIPLE_WRITE_FUNCTION(I_ULONG,ULONG)
+
+/*========== Read functions */
+
+int _mm_read_string(CHAR* buffer,int number,MREADER* reader)
+{
+ return reader->Read(reader,buffer,number);
+}
+
+UWORD _mm_read_M_UWORD(MREADER* reader)
+{
+ UWORD result=((UWORD)_mm_read_UBYTE(reader))<<8;
+ result|=_mm_read_UBYTE(reader);
+ return result;
+}
+
+UWORD _mm_read_I_UWORD(MREADER* reader)
+{
+ UWORD result=_mm_read_UBYTE(reader);
+ result|=((UWORD)_mm_read_UBYTE(reader))<<8;
+ return result;
+}
+
+ULONG _mm_read_M_ULONG(MREADER* reader)
+{
+ ULONG result=((ULONG)_mm_read_M_UWORD(reader))<<16;
+ result|=_mm_read_M_UWORD(reader);
+ return result;
+}
+
+ULONG _mm_read_I_ULONG(MREADER* reader)
+{
+ ULONG result=_mm_read_I_UWORD(reader);
+ result|=((ULONG)_mm_read_I_UWORD(reader))<<16;
+ return result;
+}
+
+SWORD _mm_read_M_SWORD(MREADER* reader)
+{
+ return((SWORD)_mm_read_M_UWORD(reader));
+}
+
+SWORD _mm_read_I_SWORD(MREADER* reader)
+{
+ return((SWORD)_mm_read_I_UWORD(reader));
+}
+
+SLONG _mm_read_M_SLONG(MREADER* reader)
+{
+ return((SLONG)_mm_read_M_ULONG(reader));
+}
+
+SLONG _mm_read_I_SLONG(MREADER* reader)
+{
+ return((SLONG)_mm_read_I_ULONG(reader));
+}
+
+#if defined __STDC__ || defined _MSC_VER || defined MPW_C
+#define DEFINE_MULTIPLE_READ_FUNCTION(type_name,type) \
+int _mm_read_##type_name##S (type *buffer,int number,MREADER* reader) \
+{ \
+ while(number-->0) \
+ *(buffer++)=_mm_read_##type_name(reader); \
+ return !reader->Eof(reader); \
+}
+#else
+#define DEFINE_MULTIPLE_READ_FUNCTION(type_name,type) \
+int _mm_read_/**/type_name/**/S (type *buffer,int number,MREADER* reader) \
+{ \
+ while(number-->0) \
+ *(buffer++)=_mm_read_/**/type_name(reader); \
+ return !reader->Eof(reader); \
+}
+#endif
+
+DEFINE_MULTIPLE_READ_FUNCTION(M_SWORD,SWORD)
+DEFINE_MULTIPLE_READ_FUNCTION(M_UWORD,UWORD)
+DEFINE_MULTIPLE_READ_FUNCTION(I_SWORD,SWORD)
+DEFINE_MULTIPLE_READ_FUNCTION(I_UWORD,UWORD)
+
+DEFINE_MULTIPLE_READ_FUNCTION(M_SLONG,SLONG)
+DEFINE_MULTIPLE_READ_FUNCTION(M_ULONG,ULONG)
+DEFINE_MULTIPLE_READ_FUNCTION(I_SLONG,SLONG)
+DEFINE_MULTIPLE_READ_FUNCTION(I_ULONG,ULONG)
+
+/* ex:set ts=4: */
diff --git a/apps/plugins/mikmod/mplayer.c b/apps/plugins/mikmod/mplayer.c
new file mode 100644
index 0000000000..92585f0320
--- /dev/null
+++ b/apps/plugins/mikmod/mplayer.c
@@ -0,0 +1,3409 @@
+/* MikMod sound library
+ (c) 1998, 1999, 2000, 2001 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: mplayer.c,v 1.4 2006/08/08 00:06:31 realtech Exp $
+
+ The Protracker Player Driver
+
+ The protracker driver supports all base Protracker 3.x commands and features.
+
+==============================================================================*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <stdarg.h>
+#ifdef SRANDOM_IN_MATH_H
+#include <math.h>
+#else
+#include <stdlib.h>
+#endif
+
+#include "mikmod_internals.h"
+
+#ifdef SUNOS
+extern int fprintf(FILE *, const char *, ...);
+extern long int random(void);
+#endif
+
+/* The currently playing module */
+MODULE *pf = NULL;
+
+#define HIGH_OCTAVE 2 /* number of above-range octaves */
+
+static UWORD oldperiods[OCTAVE*2]={
+ 0x6b00, 0x6800, 0x6500, 0x6220, 0x5f50, 0x5c80,
+ 0x5a00, 0x5740, 0x54d0, 0x5260, 0x5010, 0x4dc0,
+ 0x4b90, 0x4960, 0x4750, 0x4540, 0x4350, 0x4160,
+ 0x3f90, 0x3dc0, 0x3c10, 0x3a40, 0x38b0, 0x3700
+};
+
+static UBYTE VibratoTable[32]={
+ 0, 24, 49, 74, 97,120,141,161,180,197,212,224,235,244,250,253,
+ 255,253,250,244,235,224,212,197,180,161,141,120, 97, 74, 49, 24
+};
+
+static UBYTE avibtab[128]={
+ 0, 1, 3, 4, 6, 7, 9,10,12,14,15,17,18,20,21,23,
+ 24,25,27,28,30,31,32,34,35,36,38,39,40,41,42,44,
+ 45,46,47,48,49,50,51,52,53,54,54,55,56,57,57,58,
+ 59,59,60,60,61,61,62,62,62,63,63,63,63,63,63,63,
+ 64,63,63,63,63,63,63,63,62,62,62,61,61,60,60,59,
+ 59,58,57,57,56,55,54,54,53,52,51,50,49,48,47,46,
+ 45,44,42,41,40,39,38,36,35,34,32,31,30,28,27,25,
+ 24,23,21,20,18,17,15,14,12,10, 9, 7, 6, 4, 3, 1
+};
+
+/* Triton's linear periods to frequency translation table (for XM modules) */
+static ULONG lintab[768]={
+ 535232,534749,534266,533784,533303,532822,532341,531861,
+ 531381,530902,530423,529944,529466,528988,528511,528034,
+ 527558,527082,526607,526131,525657,525183,524709,524236,
+ 523763,523290,522818,522346,521875,521404,520934,520464,
+ 519994,519525,519057,518588,518121,517653,517186,516720,
+ 516253,515788,515322,514858,514393,513929,513465,513002,
+ 512539,512077,511615,511154,510692,510232,509771,509312,
+ 508852,508393,507934,507476,507018,506561,506104,505647,
+ 505191,504735,504280,503825,503371,502917,502463,502010,
+ 501557,501104,500652,500201,499749,499298,498848,498398,
+ 497948,497499,497050,496602,496154,495706,495259,494812,
+ 494366,493920,493474,493029,492585,492140,491696,491253,
+ 490809,490367,489924,489482,489041,488600,488159,487718,
+ 487278,486839,486400,485961,485522,485084,484647,484210,
+ 483773,483336,482900,482465,482029,481595,481160,480726,
+ 480292,479859,479426,478994,478562,478130,477699,477268,
+ 476837,476407,475977,475548,475119,474690,474262,473834,
+ 473407,472979,472553,472126,471701,471275,470850,470425,
+ 470001,469577,469153,468730,468307,467884,467462,467041,
+ 466619,466198,465778,465358,464938,464518,464099,463681,
+ 463262,462844,462427,462010,461593,461177,460760,460345,
+ 459930,459515,459100,458686,458272,457859,457446,457033,
+ 456621,456209,455797,455386,454975,454565,454155,453745,
+ 453336,452927,452518,452110,451702,451294,450887,450481,
+ 450074,449668,449262,448857,448452,448048,447644,447240,
+ 446836,446433,446030,445628,445226,444824,444423,444022,
+ 443622,443221,442821,442422,442023,441624,441226,440828,
+ 440430,440033,439636,439239,438843,438447,438051,437656,
+ 437261,436867,436473,436079,435686,435293,434900,434508,
+ 434116,433724,433333,432942,432551,432161,431771,431382,
+ 430992,430604,430215,429827,429439,429052,428665,428278,
+ 427892,427506,427120,426735,426350,425965,425581,425197,
+ 424813,424430,424047,423665,423283,422901,422519,422138,
+ 421757,421377,420997,420617,420237,419858,419479,419101,
+ 418723,418345,417968,417591,417214,416838,416462,416086,
+ 415711,415336,414961,414586,414212,413839,413465,413092,
+ 412720,412347,411975,411604,411232,410862,410491,410121,
+ 409751,409381,409012,408643,408274,407906,407538,407170,
+ 406803,406436,406069,405703,405337,404971,404606,404241,
+ 403876,403512,403148,402784,402421,402058,401695,401333,
+ 400970,400609,400247,399886,399525,399165,398805,398445,
+ 398086,397727,397368,397009,396651,396293,395936,395579,
+ 395222,394865,394509,394153,393798,393442,393087,392733,
+ 392378,392024,391671,391317,390964,390612,390259,389907,
+ 389556,389204,388853,388502,388152,387802,387452,387102,
+ 386753,386404,386056,385707,385359,385012,384664,384317,
+ 383971,383624,383278,382932,382587,382242,381897,381552,
+ 381208,380864,380521,380177,379834,379492,379149,378807,
+ 378466,378124,377783,377442,377102,376762,376422,376082,
+ 375743,375404,375065,374727,374389,374051,373714,373377,
+ 373040,372703,372367,372031,371695,371360,371025,370690,
+ 370356,370022,369688,369355,369021,368688,368356,368023,
+ 367691,367360,367028,366697,366366,366036,365706,365376,
+ 365046,364717,364388,364059,363731,363403,363075,362747,
+ 362420,362093,361766,361440,361114,360788,360463,360137,
+ 359813,359488,359164,358840,358516,358193,357869,357547,
+ 357224,356902,356580,356258,355937,355616,355295,354974,
+ 354654,354334,354014,353695,353376,353057,352739,352420,
+ 352103,351785,351468,351150,350834,350517,350201,349885,
+ 349569,349254,348939,348624,348310,347995,347682,347368,
+ 347055,346741,346429,346116,345804,345492,345180,344869,
+ 344558,344247,343936,343626,343316,343006,342697,342388,
+ 342079,341770,341462,341154,340846,340539,340231,339924,
+ 339618,339311,339005,338700,338394,338089,337784,337479,
+ 337175,336870,336566,336263,335959,335656,335354,335051,
+ 334749,334447,334145,333844,333542,333242,332941,332641,
+ 332341,332041,331741,331442,331143,330844,330546,330247,
+ 329950,329652,329355,329057,328761,328464,328168,327872,
+ 327576,327280,326985,326690,326395,326101,325807,325513,
+ 325219,324926,324633,324340,324047,323755,323463,323171,
+ 322879,322588,322297,322006,321716,321426,321136,320846,
+ 320557,320267,319978,319690,319401,319113,318825,318538,
+ 318250,317963,317676,317390,317103,316817,316532,316246,
+ 315961,315676,315391,315106,314822,314538,314254,313971,
+ 313688,313405,313122,312839,312557,312275,311994,311712,
+ 311431,311150,310869,310589,310309,310029,309749,309470,
+ 309190,308911,308633,308354,308076,307798,307521,307243,
+ 306966,306689,306412,306136,305860,305584,305308,305033,
+ 304758,304483,304208,303934,303659,303385,303112,302838,
+ 302565,302292,302019,301747,301475,301203,300931,300660,
+ 300388,300117,299847,299576,299306,299036,298766,298497,
+ 298227,297958,297689,297421,297153,296884,296617,296349,
+ 296082,295815,295548,295281,295015,294749,294483,294217,
+ 293952,293686,293421,293157,292892,292628,292364,292100,
+ 291837,291574,291311,291048,290785,290523,290261,289999,
+ 289737,289476,289215,288954,288693,288433,288173,287913,
+ 287653,287393,287134,286875,286616,286358,286099,285841,
+ 285583,285326,285068,284811,284554,284298,284041,283785,
+ 283529,283273,283017,282762,282507,282252,281998,281743,
+ 281489,281235,280981,280728,280475,280222,279969,279716,
+ 279464,279212,278960,278708,278457,278206,277955,277704,
+ 277453,277203,276953,276703,276453,276204,275955,275706,
+ 275457,275209,274960,274712,274465,274217,273970,273722,
+ 273476,273229,272982,272736,272490,272244,271999,271753,
+ 271508,271263,271018,270774,270530,270286,270042,269798,
+ 269555,269312,269069,268826,268583,268341,268099,267857
+};
+
+#define LOGFAC 2*16
+static UWORD logtab[104]={
+ LOGFAC*907,LOGFAC*900,LOGFAC*894,LOGFAC*887,
+ LOGFAC*881,LOGFAC*875,LOGFAC*868,LOGFAC*862,
+ LOGFAC*856,LOGFAC*850,LOGFAC*844,LOGFAC*838,
+ LOGFAC*832,LOGFAC*826,LOGFAC*820,LOGFAC*814,
+ LOGFAC*808,LOGFAC*802,LOGFAC*796,LOGFAC*791,
+ LOGFAC*785,LOGFAC*779,LOGFAC*774,LOGFAC*768,
+ LOGFAC*762,LOGFAC*757,LOGFAC*752,LOGFAC*746,
+ LOGFAC*741,LOGFAC*736,LOGFAC*730,LOGFAC*725,
+ LOGFAC*720,LOGFAC*715,LOGFAC*709,LOGFAC*704,
+ LOGFAC*699,LOGFAC*694,LOGFAC*689,LOGFAC*684,
+ LOGFAC*678,LOGFAC*675,LOGFAC*670,LOGFAC*665,
+ LOGFAC*660,LOGFAC*655,LOGFAC*651,LOGFAC*646,
+ LOGFAC*640,LOGFAC*636,LOGFAC*632,LOGFAC*628,
+ LOGFAC*623,LOGFAC*619,LOGFAC*614,LOGFAC*610,
+ LOGFAC*604,LOGFAC*601,LOGFAC*597,LOGFAC*592,
+ LOGFAC*588,LOGFAC*584,LOGFAC*580,LOGFAC*575,
+ LOGFAC*570,LOGFAC*567,LOGFAC*563,LOGFAC*559,
+ LOGFAC*555,LOGFAC*551,LOGFAC*547,LOGFAC*543,
+ LOGFAC*538,LOGFAC*535,LOGFAC*532,LOGFAC*528,
+ LOGFAC*524,LOGFAC*520,LOGFAC*516,LOGFAC*513,
+ LOGFAC*508,LOGFAC*505,LOGFAC*502,LOGFAC*498,
+ LOGFAC*494,LOGFAC*491,LOGFAC*487,LOGFAC*484,
+ LOGFAC*480,LOGFAC*477,LOGFAC*474,LOGFAC*470,
+ LOGFAC*467,LOGFAC*463,LOGFAC*460,LOGFAC*457,
+ LOGFAC*453,LOGFAC*450,LOGFAC*447,LOGFAC*443,
+ LOGFAC*440,LOGFAC*437,LOGFAC*434,LOGFAC*431
+};
+
+static SBYTE PanbrelloTable[256]={
+ 0, 2, 3, 5, 6, 8, 9, 11, 12, 14, 16, 17, 19, 20, 22, 23,
+ 24, 26, 27, 29, 30, 32, 33, 34, 36, 37, 38, 39, 41, 42, 43, 44,
+ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 56, 57, 58, 59,
+ 59, 60, 60, 61, 61, 62, 62, 62, 63, 63, 63, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 63, 63, 63, 62, 62, 62, 61, 61, 60, 60,
+ 59, 59, 58, 57, 56, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46,
+ 45, 44, 43, 42, 41, 39, 38, 37, 36, 34, 33, 32, 30, 29, 27, 26,
+ 24, 23, 22, 20, 19, 17, 16, 14, 12, 11, 9, 8, 6, 5, 3, 2,
+ 0,- 2,- 3,- 5,- 6,- 8,- 9,-11,-12,-14,-16,-17,-19,-20,-22,-23,
+ -24,-26,-27,-29,-30,-32,-33,-34,-36,-37,-38,-39,-41,-42,-43,-44,
+ -45,-46,-47,-48,-49,-50,-51,-52,-53,-54,-55,-56,-56,-57,-58,-59,
+ -59,-60,-60,-61,-61,-62,-62,-62,-63,-63,-63,-64,-64,-64,-64,-64,
+ -64,-64,-64,-64,-64,-64,-63,-63,-63,-62,-62,-62,-61,-61,-60,-60,
+ -59,-59,-58,-57,-56,-56,-55,-54,-53,-52,-51,-50,-49,-48,-47,-46,
+ -45,-44,-43,-42,-41,-39,-38,-37,-36,-34,-33,-32,-30,-29,-27,-26,
+ -24,-23,-22,-20,-19,-17,-16,-14,-12,-11,- 9,- 8,- 6,- 5,- 3,- 2
+};
+
+/* returns a random value between 0 and ceil-1, ceil must be a power of two */
+static int getrandom(int ceil)
+{
+#ifdef HAVE_SRANDOM
+ return random()&(ceil-1);
+#else
+ return (rand()*ceil)/(RAND_MAX+1.0);
+#endif
+}
+
+/* New Note Action Scoring System :
+ --------------------------------
+ 1) total-volume (fadevol, chanvol, volume) is the main scorer.
+ 2) a looping sample is a bonus x2
+ 3) a foreground channel is a bonus x4
+ 4) an active envelope with keyoff is a handicap -x2
+*/
+static int MP_FindEmptyChannel(MODULE *mod)
+{
+ MP_VOICE *a;
+ ULONG t,k,tvol,pp;
+
+ for (t=0;t<md_sngchn;t++)
+ if (((mod->voice[t].main.kick==KICK_ABSENT)||
+ (mod->voice[t].main.kick==KICK_ENV))&&
+ Voice_Stopped_internal(t))
+ return t;
+
+ tvol=0xffffffUL;t=-1;a=mod->voice;
+ for (k=0;k<md_sngchn;k++,a++) {
+ /* allow us to take over a nonexisting sample */
+ if (!a->main.s)
+ return k;
+
+ if ((a->main.kick==KICK_ABSENT)||(a->main.kick==KICK_ENV)) {
+ pp=a->totalvol<<((a->main.s->flags&SF_LOOP)?1:0);
+ if ((a->master)&&(a==a->master->slave))
+ pp<<=2;
+
+ if (pp<tvol) {
+ tvol=pp;
+ t=k;
+ }
+ }
+ }
+
+ if (tvol>8000*7) return -1;
+ return t;
+}
+
+static SWORD Interpolate(SWORD p,SWORD p1,SWORD p2,SWORD v1,SWORD v2)
+{
+ if ((p1==p2)||(p==p1)) return v1;
+ return v1+((SLONG)((p-p1)*(v2-v1))/(p2-p1));
+}
+
+UWORD getlinearperiod(UWORD note,ULONG fine)
+{
+ UWORD t;
+
+ t=((20L+2*HIGH_OCTAVE)*OCTAVE+2-note)*32L-(fine>>1);
+ return t;
+}
+
+static UWORD getlogperiod(UWORD note,ULONG fine)
+{
+ UWORD n,o;
+ UWORD p1,p2;
+ ULONG i;
+
+ n=note%(2*OCTAVE);
+ o=note/(2*OCTAVE);
+ i=(n<<2)+(fine>>4); /* n*8 + fine/16 */
+
+ p1=logtab[i];
+ p2=logtab[i+1];
+
+ return (Interpolate(fine>>4,0,15,p1,p2)>>o);
+}
+
+static UWORD getoldperiod(UWORD note,ULONG speed)
+{
+ UWORD n,o;
+
+ /* This happens sometimes on badly converted AMF, and old MOD */
+ if (!speed) {
+#ifdef MIKMOD_DEBUG
+ fprintf(stderr,"\rmplayer: getoldperiod() called with note=%d, speed=0 !\n",note);
+#endif
+ return 4242; /* <- prevent divide overflow.. (42 hehe) */
+ }
+
+ n=note%(2*OCTAVE);
+ o=note/(2*OCTAVE);
+ return ((8363L*(ULONG)oldperiods[n])>>o)/speed;
+}
+
+static UWORD GetPeriod(UWORD flags, UWORD note, ULONG speed)
+{
+ if (flags & UF_XMPERIODS) {
+ if (flags & UF_LINEAR)
+ return getlinearperiod(note, speed);
+ else
+ return getlogperiod(note, speed);
+ } else
+ return getoldperiod(note, speed);
+}
+
+static SWORD InterpolateEnv(SWORD p,ENVPT *a,ENVPT *b)
+{
+ return (Interpolate(p,a->pos,b->pos,a->val,b->val));
+}
+
+static SWORD DoPan(SWORD envpan,SWORD pan)
+{
+ int newpan;
+
+ newpan=pan+(((envpan-PAN_CENTER)*(128-abs(pan-PAN_CENTER)))/128);
+
+ return (newpan<PAN_LEFT)?PAN_LEFT:(newpan>PAN_RIGHT?PAN_RIGHT:newpan);
+}
+
+static SWORD StartEnvelope(ENVPR *t,UBYTE flg,UBYTE pts,UBYTE susbeg,UBYTE susend,UBYTE beg,UBYTE end,ENVPT *p,UBYTE keyoff)
+{
+ t->flg=flg;
+ t->pts=pts;
+ t->susbeg=susbeg;
+ t->susend=susend;
+ t->beg=beg;
+ t->end=end;
+ t->env=p;
+ t->p=0;
+ t->a=0;
+ t->b=((t->flg&EF_SUSTAIN)&&(!(keyoff&KEY_OFF)))?0:1;
+
+ /* Imago Orpheus sometimes stores an extra initial point in the envelope */
+ if ((t->pts>=2)&&(t->env[0].pos==t->env[1].pos)) {
+ t->a++;t->b++;
+ }
+
+ /* Fit in the envelope, still */
+ if (t->a >= t->pts)
+ t->a = t->pts - 1;
+ if (t->b >= t->pts)
+ t->b = t->pts-1;
+
+ return t->env[t->a].val;
+}
+
+/* This procedure processes all envelope types, include volume, pitch, and
+ panning. Envelopes are defined by a set of points, each with a magnitude
+ [relating either to volume, panning position, or pitch modifier] and a tick
+ position.
+
+ Envelopes work in the following manner:
+
+ (a) Each tick the envelope is moved a point further in its progression. For
+ an accurate progression, magnitudes between two envelope points are
+ interpolated.
+
+ (b) When progression reaches a defined point on the envelope, values are
+ shifted to interpolate between this point and the next, and checks for
+ loops or envelope end are done.
+
+ Misc:
+ Sustain loops are loops that are only active as long as the keyoff flag is
+ clear. When a volume envelope terminates, so does the current fadeout.
+*/
+static SWORD ProcessEnvelope(MP_VOICE *aout, ENVPR *t, SWORD v)
+{
+ if (t->flg & EF_ON) {
+ UBYTE a, b; /* actual points in the envelope */
+ UWORD p; /* the 'tick counter' - real point being played */
+
+ a = t->a;
+ b = t->b;
+ p = t->p;
+
+ /*
+ * Sustain loop on one point (XM type).
+ * Not processed if KEYOFF.
+ * Don't move and don't interpolate when the point is reached
+ */
+ if ((t->flg & EF_SUSTAIN) && t->susbeg == t->susend &&
+ (!(aout->main.keyoff & KEY_OFF) && p == t->env[t->susbeg].pos)) {
+ v = t->env[t->susbeg].val;
+ } else {
+ /*
+ * All following situations will require interpolation between
+ * two envelope points.
+ */
+
+ /*
+ * Sustain loop between two points (IT type).
+ * Not processed if KEYOFF.
+ */
+ /* if we were on a loop point, loop now */
+ if ((t->flg & EF_SUSTAIN) && !(aout->main.keyoff & KEY_OFF) &&
+ a >= t->susend) {
+ a = t->susbeg;
+ b = (t->susbeg==t->susend)?a:a+1;
+ p = t->env[a].pos;
+ v = t->env[a].val;
+ } else
+ /*
+ * Regular loop.
+ * Be sure to correctly handle single point loops.
+ */
+ if ((t->flg & EF_LOOP) && a >= t->end) {
+ a = t->beg;
+ b = t->beg == t->end ? a : a + 1;
+ p = t->env[a].pos;
+ v = t->env[a].val;
+ } else
+ /*
+ * Non looping situations.
+ */
+ if (a != b)
+ v = InterpolateEnv(p, &t->env[a], &t->env[b]);
+ else
+ v = t->env[a].val;
+
+ /*
+ * Start to fade if the volume envelope is finished.
+ */
+ if (p >= t->env[t->pts - 1].pos) {
+ if (t->flg & EF_VOLENV) {
+ aout->main.keyoff |= KEY_FADE;
+ if (!v)
+ aout->main.fadevol = 0;
+ }
+ } else {
+ p++;
+ /* did pointer reach point b? */
+ if (p >= t->env[b].pos)
+ a = b++; /* shift points a and b */
+ }
+ t->a = a;
+ t->b = b;
+ t->p = p;
+ }
+ }
+ return v;
+}
+
+/* XM linear period to frequency conversion */
+ULONG getfrequency(UWORD flags,ULONG period)
+{
+ if (flags & UF_LINEAR) {
+ SLONG shift = ((SLONG)period / 768) - HIGH_OCTAVE;
+
+ if (shift >= 0)
+ return lintab[period % 768] >> shift;
+ else
+ return lintab[period % 768] << (-shift);
+ } else
+ return (8363L*1712L)/(period?period:1);
+}
+
+/*========== Protracker effects */
+
+static void DoArpeggio(UWORD tick, UWORD flags, MP_CONTROL *a, UBYTE style)
+{
+ UBYTE note=a->main.note;
+
+ if (a->arpmem) {
+ switch (style) {
+ case 0: /* mod style: N, N+x, N+y */
+ switch (tick % 3) {
+ /* case 0: unchanged */
+ case 1:
+ note += (a->arpmem >> 4);
+ break;
+ case 2:
+ note += (a->arpmem & 0xf);
+ break;
+ }
+ break;
+ case 3: /* okt arpeggio 3: N-x, N, N+y */
+ switch (tick % 3) {
+ case 0:
+ note -= (a->arpmem >> 4);
+ break;
+ /* case 1: unchanged */
+ case 2:
+ note += (a->arpmem & 0xf);
+ break;
+ }
+ break;
+ case 4: /* okt arpeggio 4: N, N+y, N, N-x */
+ switch (tick % 4) {
+ /* case 0, case 2: unchanged */
+ case 1:
+ note += (a->arpmem & 0xf);
+ break;
+ case 3:
+ note -= (a->arpmem >> 4);
+ break;
+ }
+ break;
+ case 5: /* okt arpeggio 5: N-x, N+y, N, and nothing at tick 0 */
+ if (!tick)
+ break;
+ switch (tick % 3) {
+ /* case 0: unchanged */
+ case 1:
+ note -= (a->arpmem >> 4);
+ break;
+ case 2:
+ note += (a->arpmem & 0xf);
+ break;
+ }
+ break;
+ }
+ a->main.period = GetPeriod(flags, (UWORD)note << 1, a->speed);
+ a->ownper = 1;
+ }
+}
+
+static int DoPTEffect0(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+ UBYTE dat;
+
+ dat = UniGetByte();
+ if (!tick) {
+ if (!dat && (flags & UF_ARPMEM))
+ dat=a->arpmem;
+ else
+ a->arpmem=dat;
+ }
+ if (a->main.period)
+ DoArpeggio(tick, flags, a, 0);
+
+ return 0;
+}
+
+static int DoPTEffect1(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+ UBYTE dat;
+
+ dat = UniGetByte();
+ if (!tick && dat)
+ a->slidespeed = (UWORD)dat << 2;
+ if (a->main.period)
+ if (tick)
+ a->tmpperiod -= a->slidespeed;
+
+ return 0;
+}
+
+static int DoPTEffect2(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+ UBYTE dat;
+
+ dat = UniGetByte();
+ if (!tick && dat)
+ a->slidespeed = (UWORD)dat << 2;
+ if (a->main.period)
+ if (tick)
+ a->tmpperiod += a->slidespeed;
+
+ return 0;
+}
+
+static void DoToneSlide(UWORD tick, MP_CONTROL *a)
+{
+ if (!a->main.fadevol)
+ a->main.kick = (a->main.kick == KICK_NOTE)? KICK_NOTE : KICK_KEYOFF;
+ else
+ a->main.kick = (a->main.kick == KICK_NOTE)? KICK_ENV : KICK_ABSENT;
+
+ if (tick != 0) {
+ int dist;
+
+ /* We have to slide a->main.period towards a->wantedperiod, so compute
+ the difference between those two values */
+ dist=a->main.period-a->wantedperiod;
+
+ /* if they are equal or if portamentospeed is too big ...*/
+ if (dist == 0 || a->portspeed > abs(dist))
+ /* ...make tmpperiod equal tperiod */
+ a->tmpperiod=a->main.period=a->wantedperiod;
+ else if (dist>0) {
+ a->tmpperiod-=a->portspeed;
+ a->main.period-=a->portspeed; /* dist>0, slide up */
+ } else {
+ a->tmpperiod+=a->portspeed;
+ a->main.period+=a->portspeed; /* dist<0, slide down */
+ }
+ } else
+ a->tmpperiod=a->main.period;
+ a->ownper = 1;
+}
+
+static int DoPTEffect3(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+ UBYTE dat;
+
+ dat=UniGetByte();
+ if ((!tick)&&(dat)) a->portspeed=(UWORD)dat<<2;
+ if (a->main.period)
+ DoToneSlide(tick, a);
+
+ return 0;
+}
+
+static void DoVibrato(UWORD tick, MP_CONTROL *a)
+{
+ UBYTE q;
+ UWORD temp = 0; /* silence warning */
+
+ if (!tick)
+ return;
+
+ q=(a->vibpos>>2)&0x1f;
+
+ switch (a->wavecontrol&3) {
+ case 0: /* sine */
+ temp=VibratoTable[q];
+ break;
+ case 1: /* ramp down */
+ q<<=3;
+ if (a->vibpos<0) q=255-q;
+ temp=q;
+ break;
+ case 2: /* square wave */
+ temp=255;
+ break;
+ case 3: /* random wave */
+ temp=getrandom(256);
+ break;
+ }
+
+ temp*=a->vibdepth;
+ temp>>=7;temp<<=2;
+
+ if (a->vibpos>=0)
+ a->main.period=a->tmpperiod+temp;
+ else
+ a->main.period=a->tmpperiod-temp;
+ a->ownper = 1;
+
+ if (tick != 0)
+ a->vibpos+=a->vibspd;
+}
+
+static int DoPTEffect4(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+ UBYTE dat;
+
+ dat=UniGetByte();
+ if (!tick) {
+ if (dat&0x0f) a->vibdepth=dat&0xf;
+ if (dat&0xf0) a->vibspd=(dat&0xf0)>>2;
+ }
+ if (a->main.period)
+ DoVibrato(tick, a);
+
+ return 0;
+}
+
+static void DoVolSlide(MP_CONTROL *a, UBYTE dat)
+{
+ if (dat&0xf) {
+ a->tmpvolume-=(dat&0x0f);
+ if (a->tmpvolume<0)
+ a->tmpvolume=0;
+ } else {
+ a->tmpvolume+=(dat>>4);
+ if (a->tmpvolume>64)
+ a->tmpvolume=64;
+ }
+}
+
+static int DoPTEffect5(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+ UBYTE dat;
+
+ dat=UniGetByte();
+ if (a->main.period)
+ DoToneSlide(tick, a);
+
+ if (tick)
+ DoVolSlide(a, dat);
+
+ return 0;
+}
+
+/* DoPTEffect6 after DoPTEffectA */
+
+static int DoPTEffect7(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+ UBYTE dat;
+ UBYTE q;
+ UWORD temp = 0; /* silence warning */
+
+ dat=UniGetByte();
+ if (!tick) {
+ if (dat&0x0f) a->trmdepth=dat&0xf;
+ if (dat&0xf0) a->trmspd=(dat&0xf0)>>2;
+ }
+ if (a->main.period) {
+ q=(a->trmpos>>2)&0x1f;
+
+ switch ((a->wavecontrol>>4)&3) {
+ case 0: /* sine */
+ temp=VibratoTable[q];
+ break;
+ case 1: /* ramp down */
+ q<<=3;
+ if (a->trmpos<0) q=255-q;
+ temp=q;
+ break;
+ case 2: /* square wave */
+ temp=255;
+ break;
+ case 3: /* random wave */
+ temp=getrandom(256);
+ break;
+ }
+ temp*=a->trmdepth;
+ temp>>=6;
+
+ if (a->trmpos>=0) {
+ a->volume=a->tmpvolume+temp;
+ if (a->volume>64) a->volume=64;
+ } else {
+ a->volume=a->tmpvolume-temp;
+ if (a->volume<0) a->volume=0;
+ }
+ a->ownvol = 1;
+
+ if (tick)
+ a->trmpos+=a->trmspd;
+ }
+
+ return 0;
+}
+
+static int DoPTEffect8(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+ UBYTE dat;
+
+ dat = UniGetByte();
+ if (mod->panflag)
+ a->main.panning = mod->panning[channel] = dat;
+
+ return 0;
+}
+
+static int DoPTEffect9(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+ UBYTE dat;
+
+ dat=UniGetByte();
+ if (!tick) {
+ if (dat) a->soffset=(UWORD)dat<<8;
+ a->main.start=a->hioffset|a->soffset;
+
+ if ((a->main.s)&&(a->main.start>a->main.s->length))
+ a->main.start=a->main.s->flags&(SF_LOOP|SF_BIDI)?
+ a->main.s->loopstart:a->main.s->length;
+ }
+
+ return 0;
+}
+
+static int DoPTEffectA(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+ UBYTE dat;
+
+ dat=UniGetByte();
+ if (tick)
+ DoVolSlide(a, dat);
+
+ return 0;
+}
+
+static int DoPTEffect6(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+ if (a->main.period)
+ DoVibrato(tick, a);
+ DoPTEffectA(tick, flags, a, mod, channel);
+
+ return 0;
+}
+
+static int DoPTEffectB(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+ UBYTE dat;
+
+ dat=UniGetByte();
+
+ if (tick || mod->patdly2)
+ return 0;
+
+ /* Vincent Voois uses a nasty trick in "Universal Bolero" */
+ if (dat == mod->sngpos && mod->patbrk == mod->patpos)
+ return 0;
+
+ if (!mod->loop && !mod->patbrk &&
+ (dat < mod->sngpos ||
+ (mod->sngpos == (mod->numpos - 1) && !mod->patbrk) ||
+ (dat == mod->sngpos && (flags & UF_NOWRAP))
+ )) {
+ /* if we don't loop, better not to skip the end of the
+ pattern, after all... so:
+ mod->patbrk=0; */
+ mod->posjmp=3;
+ } else {
+ /* if we were fading, adjust... */
+ if (mod->sngpos == (mod->numpos-1))
+ mod->volume=mod->initvolume>128?128:mod->initvolume;
+ mod->sngpos=dat;
+ mod->posjmp=2;
+ mod->patpos=0;
+ }
+
+ return 0;
+}
+
+static int DoPTEffectC(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+ UBYTE dat;
+
+ dat=UniGetByte();
+ if (tick) return 0;
+ if (dat==(UBYTE)-1) a->anote=dat=0; /* note cut */
+ else if (dat>64) dat=64;
+ a->tmpvolume=dat;
+
+ return 0;
+}
+
+static int DoPTEffectD(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+ UBYTE dat;
+
+ dat=UniGetByte();
+ if ((tick)||(mod->patdly2)) return 0;
+ if ((mod->positions[mod->sngpos]!=LAST_PATTERN)&&
+ (dat>mod->pattrows[mod->positions[mod->sngpos]]))
+ dat=mod->pattrows[mod->positions[mod->sngpos]];
+ mod->patbrk=dat;
+ if (!mod->posjmp) {
+ /* don't ask me to explain this code - it makes
+ backwards.s3m and children.xm (heretic's version) play
+ correctly, among others. Take that for granted, or write
+ the page of comments yourself... you might need some
+ aspirin - Miod */
+ if ((mod->sngpos==mod->numpos-1)&&(dat)&&((mod->loop)||
+ (mod->positions[mod->sngpos]==(mod->numpat-1)
+ && !(flags&UF_NOWRAP)))) {
+ mod->sngpos=0;
+ mod->posjmp=2;
+ } else
+ mod->posjmp=3;
+ }
+
+ return 0;
+}
+
+static void DoEEffects(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod,
+ SWORD channel, UBYTE dat)
+{
+ UBYTE nib = dat & 0xf;
+
+ switch (dat>>4) {
+ case 0x0: /* hardware filter toggle, not supported */
+ break;
+ case 0x1: /* fineslide up */
+ if (a->main.period)
+ if (!tick)
+ a->tmpperiod-=(nib<<2);
+ break;
+ case 0x2: /* fineslide dn */
+ if (a->main.period)
+ if (!tick)
+ a->tmpperiod+=(nib<<2);
+ break;
+ case 0x3: /* glissando ctrl */
+ a->glissando=nib;
+ break;
+ case 0x4: /* set vibrato waveform */
+ a->wavecontrol&=0xf0;
+ a->wavecontrol|=nib;
+ break;
+ case 0x5: /* set finetune */
+ if (a->main.period) {
+ if (flags&UF_XMPERIODS)
+ a->speed=nib+128;
+ else
+ a->speed=finetune[nib];
+ a->tmpperiod=GetPeriod(flags, (UWORD)a->main.note<<1,a->speed);
+ }
+ break;
+ case 0x6: /* set patternloop */
+ if (tick)
+ break;
+ if (nib) { /* set reppos or repcnt ? */
+ /* set repcnt, so check if repcnt already is set, which means we
+ are already looping */
+ if (a->pat_repcnt)
+ a->pat_repcnt--; /* already looping, decrease counter */
+ else {
+#if 0
+ /* this would make walker.xm, shipped with Xsoundtracker,
+ play correctly, but it's better to remain compatible
+ with FT2 */
+ if ((!(flags&UF_NOWRAP))||(a->pat_reppos!=POS_NONE))
+#endif
+ a->pat_repcnt=nib; /* not yet looping, so set repcnt */
+ }
+
+ if (a->pat_repcnt) { /* jump to reppos if repcnt>0 */
+ if (a->pat_reppos==POS_NONE)
+ a->pat_reppos=mod->patpos-1;
+ if (a->pat_reppos==-1) {
+ mod->pat_repcrazy=1;
+ mod->patpos=0;
+ } else
+ mod->patpos=a->pat_reppos;
+ } else a->pat_reppos=POS_NONE;
+ } else
+ a->pat_reppos=mod->patpos-1; /* set reppos - can be (-1) */
+ break;
+ case 0x7: /* set tremolo waveform */
+ a->wavecontrol&=0x0f;
+ a->wavecontrol|=nib<<4;
+ break;
+ case 0x8: /* set panning */
+ if (mod->panflag) {
+ if (nib<=8) nib<<=4;
+ else nib*=17;
+ a->main.panning=mod->panning[channel]=nib;
+ }
+ break;
+ case 0x9: /* retrig note */
+ /* do not retrigger on tick 0, until we are emulating FT2 and effect
+ data is zero */
+ if (!tick && !((flags & UF_FT2QUIRKS) && (!nib)))
+ break;
+ /* only retrigger if data nibble > 0, or if tick 0 (FT2 compat) */
+ if (nib || !tick) {
+ if (!a->retrig) {
+ /* when retrig counter reaches 0, reset counter and restart
+ the sample */
+ if (a->main.period) a->main.kick=KICK_NOTE;
+ a->retrig=nib;
+ }
+ a->retrig--; /* countdown */
+ }
+ break;
+ case 0xa: /* fine volume slide up */
+ if (tick)
+ break;
+ a->tmpvolume+=nib;
+ if (a->tmpvolume>64) a->tmpvolume=64;
+ break;
+ case 0xb: /* fine volume slide dn */
+ if (tick)
+ break;
+ a->tmpvolume-=nib;
+ if (a->tmpvolume<0)a->tmpvolume=0;
+ break;
+ case 0xc: /* cut note */
+ /* When tick reaches the cut-note value, turn the volume to
+ zero (just like on the amiga) */
+ if (tick>=nib)
+ a->tmpvolume=0; /* just turn the volume down */
+ break;
+ case 0xd: /* note delay */
+ /* delay the start of the sample until tick==nib */
+ if (!tick)
+ a->main.notedelay=nib;
+ else if (a->main.notedelay)
+ a->main.notedelay--;
+ break;
+ case 0xe: /* pattern delay */
+ if (!tick)
+ if (!mod->patdly2)
+ mod->patdly=nib+1; /* only once, when tick=0 */
+ break;
+ case 0xf: /* invert loop, not supported */
+ break;
+ }
+}
+
+static int DoPTEffectE(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+ DoEEffects(tick, flags, a, mod, channel, UniGetByte());
+
+ return 0;
+}
+
+static int DoPTEffectF(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+ UBYTE dat;
+
+ dat=UniGetByte();
+ if (tick||mod->patdly2) return 0;
+ if (mod->extspd&&(dat>=mod->bpmlimit))
+ mod->bpm=dat;
+ else
+ if (dat) {
+ mod->sngspd=(dat>=mod->bpmlimit)?mod->bpmlimit-1:dat;
+ mod->vbtick=0;
+ }
+
+ return 0;
+}
+
+/*========== Scream Tracker effects */
+
+static int DoS3MEffectA(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+ UBYTE speed;
+
+ speed = UniGetByte();
+
+ if (tick || mod->patdly2)
+ return 0;
+
+ if (speed > 128)
+ speed -= 128;
+ if (speed) {
+ mod->sngspd = speed;
+ mod->vbtick = 0;
+ }
+
+ return 0;
+}
+
+static void DoS3MVolSlide(UWORD tick, UWORD flags, MP_CONTROL *a, UBYTE inf)
+{
+ UBYTE lo, hi;
+
+ if (inf)
+ a->s3mvolslide=inf;
+ else
+ inf=a->s3mvolslide;
+
+ lo=inf&0xf;
+ hi=inf>>4;
+
+ if (!lo) {
+ if ((tick)||(flags&UF_S3MSLIDES)) a->tmpvolume+=hi;
+ } else
+ if (!hi) {
+ if ((tick)||(flags&UF_S3MSLIDES)) a->tmpvolume-=lo;
+ } else
+ if (lo==0xf) {
+ if (!tick) a->tmpvolume+=(hi?hi:0xf);
+ } else
+ if (hi==0xf) {
+ if (!tick) a->tmpvolume-=(lo?lo:0xf);
+ } else
+ return;
+
+ if (a->tmpvolume<0)
+ a->tmpvolume=0;
+ else if (a->tmpvolume>64)
+ a->tmpvolume=64;
+}
+
+static int DoS3MEffectD(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+ DoS3MVolSlide(tick, flags, a, UniGetByte());
+
+ return 1;
+}
+
+static void DoS3MSlideDn(UWORD tick, MP_CONTROL *a, UBYTE inf)
+{
+ UBYTE hi,lo;
+
+ if (inf)
+ a->slidespeed=inf;
+ else
+ inf=a->slidespeed;
+
+ hi=inf>>4;
+ lo=inf&0xf;
+
+ if (hi==0xf) {
+ if (!tick) a->tmpperiod+=(UWORD)lo<<2;
+ } else
+ if (hi==0xe) {
+ if (!tick) a->tmpperiod+=lo;
+ } else {
+ if (tick) a->tmpperiod+=(UWORD)inf<<2;
+ }
+}
+
+static int DoS3MEffectE(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+ UBYTE dat;
+
+ dat=UniGetByte();
+ if (a->main.period)
+ DoS3MSlideDn(tick, a,dat);
+
+ return 0;
+}
+
+static void DoS3MSlideUp(UWORD tick, MP_CONTROL *a, UBYTE inf)
+{
+ UBYTE hi,lo;
+
+ if (inf) a->slidespeed=inf;
+ else inf=a->slidespeed;
+
+ hi=inf>>4;
+ lo=inf&0xf;
+
+ if (hi==0xf) {
+ if (!tick) a->tmpperiod-=(UWORD)lo<<2;
+ } else
+ if (hi==0xe) {
+ if (!tick) a->tmpperiod-=lo;
+ } else {
+ if (tick) a->tmpperiod-=(UWORD)inf<<2;
+ }
+}
+
+static int DoS3MEffectF(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+ UBYTE dat;
+
+ dat=UniGetByte();
+ if (a->main.period)
+ DoS3MSlideUp(tick, a,dat);
+
+ return 0;
+}
+
+static int DoS3MEffectI(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+ UBYTE inf, on, off;
+
+ inf = UniGetByte();
+ if (inf)
+ a->s3mtronof = inf;
+ else {
+ inf = a->s3mtronof;
+ if (!inf)
+ return 0;
+ }
+
+ if (!tick)
+ return 0;
+
+ on=(inf>>4)+1;
+ off=(inf&0xf)+1;
+ a->s3mtremor%=(on+off);
+ a->volume=(a->s3mtremor<on)?a->tmpvolume:0;
+ a->ownvol=1;
+ a->s3mtremor++;
+
+ return 0;
+}
+
+static int DoS3MEffectQ(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+ UBYTE inf;
+
+ inf = UniGetByte();
+ if (a->main.period) {
+ if (inf) {
+ a->s3mrtgslide=inf>>4;
+ a->s3mrtgspeed=inf&0xf;
+ }
+
+ /* only retrigger if low nibble > 0 */
+ if (a->s3mrtgspeed>0) {
+ if (!a->retrig) {
+ /* when retrig counter reaches 0, reset counter and restart the
+ sample */
+ if (a->main.kick!=KICK_NOTE) a->main.kick=KICK_KEYOFF;
+ a->retrig=a->s3mrtgspeed;
+
+ if ((tick)||(flags&UF_S3MSLIDES)) {
+ switch (a->s3mrtgslide) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ a->tmpvolume-=(1<<(a->s3mrtgslide-1));
+ break;
+ case 6:
+ a->tmpvolume=(2*a->tmpvolume)/3;
+ break;
+ case 7:
+ a->tmpvolume>>=1;
+ break;
+ case 9:
+ case 0xa:
+ case 0xb:
+ case 0xc:
+ case 0xd:
+ a->tmpvolume+=(1<<(a->s3mrtgslide-9));
+ break;
+ case 0xe:
+ a->tmpvolume=(3*a->tmpvolume)>>1;
+ break;
+ case 0xf:
+ a->tmpvolume=a->tmpvolume<<1;
+ break;
+ }
+ if (a->tmpvolume<0)
+ a->tmpvolume=0;
+ else if (a->tmpvolume>64)
+ a->tmpvolume=64;
+ }
+ }
+ a->retrig--; /* countdown */
+ }
+ }
+
+ return 0;
+}
+
+static int DoS3MEffectR(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+ UBYTE dat, q;
+ UWORD temp=0; /* silence warning */
+
+ dat = UniGetByte();
+ if (!tick) {
+ if (dat&0x0f) a->trmdepth=dat&0xf;
+ if (dat&0xf0) a->trmspd=(dat&0xf0)>>2;
+ }
+
+ q=(a->trmpos>>2)&0x1f;
+
+ switch ((a->wavecontrol>>4)&3) {
+ case 0: /* sine */
+ temp=VibratoTable[q];
+ break;
+ case 1: /* ramp down */
+ q<<=3;
+ if (a->trmpos<0) q=255-q;
+ temp=q;
+ break;
+ case 2: /* square wave */
+ temp=255;
+ break;
+ case 3: /* random */
+ temp=getrandom(256);
+ break;
+ }
+
+ temp*=a->trmdepth;
+ temp>>=7;
+
+ if (a->trmpos>=0) {
+ a->volume=a->tmpvolume+temp;
+ if (a->volume>64) a->volume=64;
+ } else {
+ a->volume=a->tmpvolume-temp;
+ if (a->volume<0) a->volume=0;
+ }
+ a->ownvol = 1;
+
+ if (tick)
+ a->trmpos+=a->trmspd;
+
+ return 0;
+}
+
+static int DoS3MEffectT(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+ UBYTE tempo;
+
+ tempo = UniGetByte();
+
+ if (tick || mod->patdly2)
+ return 0;
+
+ mod->bpm = (tempo < 32) ? 32 : tempo;
+
+ return 0;
+}
+
+static int DoS3MEffectU(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+ UBYTE dat, q;
+ UWORD temp = 0; /* silence warning */
+
+ dat = UniGetByte();
+ if (!tick) {
+ if (dat&0x0f) a->vibdepth=dat&0xf;
+ if (dat&0xf0) a->vibspd=(dat&0xf0)>>2;
+ } else
+ if (a->main.period) {
+ q=(a->vibpos>>2)&0x1f;
+
+ switch (a->wavecontrol&3) {
+ case 0: /* sine */
+ temp=VibratoTable[q];
+ break;
+ case 1: /* ramp down */
+ q<<=3;
+ if (a->vibpos<0) q=255-q;
+ temp=q;
+ break;
+ case 2: /* square wave */
+ temp=255;
+ break;
+ case 3: /* random */
+ temp=getrandom(256);
+ break;
+ }
+
+ temp*=a->vibdepth;
+ temp>>=8;
+
+ if (a->vibpos>=0)
+ a->main.period=a->tmpperiod+temp;
+ else
+ a->main.period=a->tmpperiod-temp;
+ a->ownper = 1;
+
+ a->vibpos+=a->vibspd;
+ }
+
+ return 0;
+}
+
+/*========== Envelope helpers */
+
+static int DoKeyOff(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+ a->main.keyoff|=KEY_OFF;
+ if ((!(a->main.volflg&EF_ON))||(a->main.volflg&EF_LOOP))
+ a->main.keyoff=KEY_KILL;
+
+ return 0;
+}
+
+static int DoKeyFade(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+ UBYTE dat;
+
+ dat=UniGetByte();
+ if ((tick>=dat)||(tick==mod->sngspd-1)) {
+ a->main.keyoff=KEY_KILL;
+ if (!(a->main.volflg&EF_ON))
+ a->main.fadevol=0;
+ }
+
+ return 0;
+}
+
+/*========== Fast Tracker effects */
+
+/* DoXMEffect6 after DoXMEffectA */
+
+static int DoXMEffectA(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+ UBYTE inf, lo, hi;
+
+ inf = UniGetByte();
+ if (inf)
+ a->s3mvolslide = inf;
+ else
+ inf = a->s3mvolslide;
+
+ if (tick) {
+ lo=inf&0xf;
+ hi=inf>>4;
+
+ if (!hi) {
+ a->tmpvolume-=lo;
+ if (a->tmpvolume<0) a->tmpvolume=0;
+ } else {
+ a->tmpvolume+=hi;
+ if (a->tmpvolume>64) a->tmpvolume=64;
+ }
+ }
+
+ return 0;
+}
+
+static int DoXMEffect6(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+ if (a->main.period)
+ DoVibrato(tick, a);
+
+ return DoXMEffectA(tick, flags, a, mod, channel);
+}
+
+static int DoXMEffectE1(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+ UBYTE dat;
+
+ dat=UniGetByte();
+ if (!tick) {
+ if (dat) a->fportupspd=dat;
+ if (a->main.period)
+ a->tmpperiod-=(a->fportupspd<<2);
+ }
+
+ return 0;
+}
+
+static int DoXMEffectE2(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+ UBYTE dat;
+
+ dat=UniGetByte();
+ if (!tick) {
+ if (dat) a->fportdnspd=dat;
+ if (a->main.period)
+ a->tmpperiod+=(a->fportdnspd<<2);
+ }
+
+ return 0;
+}
+
+static int DoXMEffectEA(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+ UBYTE dat;
+
+ dat=UniGetByte();
+ if (!tick)
+ if (dat) a->fslideupspd=dat;
+ a->tmpvolume+=a->fslideupspd;
+ if (a->tmpvolume>64) a->tmpvolume=64;
+
+ return 0;
+}
+
+static int DoXMEffectEB(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+ UBYTE dat;
+
+ dat=UniGetByte();
+ if (!tick)
+ if (dat) a->fslidednspd=dat;
+ a->tmpvolume-=a->fslidednspd;
+ if (a->tmpvolume<0) a->tmpvolume=0;
+
+ return 0;
+}
+
+static int DoXMEffectG(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+ mod->volume=UniGetByte()<<1;
+ if (mod->volume>128) mod->volume=128;
+
+ return 0;
+}
+
+static int DoXMEffectH(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+ UBYTE inf;
+
+ inf = UniGetByte();
+
+ if (tick) {
+ if (inf) mod->globalslide=inf;
+ else inf=mod->globalslide;
+ if (inf & 0xf0) inf&=0xf0;
+ mod->volume=mod->volume+((inf>>4)-(inf&0xf))*2;
+
+ if (mod->volume<0)
+ mod->volume=0;
+ else if (mod->volume>128)
+ mod->volume=128;
+ }
+
+ return 0;
+}
+
+static int DoXMEffectL(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+ UBYTE dat;
+
+ dat=UniGetByte();
+ if ((!tick)&&(a->main.i)) {
+ UWORD points;
+ INSTRUMENT *i=a->main.i;
+ MP_VOICE *aout;
+
+ if ((aout=a->slave)) {
+ if (aout->venv.env) {
+ points=i->volenv[i->volpts-1].pos;
+ aout->venv.p=aout->venv.env[(dat>points)?points:dat].pos;
+ }
+ if (aout->penv.env) {
+ points=i->panenv[i->panpts-1].pos;
+ aout->penv.p=aout->penv.env[(dat>points)?points:dat].pos;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int DoXMEffectP(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+ UBYTE inf, lo, hi;
+ SWORD pan;
+
+ inf = UniGetByte();
+ if (!mod->panflag)
+ return 0;
+
+ if (inf)
+ a->pansspd = inf;
+ else
+ inf =a->pansspd;
+
+ if (tick) {
+ lo=inf&0xf;
+ hi=inf>>4;
+
+ /* slide right has absolute priority */
+ if (hi)
+ lo = 0;
+
+ pan=((a->main.panning==PAN_SURROUND)?PAN_CENTER:a->main.panning)+hi-lo;
+ a->main.panning=(pan<PAN_LEFT)?PAN_LEFT:(pan>PAN_RIGHT?PAN_RIGHT:pan);
+ }
+
+ return 0;
+}
+
+static int DoXMEffectX1(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+ UBYTE dat;
+
+ dat = UniGetByte();
+ if (dat)
+ a->ffportupspd = dat;
+ else
+ dat = a->ffportupspd;
+
+ if (a->main.period)
+ if (!tick) {
+ a->main.period-=dat;
+ a->tmpperiod-=dat;
+ a->ownper = 1;
+ }
+
+ return 0;
+}
+
+static int DoXMEffectX2(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+ UBYTE dat;
+
+ dat = UniGetByte();
+ if (dat)
+ a->ffportdnspd=dat;
+ else
+ dat = a->ffportdnspd;
+
+ if (a->main.period)
+ if (!tick) {
+ a->main.period+=dat;
+ a->tmpperiod+=dat;
+ a->ownper = 1;
+ }
+
+ return 0;
+}
+
+/*========== Impulse Tracker effects */
+
+static void DoITToneSlide(UWORD tick, MP_CONTROL *a, UBYTE dat)
+{
+ if (dat)
+ a->portspeed = dat;
+
+ /* if we don't come from another note, ignore the slide and play the note
+ as is */
+ if (!a->oldnote || !a->main.period)
+ return;
+
+ if ((!tick)&&(a->newsamp)){
+ a->main.kick=KICK_NOTE;
+ a->main.start=-1;
+ } else
+ a->main.kick=(a->main.kick==KICK_NOTE)?KICK_ENV:KICK_ABSENT;
+
+ if (tick) {
+ int dist;
+
+ /* We have to slide a->main.period towards a->wantedperiod, compute the
+ difference between those two values */
+ dist=a->main.period-a->wantedperiod;
+
+ /* if they are equal or if portamentospeed is too big... */
+ if ((!dist)||((a->portspeed<<2)>abs(dist)))
+ /* ... make tmpperiod equal tperiod */
+ a->tmpperiod=a->main.period=a->wantedperiod;
+ else
+ if (dist>0) {
+ a->tmpperiod-=a->portspeed<<2;
+ a->main.period-=a->portspeed<<2; /* dist>0 slide up */
+ } else {
+ a->tmpperiod+=a->portspeed<<2;
+ a->main.period+=a->portspeed<<2; /* dist<0 slide down */
+ }
+ } else
+ a->tmpperiod=a->main.period;
+ a->ownper=1;
+}
+
+static int DoITEffectG(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+ DoITToneSlide(tick, a, UniGetByte());
+
+ return 0;
+}
+
+static void DoITVibrato(UWORD tick, MP_CONTROL *a, UBYTE dat)
+{
+ UBYTE q;
+ UWORD temp=0;
+
+ if (!tick) {
+ if (dat&0x0f) a->vibdepth=dat&0xf;
+ if (dat&0xf0) a->vibspd=(dat&0xf0)>>2;
+ }
+ if (!a->main.period)
+ return;
+
+ q=(a->vibpos>>2)&0x1f;
+
+ switch (a->wavecontrol&3) {
+ case 0: /* sine */
+ temp=VibratoTable[q];
+ break;
+ case 1: /* square wave */
+ temp=255;
+ break;
+ case 2: /* ramp down */
+ q<<=3;
+ if (a->vibpos<0) q=255-q;
+ temp=q;
+ break;
+ case 3: /* random */
+ temp=getrandom(256);
+ break;
+ }
+
+ temp*=a->vibdepth;
+ temp>>=8;
+ temp<<=2;
+
+ if (a->vibpos>=0)
+ a->main.period=a->tmpperiod+temp;
+ else
+ a->main.period=a->tmpperiod-temp;
+ a->ownper=1;
+
+ a->vibpos+=a->vibspd;
+}
+
+static int DoITEffectH(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+ DoITVibrato(tick, a, UniGetByte());
+
+ return 0;
+}
+
+static int DoITEffectI(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+ UBYTE inf, on, off;
+
+ inf = UniGetByte();
+ if (inf)
+ a->s3mtronof = inf;
+ else {
+ inf = a->s3mtronof;
+ if (!inf)
+ return 0;
+ }
+
+ on=(inf>>4);
+ off=(inf&0xf);
+
+ a->s3mtremor%=(on+off);
+ a->volume=(a->s3mtremor<on)?a->tmpvolume:0;
+ a->ownvol = 1;
+ a->s3mtremor++;
+
+ return 0;
+}
+
+static int DoITEffectM(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+ a->main.chanvol=UniGetByte();
+ if (a->main.chanvol>64)
+ a->main.chanvol=64;
+ else if (a->main.chanvol<0)
+ a->main.chanvol=0;
+
+ return 0;
+}
+
+static int DoITEffectN(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+ UBYTE inf, lo, hi;
+
+ inf = UniGetByte();
+
+ if (inf)
+ a->chanvolslide = inf;
+ else
+ inf = a->chanvolslide;
+
+ lo=inf&0xf;
+ hi=inf>>4;
+
+ if (!hi)
+ a->main.chanvol-=lo;
+ else
+ if (!lo) {
+ a->main.chanvol+=hi;
+ } else
+ if (hi==0xf) {
+ if (!tick) a->main.chanvol-=lo;
+ } else
+ if (lo==0xf) {
+ if (!tick) a->main.chanvol+=hi;
+ }
+
+ if (a->main.chanvol<0)
+ a->main.chanvol=0;
+ else if (a->main.chanvol>64)
+ a->main.chanvol=64;
+
+ return 0;
+}
+
+static int DoITEffectP(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+ UBYTE inf, lo, hi;
+ SWORD pan;
+
+ inf = UniGetByte();
+ if (inf)
+ a->pansspd = inf;
+ else
+ inf = a->pansspd;
+
+ if (!mod->panflag)
+ return 0;
+
+ lo=inf&0xf;
+ hi=inf>>4;
+
+ pan=(a->main.panning==PAN_SURROUND)?PAN_CENTER:a->main.panning;
+
+ if (!hi)
+ pan+=lo<<2;
+ else
+ if (!lo) {
+ pan-=hi<<2;
+ } else
+ if (hi==0xf) {
+ if (!tick) pan+=lo<<2;
+ } else
+ if (lo==0xf) {
+ if (!tick) pan-=hi<<2;
+ }
+ a->main.panning=
+ (pan<PAN_LEFT)?PAN_LEFT:(pan>PAN_RIGHT?PAN_RIGHT:pan);
+
+ return 0;
+}
+
+static int DoITEffectT(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+ UBYTE tempo;
+ SWORD temp;
+
+ tempo = UniGetByte();
+
+ if (mod->patdly2)
+ return 0;
+
+ temp = mod->bpm;
+ if (tempo & 0x10)
+ temp += (tempo & 0x0f);
+ else
+ temp -= tempo;
+
+ mod->bpm=(temp>255)?255:(temp<1?1:temp);
+
+ return 0;
+}
+
+static int DoITEffectU(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+ UBYTE dat, q;
+ UWORD temp = 0; /* silence warning */
+
+ dat = UniGetByte();
+ if (!tick) {
+ if (dat&0x0f) a->vibdepth=dat&0xf;
+ if (dat&0xf0) a->vibspd=(dat&0xf0)>>2;
+ }
+ if (a->main.period) {
+ q=(a->vibpos>>2)&0x1f;
+
+ switch (a->wavecontrol&3) {
+ case 0: /* sine */
+ temp=VibratoTable[q];
+ break;
+ case 1: /* square wave */
+ temp=255;
+ break;
+ case 2: /* ramp down */
+ q<<=3;
+ if (a->vibpos<0) q=255-q;
+ temp=q;
+ break;
+ case 3: /* random */
+ temp=getrandom(256);
+ break;
+ }
+
+ temp*=a->vibdepth;
+ temp>>=8;
+
+ if (a->vibpos>=0)
+ a->main.period=a->tmpperiod+temp;
+ else
+ a->main.period=a->tmpperiod-temp;
+ a->ownper = 1;
+
+ a->vibpos+=a->vibspd;
+ }
+
+ return 0;
+}
+
+static int DoITEffectW(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+ UBYTE inf, lo, hi;
+
+ inf = UniGetByte();
+
+ if (inf)
+ mod->globalslide = inf;
+ else
+ inf = mod->globalslide;
+
+ lo=inf&0xf;
+ hi=inf>>4;
+
+ if (!lo) {
+ if (tick) mod->volume+=hi;
+ } else
+ if (!hi) {
+ if (tick) mod->volume-=lo;
+ } else
+ if (lo==0xf) {
+ if (!tick) mod->volume+=hi;
+ } else
+ if (hi==0xf) {
+ if (!tick) mod->volume-=lo;
+ }
+
+ if (mod->volume<0)
+ mod->volume=0;
+ else if (mod->volume>128)
+ mod->volume=128;
+
+ return 0;
+}
+
+static int DoITEffectY(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+ UBYTE dat, q;
+ SLONG temp = 0; /* silence warning */
+
+
+ dat=UniGetByte();
+ if (!tick) {
+ if (dat&0x0f) a->panbdepth=(dat&0xf);
+ if (dat&0xf0) a->panbspd=(dat&0xf0)>>4;
+ }
+ if (mod->panflag) {
+ q=a->panbpos;
+
+ switch (a->panbwave) {
+ case 0: /* sine */
+ temp=PanbrelloTable[q];
+ break;
+ case 1: /* square wave */
+ temp=(q<0x80)?64:0;
+ break;
+ case 2: /* ramp down */
+ q<<=3;
+ temp=q;
+ break;
+ case 3: /* random */
+ temp=getrandom(256);
+ break;
+ }
+
+ temp*=a->panbdepth;
+ temp=(temp/8)+mod->panning[channel];
+
+ a->main.panning=
+ (temp<PAN_LEFT)?PAN_LEFT:(temp>PAN_RIGHT?PAN_RIGHT:temp);
+ a->panbpos+=a->panbspd;
+
+ }
+
+ return 0;
+}
+
+static void DoNNAEffects(MODULE *, MP_CONTROL *, UBYTE);
+
+/* Impulse/Scream Tracker Sxx effects.
+ All Sxx effects share the same memory space. */
+static int DoITEffectS0(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+ UBYTE dat, inf, c;
+
+ dat = UniGetByte();
+ inf=dat&0xf;
+ c=dat>>4;
+
+ if (!dat) {
+ c=a->sseffect;
+ inf=a->ssdata;
+ } else {
+ a->sseffect=c;
+ a->ssdata=inf;
+ }
+
+ switch (c) {
+ case SS_GLISSANDO: /* S1x set glissando voice */
+ DoEEffects(tick, flags, a, mod, channel, 0x30|inf);
+ break;
+ case SS_FINETUNE: /* S2x set finetune */
+ DoEEffects(tick, flags, a, mod, channel, 0x50|inf);
+ break;
+ case SS_VIBWAVE: /* S3x set vibrato waveform */
+ DoEEffects(tick, flags, a, mod, channel, 0x40|inf);
+ break;
+ case SS_TREMWAVE: /* S4x set tremolo waveform */
+ DoEEffects(tick, flags, a, mod, channel, 0x70|inf);
+ break;
+ case SS_PANWAVE: /* S5x panbrello */
+ a->panbwave=inf;
+ break;
+ case SS_FRAMEDELAY: /* S6x delay x number of frames (patdly) */
+ DoEEffects(tick, flags, a, mod, channel, 0xe0|inf);
+ break;
+ case SS_S7EFFECTS: /* S7x instrument / NNA commands */
+ DoNNAEffects(mod, a, inf);
+ break;
+ case SS_PANNING: /* S8x set panning position */
+ DoEEffects(tick, flags, a, mod, channel, 0x80 | inf);
+ break;
+ case SS_SURROUND: /* S9x set surround sound */
+ if (mod->panflag)
+ a->main.panning = mod->panning[channel] = PAN_SURROUND;
+ break;
+ case SS_HIOFFSET: /* SAy set high order sample offset yxx00h */
+ if (!tick) {
+ a->hioffset=inf<<16;
+ a->main.start=a->hioffset|a->soffset;
+
+ if ((a->main.s)&&(a->main.start>a->main.s->length))
+ a->main.start=a->main.s->flags&(SF_LOOP|SF_BIDI)?
+ a->main.s->loopstart:a->main.s->length;
+ }
+ break;
+ case SS_PATLOOP: /* SBx pattern loop */
+ DoEEffects(tick, flags, a, mod, channel, 0x60|inf);
+ break;
+ case SS_NOTECUT: /* SCx notecut */
+ if (!inf) inf = 1;
+ DoEEffects(tick, flags, a, mod, channel, 0xC0|inf);
+ break;
+ case SS_NOTEDELAY: /* SDx notedelay */
+ DoEEffects(tick, flags, a, mod, channel, 0xD0|inf);
+ break;
+ case SS_PATDELAY: /* SEx patterndelay */
+ DoEEffects(tick, flags, a, mod, channel, 0xE0|inf);
+ break;
+ }
+
+ return 0;
+}
+
+/*========== Impulse Tracker Volume/Pan Column effects */
+
+/*
+ * All volume/pan column effects share the same memory space.
+ */
+
+static int DoVolEffects(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+ UBYTE c, inf;
+
+ c = UniGetByte();
+ inf = UniGetByte();
+
+ if ((!c)&&(!inf)) {
+ c=a->voleffect;
+ inf=a->voldata;
+ } else {
+ a->voleffect=c;
+ a->voldata=inf;
+ }
+
+ if (c)
+ switch (c) {
+ case VOL_VOLUME:
+ if (tick) break;
+ if (inf>64) inf=64;
+ a->tmpvolume=inf;
+ break;
+ case VOL_PANNING:
+ if (mod->panflag)
+ a->main.panning=inf;
+ break;
+ case VOL_VOLSLIDE:
+ DoS3MVolSlide(tick, flags, a, inf);
+ return 1;
+ case VOL_PITCHSLIDEDN:
+ if (a->main.period)
+ DoS3MSlideDn(tick, a, inf);
+ break;
+ case VOL_PITCHSLIDEUP:
+ if (a->main.period)
+ DoS3MSlideUp(tick, a, inf);
+ break;
+ case VOL_PORTAMENTO:
+ DoITToneSlide(tick, a, inf);
+ break;
+ case VOL_VIBRATO:
+ DoITVibrato(tick, a, inf);
+ break;
+ }
+
+ return 0;
+}
+
+/*========== UltraTracker effects */
+
+static int DoULTEffect9(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+ UWORD offset=UniGetWord();
+
+ if (offset)
+ a->ultoffset=offset;
+
+ a->main.start=a->ultoffset<<2;
+ if ((a->main.s)&&(a->main.start>a->main.s->length))
+ a->main.start=a->main.s->flags&(SF_LOOP|SF_BIDI)?
+ a->main.s->loopstart:a->main.s->length;
+
+ return 0;
+}
+
+/*========== OctaMED effects */
+
+static int DoMEDSpeed(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+ UWORD speed=UniGetWord();
+
+ mod->bpm=speed;
+
+ return 0;
+}
+
+static int DoMEDEffectF1(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+ DoEEffects(tick, flags, a, mod, channel, 0x90|(mod->sngspd/2));
+
+ return 0;
+}
+
+static int DoMEDEffectF2(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+ DoEEffects(tick, flags, a, mod, channel, 0xd0|(mod->sngspd/2));
+
+ return 0;
+}
+
+static int DoMEDEffectF3(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+ DoEEffects(tick, flags, a, mod, channel, 0x90|(mod->sngspd/3));
+
+ return 0;
+}
+
+/*========== Oktalyzer effects */
+
+static int DoOktArp(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+ UBYTE dat, dat2;
+
+ dat2 = UniGetByte(); /* arpeggio style */
+ dat = UniGetByte();
+ if (!tick) {
+ if (!dat && (flags & UF_ARPMEM))
+ dat=a->arpmem;
+ else
+ a->arpmem=dat;
+ }
+ if (a->main.period)
+ DoArpeggio(tick, flags, a, dat2);
+
+ return 0;
+}
+
+/*========== General player functions */
+
+static int DoNothing(UWORD tick, UWORD flags, MP_CONTROL *a, MODULE *mod, SWORD channel)
+{
+ UniSkipOpcode();
+
+ return 0;
+}
+
+typedef int (*effect_func) (UWORD, UWORD, MP_CONTROL *, MODULE *, SWORD);
+
+static effect_func effects[UNI_LAST] = {
+ DoNothing, /* 0 */
+ DoNothing, /* UNI_NOTE */
+ DoNothing, /* UNI_INSTRUMENT */
+ DoPTEffect0, /* UNI_PTEFFECT0 */
+ DoPTEffect1, /* UNI_PTEFFECT1 */
+ DoPTEffect2, /* UNI_PTEFFECT2 */
+ DoPTEffect3, /* UNI_PTEFFECT3 */
+ DoPTEffect4, /* UNI_PTEFFECT4 */
+ DoPTEffect5, /* UNI_PTEFFECT5 */
+ DoPTEffect6, /* UNI_PTEFFECT6 */
+ DoPTEffect7, /* UNI_PTEFFECT7 */
+ DoPTEffect8, /* UNI_PTEFFECT8 */
+ DoPTEffect9, /* UNI_PTEFFECT9 */
+ DoPTEffectA, /* UNI_PTEFFECTA */
+ DoPTEffectB, /* UNI_PTEFFECTB */
+ DoPTEffectC, /* UNI_PTEFFECTC */
+ DoPTEffectD, /* UNI_PTEFFECTD */
+ DoPTEffectE, /* UNI_PTEFFECTE */
+ DoPTEffectF, /* UNI_PTEFFECTF */
+ DoS3MEffectA, /* UNI_S3MEFFECTA */
+ DoS3MEffectD, /* UNI_S3MEFFECTD */
+ DoS3MEffectE, /* UNI_S3MEFFECTE */
+ DoS3MEffectF, /* UNI_S3MEFFECTF */
+ DoS3MEffectI, /* UNI_S3MEFFECTI */
+ DoS3MEffectQ, /* UNI_S3MEFFECTQ */
+ DoS3MEffectR, /* UNI_S3MEFFECTR */
+ DoS3MEffectT, /* UNI_S3MEFFECTT */
+ DoS3MEffectU, /* UNI_S3MEFFECTU */
+ DoKeyOff, /* UNI_KEYOFF */
+ DoKeyFade, /* UNI_KEYFADE */
+ DoVolEffects, /* UNI_VOLEFFECTS */
+ DoPTEffect4, /* UNI_XMEFFECT4 */
+ DoXMEffect6, /* UNI_XMEFFECT6 */
+ DoXMEffectA, /* UNI_XMEFFECTA */
+ DoXMEffectE1, /* UNI_XMEFFECTE1 */
+ DoXMEffectE2, /* UNI_XMEFFECTE2 */
+ DoXMEffectEA, /* UNI_XMEFFECTEA */
+ DoXMEffectEB, /* UNI_XMEFFECTEB */
+ DoXMEffectG, /* UNI_XMEFFECTG */
+ DoXMEffectH, /* UNI_XMEFFECTH */
+ DoXMEffectL, /* UNI_XMEFFECTL */
+ DoXMEffectP, /* UNI_XMEFFECTP */
+ DoXMEffectX1, /* UNI_XMEFFECTX1 */
+ DoXMEffectX2, /* UNI_XMEFFECTX2 */
+ DoITEffectG, /* UNI_ITEFFECTG */
+ DoITEffectH, /* UNI_ITEFFECTH */
+ DoITEffectI, /* UNI_ITEFFECTI */
+ DoITEffectM, /* UNI_ITEFFECTM */
+ DoITEffectN, /* UNI_ITEFFECTN */
+ DoITEffectP, /* UNI_ITEFFECTP */
+ DoITEffectT, /* UNI_ITEFFECTT */
+ DoITEffectU, /* UNI_ITEFFECTU */
+ DoITEffectW, /* UNI_ITEFFECTW */
+ DoITEffectY, /* UNI_ITEFFECTY */
+ DoNothing, /* UNI_ITEFFECTZ */
+ DoITEffectS0, /* UNI_ITEFFECTS0 */
+ DoULTEffect9, /* UNI_ULTEFFECT9 */
+ DoMEDSpeed, /* UNI_MEDSPEED */
+ DoMEDEffectF1, /* UNI_MEDEFFECTF1 */
+ DoMEDEffectF2, /* UNI_MEDEFFECTF2 */
+ DoMEDEffectF3, /* UNI_MEDEFFECTF3 */
+ DoOktArp, /* UNI_OKTARP */
+};
+
+static int pt_playeffects(MODULE *mod, SWORD channel, MP_CONTROL *a)
+{
+ UWORD tick = mod->vbtick;
+ UWORD flags = mod->flags;
+ UBYTE c;
+ int explicitslides = 0;
+ effect_func f;
+
+ while((c=UniGetByte())) {
+ f = effects[c];
+ if (f != DoNothing)
+ a->sliding = 0;
+ explicitslides |= f(tick, flags, a, mod, channel);
+ }
+ return explicitslides;
+}
+
+static void DoNNAEffects(MODULE *mod, MP_CONTROL *a, UBYTE dat)
+{
+ int t;
+ MP_VOICE *aout;
+
+ dat&=0xf;
+ aout=(a->slave)?a->slave:NULL;
+
+ switch (dat) {
+ case 0x0: /* past note cut */
+ for (t=0;t<md_sngchn;t++)
+ if (mod->voice[t].master==a)
+ mod->voice[t].main.fadevol=0;
+ break;
+ case 0x1: /* past note off */
+ for (t=0;t<md_sngchn;t++)
+ if (mod->voice[t].master==a) {
+ mod->voice[t].main.keyoff|=KEY_OFF;
+ if ((!(mod->voice[t].venv.flg & EF_ON))||
+ (mod->voice[t].venv.flg & EF_LOOP))
+ mod->voice[t].main.keyoff=KEY_KILL;
+ }
+ break;
+ case 0x2: /* past note fade */
+ for (t=0;t<md_sngchn;t++)
+ if (mod->voice[t].master==a)
+ mod->voice[t].main.keyoff|=KEY_FADE;
+ break;
+ case 0x3: /* set NNA note cut */
+ a->main.nna=(a->main.nna&~NNA_MASK)|NNA_CUT;
+ break;
+ case 0x4: /* set NNA note continue */
+ a->main.nna=(a->main.nna&~NNA_MASK)|NNA_CONTINUE;
+ break;
+ case 0x5: /* set NNA note off */
+ a->main.nna=(a->main.nna&~NNA_MASK)|NNA_OFF;
+ break;
+ case 0x6: /* set NNA note fade */
+ a->main.nna=(a->main.nna&~NNA_MASK)|NNA_FADE;
+ break;
+ case 0x7: /* disable volume envelope */
+ if (aout)
+ aout->main.volflg&=~EF_ON;
+ break;
+ case 0x8: /* enable volume envelope */
+ if (aout)
+ aout->main.volflg|=EF_ON;
+ break;
+ case 0x9: /* disable panning envelope */
+ if (aout)
+ aout->main.panflg&=~EF_ON;
+ break;
+ case 0xa: /* enable panning envelope */
+ if (aout)
+ aout->main.panflg|=EF_ON;
+ break;
+ case 0xb: /* disable pitch envelope */
+ if (aout)
+ aout->main.pitflg&=~EF_ON;
+ break;
+ case 0xc: /* enable pitch envelope */
+ if (aout)
+ aout->main.pitflg|=EF_ON;
+ break;
+ }
+}
+
+void pt_UpdateVoices(MODULE *mod, int max_volume)
+{
+ SWORD envpan,envvol,envpit,channel;
+ UWORD playperiod;
+ SLONG vibval,vibdpt;
+ ULONG tmpvol;
+
+ MP_VOICE *aout;
+ INSTRUMENT *i;
+ SAMPLE *s;
+
+ mod->totalchn=mod->realchn=0;
+ for (channel=0;channel<md_sngchn;channel++) {
+ aout=&mod->voice[channel];
+ i=aout->main.i;
+ s=aout->main.s;
+
+ if (!s || !s->length) continue;
+
+ if (aout->main.period<40)
+ aout->main.period=40;
+ else if (aout->main.period>50000)
+ aout->main.period=50000;
+
+ if ((aout->main.kick==KICK_NOTE)||(aout->main.kick==KICK_KEYOFF)) {
+ Voice_Play_internal(channel,s,(aout->main.start==-1)?
+ ((s->flags&SF_UST_LOOP)?s->loopstart:0):aout->main.start);
+ aout->main.fadevol=32768;
+ aout->aswppos=0;
+ }
+
+ envvol = 256;
+ envpan = PAN_CENTER;
+ envpit = 32;
+ if (i && ((aout->main.kick==KICK_NOTE)||(aout->main.kick==KICK_ENV))) {
+ if (aout->main.volflg & EF_ON)
+ envvol = StartEnvelope(&aout->venv,aout->main.volflg,
+ i->volpts,i->volsusbeg,i->volsusend,
+ i->volbeg,i->volend,i->volenv,aout->main.keyoff);
+ if (aout->main.panflg & EF_ON)
+ envpan = StartEnvelope(&aout->penv,aout->main.panflg,
+ i->panpts,i->pansusbeg,i->pansusend,
+ i->panbeg,i->panend,i->panenv,aout->main.keyoff);
+ if (aout->main.pitflg & EF_ON)
+ envpit = StartEnvelope(&aout->cenv,aout->main.pitflg,
+ i->pitpts,i->pitsusbeg,i->pitsusend,
+ i->pitbeg,i->pitend,i->pitenv,aout->main.keyoff);
+
+ if (aout->cenv.flg & EF_ON)
+ aout->masterperiod=GetPeriod(mod->flags,
+ (UWORD)aout->main.note<<1, aout->master->speed);
+ } else {
+ if (aout->main.volflg & EF_ON)
+ envvol = ProcessEnvelope(aout,&aout->venv,256);
+ if (aout->main.panflg & EF_ON)
+ envpan = ProcessEnvelope(aout,&aout->penv,PAN_CENTER);
+ if (aout->main.pitflg & EF_ON)
+ envpit = ProcessEnvelope(aout,&aout->cenv,32);
+ }
+ if (aout->main.kick == KICK_NOTE) {
+ aout->main.kick_flag = 1;
+ }
+ aout->main.kick=KICK_ABSENT;
+
+ tmpvol = aout->main.fadevol; /* max 32768 */
+ tmpvol *= aout->main.chanvol; /* * max 64 */
+ tmpvol *= aout->main.outvolume; /* * max 256 */
+ tmpvol /= (256 * 64); /* tmpvol is max 32768 again */
+ aout->totalvol = tmpvol >> 2; /* used to determine samplevolume */
+ tmpvol *= envvol; /* * max 256 */
+ tmpvol *= mod->volume; /* * max 128 */
+ tmpvol /= (128 * 256 * 128);
+
+ /* fade out */
+ if (mod->sngpos>=mod->numpos)
+ tmpvol=0;
+ else
+ tmpvol=(tmpvol*max_volume)/128;
+
+ if ((aout->masterchn!=-1)&& mod->control[aout->masterchn].muted)
+ Voice_SetVolume_internal(channel,0);
+ else {
+ Voice_SetVolume_internal(channel,tmpvol);
+ if ((tmpvol)&&(aout->master)&&(aout->master->slave==aout))
+ mod->realchn++;
+ mod->totalchn++;
+ }
+
+ if (aout->main.panning==PAN_SURROUND)
+ Voice_SetPanning_internal(channel,PAN_SURROUND);
+ else
+ if ((mod->panflag)&&(aout->penv.flg & EF_ON))
+ Voice_SetPanning_internal(channel,
+ DoPan(envpan,aout->main.panning));
+ else
+ Voice_SetPanning_internal(channel,aout->main.panning);
+
+ if (aout->main.period && s->vibdepth)
+ switch (s->vibtype) {
+ case 0:
+ vibval=avibtab[s->avibpos&127];
+ if (aout->avibpos & 0x80) vibval=-vibval;
+ break;
+ case 1:
+ vibval=64;
+ if (aout->avibpos & 0x80) vibval=-vibval;
+ break;
+ case 2:
+ vibval=63-(((aout->avibpos+128)&255)>>1);
+ break;
+ default:
+ vibval=(((aout->avibpos+128)&255)>>1)-64;
+ break;
+ }
+ else
+ vibval=0;
+
+ if (s->vibflags & AV_IT) {
+ if ((aout->aswppos>>8)<s->vibdepth) {
+ aout->aswppos += s->vibsweep;
+ vibdpt=aout->aswppos;
+ } else
+ vibdpt=s->vibdepth<<8;
+ vibval=(vibval*vibdpt)>>16;
+ if (aout->mflag) {
+ if (!(mod->flags&UF_LINEAR)) vibval>>=1;
+ aout->main.period-=vibval;
+ }
+ } else {
+ /* do XM style auto-vibrato */
+ if (!(aout->main.keyoff & KEY_OFF)) {
+ if (aout->aswppos<s->vibsweep) {
+ vibdpt=(aout->aswppos*s->vibdepth)/s->vibsweep;
+ aout->aswppos++;
+ } else
+ vibdpt=s->vibdepth;
+ } else {
+ /* keyoff -> depth becomes 0 if final depth wasn't reached or
+ stays at final level if depth WAS reached */
+ if (aout->aswppos>=s->vibsweep)
+ vibdpt=s->vibdepth;
+ else
+ vibdpt=0;
+ }
+ vibval=(vibval*vibdpt)>>8;
+ aout->main.period-=vibval;
+ }
+
+ /* update vibrato position */
+ aout->avibpos=(aout->avibpos+s->vibrate)&0xff;
+
+ /* process pitch envelope */
+ playperiod=aout->main.period;
+
+ if ((aout->main.pitflg&EF_ON)&&(envpit!=32)) {
+ long p1;
+
+ envpit-=32;
+ if ((aout->main.note<<1)+envpit<=0) envpit=-(aout->main.note<<1);
+
+ p1=GetPeriod(mod->flags, ((UWORD)aout->main.note<<1)+envpit,
+ aout->master->speed)-aout->masterperiod;
+ if (p1>0) {
+ if ((UWORD)(playperiod+p1)<=playperiod) {
+ p1=0;
+ aout->main.keyoff|=KEY_OFF;
+ }
+ } else if (p1<0) {
+ if ((UWORD)(playperiod+p1)>=playperiod) {
+ p1=0;
+ aout->main.keyoff|=KEY_OFF;
+ }
+ }
+ playperiod+=p1;
+ }
+
+ if (!aout->main.fadevol) { /* check for a dead note (fadevol=0) */
+ Voice_Stop_internal(channel);
+ mod->totalchn--;
+ if ((tmpvol)&&(aout->master)&&(aout->master->slave==aout))
+ mod->realchn--;
+ } else {
+ Voice_SetFrequency_internal(channel,
+ getfrequency(mod->flags,playperiod));
+
+ /* if keyfade, start substracting fadeoutspeed from fadevol: */
+ if ((i)&&(aout->main.keyoff&KEY_FADE)) {
+ if (aout->main.fadevol>=i->volfade)
+ aout->main.fadevol-=i->volfade;
+ else
+ aout->main.fadevol=0;
+ }
+ }
+
+ md_bpm=mod->bpm+mod->relspd;
+ if (md_bpm<32)
+ md_bpm=32;
+ else if ((!(mod->flags&UF_HIGHBPM)) && md_bpm>255)
+ md_bpm=255;
+ }
+}
+
+/* Handles new notes or instruments */
+void pt_Notes(MODULE *mod)
+{
+ SWORD channel;
+ MP_CONTROL *a;
+ UBYTE c,inst;
+ int tr,funky; /* funky is set to indicate note or instrument change */
+
+ for (channel=0;channel<mod->numchn;channel++) {
+ a=&mod->control[channel];
+
+ if (mod->sngpos>=mod->numpos) {
+ tr=mod->numtrk;
+ mod->numrow=0;
+ } else {
+ tr=mod->patterns[(mod->positions[mod->sngpos]*mod->numchn)+channel];
+ mod->numrow=mod->pattrows[mod->positions[mod->sngpos]];
+ }
+
+ a->row=(tr<mod->numtrk)?UniFindRow(mod->tracks[tr],mod->patpos):NULL;
+ a->newsamp=0;
+ if (!mod->vbtick) a->main.notedelay=0;
+
+ if (!a->row) continue;
+ UniSetRow(a->row);
+ funky=0;
+
+ while((c=UniGetByte()))
+ switch (c) {
+ case UNI_NOTE:
+ funky|=1;
+ a->oldnote=a->anote,a->anote=UniGetByte();
+ a->main.kick =KICK_NOTE;
+ a->main.start=-1;
+ a->sliding=0;
+
+ /* retrig tremolo and vibrato waves ? */
+ if (!(a->wavecontrol & 0x80)) a->trmpos=0;
+ if (!(a->wavecontrol & 0x08)) a->vibpos=0;
+ if (!a->panbwave) a->panbpos=0;
+ break;
+ case UNI_INSTRUMENT:
+ inst=UniGetByte();
+ if (inst>=mod->numins) break; /* safety valve */
+ funky|=2;
+ a->main.i=(mod->flags & UF_INST)?&mod->instruments[inst]:NULL;
+ a->retrig=0;
+ a->s3mtremor=0;
+ a->ultoffset=0;
+ a->main.sample=inst;
+ break;
+ default:
+ UniSkipOpcode();
+ break;
+ }
+
+ if (funky) {
+ INSTRUMENT *i;
+ SAMPLE *s;
+
+ if ((i=a->main.i)) {
+ if (i->samplenumber[a->anote] >= mod->numsmp) continue;
+ s=&mod->samples[i->samplenumber[a->anote]];
+ a->main.note=i->samplenote[a->anote];
+ } else {
+ a->main.note=a->anote;
+ s=&mod->samples[a->main.sample];
+ }
+
+ if (a->main.s!=s) {
+ a->main.s=s;
+ a->newsamp=a->main.period;
+ }
+
+ /* channel or instrument determined panning ? */
+ a->main.panning=mod->panning[channel];
+ if (s->flags & SF_OWNPAN)
+ a->main.panning=s->panning;
+ else if ((i)&&(i->flags & IF_OWNPAN))
+ a->main.panning=i->panning;
+
+ a->main.handle=s->handle;
+ a->speed=s->speed;
+
+ if (i) {
+ if ((mod->panflag)&&(i->flags & IF_PITCHPAN)
+ &&(a->main.panning!=PAN_SURROUND)){
+ a->main.panning+=
+ ((a->anote-i->pitpancenter)*i->pitpansep)/8;
+ if (a->main.panning<PAN_LEFT)
+ a->main.panning=PAN_LEFT;
+ else if (a->main.panning>PAN_RIGHT)
+ a->main.panning=PAN_RIGHT;
+ }
+ a->main.pitflg=i->pitflg;
+ a->main.volflg=i->volflg;
+ a->main.panflg=i->panflg;
+ a->main.nna=i->nnatype;
+ a->dca=i->dca;
+ a->dct=i->dct;
+ } else {
+ a->main.pitflg=a->main.volflg=a->main.panflg=0;
+ a->main.nna=a->dca=0;
+ a->dct=DCT_OFF;
+ }
+
+ if (funky&2) /* instrument change */ {
+ /* IT random volume variations: 0:8 bit fixed, and one bit for
+ sign. */
+ a->volume=a->tmpvolume=s->volume;
+ if ((s)&&(i)) {
+ if (i->rvolvar) {
+ a->volume=a->tmpvolume=s->volume+
+ ((s->volume*((SLONG)i->rvolvar*(SLONG)getrandom(512)
+ ))/25600);
+ if (a->volume<0)
+ a->volume=a->tmpvolume=0;
+ else if (a->volume>64)
+ a->volume=a->tmpvolume=64;
+ }
+ if ((mod->panflag)&&(a->main.panning!=PAN_SURROUND)) {
+ a->main.panning+=((a->main.panning*((SLONG)i->rpanvar*
+ (SLONG)getrandom(512)))/25600);
+ if (a->main.panning<PAN_LEFT)
+ a->main.panning=PAN_LEFT;
+ else if (a->main.panning>PAN_RIGHT)
+ a->main.panning=PAN_RIGHT;
+ }
+ }
+ }
+
+ a->wantedperiod=a->tmpperiod=
+ GetPeriod(mod->flags, (UWORD)a->main.note<<1,a->speed);
+ a->main.keyoff=KEY_KICK;
+ }
+ }
+}
+
+/* Handles effects */
+void pt_EffectsPass1(MODULE *mod)
+{
+ SWORD channel;
+ MP_CONTROL *a;
+ MP_VOICE *aout;
+ int explicitslides;
+
+ for (channel=0;channel<mod->numchn;channel++) {
+ a=&mod->control[channel];
+
+ if ((aout=a->slave)) {
+ a->main.fadevol=aout->main.fadevol;
+ a->main.period=aout->main.period;
+ if (a->main.kick==KICK_KEYOFF)
+ a->main.keyoff=aout->main.keyoff;
+ }
+
+ if (!a->row) continue;
+ UniSetRow(a->row);
+
+ a->ownper=a->ownvol=0;
+ explicitslides = pt_playeffects(mod, channel, a);
+
+ /* continue volume slide if necessary for XM and IT */
+ if (mod->flags&UF_BGSLIDES) {
+ if (!explicitslides && a->sliding)
+ DoS3MVolSlide(mod->vbtick, mod->flags, a, 0);
+ else if (a->tmpvolume)
+ a->sliding = explicitslides;
+ }
+
+ if (!a->ownper)
+ a->main.period=a->tmpperiod;
+ if (!a->ownvol)
+ a->volume=a->tmpvolume;
+
+ if (a->main.s) {
+ if (a->main.i)
+ a->main.outvolume=
+ (a->volume*a->main.s->globvol*a->main.i->globvol)>>10;
+ else
+ a->main.outvolume=(a->volume*a->main.s->globvol)>>4;
+ if (a->main.outvolume>256)
+ a->main.outvolume=256;
+ else if (a->main.outvolume<0)
+ a->main.outvolume=0;
+ }
+ }
+}
+
+/* NNA management */
+void pt_NNA(MODULE *mod)
+{
+ SWORD channel;
+ MP_CONTROL *a;
+
+ for (channel=0;channel<mod->numchn;channel++) {
+ a=&mod->control[channel];
+
+ if (a->main.kick==KICK_NOTE) {
+ int kill=0;
+
+ if (a->slave) {
+ MP_VOICE *aout;
+
+ aout=a->slave;
+ if (aout->main.nna & NNA_MASK) {
+ /* Make sure the old MP_VOICE channel knows it has no
+ master now ! */
+ a->slave=NULL;
+ /* assume the channel is taken by NNA */
+ aout->mflag=0;
+
+ switch (aout->main.nna) {
+ case NNA_CONTINUE: /* continue note, do nothing */
+ break;
+ case NNA_OFF: /* note off */
+ aout->main.keyoff|=KEY_OFF;
+ if ((!(aout->main.volflg & EF_ON))||
+ (aout->main.volflg & EF_LOOP))
+ aout->main.keyoff=KEY_KILL;
+ break;
+ case NNA_FADE:
+ aout->main.keyoff |= KEY_FADE;
+ break;
+ }
+ }
+ }
+
+ if (a->dct!=DCT_OFF) {
+ int t;
+
+ for (t=0;t<md_sngchn;t++)
+ if ((!Voice_Stopped_internal(t))&&
+ (mod->voice[t].masterchn==channel)&&
+ (a->main.sample==mod->voice[t].main.sample)) {
+ kill=0;
+ switch (a->dct) {
+ case DCT_NOTE:
+ if (a->main.note==mod->voice[t].main.note)
+ kill=1;
+ break;
+ case DCT_SAMPLE:
+ if (a->main.handle==mod->voice[t].main.handle)
+ kill=1;
+ break;
+ case DCT_INST:
+ kill=1;
+ break;
+ }
+ if (kill)
+ switch (a->dca) {
+ case DCA_CUT:
+ mod->voice[t].main.fadevol=0;
+ break;
+ case DCA_OFF:
+ mod->voice[t].main.keyoff|=KEY_OFF;
+ if ((!(mod->voice[t].main.volflg&EF_ON))||
+ (mod->voice[t].main.volflg&EF_LOOP))
+ mod->voice[t].main.keyoff=KEY_KILL;
+ break;
+ case DCA_FADE:
+ mod->voice[t].main.keyoff|=KEY_FADE;
+ break;
+ }
+ }
+ }
+ } /* if (a->main.kick==KICK_NOTE) */
+ }
+}
+
+/* Setup module and NNA voices */
+void pt_SetupVoices(MODULE *mod)
+{
+ SWORD channel;
+ MP_CONTROL *a;
+ MP_VOICE *aout;
+
+ for (channel=0;channel<mod->numchn;channel++) {
+ a=&mod->control[channel];
+
+ if (a->main.notedelay) continue;
+ if (a->main.kick==KICK_NOTE) {
+ /* if no channel was cut above, find an empty or quiet channel
+ here */
+ if (mod->flags&UF_NNA) {
+ if (!a->slave) {
+ int newchn;
+
+ if ((newchn=MP_FindEmptyChannel(mod))!=-1)
+ a->slave=&mod->voice[a->slavechn=newchn];
+ }
+ } else
+ a->slave=&mod->voice[a->slavechn=channel];
+
+ /* assign parts of MP_VOICE only done for a KICK_NOTE */
+ if ((aout=a->slave)) {
+ if (aout->mflag && aout->master) aout->master->slave=NULL;
+ aout->master=a;
+ a->slave=aout;
+ aout->masterchn=channel;
+ aout->mflag=1;
+ }
+ } else
+ aout=a->slave;
+
+ if (aout)
+ aout->main=a->main;
+ a->main.kick=KICK_ABSENT;
+ }
+}
+
+/* second effect pass */
+void pt_EffectsPass2(MODULE *mod)
+{
+ SWORD channel;
+ MP_CONTROL *a;
+ UBYTE c;
+
+ for (channel=0;channel<mod->numchn;channel++) {
+ a=&mod->control[channel];
+
+ if (!a->row) continue;
+ UniSetRow(a->row);
+
+ while((c=UniGetByte()))
+ if (c==UNI_ITEFFECTS0) {
+ c=UniGetByte();
+ if ((c>>4)==SS_S7EFFECTS)
+ DoNNAEffects(mod, a, c&0xf);
+ } else
+ UniSkipOpcode();
+ }
+}
+
+void Player_HandleTick(void)
+{
+ SWORD channel;
+ int max_volume;
+
+#if 0
+ /* don't handle the very first ticks, this allows the other hardware to
+ settle down so we don't loose any starting notes */
+ if (isfirst) {
+ isfirst--;
+ return;
+ }
+#endif
+
+ if ((!pf)||(pf->forbid)||(pf->sngpos>=pf->numpos)) return;
+
+ /* update time counter (sngtime is in milliseconds (in fact 2^-10)) */
+ pf->sngremainder+=(1<<9)*5; /* thus 2.5*(1<<10), since fps=0.4xtempo */
+ pf->sngtime+=pf->sngremainder/pf->bpm;
+ pf->sngremainder%=pf->bpm;
+
+ if (++pf->vbtick>=pf->sngspd) {
+ if (pf->pat_repcrazy)
+ pf->pat_repcrazy=0; /* play 2 times row 0 */
+ else
+ pf->patpos++;
+ pf->vbtick=0;
+
+ /* process pattern-delay. pf->patdly2 is the counter and pf->patdly is
+ the command memory. */
+ if (pf->patdly)
+ pf->patdly2=pf->patdly,pf->patdly=0;
+ if (pf->patdly2) {
+ /* patterndelay active */
+ if (--pf->patdly2)
+ /* so turn back pf->patpos by 1 */
+ if (pf->patpos) pf->patpos--;
+ }
+
+ /* do we have to get a new patternpointer ? (when pf->patpos reaches the
+ pattern size, or when a patternbreak is active) */
+ if (((pf->patpos>=pf->numrow)&&(pf->numrow>0))&&(!pf->posjmp))
+ pf->posjmp=3;
+
+ if (pf->posjmp) {
+ pf->patpos=pf->numrow?(pf->patbrk%pf->numrow):0;
+ pf->pat_repcrazy=0;
+ pf->sngpos+=(pf->posjmp-2);
+ for (channel=0;channel<pf->numchn;channel++)
+ pf->control[channel].pat_reppos=-1;
+
+ pf->patbrk=pf->posjmp=0;
+ /* handle the "---" (end of song) pattern since it can occur
+ *inside* the module in some formats */
+ if ((pf->sngpos>=pf->numpos)||
+ (pf->positions[pf->sngpos]==LAST_PATTERN)) {
+ if (!pf->wrap) return;
+ if (!(pf->sngpos=pf->reppos)) {
+ pf->volume=pf->initvolume>128?128:pf->initvolume;
+ if(pf->initspeed!=0)
+ pf->sngspd=pf->initspeed<32?pf->initspeed:32;
+ else
+ pf->sngspd=6;
+ pf->bpm=pf->inittempo<32?32:pf->inittempo;
+ }
+ }
+ if (pf->sngpos<0) pf->sngpos=pf->numpos-1;
+ }
+
+ if (!pf->patdly2)
+ pt_Notes(pf);
+ }
+
+ /* Fade global volume if enabled and we're playing the last pattern */
+ if (((pf->sngpos==pf->numpos-1)||
+ (pf->positions[pf->sngpos+1]==LAST_PATTERN))&&
+ (pf->fadeout))
+ max_volume=pf->numrow?((pf->numrow-pf->patpos)*128)/pf->numrow:0;
+ else
+ max_volume=128;
+
+ pt_EffectsPass1(pf);
+ if (pf->flags&UF_NNA)
+ pt_NNA(pf);
+ pt_SetupVoices(pf);
+ pt_EffectsPass2(pf);
+
+ /* now set up the actual hardware channel playback information */
+ pt_UpdateVoices(pf, max_volume);
+}
+
+static void Player_Init_internal(MODULE* mod)
+{
+ int t;
+
+ for (t=0;t<mod->numchn;t++) {
+ mod->control[t].main.chanvol=mod->chanvol[t];
+ mod->control[t].main.panning=mod->panning[t];
+ }
+
+ mod->sngtime=0;
+ mod->sngremainder=0;
+
+ mod->pat_repcrazy=0;
+ mod->sngpos=0;
+ if(mod->initspeed!=0)
+ mod->sngspd=mod->initspeed<32?mod->initspeed:32;
+ else
+ mod->sngspd=6;
+ mod->volume=mod->initvolume>128?128:mod->initvolume;
+
+ mod->vbtick=mod->sngspd;
+ mod->patdly=0;
+ mod->patdly2=0;
+ mod->bpm=mod->inittempo<32?32:mod->inittempo;
+ mod->realchn=0;
+
+ mod->patpos=0;
+ mod->posjmp=2; /* make sure the player fetches the first note */
+ mod->numrow=-1;
+ mod->patbrk=0;
+}
+
+int Player_Init(MODULE* mod)
+{
+ mod->extspd=1;
+ mod->panflag=1;
+ mod->wrap=0;
+ mod->loop=1;
+ mod->fadeout=0;
+
+ mod->relspd=0;
+
+ /* make sure the player doesn't start with garbage */
+ if (!(mod->control=(MP_CONTROL*)MikMod_calloc(mod->numchn,sizeof(MP_CONTROL))))
+ return 1;
+ if (!(mod->voice=(MP_VOICE*)MikMod_calloc(md_sngchn,sizeof(MP_VOICE))))
+ return 1;
+
+ Player_Init_internal(mod);
+ return 0;
+}
+
+void Player_Exit_internal(MODULE* mod)
+{
+ if (!mod)
+ return;
+
+ /* Stop playback if necessary */
+ if (mod==pf) {
+ Player_Stop_internal();
+ pf=NULL;
+ }
+
+ if (mod->control)
+ MikMod_free(mod->control);
+ if (mod->voice)
+ MikMod_free(mod->voice);
+ mod->control=NULL;
+ mod->voice=NULL;
+}
+
+void Player_Exit(MODULE* mod)
+{
+ MUTEX_LOCK(vars);
+ Player_Exit_internal(mod);
+ MUTEX_UNLOCK(vars);
+}
+
+MIKMODAPI void Player_SetVolume(SWORD volume)
+{
+ MUTEX_LOCK(vars);
+ if (pf)
+ pf->volume=(volume<0)?0:(volume>128)?128:volume;
+ MUTEX_UNLOCK(vars);
+}
+
+MIKMODAPI MODULE* Player_GetModule(void)
+{
+ MODULE* result;
+
+ MUTEX_LOCK(vars);
+ result=pf;
+ MUTEX_UNLOCK(vars);
+
+ return result;
+}
+
+MIKMODAPI void Player_Start(MODULE *mod)
+{
+ int t;
+
+ if (!mod)
+ return;
+
+ if (!MikMod_Active())
+ MikMod_EnableOutput();
+
+ mod->forbid=0;
+
+ MUTEX_LOCK(vars);
+ if (pf!=mod) {
+ /* new song is being started, so completely stop out the old one. */
+ if (pf) pf->forbid=1;
+ for (t=0;t<md_sngchn;t++) Voice_Stop_internal(t);
+ }
+ pf=mod;
+ MUTEX_UNLOCK(vars);
+}
+
+void Player_Stop_internal(void)
+{
+ if (!md_sfxchn) MikMod_DisableOutput_internal();
+ if (pf) pf->forbid=1;
+ pf=NULL;
+}
+
+MIKMODAPI void Player_Stop(void)
+{
+ MUTEX_LOCK(vars);
+ Player_Stop_internal();
+ MUTEX_UNLOCK(vars);
+}
+
+MIKMODAPI int Player_Active(void)
+{
+ int result=0;
+
+ MUTEX_LOCK(vars);
+ if (pf)
+ result=(!(pf->sngpos>=pf->numpos));
+ MUTEX_UNLOCK(vars);
+
+ return result;
+}
+
+MIKMODAPI void Player_NextPosition(void)
+{
+ MUTEX_LOCK(vars);
+ if (pf) {
+ int t;
+
+ pf->forbid=1;
+ pf->posjmp=3;
+ pf->patbrk=0;
+ pf->vbtick=pf->sngspd;
+
+ for (t=0;t<md_sngchn;t++) {
+ Voice_Stop_internal(t);
+ pf->voice[t].main.i=NULL;
+ pf->voice[t].main.s=NULL;
+ }
+ for (t=0;t<pf->numchn;t++) {
+ pf->control[t].main.i=NULL;
+ pf->control[t].main.s=NULL;
+ }
+ pf->forbid=0;
+ }
+ MUTEX_UNLOCK(vars);
+}
+
+MIKMODAPI void Player_PrevPosition(void)
+{
+ MUTEX_LOCK(vars);
+ if (pf) {
+ int t;
+
+ pf->forbid=1;
+ pf->posjmp=1;
+ pf->patbrk=0;
+ pf->vbtick=pf->sngspd;
+
+ for (t=0;t<md_sngchn;t++) {
+ Voice_Stop_internal(t);
+ pf->voice[t].main.i=NULL;
+ pf->voice[t].main.s=NULL;
+ }
+ for (t=0;t<pf->numchn;t++) {
+ pf->control[t].main.i=NULL;
+ pf->control[t].main.s=NULL;
+ }
+ pf->forbid=0;
+ }
+ MUTEX_UNLOCK(vars);
+}
+
+MIKMODAPI void Player_SetPosition(UWORD pos)
+{
+ MUTEX_LOCK(vars);
+ if (pf) {
+ int t;
+
+ pf->forbid=1;
+ if (pos>=pf->numpos) pos=pf->numpos;
+ pf->posjmp=2;
+ pf->patbrk=0;
+ pf->sngpos=pos;
+ pf->vbtick=pf->sngspd;
+
+ for (t=0;t<md_sngchn;t++) {
+ Voice_Stop_internal(t);
+ pf->voice[t].main.i=NULL;
+ pf->voice[t].main.s=NULL;
+ }
+ for (t=0;t<pf->numchn;t++) {
+ pf->control[t].main.i=NULL;
+ pf->control[t].main.s=NULL;
+ }
+ pf->forbid=0;
+
+ if (!pos)
+ Player_Init_internal(pf);
+ }
+ MUTEX_UNLOCK(vars);
+}
+
+static void Player_Unmute_internal(SLONG arg1,va_list ap)
+{
+ SLONG t,arg2,arg3=0;
+
+ if (pf) {
+ switch (arg1) {
+ case MUTE_INCLUSIVE:
+ if (((!(arg2=va_arg(ap,SLONG)))&&(!(arg3=va_arg(ap,SLONG))))||
+ (arg2>arg3)||(arg3>=pf->numchn))
+ return;
+ for (;arg2<pf->numchn && arg2<=arg3;arg2++)
+ pf->control[arg2].muted=0;
+ break;
+ case MUTE_EXCLUSIVE:
+ if (((!(arg2=va_arg(ap,SLONG)))&&(!(arg3=va_arg(ap,SLONG))))||
+ (arg2>arg3)||(arg3>=pf->numchn))
+ return;
+ for (t=0;t<pf->numchn;t++) {
+ if ((t>=arg2) && (t<=arg3))
+ continue;
+ pf->control[t].muted=0;
+ }
+ break;
+ default:
+ if (arg1<pf->numchn) pf->control[arg1].muted=0;
+ break;
+ }
+ }
+}
+
+MIKMODAPI void Player_Unmute(SLONG arg1, ...)
+{
+ va_list args;
+
+ va_start(args,arg1);
+ MUTEX_LOCK(vars);
+ Player_Unmute_internal(arg1,args);
+ MUTEX_UNLOCK(vars);
+ va_end(args);
+}
+
+static void Player_Mute_internal(SLONG arg1,va_list ap)
+{
+ SLONG t,arg2,arg3=0;
+
+ if (pf) {
+ switch (arg1) {
+ case MUTE_INCLUSIVE:
+ if (((!(arg2=va_arg(ap,SLONG)))&&(!(arg3=va_arg(ap,SLONG))))||
+ (arg2>arg3)||(arg3>=pf->numchn))
+ return;
+ for (;arg2<pf->numchn && arg2<=arg3;arg2++)
+ pf->control[arg2].muted=1;
+ break;
+ case MUTE_EXCLUSIVE:
+ if (((!(arg2=va_arg(ap,SLONG)))&&(!(arg3=va_arg(ap,SLONG))))||
+ (arg2>arg3)||(arg3>=pf->numchn))
+ return;
+ for (t=0;t<pf->numchn;t++) {
+ if ((t>=arg2) && (t<=arg3))
+ continue;
+ pf->control[t].muted=1;
+ }
+ break;
+ default:
+ if (arg1<pf->numchn)
+ pf->control[arg1].muted=1;
+ break;
+ }
+ }
+}
+
+MIKMODAPI void Player_Mute(SLONG arg1,...)
+{
+ va_list args;
+
+ va_start(args,arg1);
+ MUTEX_LOCK(vars);
+ Player_Mute_internal(arg1,args);
+ MUTEX_UNLOCK(vars);
+ va_end(args);
+}
+
+static void Player_ToggleMute_internal(SLONG arg1,va_list ap)
+{
+ SLONG arg2,arg3=0;
+ ULONG t;
+
+ if (pf) {
+ switch (arg1) {
+ case MUTE_INCLUSIVE:
+ if (((!(arg2=va_arg(ap,SLONG)))&&(!(arg3=va_arg(ap,SLONG))))||
+ (arg2>arg3)||(arg3>=pf->numchn))
+ return;
+ for (;arg2<pf->numchn && arg2<=arg3;arg2++)
+ pf->control[arg2].muted=1-pf->control[arg2].muted;
+ break;
+ case MUTE_EXCLUSIVE:
+ if (((!(arg2=va_arg(ap,SLONG)))&&(!(arg3=va_arg(ap,SLONG))))||
+ (arg2>arg3)||(arg3>=pf->numchn))
+ return;
+ for (t=0;t<pf->numchn;t++) {
+ if ((t>=arg2) && (t<=arg3))
+ continue;
+ pf->control[t].muted=1-pf->control[t].muted;
+ }
+ break;
+ default:
+ if (arg1<pf->numchn)
+ pf->control[arg1].muted=1-pf->control[arg1].muted;
+ break;
+ }
+ }
+}
+
+MIKMODAPI void Player_ToggleMute(SLONG arg1,...)
+{
+ va_list args;
+
+ va_start(args,arg1);
+ MUTEX_LOCK(vars);
+ Player_ToggleMute_internal(arg1,args);
+ MUTEX_UNLOCK(vars);
+ va_end(args);
+}
+
+MIKMODAPI int Player_Muted(UBYTE chan)
+{
+ int result=1;
+
+ MUTEX_LOCK(vars);
+ if (pf)
+ result=(chan<pf->numchn)?pf->control[chan].muted:1;
+ MUTEX_UNLOCK(vars);
+
+ return result;
+}
+
+MIKMODAPI int Player_GetChannelVoice(UBYTE chan)
+{
+ int result=0;
+
+ MUTEX_LOCK(vars);
+ if (pf)
+ result=(chan<pf->numchn)?pf->control[chan].slavechn:-1;
+ MUTEX_UNLOCK(vars);
+
+ return result;
+}
+
+MIKMODAPI UWORD Player_GetChannelPeriod(UBYTE chan)
+{
+ UWORD result=0;
+
+ MUTEX_LOCK(vars);
+ if (pf)
+ result=(chan<pf->numchn)?pf->control[chan].main.period:0;
+ MUTEX_UNLOCK(vars);
+
+ return result;
+}
+
+int Player_Paused_internal(void)
+{
+ return pf?pf->forbid:1;
+}
+
+MIKMODAPI int Player_Paused(void)
+{
+ int result;
+
+ MUTEX_LOCK(vars);
+ result=Player_Paused_internal();
+ MUTEX_UNLOCK(vars);
+
+ return result;
+}
+
+MIKMODAPI void Player_TogglePause(void)
+{
+ MUTEX_LOCK(vars);
+ if (pf)
+ pf->forbid=1-pf->forbid;
+ MUTEX_UNLOCK(vars);
+}
+
+MIKMODAPI void Player_SetSpeed(UWORD speed)
+{
+ MUTEX_LOCK(vars);
+ if (pf)
+ pf->sngspd=speed?(speed<32?speed:32):1;
+ MUTEX_UNLOCK(vars);
+}
+
+MIKMODAPI void Player_SetTempo(UWORD tempo)
+{
+ if (tempo<32) tempo=32;
+ MUTEX_LOCK(vars);
+ if (pf) {
+ if ((!(pf->flags&UF_HIGHBPM))&&(tempo>255)) tempo=255;
+ pf->bpm=tempo;
+ }
+ MUTEX_UNLOCK(vars);
+}
+
+MIKMODAPI int Player_QueryVoices(UWORD numvoices, VOICEINFO *vinfo)
+{
+ int i;
+
+ if (numvoices > md_sngchn)
+ numvoices = md_sngchn;
+
+ MUTEX_LOCK(vars);
+ if (pf)
+ for (i = 0; i < md_sngchn; i++) {
+ vinfo [i].i = pf->voice[i].main.i;
+ vinfo [i].s = pf->voice[i].main.s;
+ vinfo [i].panning = pf->voice [i].main.panning;
+ vinfo [i].volume = pf->voice [i].main.chanvol;
+ vinfo [i].period = pf->voice [i].main.period;
+ vinfo [i].kick = pf->voice [i].main.kick_flag;
+ pf->voice [i].main.kick_flag = 0;
+ }
+ MUTEX_UNLOCK(vars);
+
+ return numvoices;
+}
+
+
+// Get current module order
+MIKMODAPI int Player_GetOrder(void)
+{
+ int ret;
+ MUTEX_LOCK(vars);
+ ret = pf ? pf->sngpos :0; // pf->positions[pf->sngpos ? pf->sngpos-1 : 0]: 0;
+ MUTEX_UNLOCK(vars);
+ return ret;
+}
+
+// Get current module row
+MIKMODAPI int Player_GetRow(void)
+{
+ int ret;
+ MUTEX_LOCK(vars);
+ ret = pf ? pf->patpos : 0;
+ MUTEX_UNLOCK(vars);
+ return ret;
+}
+
+
+/* ex:set ts=4: */
diff --git a/apps/plugins/mikmod/munitrk.c b/apps/plugins/mikmod/munitrk.c
new file mode 100644
index 0000000000..f0a8f58af7
--- /dev/null
+++ b/apps/plugins/mikmod/munitrk.c
@@ -0,0 +1,303 @@
+/* MikMod sound library
+ (c) 1998, 1999, 2000, 2001 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: munitrk.c,v 1.2 2005/03/30 19:11:46 realtech Exp $
+
+ All routines dealing with the manipulation of UNITRK streams
+
+==============================================================================*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "mikmod_internals.h"
+
+#include <string.h>
+
+/* Unibuffer chunk size */
+#define BUFPAGE 128
+
+UWORD unioperands[UNI_LAST]={
+ 0, /* not used */
+ 1, /* UNI_NOTE */
+ 1, /* UNI_INSTRUMENT */
+ 1, /* UNI_PTEFFECT0 */
+ 1, /* UNI_PTEFFECT1 */
+ 1, /* UNI_PTEFFECT2 */
+ 1, /* UNI_PTEFFECT3 */
+ 1, /* UNI_PTEFFECT4 */
+ 1, /* UNI_PTEFFECT5 */
+ 1, /* UNI_PTEFFECT6 */
+ 1, /* UNI_PTEFFECT7 */
+ 1, /* UNI_PTEFFECT8 */
+ 1, /* UNI_PTEFFECT9 */
+ 1, /* UNI_PTEFFECTA */
+ 1, /* UNI_PTEFFECTB */
+ 1, /* UNI_PTEFFECTC */
+ 1, /* UNI_PTEFFECTD */
+ 1, /* UNI_PTEFFECTE */
+ 1, /* UNI_PTEFFECTF */
+ 1, /* UNI_S3MEFFECTA */
+ 1, /* UNI_S3MEFFECTD */
+ 1, /* UNI_S3MEFFECTE */
+ 1, /* UNI_S3MEFFECTF */
+ 1, /* UNI_S3MEFFECTI */
+ 1, /* UNI_S3MEFFECTQ */
+ 1, /* UNI_S3MEFFECTR */
+ 1, /* UNI_S3MEFFECTT */
+ 1, /* UNI_S3MEFFECTU */
+ 0, /* UNI_KEYOFF */
+ 1, /* UNI_KEYFADE */
+ 2, /* UNI_VOLEFFECTS */
+ 1, /* UNI_XMEFFECT4 */
+ 1, /* UNI_XMEFFECT6 */
+ 1, /* UNI_XMEFFECTA */
+ 1, /* UNI_XMEFFECTE1 */
+ 1, /* UNI_XMEFFECTE2 */
+ 1, /* UNI_XMEFFECTEA */
+ 1, /* UNI_XMEFFECTEB */
+ 1, /* UNI_XMEFFECTG */
+ 1, /* UNI_XMEFFECTH */
+ 1, /* UNI_XMEFFECTL */
+ 1, /* UNI_XMEFFECTP */
+ 1, /* UNI_XMEFFECTX1 */
+ 1, /* UNI_XMEFFECTX2 */
+ 1, /* UNI_ITEFFECTG */
+ 1, /* UNI_ITEFFECTH */
+ 1, /* UNI_ITEFFECTI */
+ 1, /* UNI_ITEFFECTM */
+ 1, /* UNI_ITEFFECTN */
+ 1, /* UNI_ITEFFECTP */
+ 1, /* UNI_ITEFFECTT */
+ 1, /* UNI_ITEFFECTU */
+ 1, /* UNI_ITEFFECTW */
+ 1, /* UNI_ITEFFECTY */
+ 2, /* UNI_ITEFFECTZ */
+ 1, /* UNI_ITEFFECTS0 */
+ 2, /* UNI_ULTEFFECT9 */
+ 2, /* UNI_MEDSPEED */
+ 0, /* UNI_MEDEFFECTF1 */
+ 0, /* UNI_MEDEFFECTF2 */
+ 0, /* UNI_MEDEFFECTF3 */
+ 2, /* UNI_OKTARP */
+};
+
+/* Sparse description of the internal module format
+ ------------------------------------------------
+
+ A UNITRK stream is an array of bytes representing a single track of a pattern.
+It's made up of 'repeat/length' bytes, opcodes and operands (sort of a assembly
+language):
+
+rrrlllll
+[REP/LEN][OPCODE][OPERAND][OPCODE][OPERAND] [REP/LEN][OPCODE][OPERAND]..
+^ ^ ^
+|-------ROWS 0 - 0+REP of a track---------| |-------ROWS xx - xx+REP of a track...
+
+ The rep/len byte contains the number of bytes in the current row, _including_
+the length byte itself (So the LENGTH byte of row 0 in the previous example
+would have a value of 5). This makes it easy to search through a stream for a
+particular row. A track is concluded by a 0-value length byte.
+
+ The upper 3 bits of the rep/len byte contain the number of times -1 this row
+is repeated for this track. (so a value of 7 means this row is repeated 8 times)
+
+ Opcodes can range from 1 to 255 but currently only opcodes 1 to 62 are being
+used. Each opcode can have a different number of operands. You can find the
+number of operands to a particular opcode by using the opcode as an index into
+the 'unioperands' table.
+
+*/
+
+/*========== Reading routines */
+
+static UBYTE *rowstart; /* startadress of a row */
+static UBYTE *rowend; /* endaddress of a row (exclusive) */
+static UBYTE *rowpc; /* current unimod(tm) programcounter */
+
+static UBYTE lastbyte; /* for UniSkipOpcode() */
+
+void UniSetRow(UBYTE* t)
+{
+ rowstart = t;
+ rowpc = rowstart;
+ rowend = t?rowstart+(*(rowpc++)&0x1f):t;
+}
+
+UBYTE UniGetByte(void)
+{
+ return lastbyte = (rowpc<rowend)?*(rowpc++):0;
+}
+
+UWORD UniGetWord(void)
+{
+ return ((UWORD)UniGetByte()<<8)|UniGetByte();
+}
+
+void UniSkipOpcode(void)
+{
+ if (lastbyte < UNI_LAST) {
+ UWORD t = unioperands[lastbyte];
+
+ while (t--)
+ UniGetByte();
+ }
+}
+
+/* Finds the address of row number 'row' in the UniMod(tm) stream 't' returns
+ NULL if the row can't be found. */
+UBYTE *UniFindRow(UBYTE* t,UWORD row)
+{
+ UBYTE c,l;
+
+ if(t)
+ while(1) {
+ c = *t; /* get rep/len byte */
+ if(!c) return NULL; /* zero ? -> end of track.. */
+ l = (c>>5)+1; /* extract repeat value */
+ if(l>row) break; /* reached wanted row? -> return pointer */
+ row -= l; /* haven't reached row yet.. update row */
+ t += c&0x1f; /* point t to the next row */
+ }
+ return t;
+}
+
+/*========== Writing routines */
+
+static UBYTE *unibuf; /* pointer to the temporary unitrk buffer */
+static UWORD unimax; /* buffer size */
+
+static UWORD unipc; /* buffer cursor */
+static UWORD unitt; /* current row index */
+static UWORD lastp; /* previous row index */
+
+/* Resets index-pointers to create a new track. */
+void UniReset(void)
+{
+ unitt = 0; /* reset index to rep/len byte */
+ unipc = 1; /* first opcode will be written to index 1 */
+ lastp = 0; /* no previous row yet */
+ unibuf[0] = 0; /* clear rep/len byte */
+}
+
+/* Expands the buffer */
+static int UniExpand(int wanted)
+{
+ if ((unipc+wanted)>=unimax) {
+ UBYTE *newbuf;
+
+ /* Expand the buffer by BUFPAGE bytes */
+ newbuf=(UBYTE*)MikMod_realloc(unibuf,(unimax+BUFPAGE)*sizeof(UBYTE));
+
+ /* Check if MikMod_realloc succeeded */
+ if(newbuf) {
+ unibuf = newbuf;
+ unimax+=BUFPAGE;
+ return 1;
+ } else
+ return 0;
+ }
+ return 1;
+}
+
+/* Appends one byte of data to the current row of a track. */
+void UniWriteByte(UBYTE data)
+{
+ if (UniExpand(1))
+ /* write byte to current position and update */
+ unibuf[unipc++]=data;
+}
+
+void UniWriteWord(UWORD data)
+{
+ if (UniExpand(2)) {
+ unibuf[unipc++]=data>>8;
+ unibuf[unipc++]=data&0xff;
+ }
+}
+
+static int MyCmp(UBYTE* a,UBYTE* b,UWORD l)
+{
+ UWORD t;
+
+ for(t=0;t<l;t++)
+ if(*(a++)!=*(b++)) return 0;
+ return 1;
+}
+
+/* Closes the current row of a unitrk stream (updates the rep/len byte) and sets
+ pointers to start a new row. */
+void UniNewline(void)
+{
+ UWORD n,l,len;
+
+ n = (unibuf[lastp]>>5)+1; /* repeat of previous row */
+ l = (unibuf[lastp]&0x1f); /* length of previous row */
+
+ len = unipc-unitt; /* length of current row */
+
+ /* Now, check if the previous and the current row are identical.. when they
+ are, just increase the repeat field of the previous row */
+ if(n<8 && len==l && MyCmp(&unibuf[lastp+1],&unibuf[unitt+1],len-1)) {
+ unibuf[lastp]+=0x20;
+ unipc = unitt+1;
+ } else {
+ if (UniExpand(unitt-unipc)) {
+ /* current and previous row aren't equal... update the pointers */
+ unibuf[unitt] = len;
+ lastp = unitt;
+ unitt = unipc++;
+ }
+ }
+}
+
+/* Terminates the current unitrk stream and returns a pointer to a copy of the
+ stream. */
+UBYTE* UniDup(void)
+{
+ UBYTE *d;
+
+ if (!UniExpand(unitt-unipc)) return NULL;
+ unibuf[unitt] = 0;
+
+ if(!(d=(UBYTE *)MikMod_malloc(unipc))) return NULL;
+ memcpy(d,unibuf,unipc);
+
+ return d;
+}
+
+int UniInit(void)
+{
+ unimax = BUFPAGE;
+
+ if(!(unibuf=(UBYTE*)MikMod_malloc(unimax*sizeof(UBYTE)))) return 0;
+ return 1;
+}
+
+void UniCleanup(void)
+{
+ if(unibuf) MikMod_free(unibuf);
+ unibuf = NULL;
+}
+
+/* ex:set ts=4: */
diff --git a/apps/plugins/mikmod/npertab.c b/apps/plugins/mikmod/npertab.c
new file mode 100644
index 0000000000..4aa5ef9a17
--- /dev/null
+++ b/apps/plugins/mikmod/npertab.c
@@ -0,0 +1,48 @@
+/* MikMod sound library
+ (c) 1998, 1999 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: npertab.c,v 1.2 2005/03/30 19:11:47 realtech Exp $
+
+ MOD format period table. Used by both the MOD and M15 (15-inst mod) Loaders.
+
+==============================================================================*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "mikmod_internals.h"
+
+UWORD npertab[7 * OCTAVE] = {
+ /* Octaves 6 -> 0 */
+ /* C C# D D# E F F# G G# A A# B */
+ 0x6b0,0x650,0x5f4,0x5a0,0x54c,0x500,0x4b8,0x474,0x434,0x3f8,0x3c0,0x38a,
+ 0x358,0x328,0x2fa,0x2d0,0x2a6,0x280,0x25c,0x23a,0x21a,0x1fc,0x1e0,0x1c5,
+ 0x1ac,0x194,0x17d,0x168,0x153,0x140,0x12e,0x11d,0x10d,0x0fe,0x0f0,0x0e2,
+ 0x0d6,0x0ca,0x0be,0x0b4,0x0aa,0x0a0,0x097,0x08f,0x087,0x07f,0x078,0x071,
+ 0x06b,0x065,0x05f,0x05a,0x055,0x050,0x04b,0x047,0x043,0x03f,0x03c,0x038,
+ 0x035,0x032,0x02f,0x02d,0x02a,0x028,0x025,0x023,0x021,0x01f,0x01e,0x01c,
+ 0x01b,0x019,0x018,0x016,0x015,0x014,0x013,0x012,0x011,0x010,0x00f,0x00e
+};
+
+/* ex:set ts=4: */
+
diff --git a/apps/plugins/mikmod/sloader.c b/apps/plugins/mikmod/sloader.c
new file mode 100644
index 0000000000..8b15b0d453
--- /dev/null
+++ b/apps/plugins/mikmod/sloader.c
@@ -0,0 +1,519 @@
+/* MikMod sound library
+ (c) 1998, 1999, 2000, 2001 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: sloader.c,v 1.3 2007/12/06 17:46:08 denis111 Exp $
+
+ Routines for loading samples. The sample loader utilizes the routines
+ provided by the "registered" sample loader.
+
+==============================================================================*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "mikmod_internals.h"
+
+static int sl_rlength;
+static SWORD sl_old;
+static SWORD *sl_buffer=NULL;
+static SAMPLOAD *musiclist=NULL,*sndfxlist=NULL;
+
+/* size of the loader buffer in words */
+#define SLBUFSIZE 2048
+
+/* IT-Compressed status structure */
+typedef struct ITPACK {
+ UWORD bits; /* current number of bits */
+ UWORD bufbits; /* bits in buffer */
+ SWORD last; /* last output */
+ UBYTE buf; /* bit buffer */
+} ITPACK;
+
+int SL_Init(SAMPLOAD* s)
+{
+ if(!sl_buffer)
+ if(!(sl_buffer=MikMod_malloc(SLBUFSIZE*sizeof(SWORD)))) return 0;
+
+ sl_rlength = s->length;
+ if(s->infmt & SF_16BITS) sl_rlength>>=1;
+ sl_old = 0;
+
+ return 1;
+}
+
+void SL_Exit(SAMPLOAD *s)
+{
+ if(sl_rlength>0) _mm_fseek(s->reader,sl_rlength,SEEK_CUR);
+ if(sl_buffer) {
+ MikMod_free(sl_buffer);
+ sl_buffer=NULL;
+ }
+}
+
+/* unpack a 8bit IT packed sample */
+static int read_itcompr8(ITPACK* status,MREADER *reader,SWORD *sl_buffer,UWORD count,UWORD* incnt)
+{
+ SWORD *dest=sl_buffer,*end=sl_buffer+count;
+ UWORD x,y,needbits,havebits,new_count=0;
+ UWORD bits = status->bits;
+ UWORD bufbits = status->bufbits;
+ SBYTE last = status->last;
+ UBYTE buf = status->buf;
+
+ while (dest<end) {
+ needbits=new_count?3:bits;
+ x=havebits=0;
+ while (needbits) {
+ /* feed buffer */
+ if (!bufbits) {
+ if((*incnt)--)
+ buf=_mm_read_UBYTE(reader);
+ else
+ buf=0;
+ bufbits=8;
+ }
+ /* get as many bits as necessary */
+ y = needbits<bufbits?needbits:bufbits;
+ x|= (buf & ((1<<y)- 1))<<havebits;
+ buf>>=y;
+ bufbits-=y;
+ needbits-=y;
+ havebits+=y;
+ }
+ if (new_count) {
+ new_count = 0;
+ if (++x >= bits)
+ x++;
+ bits = x;
+ continue;
+ }
+ if (bits<7) {
+ if (x==(1<<(bits-1))) {
+ new_count = 1;
+ continue;
+ }
+ }
+ else if (bits<9) {
+ y = (0xff >> (9-bits)) - 4;
+ if ((x>y)&&(x<=y+8)) {
+ if ((x-=y)>=bits)
+ x++;
+ bits = x;
+ continue;
+ }
+ }
+ else if (bits<10) {
+ if (x>=0x100) {
+ bits=x-0x100+1;
+ continue;
+ }
+ } else {
+ /* error in compressed data... */
+ _mm_errno=MMERR_ITPACK_INVALID_DATA;
+ return 0;
+ }
+
+ if (bits<8) /* extend sign */
+ x = ((SBYTE)(x <<(8-bits))) >> (8-bits);
+ *(dest++)= (last+=x) << 8; /* convert to 16 bit */
+ }
+ status->bits = bits;
+ status->bufbits = bufbits;
+ status->last = last;
+ status->buf = buf;
+ return (dest-sl_buffer);
+}
+
+/* unpack a 16bit IT packed sample */
+static int read_itcompr16(ITPACK *status,MREADER *reader,SWORD *sl_buffer,UWORD count,UWORD* incnt)
+{
+ SWORD *dest=sl_buffer,*end=sl_buffer+count;
+ SLONG x,y,needbits,havebits,new_count=0;
+ UWORD bits = status->bits;
+ UWORD bufbits = status->bufbits;
+ SWORD last = status->last;
+ UBYTE buf = status->buf;
+
+ while (dest<end) {
+ needbits=new_count?4:bits;
+ x=havebits=0;
+ while (needbits) {
+ /* feed buffer */
+ if (!bufbits) {
+ if((*incnt)--)
+ buf=_mm_read_UBYTE(reader);
+ else
+ buf=0;
+ bufbits=8;
+ }
+ /* get as many bits as necessary */
+ y=needbits<bufbits?needbits:bufbits;
+ x|=(buf &((1<<y)-1))<<havebits;
+ buf>>=y;
+ bufbits-=(UWORD)y;
+ needbits-=(UWORD)y;
+ havebits+=(UWORD)y;
+ }
+ if (new_count) {
+ new_count = 0;
+ if (++x >= bits)
+ x++;
+ bits = (UWORD)x;
+ continue;
+ }
+ if (bits<7) {
+ if (x==(1<<(bits-1))) {
+ new_count=1;
+ continue;
+ }
+ }
+ else if (bits<17) {
+ y=(0xffff>>(17-bits))-8;
+ if ((x>y)&&(x<=y+16)) {
+ if ((x-=y)>=bits)
+ x++;
+ bits = (UWORD)x;
+ continue;
+ }
+ }
+ else if (bits<18) {
+ if (x>=0x10000) {
+ bits=(UWORD)(x-0x10000+1);
+ continue;
+ }
+ } else {
+ /* error in compressed data... */
+ _mm_errno=MMERR_ITPACK_INVALID_DATA;
+ return 0;
+ }
+
+ if (bits<16) /* extend sign */
+ x = ((SWORD)(x<<(16-bits)))>>(16-bits);
+ *(dest++)=(last+=x);
+ }
+ status->bits = bits;
+ status->bufbits = bufbits;
+ status->last = last;
+ status->buf = buf;
+ return (dest-sl_buffer);
+}
+
+static int SL_LoadInternal(void* buffer,UWORD infmt,UWORD outfmt,int scalefactor,ULONG length,MREADER* reader,int dither)
+{
+ SBYTE *bptr = (SBYTE*)buffer;
+ SWORD *wptr = (SWORD*)buffer;
+ int stodo,t,u;
+
+ int result,c_block=0; /* compression bytes until next block */
+ ITPACK status;
+ UWORD incnt;
+
+ while(length) {
+ stodo=(length<SLBUFSIZE)?length:SLBUFSIZE;
+
+ if(infmt&SF_ITPACKED) {
+ sl_rlength=0;
+ if (!c_block) {
+ status.bits = (infmt & SF_16BITS) ? 17 : 9;
+ status.last = status.bufbits = 0;
+ incnt=_mm_read_I_UWORD(reader);
+ c_block = (infmt & SF_16BITS) ? 0x4000 : 0x8000;
+ if(infmt&SF_DELTA) sl_old=0;
+ }
+ if (infmt & SF_16BITS) {
+ if(!(result=read_itcompr16(&status,reader,sl_buffer,stodo,&incnt)))
+ return 1;
+ } else {
+ if(!(result=read_itcompr8(&status,reader,sl_buffer,stodo,&incnt)))
+ return 1;
+ }
+ if(result!=stodo) {
+ _mm_errno=MMERR_ITPACK_INVALID_DATA;
+ return 1;
+ }
+ c_block -= stodo;
+ } else {
+ if(infmt&SF_16BITS) {
+ if(infmt&SF_BIG_ENDIAN)
+ _mm_read_M_SWORDS(sl_buffer,stodo,reader);
+ else
+ _mm_read_I_SWORDS(sl_buffer,stodo,reader);
+ } else {
+ SBYTE *src;
+ SWORD *dest;
+
+ reader->Read(reader,sl_buffer,sizeof(SBYTE)*stodo);
+ src = (SBYTE*)sl_buffer;
+ dest = sl_buffer;
+ src += stodo;dest += stodo;
+
+ for(t=0;t<stodo;t++) {
+ src--;dest--;
+ *dest = (*src)<<8;
+ }
+ }
+ sl_rlength-=stodo;
+ }
+
+ if(infmt & SF_DELTA)
+ for(t=0;t<stodo;t++) {
+ sl_buffer[t] += sl_old;
+ sl_old = sl_buffer[t];
+ }
+
+ if((infmt^outfmt) & SF_SIGNED)
+ for(t=0;t<stodo;t++)
+ sl_buffer[t]^= 0x8000;
+
+ if(scalefactor) {
+ int idx = 0;
+ SLONG scaleval;
+
+ /* Sample Scaling... average values for better results. */
+ t= 0;
+ while(t<stodo && length) {
+ scaleval = 0;
+ for(u=scalefactor;u && t<stodo;u--,t++)
+ scaleval+=sl_buffer[t];
+ sl_buffer[idx++]=(UWORD)(scaleval/(scalefactor-u));
+ length--;
+ }
+ stodo = idx;
+ } else
+ length -= stodo;
+
+ if (dither) {
+ if((infmt & SF_STEREO) && !(outfmt & SF_STEREO)) {
+ /* dither stereo to mono, average together every two samples */
+ SLONG avgval;
+ int idx = 0;
+
+ t=0;
+ while(t<stodo && length) {
+ avgval=sl_buffer[t++];
+ avgval+=sl_buffer[t++];
+ sl_buffer[idx++]=(SWORD)(avgval>>1);
+ length-=2;
+ }
+ stodo = idx;
+ }
+ }
+
+ if(outfmt & SF_16BITS) {
+ for(t=0;t<stodo;t++)
+ *(wptr++)=sl_buffer[t];
+ } else {
+ for(t=0;t<stodo;t++)
+ *(bptr++)=sl_buffer[t]>>8;
+ }
+ }
+ return 0;
+}
+
+int SL_Load(void* buffer,SAMPLOAD *smp,ULONG length)
+{
+ return SL_LoadInternal(buffer,smp->infmt,smp->outfmt,smp->scalefactor,
+ length,smp->reader,0);
+}
+
+/* Registers a sample for loading when SL_LoadSamples() is called. */
+SAMPLOAD* SL_RegisterSample(SAMPLE* s,int type,MREADER* reader)
+{
+ SAMPLOAD *news,**samplist,*cruise;
+
+ if(type==MD_MUSIC) {
+ samplist = &musiclist;
+ cruise = musiclist;
+ } else
+ if (type==MD_SNDFX) {
+ samplist = &sndfxlist;
+ cruise = sndfxlist;
+ } else
+ return NULL;
+
+ /* Allocate and add structure to the END of the list */
+ if(!(news=(SAMPLOAD*)MikMod_malloc(sizeof(SAMPLOAD)))) return NULL;
+
+ if(cruise) {
+ while(cruise->next) cruise=cruise->next;
+ cruise->next = news;
+ } else
+ *samplist = news;
+
+ news->infmt = s->flags & SF_FORMATMASK;
+ news->outfmt = news->infmt;
+ news->reader = reader;
+ news->sample = s;
+ news->length = s->length;
+ news->loopstart = s->loopstart;
+ news->loopend = s->loopend;
+
+ return news;
+}
+
+static void FreeSampleList(SAMPLOAD* s)
+{
+ SAMPLOAD *old;
+
+ while(s) {
+ old = s;
+ s = s->next;
+ MikMod_free(old);
+ }
+}
+
+/* Returns the total amount of memory required by the samplelist queue. */
+static ULONG SampleTotal(SAMPLOAD* samplist,int type)
+{
+ int total = 0;
+
+ while(samplist) {
+ samplist->sample->flags=
+ (samplist->sample->flags&~SF_FORMATMASK)|samplist->outfmt;
+ total += MD_SampleLength(type,samplist->sample);
+ samplist=samplist->next;
+ }
+
+ return total;
+}
+
+static ULONG RealSpeed(SAMPLOAD *s)
+{
+ return(s->sample->speed/(s->scalefactor?s->scalefactor:1));
+}
+
+static int DitherSamples(SAMPLOAD* samplist,int type)
+{
+ SAMPLOAD *c2smp=NULL;
+ ULONG maxsize, speed;
+ SAMPLOAD *s;
+
+ if(!samplist) return 0;
+
+ if((maxsize=MD_SampleSpace(type)*1024))
+ while(SampleTotal(samplist,type)>maxsize) {
+ /* First Pass - check for any 16 bit samples */
+ s = samplist;
+ while(s) {
+ if(s->outfmt & SF_16BITS) {
+ SL_Sample16to8(s);
+ break;
+ }
+ s=s->next;
+ }
+ /* Second pass (if no 16bits found above) is to take the sample with
+ the highest speed and dither it by half. */
+ if(!s) {
+ s = samplist;
+ speed = 0;
+ while(s) {
+ if((s->sample->length) && (RealSpeed(s)>speed)) {
+ speed=RealSpeed(s);
+ c2smp=s;
+ }
+ s=s->next;
+ }
+ if (c2smp)
+ SL_HalveSample(c2smp,2);
+ }
+ }
+
+ /* Samples dithered, now load them ! */
+ s = samplist;
+ while(s) {
+ /* sample has to be loaded ? -> increase number of samples, allocate
+ memory and load sample. */
+ if(s->sample->length) {
+ if(s->sample->seekpos)
+ _mm_fseek(s->reader, s->sample->seekpos, SEEK_SET);
+
+ /* Call the sample load routine of the driver module. It has to
+ return a 'handle' (>=0) that identifies the sample. */
+ s->sample->handle = MD_SampleLoad(s, type);
+ s->sample->flags = (s->sample->flags & ~SF_FORMATMASK) | s->outfmt;
+ if(s->sample->handle<0) {
+ FreeSampleList(samplist);
+ if(_mm_errorhandler) _mm_errorhandler();
+ return 1;
+ }
+ }
+ s = s->next;
+ }
+
+ FreeSampleList(samplist);
+ return 0;
+}
+
+int SL_LoadSamples(void)
+{
+ int ok;
+
+ _mm_critical = 0;
+
+ if((!musiclist)&&(!sndfxlist)) return 0;
+ ok=DitherSamples(musiclist,MD_MUSIC)||DitherSamples(sndfxlist,MD_SNDFX);
+ musiclist=sndfxlist=NULL;
+
+ return ok;
+}
+
+void SL_Sample16to8(SAMPLOAD* s)
+{
+ s->outfmt &= ~SF_16BITS;
+ s->sample->flags = (s->sample->flags&~SF_FORMATMASK) | s->outfmt;
+}
+
+void SL_Sample8to16(SAMPLOAD* s)
+{
+ s->outfmt |= SF_16BITS;
+ s->sample->flags = (s->sample->flags&~SF_FORMATMASK) | s->outfmt;
+}
+
+void SL_SampleSigned(SAMPLOAD* s)
+{
+ s->outfmt |= SF_SIGNED;
+ s->sample->flags = (s->sample->flags&~SF_FORMATMASK) | s->outfmt;
+}
+
+void SL_SampleUnsigned(SAMPLOAD* s)
+{
+ s->outfmt &= ~SF_SIGNED;
+ s->sample->flags = (s->sample->flags&~SF_FORMATMASK) | s->outfmt;
+}
+
+void SL_HalveSample(SAMPLOAD* s,int factor)
+{
+ s->scalefactor=factor>0?factor:2;
+
+ s->sample->divfactor = s->scalefactor;
+ s->sample->length = s->length / s->scalefactor;
+ s->sample->loopstart = s->loopstart / s->scalefactor;
+ s->sample->loopend = s->loopend / s->scalefactor;
+}
+
+
+/* ex:set ts=4: */
diff --git a/apps/plugins/mikmod/strdup.c b/apps/plugins/mikmod/strdup.c
new file mode 100644
index 0000000000..f8c1438bee
--- /dev/null
+++ b/apps/plugins/mikmod/strdup.c
@@ -0,0 +1,23 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include "mikmod.h"
+
+#undef strdup
+
+char* strdup(const char *__s)
+{
+ char *charptr;
+
+ if (!__s)
+ return NULL;
+
+ charptr=(char *)MikMod_malloc(sizeof(char) * (strlen(__s) + 1));
+ if (charptr)
+ strcpy(charptr, __s);
+
+ return charptr;
+}
diff --git a/apps/plugins/mikmod/strstr.c b/apps/plugins/mikmod/strstr.c
new file mode 100644
index 0000000000..c2cf97ecde
--- /dev/null
+++ b/apps/plugins/mikmod/strstr.c
@@ -0,0 +1,21 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+
+#include "mikmod_supp.h"
+
+char *strstr(const char *haystack, const char *needle)
+{
+ const char *scan;
+ size_t len;
+ char firstc;
+
+ firstc = *needle;
+ len = strlen(needle);
+ for (scan = haystack; *scan != firstc || strncmp(scan, needle, len); )
+ if (!*scan++)
+ return NULL;
+ return (char *)scan;
+}
diff --git a/apps/plugins/mikmod/virtch.c b/apps/plugins/mikmod/virtch.c
new file mode 100644
index 0000000000..43a61a3c2c
--- /dev/null
+++ b/apps/plugins/mikmod/virtch.c
@@ -0,0 +1,1319 @@
+/* MikMod sound library
+ (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file
+ AUTHORS for complete list.