1
0
Fork 0
forked from len0rd/rockbox

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
This commit is contained in:
Frank Gevaerts 2010-12-12 15:03:30 +00:00
parent d192bdf11e
commit 26f2bfde03
47 changed files with 22320 additions and 1 deletions

View file

@ -56,6 +56,7 @@ mem_mon,apps
metronome,apps
midi2wav,viewers
midi,viewers
mikmod,viewers
minesweeper,games
mosaique,demos
mp3_encoder,apps

View file

@ -66,6 +66,7 @@ doom
#if MEMORYSIZE > 2 /* we need a lot of RAM for instruments */
midi
mikmod
#endif
/* beatbox */

View file

@ -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

View file

@ -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: */

View file

@ -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: */

View file

@ -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: */

View file

@ -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: */

View file

@ -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: */

View file

@ -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: */

View file

@ -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: */

View file

@ -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
};

View file

@ -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: */

File diff suppressed because it is too large Load diff

View file

@ -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: */

View file

@ -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: */

View file

@ -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: */

View file

@ -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: */

View file

@ -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: */

View file

@ -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: */

View file

@ -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: */

View file

@ -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: */

View file

@ -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: */

View file

@ -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: */

View file

@ -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: */

131
apps/plugins/mikmod/mdreg.c Normal file
View file

@ -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: */

View file

@ -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: */

View file

@ -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;
}

View file

@ -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: */

View file

@ -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 $@

View file

@ -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: */

View file

@ -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

View file

@ -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: */

View file

@ -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: */

View file

@ -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: */

View file

@ -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: */

View file

@ -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: */

517
apps/plugins/mikmod/mmio.c Normal file
View file

@ -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: */

File diff suppressed because it is too large Load diff

View file

@ -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: */

View file

@ -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: */

View file

@ -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: */

View file

@ -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;
}

View file

@ -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;
}

