⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 load_xm.c

📁 这是著名的TCPMP播放器在WINDWOWS,和WINCE下编译通过的源程序.笔者对其中的LIBMAD库做了针对ARM MPU的优化. 并增加了词幕功能.
💻 C
📖 第 1 页 / 共 2 页
字号:
/*	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.2 2004/02/06 19:29:03 raph 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 reallocation */
#define XM_SMPINCR 64
static	ULONG *nextwav=NULL;
static	XMWAVHEADER *wh=NULL,*s=NULL;

/*========== Loader code */

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

BOOL XM_Init(void)
{
	if(!(mh=(XMHEADER *)_mm_malloc(sizeof(XMHEADER)))) return 0;
	return 1;
}

void XM_Cleanup(void)
{
	_mm_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 BOOL LoadPatterns(BOOL 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*)_mm_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) {
							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)) {
				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);

			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*)_mm_calloc(64*of.numchn,sizeof(XMNOTE)))) return 0;
		for(v=0;v<of.numchn;v++)
			of.tracks[numtrk++]=XM_Convert(&xmpat[v*64],64);
		free(xmpat);xmpat=NULL;
	}

	return 1;
}

static void FixEnvelope(ENVPT *cur, int pts)
{
		int u, old, tmp;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -