📄 load_med.c
字号:
/* 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.1.1.1 2004/01/21 01:36:35 raph 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 BOOL decimalvolumes;
static BOOL 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 */
BOOL 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;
}
BOOL MED_Init(void)
{
if (!(me = (MEDEXP *)_mm_malloc(sizeof(MEDEXP))))
return 0;
if (!(mh = (MEDHEADER *)_mm_malloc(sizeof(MEDHEADER))))
return 0;
if (!(ms = (MEDSONG *)_mm_malloc(sizeof(MEDSONG))))
return 0;
return 1;
}
void MED_Cleanup(void)
{
_mm_free(me);
_mm_free(mh);
_mm_free(ms);
_mm_free(ba);
_mm_free(mmd0pat);
_mm_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 BOOL 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 *)_mm_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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -