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

📄 load_amf.c

📁 MIDI解码程序(用VC编写)
💻 C
字号:
/*      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: load_amf.c,v 1.28 1999/10/25 16:31:41 miod Exp $  DMP Advanced Module Format loader==============================================================================*/#ifdef HAVE_CONFIG_H#include "config.h"#endif#include <string.h>#include "unimod_priv.h"/*========== 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 22static CHAR AMF_Version[AMFTEXTLEN + 1] = "DSMI Module Format 0.0";static AMFNOTE *track = NULL;/*========== Loader code */BOOL 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;}BOOL AMF_Init (void){  if (!(mh = (AMFHEADER *) _mm_malloc (sizeof (AMFHEADER))))    return 0;  if (!(track = (AMFNOTE *) _mm_calloc (64, sizeof (AMFNOTE))))    return 0;  return 1;}void AMF_Cleanup (void){  _mm_free (mh);  _mm_free (track);}static BOOL AMF_UnpackTrack (URL 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 (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);	      break;	    }	}      if (track[row].volume)	UniVolEffect (VOL_VOLUME, track[row].volume - 1);      UniNewline ();    }  return UniDup ();}BOOL AMF_Load (BOOL curious){  int t, u, realtrackcnt, realsmpcnt;  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.songname = DupStr (mh->songname, 32, 1);  of.numpos = mh->numorders;  of.numpat = mh->numorders;  of.reppos = 0;  of.flags |= UF_S3MSLIDES;  for (t = 0; t < 32; t++)    {      if (mh->panpos[t] > 64)	of.panning[t] = PAN_SURROUND;      else if (mh->panpos[t] == 64)	of.panning[t] = 255;      else	of.panning[t] = (mh->panpos[t] + 64) << 1;    }  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 = _mm_calloc (mh->numtracks + 1, sizeof (UWORD))))    return 0;  _mm_read_I_UWORDS (track_remap + 1, mh->numtracks, modreader);  if (_mm_eof (modreader))    {      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;  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 en 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 */MLOADER load_amf ={  NULL,  "AMF",  "AMF (DSMI Advanced Module Format)",  AMF_Init,  AMF_Test,  AMF_Load,  AMF_Cleanup,  AMF_LoadTitle};/* ex:set ts=4: */

⌨️ 快捷键说明

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