1319
apps/plugins/mikmod/virtch.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,464 @@
/* 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: virtch_common.c,v 1.2 2005/03/30 19:11:50 realtech Exp $
Common source parts between the two software mixers.
This file is probably the ugliest part of libmikmod...
==============================================================================*/
#ifndef _IN_VIRTCH_
#include "mikmod_internals.h"
extern int VC1_Init(void);
//extern int VC2_Init(void);
static int (*VC_Init_ptr)(void)=VC1_Init;
extern void VC1_Exit(void);
//extern void VC2_Exit(void);
static void (*VC_Exit_ptr)(void)=VC1_Exit;
extern int VC1_SetNumVoices(void);
//extern int VC2_SetNumVoices(void);
static int (*VC_SetNumVoices_ptr)(void);
extern ULONG VC1_SampleSpace(int);
//extern ULONG VC2_SampleSpace(int);
static ULONG (*VC_SampleSpace_ptr)(int);
extern ULONG VC1_SampleLength(int,SAMPLE*);
//extern ULONG VC2_SampleLength(int,SAMPLE*);
static ULONG (*VC_SampleLength_ptr)(int,SAMPLE*);
extern int VC1_PlayStart(void);
//extern int VC2_PlayStart(void);
static int (*VC_PlayStart_ptr)(void);
extern void VC1_PlayStop(void);
extern void VC2_PlayStop(void);
static void (*VC_PlayStop_ptr)(void);
extern SWORD VC1_SampleLoad(struct SAMPLOAD*,int);
//extern SWORD VC2_SampleLoad(struct SAMPLOAD*,int);
static SWORD (*VC_SampleLoad_ptr)(struct SAMPLOAD*,int);
extern void VC1_SampleUnload(SWORD);
//extern void VC2_SampleUnload(SWORD);
static void (*VC_SampleUnload_ptr)(SWORD);
extern ULONG VC1_WriteBytes(SBYTE*,ULONG);
//extern ULONG VC2_WriteBytes(SBYTE*,ULONG);
static ULONG (*VC_WriteBytes_ptr)(SBYTE*,ULONG);
extern ULONG VC1_SilenceBytes(SBYTE*,ULONG);
//extern ULONG VC2_SilenceBytes(SBYTE*,ULONG);
static ULONG (*VC_SilenceBytes_ptr)(SBYTE*,ULONG);
extern void VC1_VoiceSetVolume(UBYTE,UWORD);
//extern void VC2_VoiceSetVolume(UBYTE,UWORD);
static void (*VC_VoiceSetVolume_ptr)(UBYTE,UWORD);
extern UWORD VC1_VoiceGetVolume(UBYTE);
//extern UWORD VC2_VoiceGetVolume(UBYTE);
static UWORD (*VC_VoiceGetVolume_ptr)(UBYTE);
extern void VC1_VoiceSetFrequency(UBYTE,ULONG);
//extern void VC2_VoiceSetFrequency(UBYTE,ULONG);
static void (*VC_VoiceSetFrequency_ptr)(UBYTE,ULONG);
extern ULONG VC1_VoiceGetFrequency(UBYTE);
//extern ULONG VC2_VoiceGetFrequency(UBYTE);
static ULONG (*VC_VoiceGetFrequency_ptr)(UBYTE);
extern void VC1_VoiceSetPanning(UBYTE,ULONG);
//extern void VC2_VoiceSetPanning(UBYTE,ULONG);
static void (*VC_VoiceSetPanning_ptr)(UBYTE,ULONG);
extern ULONG VC1_VoiceGetPanning(UBYTE);
//extern ULONG VC2_VoiceGetPanning(UBYTE);
static ULONG (*VC_VoiceGetPanning_ptr)(UBYTE);
extern void VC1_VoicePlay(UBYTE,SWORD,ULONG,ULONG,ULONG,ULONG,UWORD);
//extern void VC2_VoicePlay(UBYTE,SWORD,ULONG,ULONG,ULONG,ULONG,UWORD);
static void (*VC_VoicePlay_ptr)(UBYTE,SWORD,ULONG,ULONG,ULONG,ULONG,UWORD);
extern void VC1_VoiceStop(UBYTE);
//extern void VC2_VoiceStop(UBYTE);
static void (*VC_VoiceStop_ptr)(UBYTE);
extern int VC1_VoiceStopped(UBYTE);
//extern int VC2_VoiceStopped(UBYTE);
static int (*VC_VoiceStopped_ptr)(UBYTE);
extern SLONG VC1_VoiceGetPosition(UBYTE);
//extern SLONG VC2_VoiceGetPosition(UBYTE);
static SLONG (*VC_VoiceGetPosition_ptr)(UBYTE);
extern ULONG VC1_VoiceRealVolume(UBYTE);
//extern ULONG VC2_VoiceRealVolume(UBYTE);
static ULONG (*VC_VoiceRealVolume_ptr)(UBYTE);
#if defined __STDC__ || defined _MSC_VER || defined MPW_C
#define VC_PROC0(suffix) \
MIKMODAPI void VC_##suffix (void) { VC_##suffix##_ptr(); }
#define VC_FUNC0(suffix,ret) \
MIKMODAPI ret VC_##suffix (void) { return VC_##suffix##_ptr(); }
#define VC_PROC1(suffix,typ1) \
MIKMODAPI void VC_##suffix (typ1 a) { VC_##suffix##_ptr(a); }
#define VC_FUNC1(suffix,ret,typ1) \
MIKMODAPI ret VC_##suffix (typ1 a) { return VC_##suffix##_ptr(a); }
#define VC_PROC2(suffix,typ1,typ2) \
MIKMODAPI void VC_##suffix (typ1 a,typ2 b) { VC_##suffix##_ptr(a,b); }
#define VC_FUNC2(suffix,ret,typ1,typ2) \
MIKMODAPI ret VC_##suffix (typ1 a,typ2 b) { return VC_##suffix##_ptr(a,b); }
#else
#define VC_PROC0(suffix) \
MIKMODAPI void VC_/**/suffix (void) { VC_/**/suffix/**/_ptr(); }
#define VC_FUNC0(suffix,ret) \
MIKMODAPI ret VC_/**/suffix (void) { return VC_/**/suffix/**/_ptr(); }
#define VC_PROC1(suffix,typ1) \
MIKMODAPI void VC_/**/suffix (typ1 a) { VC_/**/suffix/**/_ptr(a); }
#define VC_FUNC1(suffix,ret,typ1) \
MIKMODAPI ret VC_/**/suffix (typ1 a) { return VC_/**/suffix/**/_ptr(a); }
#define VC_PROC2(suffix,typ1,typ2) \
MIKMODAPI void VC_/**/suffix (typ1 a,typ2 b) { VC_/**/suffix/**/_ptr(a,b); }
#define VC_FUNC2(suffix,ret,typ1,typ2) \
MIKMODAPI ret VC_/**/suffix (typ1 a,typ2 b) { return VC_/**/suffix/**/_ptr(a,b); }
#endif
VC_FUNC0(Init,int)
VC_PROC0(Exit)
VC_FUNC0(SetNumVoices,int)
VC_FUNC1(SampleSpace,ULONG,int)
VC_FUNC2(SampleLength,ULONG,int,SAMPLE*)
VC_FUNC0(PlayStart,int)
VC_PROC0(PlayStop)
VC_FUNC2(SampleLoad,SWORD,struct SAMPLOAD*,int)
VC_PROC1(SampleUnload,SWORD)
VC_FUNC2(WriteBytes,ULONG,SBYTE*,ULONG)
VC_FUNC2(SilenceBytes,ULONG,SBYTE*,ULONG)
VC_PROC2(VoiceSetVolume,UBYTE,UWORD)
VC_FUNC1(VoiceGetVolume,UWORD,UBYTE)
VC_PROC2(VoiceSetFrequency,UBYTE,ULONG)
VC_FUNC1(VoiceGetFrequency,ULONG,UBYTE)
VC_PROC2(VoiceSetPanning,UBYTE,ULONG)
VC_FUNC1(VoiceGetPanning,ULONG,UBYTE)
void VC_VoicePlay(UBYTE a,SWORD b,ULONG c,ULONG d,ULONG e,ULONG f,UWORD g)
{ VC_VoicePlay_ptr(a,b,c,d,e,f,g); }
VC_PROC1(VoiceStop,UBYTE)
VC_FUNC1(VoiceStopped,int,UBYTE)
VC_FUNC1(VoiceGetPosition,SLONG,UBYTE)
VC_FUNC1(VoiceRealVolume,ULONG,UBYTE)
void VC_SetupPointers(void)
{
/*
if (md_mode&DMODE_HQMIXER) {
VC_Init_ptr=VC2_Init;
VC_Exit_ptr=VC2_Exit;
VC_SetNumVoices_ptr=VC2_SetNumVoices;
VC_SampleSpace_ptr=VC2_SampleSpace;
VC_SampleLength_ptr=VC2_SampleLength;
VC_PlayStart_ptr=VC2_PlayStart;
VC_PlayStop_ptr=VC2_PlayStop;
VC_SampleLoad_ptr=VC2_SampleLoad;
VC_SampleUnload_ptr=VC2_SampleUnload;
VC_WriteBytes_ptr=VC2_WriteBytes;
VC_SilenceBytes_ptr=VC2_SilenceBytes;
VC_VoiceSetVolume_ptr=VC2_VoiceSetVolume;
VC_VoiceGetVolume_ptr=VC2_VoiceGetVolume;
VC_VoiceSetFrequency_ptr=VC2_VoiceSetFrequency;
VC_VoiceGetFrequency_ptr=VC2_VoiceGetFrequency;
VC_VoiceSetPanning_ptr=VC2_VoiceSetPanning;
VC_VoiceGetPanning_ptr=VC2_VoiceGetPanning;
VC_VoicePlay_ptr=VC2_VoicePlay;
VC_VoiceStop_ptr=VC2_VoiceStop;
VC_VoiceStopped_ptr=VC2_VoiceStopped;
VC_VoiceGetPosition_ptr=VC2_VoiceGetPosition;
VC_VoiceRealVolume_ptr=VC2_VoiceRealVolume;
} else {
*/
VC_Init_ptr=VC1_Init;
VC_Exit_ptr=VC1_Exit;
VC_SetNumVoices_ptr=VC1_SetNumVoices;
VC_SampleSpace_ptr=VC1_SampleSpace;
VC_SampleLength_ptr=VC1_SampleLength;
VC_PlayStart_ptr=VC1_PlayStart;
VC_PlayStop_ptr=VC1_PlayStop;
VC_SampleLoad_ptr=VC1_SampleLoad;
VC_SampleUnload_ptr=VC1_SampleUnload;
VC_WriteBytes_ptr=VC1_WriteBytes;
VC_SilenceBytes_ptr=VC1_SilenceBytes;
VC_VoiceSetVolume_ptr=VC1_VoiceSetVolume;
VC_VoiceGetVolume_ptr=VC1_VoiceGetVolume;
VC_VoiceSetFrequency_ptr=VC1_VoiceSetFrequency;
VC_VoiceGetFrequency_ptr=VC1_VoiceGetFrequency;
VC_VoiceSetPanning_ptr=VC1_VoiceSetPanning;
VC_VoiceGetPanning_ptr=VC1_VoiceGetPanning;
VC_VoicePlay_ptr=VC1_VoicePlay;
VC_VoiceStop_ptr=VC1_VoiceStop;
VC_VoiceStopped_ptr=VC1_VoiceStopped;
VC_VoiceGetPosition_ptr=VC1_VoiceGetPosition;
VC_VoiceRealVolume_ptr=VC1_VoiceRealVolume;
//}
}
#else
#ifndef _VIRTCH_COMMON_
#define _VIRTCH_COMMON_
static ULONG samples2bytes(ULONG samples)
{
if(vc_mode & DMODE_FLOAT) samples <<= 2;
else if(vc_mode & DMODE_16BITS) samples <<= 1;
if(vc_mode & DMODE_STEREO) samples <<= 1;
return samples;
}
static ULONG bytes2samples(ULONG bytes)
{
if(vc_mode & DMODE_FLOAT) bytes >>= 2;
else if(vc_mode & DMODE_16BITS) bytes >>= 1;
if(vc_mode & DMODE_STEREO) bytes >>= 1;
return bytes;
}
/* Fill the buffer with 'todo' bytes of silence (it depends on the mixing mode
how the buffer is filled) */
ULONG VC1_SilenceBytes(SBYTE* buf,ULONG todo)
{
todo=samples2bytes(bytes2samples(todo));
/* clear the buffer to zero (16 bits signed) or 0x80 (8 bits unsigned) */
if(vc_mode & DMODE_FLOAT)
memset(buf,0,todo);
else if(vc_mode & DMODE_16BITS)
memset(buf,0,todo);
else
memset(buf,0x80,todo);
return todo;
}
void VC1_WriteSamples(SBYTE*,ULONG);
/* Writes 'todo' mixed SBYTES (!!) to 'buf'. It returns the number of SBYTES
actually written to 'buf' (which is rounded to number of samples that fit
into 'todo' bytes). */
ULONG VC1_WriteBytes(SBYTE* buf,ULONG todo)
{
if(!vc_softchn)
return VC1_SilenceBytes(buf,todo);
todo = bytes2samples(todo);
VC1_WriteSamples(buf,todo);
return samples2bytes(todo);
}
void VC1_Exit(void)
{
if(vc_tickbuf) MikMod_free(vc_tickbuf);
if(vinf) MikMod_free(vinf);
if(Samples) MikMod_free(Samples);
vc_tickbuf = NULL;
vinf = NULL;
Samples = NULL;
VC_SetupPointers();
}
UWORD VC1_VoiceGetVolume(UBYTE voice)
{
return vinf[voice].vol;
}
ULONG VC1_VoiceGetPanning(UBYTE voice)
{
return vinf[voice].pan;
}
void VC1_VoiceSetFrequency(UBYTE voice,ULONG frq)
{
vinf[voice].frq=frq;
}
ULONG VC1_VoiceGetFrequency(UBYTE voice)
{
return vinf[voice].frq;
}
void VC1_VoicePlay(UBYTE voice,SWORD handle,ULONG start,ULONG size,ULONG reppos,ULONG repend,UWORD flags)
{
vinf[voice].flags = flags;
vinf[voice].handle = handle;
vinf[voice].start = start;
vinf[voice].size = size;
vinf[voice].reppos = reppos;
vinf[voice].repend = repend;
vinf[voice].kick = 1;
}
void VC1_VoiceStop(UBYTE voice)
{
vinf[voice].active = 0;
}
int VC1_VoiceStopped(UBYTE voice)
{
return(vinf[voice].active==0);
}
SLONG VC1_VoiceGetPosition(UBYTE voice)
{
return (SLONG)(vinf[voice].current>>FRACBITS);
}
void VC1_VoiceSetVolume(UBYTE voice,UWORD vol)
{
/* protect against clicks if volume variation is too high */
if(abs((int)vinf[voice].vol-(int)vol)>32)
vinf[voice].rampvol=CLICK_BUFFER;
vinf[voice].vol=vol;
}
void VC1_VoiceSetPanning(UBYTE voice,ULONG pan)
{
/* protect against clicks if panning variation is too high */
if(abs((int)vinf[voice].pan-(int)pan)>48)
vinf[voice].rampvol=CLICK_BUFFER;
vinf[voice].pan=pan;
}
/*========== External mixer interface */
void VC1_SampleUnload(SWORD handle)
{
if (handle<MAXSAMPLEHANDLES) {
if (Samples[handle])
MikMod_free(Samples[handle]);
Samples[handle]=NULL;
}
}
SWORD VC1_SampleLoad(struct SAMPLOAD* sload,int type)
{
SAMPLE *s = sload->sample;
int handle;
ULONG t, length,loopstart,loopend;
if(type==MD_HARDWARE) return -1;
/* Find empty slot to put sample address in */
for(handle=0;handle<MAXSAMPLEHANDLES;handle++)
if(!Samples[handle]) break;
if(handle==MAXSAMPLEHANDLES) {
_mm_errno = MMERR_OUT_OF_HANDLES;
return -1;
}
/* Reality check for loop settings */
if (s->loopend > s->length)
s->loopend = s->length;
if (s->loopstart >= s->loopend)
s->flags &= ~SF_LOOP;
length = s->length;
loopstart = s->loopstart;
loopend = s->loopend;
SL_SampleSigned(sload);
SL_Sample8to16(sload);
if(!(Samples[handle]=(SWORD*)MikMod_malloc((length+20)<<1))) {
_mm_errno = MMERR_SAMPLE_TOO_BIG;
return -1;
}
/* read sample into buffer */
if (SL_Load(Samples[handle],sload,length))
return -1;
/* Unclick sample */
if(s->flags & SF_LOOP) {
if(s->flags & SF_BIDI)
for(t=0;t<16;t++)
Samples[handle][loopend+t]=Samples[handle][(loopend-t)-1];
else
for(t=0;t<16;t++)
Samples[handle][loopend+t]=Samples[handle][t+loopstart];
} else
for(t=0;t<16;t++)
Samples[handle][t+length]=0;
return handle;
}
ULONG VC1_SampleSpace(int type)
{
return vc_memory;
}
ULONG VC1_SampleLength(int type,SAMPLE* s)
{
if (!s) return 0;
return (s->length*((s->flags&SF_16BITS)?2:1))+16;
}
ULONG VC1_VoiceRealVolume(UBYTE voice)
{
ULONG i,s,size;
int k,j;
SWORD *smp;
SLONG t;
t = (SLONG)(vinf[voice].current>>FRACBITS);
if(!vinf[voice].active) return 0;
s = vinf[voice].handle;
size = vinf[voice].size;
i=64; t-=64; k=0; j=0;
if(i>size) i = size;
if(t<0) t = 0;
if(t+i > size) t = size-i;
i &= ~1; /* make sure it's EVEN. */
smp = &Samples[s][t];
for(;i;i--,smp++) {
if(k<*smp) k = *smp;
if(j>*smp) j = *smp;
}
return abs(k-j);
}
#endif
MikMod_callback_t vc_callback;
#endif
/* ex:set ts=4: */

