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

📄 mod.c

📁 MIDI解码程序(用VC编写)
💻 C
📖 第 1 页 / 共 5 页
字号:
/*    TiMidity++ -- MIDI to WAVE converter and player    Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>    Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>    Most of this file is taken from the MikMod sound library, which is    (c) 1998, 1999 Miodrag Vallat and others - see file libunimod/AUTHORS    for complete list.    This program is free software; you can redistribute it and/or modify    it under the terms of the GNU 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 General Public License for more details.    You should have received a copy of the GNU General Public License    along with this program; if not, write to the Free Software    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA*//* Interface to libunimod + module player */#ifdef HAVE_CONFIG_H#include "config.h"#endif /* HAVE_CONFIG_H */#include <stdio.h>#include <stdlib.h>#include <math.h>#ifdef SUNOSextern long int random (void);#endif#ifndef NO_STRING_H#include <string.h>#else#include <strings.h>#endif#include "timidity.h"#include "common.h"#include "instrum.h"#include "playmidi.h"#include "readmidi.h"#include "tables.h"#include "mod.h"#include "output.h"#include "controls.h"#include "unimod.h"#include "unimod_priv.h"#include "mod2midi.h"static BOOL mod_do_play (MODULE *);int load_module_file (struct timidity_file *tf, int mod_type){  MODULE *mf;#ifdef LOOKUP_HACK  ML_8bitsamples = 1;#else  ML_8bitsamples = 0;#endif  ML_monosamples = 1;  ML_RegisterAllLoaders ();  mf = ML_Load (tf->url, MOD_NUM_VOICES, 0);  if (ML_errno)    return 1;  current_file_info->file_type = mod_type;  load_module_samples (mf->samples, mf->numsmp, mod_type == IS_MOD_FILE);  mod_do_play (mf);  ML_Free (mf);  return 0;}int get_module_type (char *fn){  if (check_file_extension (fn, ".mod", 1))	/* Most common first */    return IS_MOD_FILE;  if (check_file_extension (fn, ".xm", 1)      || check_file_extension (fn, ".s3m", 1)      || check_file_extension (fn, ".it", 1)      || check_file_extension (fn, ".669", 1)	/* Then the others in alphabetic order */      || check_file_extension (fn, ".amf", 1)      || check_file_extension (fn, ".dsm", 1)      || check_file_extension (fn, ".far", 1)      || check_file_extension (fn, ".gdm", 1)      || check_file_extension (fn, ".imf", 1)      || check_file_extension (fn, ".med", 1)      || check_file_extension (fn, ".mtm", 1)      || check_file_extension (fn, ".stm", 1)      || check_file_extension (fn, ".stx", 1)      || check_file_extension (fn, ".ult", 1)      || check_file_extension (fn, ".uni", 1))    return IS_S3M_FILE;  return IS_OTHER_FILE;}char *get_module_title (struct timidity_file *tf, int mod_type){  return ML_LoadTitle (tf->url);}/*========== Playing */#define POS_NONE        (-2)	/* no loop position defined */typedef struct ENVPR{  UBYTE flg;			/* envelope flag */  UBYTE pts;			/* number of envelope points */  UBYTE susbeg;			/* envelope sustain index begin */  UBYTE susend;			/* envelope sustain index end */  UBYTE beg;			/* envelope loop begin */  UBYTE end;			/* envelope loop end */  SWORD p;			/* current envelope counter */  UWORD a;			/* envelope index a */  UWORD b;			/* envelope index b */  ENVPT *env;			/* envelope points */}ENVPR;typedef struct MP_CONTROL  {    INSTRUMENT *i;    SAMPLE *s;    UBYTE sample;		/* which sample number */    UBYTE note;			/* the audible note as heard, direct rep of period */    SWORD outvolume;		/* output volume (vol + sampcol + instvol) */    SBYTE chanvol;		/* channel's "global" volume */    UWORD fadevol;		/* fading volume rate */    SWORD panning;		/* panning position */    UBYTE kick;			/* if true = sample has to be restarted */    UWORD period;		/* period to play the sample at */    UBYTE nna;			/* New note action type + master/slave flags */    UBYTE volflg;		/* volume envelope settings */    UBYTE panflg;		/* panning envelope settings */    UBYTE pitflg;		/* pitch envelope settings */    UBYTE keyoff;		/* if true = fade out and stuff */    SWORD *data;		/* which sample-data to play */    UBYTE notedelay;		/* (used for note delay) */    SLONG start;		/* The starting byte index in the sample */    UWORD ultoffset;		/* fine sample offset memory */    struct MP_VOICE *slave;	/* Audio Slave of current effects control channel */    UBYTE slavechn;		/* Audio Slave of current effects control channel */    UBYTE anote;		/* the note that indexes the audible */    UBYTE oldnote;    SWORD ownper;    SWORD ownvol;    UBYTE dca;			/* duplicate check action */    UBYTE dct;			/* duplicate check type */    UBYTE *row;			/* row currently playing on this channel */    SBYTE retrig;		/* retrig value (0 means don't retrig) */    ULONG speed;		/* what finetune to use */    SWORD volume;		/* amiga volume (0 t/m 64) to play the sample at */    SWORD tmpvolume;		/* tmp volume */    UWORD tmpperiod;		/* tmp period */    UWORD wantedperiod;		/* period to slide to (with effect 3 or 5) */    UBYTE arpmem;		/* arpeggio command memory */    UBYTE pansspd;		/* panslide speed */    UWORD slidespeed;		/* */    UWORD portspeed;		/* noteslide speed (toneportamento) */    UBYTE s3mtremor;		/* s3m tremor (effect I) counter */    UBYTE s3mtronof;		/* s3m tremor ontime/offtime */    UBYTE s3mvolslide;		/* last used volslide */    SBYTE sliding;    UBYTE s3mrtgspeed;		/* last used retrig speed */    UBYTE s3mrtgslide;		/* last used retrig slide */    UBYTE glissando;		/* glissando (0 means off) */    UBYTE wavecontrol;    SBYTE vibpos;		/* current vibrato position */    UBYTE vibspd;		/* "" speed */    UBYTE vibdepth;		/* "" depth */    SBYTE trmpos;		/* current tremolo position */    UBYTE trmspd;		/* "" speed */    UBYTE trmdepth;		/* "" depth */    UBYTE fslideupspd;    UBYTE fslidednspd;    UBYTE fportupspd;		/* fx E1 (extra fine portamento up) data */    UBYTE fportdnspd;		/* fx E2 (extra fine portamento dn) data */    UBYTE ffportupspd;		/* fx X1 (extra fine portamento up) data */    UBYTE ffportdnspd;		/* fx X2 (extra fine portamento dn) data */    ULONG hioffset;		/* last used high order of sample offset */    UWORD soffset;		/* last used low order of sample-offset (effect 9) */    UBYTE sseffect;		/* last used Sxx effect */    UBYTE ssdata;		/* last used Sxx data info */    UBYTE chanvolslide;		/* last used channel volume slide */    UBYTE panbwave;		/* current panbrello waveform */    UBYTE panbpos;		/* current panbrello position */    SBYTE panbspd;		/* "" speed */    UBYTE panbdepth;		/* "" depth */    UWORD newsamp;		/* set to 1 upon a sample / inst change */    UBYTE voleffect;		/* Volume Column Effect Memory as used by IT */    UBYTE voldata;		/* Volume Column Data Memory */    SWORD pat_reppos;		/* patternloop position */    UWORD pat_repcnt;		/* times to loop */  }MP_CONTROL;/* Used by NNA only player (audio control.  MP_CONTROL is used for full effects   control). */typedef struct MP_VOICE  {    INSTRUMENT *i;    SAMPLE *s;    UBYTE sample;		/* which instrument number */    SWORD volume;		/* output volume (vol + sampcol + instvol) */    SWORD panning;		/* panning position */    SBYTE chanvol;		/* channel's "global" volume */    UWORD fadevol;		/* fading volume rate */    UWORD period;		/* period to play the sample at */    UBYTE volflg;		/* volume envelope settings */    UBYTE panflg;		/* panning envelope settings */    UBYTE pitflg;		/* pitch envelope settings */    UBYTE keyoff;		/* if true = fade out and stuff */    UBYTE kick;			/* if true = sample has to be restarted */    UBYTE note;			/* the audible note (as heard, direct rep of period) */    UBYTE nna;			/* New note action type + master/slave flags */    SWORD *data;		/* which sample-data to play */    SLONG start;		/* The start byte index in the sample *//* Below here is info NOT in MP_CONTROL!! */    ENVPR venv;    ENVPR penv;    ENVPR cenv;    UWORD avibpos;		/* autovibrato pos */    UWORD aswppos;		/* autovibrato sweep pos */    ULONG totalvol;		/* total volume of channel (before global mixings) */    BOOL mflag;    SWORD masterchn;    UWORD masterperiod;    MP_CONTROL *master;		/* index of "master" effects channel */  }MP_VOICE;typedef struct MP_STATUS  {    SWORD channel;		/* channel we're working on */    UWORD oldsngspd;		/* old song speed */    UWORD sngspd;		/* current song speed */    SWORD volume;		/* song volume (0-128) (or user volume) */    UWORD bpm;			/* current beats-per-minute speed */    UWORD newbpm;		/* next beats-per-minute speed */    UBYTE realchn;		/* real number of channels used */    UBYTE totalchn;		/* total number of channels used (incl NNAs) */    UWORD patpos;		/* current row number */    SWORD sngpos;		/* current song position */    UWORD numrow;		/* number of rows on current pattern */    UWORD vbtick;		/* tick counter (counts from 0 to sngspd) */    struct MP_CONTROL *control;	/* Effects Channel info (size pf->numchn) */    struct MP_VOICE voice[MOD_NUM_VOICES];	/* Audio Voice information */    UBYTE globalslide;		/* global volume slide rate */    UBYTE pat_repcrazy;		/* module has just looped to position -1 */    UWORD patbrk;		/* position where to start a new pattern */    UBYTE patdly;		/* patterndelay counter (command memory) */    UBYTE patdly2;		/* patterndelay counter (real one) */    SWORD posjmp;		/* flag to indicate a jump is needed... */    int explicitslides;  }MP_STATUS;MODULE *pf = NULL;		/* modfile being played */static MP_CONTROL *a;		/* current AUDTMP we're working on */static MP_STATUS mp;		/* player status */static UBYTE VibratoTable[32] ={  0, 24, 49, 74, 97, 120, 141, 161, 180, 197, 212, 224, 235, 244, 250, 253,  255, 253, 250, 244, 235, 224, 212, 197, 180, 161, 141, 120, 97, 74, 49, 24};static UBYTE avibtab[128] ={  0, 1, 3, 4, 6, 7, 9, 10, 12, 14, 15, 17, 18, 20, 21, 23,  24, 25, 27, 28, 30, 31, 32, 34, 35, 36, 38, 39, 40, 41, 42, 44,  45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 54, 55, 56, 57, 57, 58,  59, 59, 60, 60, 61, 61, 62, 62, 62, 63, 63, 63, 63, 63, 63, 63,  64, 63, 63, 63, 63, 63, 63, 63, 62, 62, 62, 61, 61, 60, 60, 59,  59, 58, 57, 57, 56, 55, 54, 54, 53, 52, 51, 50, 49, 48, 47, 46,  45, 44, 42, 41, 40, 39, 38, 36, 35, 34, 32, 31, 30, 28, 27, 25,  24, 23, 21, 20, 18, 17, 15, 14, 12, 10, 9, 7, 6, 4, 3, 1};static SBYTE PanbrelloTable[256] ={  0, 2, 3, 5, 6, 8, 9, 11, 12, 14, 16, 17, 19, 20, 22, 23,  24, 26, 27, 29, 30, 32, 33, 34, 36, 37, 38, 39, 41, 42, 43, 44,  45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 56, 57, 58, 59,  59, 60, 60, 61, 61, 62, 62, 62, 63, 63, 63, 64, 64, 64, 64, 64,  64, 64, 64, 64, 64, 64, 63, 63, 63, 62, 62, 62, 61, 61, 60, 60,  59, 59, 58, 57, 56, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46,  45, 44, 43, 42, 41, 39, 38, 37, 36, 34, 33, 32, 30, 29, 27, 26,  24, 23, 22, 20, 19, 17, 16, 14, 12, 11, 9, 8, 6, 5, 3, 2,  0, -2, -3, -5, -6, -8, -9, -11, -12, -14, -16, -17, -19, -20, -22, -23,  -24, -26, -27, -29, -30, -32, -33, -34, -36, -37, -38, -39, -41, -42, -43, -44,  -45, -46, -47, -48, -49, -50, -51, -52, -53, -54, -55, -56, -56, -57, -58, -59,  -59, -60, -60, -61, -61, -62, -62, -62, -63, -63, -63, -64, -64, -64, -64, -64,  -64, -64, -64, -64, -64, -64, -63, -63, -63, -62, -62, -62, -61, -61, -60, -60,  -59, -59, -58, -57, -56, -56, -55, -54, -53, -52, -51, -50, -49, -48, -47, -46,  -45, -44, -43, -42, -41, -39, -38, -37, -36, -34, -33, -32, -30, -29, -27, -26,  -24, -23, -22, -20, -19, -17, -16, -14, -12, -11, -9, -8, -6, -5, -3, -2};/* returns a random value between 0 and ceil-1, ceil must be a power of two */static int getrandom (int ceil){#ifdef HAVE_SRANDOM  return random () & (ceil - 1);#else  return (rand () * ceil) / (RAND_MAX + 1.0);#endif}/*      New Note Action Scoring System :   --------------------------------   1)   total-volume (fadevol, chanvol, volume) is the main scorer.   2)   a looping sample is a bonus x2   3)   a foreground channel is a bonus x4   4)   an active envelope with keyoff is a handicap -x2                          */static int MP_FindEmptyChannel (void){  MP_VOICE *a;  ULONG t, k, tvol, pp;  a = mp.voice;  for (t = 0; t < MOD_NUM_VOICES; t++)    {      /* allow us to take over a nonexisting sample */      if (!a->s)        return t;      if (((mp.voice[t].kick == KICK_ABSENT) || (mp.voice[t].kick == KICK_ENV)) &&	  Voice_Stopped (t))        return t;    }  tvol = 0xffffffUL;  t = 0;  for (k = 0; k < MOD_NUM_VOICES; k++, a++)    if ((a->kick == KICK_ABSENT) || (a->kick == KICK_ENV))      {	pp = a->totalvol << ((a->s->flags & SF_LOOP) ? 1 : 0);	if ((a->master) && (a == a->master->slave))	  pp <<= 2;	if (pp < tvol)	  {	    tvol = pp;	    t = k;	  }      }  if (tvol > 8000 * 7)    return -1;  return t;}static UWORD GetPeriod (UWORD note, ULONG speed){  if (pf->flags & UF_XMPERIODS)    return (pf->flags & UF_LINEAR) ? getlinearperiod (note, speed) : getlogperiod (note, speed);  return getoldperiod (note, speed);}static SWORD Interpolate (SWORD p, SWORD p1, SWORD p2, SWORD v1, SWORD v2){  if ((p1 == p2) || (p == p1))    return v1;  return v1 + ((SLONG) ((p - p1) * (v2 - v1)) / (p2 - p1));}static SWORD InterpolateEnv (SWORD p, ENVPT * a, ENVPT * b){  return (Interpolate (p, a->pos, b->pos, a->val, b->val));}static SWORD DoPan (SWORD envpan, SWORD pan){  int newpan;  newpan = pan + (((envpan - PAN_CENTER) * (128 - abs (pan - PAN_CENTER))) / 128);  return (newpan < PAN_LEFT) ? PAN_LEFT : (newpan > PAN_RIGHT ? PAN_RIGHT : newpan);}static void StartEnvelope (ENVPR * t, UBYTE flg, UBYTE pts, UBYTE susbeg, UBYTE susend, UBYTE beg, UBYTE end, ENVPT * p, UBYTE keyoff){  t->flg = flg;  t->pts = pts;  t->susbeg = susbeg;  t->susend = susend;  t->beg = beg;  t->end = end;  t->env = p;  t->p = 0;  t->a = 0;  t->b = ((t->flg & EF_SUSTAIN) && (!(keyoff & KEY_OFF))) ? 0 : 1;  /* Imago Orpheus sometimes stores an extra initial point in the envelope */  if ((t->pts >= 2) && (t->env[0].pos == t->env[1].pos))    {      t->a++;      t->b++;    }  if (t->b >= t->pts)    t->b = t->pts - 1;}/* This procedure processes all envelope types, include volume, pitch, and   panning.  Envelopes are defined by a set of points, each with a magnitude   [relating either to volume, panning position, or pitch modifier] and a tick   position.   Envelopes work in the following manner:   (a) Each tick the envelope is moved a point further in its progression. For   an accurate progression, magnitudes between two envelope points are   interpolated.   (b) When progression reaches a defined point on the envelope, values are   shifted to interpolate between this point and the next, and checks for   loops or envelope end are done.   Misc:   Sustain loops are loops that are only active as long as the keyoff flag is   clear.  When a volume envelope terminates, so does the current fadeout.  */static SWORD ProcessEnvelope (ENVPR * t, SWORD v, UBYTE keyoff){  if (t->flg & EF_ON)    {      UBYTE a, b;		/* actual points in the envelope */      UWORD p;			/* the 'tick counter' - real point being played */      a = t->a;      b = t->b;      p = t->p;      /* if sustain loop on one point (XM type), don't move and don't         interpolate when the point is reached */      if ((t->flg & EF_SUSTAIN) && (t->susbeg == t->susend) &&	  (!(keyoff & KEY_OFF)) && (p == t->env[t->susbeg].pos))	v = t->env[t->susbeg].val;      else	{	  /* compute the current envelope value between points a and b */	  if (a == b)	    v = t->env[a].val;	  else	    v = InterpolateEnv (p, &t->env[a], &t->env[b]);	  p++;	  /* pointer reached point b? */	  if (p >= t->env[b].pos)	    {	      a = b++;		/* shift points a and b */	      /* Check for loops, sustain loops, or end of envelope. */	      if ((t->flg & EF_SUSTAIN) && (!(keyoff & KEY_OFF)) && (b > t->susend))		{		  a = t->susbeg;		  b = (t->susbeg == t->susend) ? a : a + 1;		  p = t->env[a].pos;		}	      else if ((t->flg & EF_LOOP) && (b > t->end))		{		  a = t->beg;		  b = (t->beg == t->end) ? a : a + 1;		  p = t->env[a].pos;		}	      else		{		  if (b >= t->pts)		    {		      if ((t->flg & EF_VOLENV) && (mp.channel != -1))			{			  mp.voice[mp.channel].keyoff |= KEY_FADE;			  if (!v)			    mp.voice[mp.channel].fadevol = 0;			}		      b--;		      p--;		    }		}	    }	  t->a = a;	  t->b = b;	  t->p = p;	}    }  return v;}/*========== Protracker effects */static void DoEEffects (UBYTE dat){  UBYTE nib = dat & 0xf;  switch (dat >> 4)    {    case 0x0:			/* hardware filter toggle, not supported */      break;    case 0x1:			/* fineslide up */      if (a->period)	if (!mp.vbtick)	  a->tmpperiod -= (nib << 2);      break;    case 0x2:			/* fineslide dn */      if (a->period)	if (!mp.vbtick)	  a->tmpperiod += (nib << 2);      break;    case 0x3:			/* glissando ctrl */      a->glissando = nib;      break;    case 0x4:			/* set vibrato waveform */      a->wavecontrol &= 0xf0;      a->wavecontrol |= nib;      break;    case 0x5:			/* set finetune */      if (a->period)	{	  if (pf->flags & UF_XMPERIODS)	    a->speed = nib + 128;	  else	    a->speed = finetune[nib];	  a->tmpperiod = GetPeriod ((UWORD) a->note << 1, a->speed);	}      break;    case 0x6:			/* set patternloop */      if (mp.vbtick)	break;      if (nib)

⌨️ 快捷键说明

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