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

📄 load_mod.c

📁 SDL_mixer 是一个基于 SDL 的混音器
💻 C
字号:
/*	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: load_mod.c 346 2001-09-11 18:49:18Z slouken $  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 <string.h>#include "mikmod_internals.h"/*========== 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 0x438static 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 = 0;/*========== Loader code *//* given the module ID, determine the number of channels and the tracker   description ; also alters modtype */static BOOL MOD_CheckType(UBYTE *id, UBYTE *numchn, CHAR **descr){	/* 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 = 1;		*numchn = id[3] - '0';		if (*numchn == 4)			return 1;#ifdef MIKMOD_DEBUG		if (*numchn == 8)			fprintf(stderr, "\rFLT8 modules not supported yet\n");		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 BOOL 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 BOOL MOD_Init(void){	if (!(mh = (MODULEHEADER *)_mm_malloc(sizeof(MODULEHEADER))))		return 0;	return 1;}static void MOD_Cleanup(void){	_mm_free(mh);	_mm_free(patbuf);}/*Old (amiga) noteinfo:_____byte 1_____   byte2_    _____byte 3_____   byte4_/                \ /      \  /                \ /      \0000          0000-00000000  0000          0000-00000000Upper four    12 bits for    Lower four    Effect command.bits of sam-  note period.   bits of sam-ple number.                  ple number.*/static void ConvertNote(MODNOTE *n){	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;		/* Ignore 100, 200 and 300 (there is no porta memory in mod files) */	if ((!effdat) && ((effect == 1)||(effect == 2)||(effect ==3)))		effect = 0;	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 BOOL 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 *)_mm_calloc(64U * of.numchn, 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 * 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 BOOL MOD_Load(BOOL 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);	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;	}	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;		/* 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 *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: */

⌨️ 快捷键说明

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