📄 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 SUNOSextern 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 0x4D4D4431static 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 + -