View file

@ -33,6 +33,26 @@ gbc,viewers/rockboy,6
sgb,viewers/rockboy,6
mid,viewers/midi,7
rmi,viewers/midi,7
669,viewers/mikmod,7
amf,viewers/mikmod,7
asy,viewers/mikmod,7
dsm,viewers/mikmod,7
far,viewers/mikmod,7
gdm,viewers/mikmod,7
gt2,viewers/mikmod,7
imf,viewers/mikmod,7
it,viewers/mikmod,7
m15,viewers/mikmod,7
med,viewers/mikmod,7
mod,viewers/mikmod,7
mtm,viewers/mikmod,7
okt,viewers/mikmod,7
s3m,viewers/mikmod,7
stm,viewers/mikmod,7
stx,viewers/mikmod,7
ult,viewers/mikmod,7
uni,viewers/mikmod,7
xm,viewers/mikmod,7
pd,viewers/pdbox,2
rsp,viewers/searchengine,8
sok,games/sokoban,1

View file

@ -568,6 +568,8 @@ Franz-Josef Haider
Michael Hohmuth
Sergio Vera
Michael Leslie
Craig Mann
William Peters
The libmad team
The wavpack team
@ -593,4 +595,4 @@ The libmtp team
The asap team
The libpng team
The Pure Data team (Miller Puckette and others)
The MikMod team