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

📄 midi.h

📁 这个版本修正了已知的Bug,同时添加了部分函数
💻 H
📖 第 1 页 / 共 4 页
字号:
	    p++;
	    if ((event != 0xF0) && (event != 0xF7) && (event != 0xFF))
	       running_status = event;
	 }
	 else                                   /* use running status */
	    event = running_status; 

	 switch (event>>4) {

	    case 0x0C:                          /* program change! */
	       patches[*p] = TRUE;
	       p++;
	       break;

	    case 0x09:                          /* note on, is it a drum? */
	       if ((event & 0x0F) == 9)
		  drums[*p] = TRUE;
	       p += 2;
	       break;

	    case 0x08:                          /* note off */
	    case 0x0A:                          /* note aftertouch */
	    case 0x0B:                          /* control change */
	    case 0x0E:                          /* pitch bend */
	       p += 2;
	       break;

	    case 0x0D:                          /* channel aftertouch */
	       p += 1;
	       break;

	    case 0x0F:                          /* special event */
	       switch (event) {
		  case 0xF0:                    /* sysex */
		  case 0xF7: 
		     l = parse_var_len(&p);
		     p += l;
		     break;

		  case 0xF2:                    /* song position */
		     p += 2;
		     break;

		  case 0xF3:                    /* song select */
		     p++;
		     break;

		  case 0xFF:                    /* meta-event */
		     p++;
		     l = parse_var_len(&p);
		     p += l;
		     break;

		  default:
		     /* the other special events don't have any data bytes,
			so we don't need to bother skipping past them */
		     break;
	       }
	       break;

	    default:
	       /* something has gone badly wrong if we ever get to here */
	       break;
	 }

	 if (p < end)                           /* skip time offset */
	    parse_var_len(&p);
      }
   }

   /* tell the driver to do its stuff */ 
   return midi_driver->load_patches(patches, drums);
}

int MidiPlay(MIDI *midi, int loop)
{
   int c;

   if (!MidiFlag) return -1;

   remove_int(midi_player);
   for (c=0; c<16; c++)
      all_notes_off(c);
   if (midi) {
      if (!midi_loaded_patches)
	 if (load_patches(midi) != 0)
	    return -1;

      midi_loop = loop;
      midi_loop_start = -1;
      midi_loop_end = -1;

      prepare_to_play(midi);
      /* arbitrary speed, () will adjust it */
   install_int(midi_player, 20);
   }
   else {
      midifile = NULL;
      midi_pos = -1;
   }

   return 0;
}

/* midi_init:
 *  Sets up the MIDI player ready for use. Returns non-zero on failure.
 */

 int midi_init(char driver)
{
   int c, c2, c3;
   int back = 0;
   char buf[16];

   midi_loaded_patches = FALSE;

   switch (driver)
    { case MIDI_AUTO:  midi_driver = &Midi_adlib; break;
      case MIDI_ADLIB: midi_driver = &Midi_adlib; break;
      case MIDI_DIGI:  printf("Haven't supported digi midi\n");
                       back = 1; break;
      default: back = 1;
    }

   if (back) return FALSE;

   if (!midi_driver->detect()) {
      sprintf(grp_err,"MIDI detect failed\n");

      return FALSE;
   }

   if (!midi_driver->init(64)) {
         sprintf(grp_err,"MIDI init failed\n");

      return FALSE;
   }

   timer_init();

   for (c=0; c<16; c++) {
      midi_channel[c].volume = 128;
      midi_channel[c].pitch_bend = 0x2000;

      for (c2=0; c2<128; c2++)
	 for (c3=0; c3<MIDI_LAYERS; c3++)
	    midi_channel[c].note[c2][c3] = -1;
   }

   for (c=0; c<MIDI_VOICES; c++) {
      midi_voice[c].note = -1;
      midi_voice[c].time = 0;
   }

   for (c=0; c<128; c++) {
      sprintf(buf, "p%d", c+1);

	 patch_table[c].bank1 = -1;
	 patch_table[c].bank2 = -1;
	 patch_table[c].prog = c;
	 patch_table[c].pitch = 0;
      }

   return TRUE;
}

 void midi_exit()
{
   StopMidi();
   midi_driver->exit();
}

 void prepare_to_play(MIDI *midi)
{
   int c;

   for (c=0; c<16; c++)
      reset_controllers(c);

   update_controllers();

   midifile = midi;
   midi_pos = 0;
   midi_pos_counter = 0;
   midi_speed = TIMERS_PER_SECOND / 2 / midifile->divisions;   /* 120 bpm */
   midi_new_speed = -1;
   midi_pos_speed = midi_speed * midifile->divisions;
   midi_timer_speed = 0;
   midi_seeking = 0;
   midi_looping = 0;

   for (c=0; c<16; c++) {
      midi_channel[c].patch = 0;
      if (midi_driver->raw_midi)
	 raw_program_change(c, 0);
   }

   for (c=0; c<MIDI_TRACKS; c++) {
      if (midi->track[c].data) {
	 midi_track[c].pos = midi->track[c].data;
	 midi_track[c].timer = parse_var_len(&midi_track[c].pos);
	 midi_track[c].timer *= midi_speed;
      }
      else {
	 midi_track[c].pos = NULL;
	 midi_track[c].timer = LONG_MAX;
      }
      midi_track[c].running_status = 0;
   }
}

void  _set_volume(int digi_volume,int midi_volume)
{  if (midi_volume >= 0) {
      if (midi_volume<0) midi_volume=0;
      if (midi_volume>255) midi_volume=255;

      if ((midi_driver->mixer_volume) && 
	  (midi_driver->mixer_volume(midi_volume) == 0))
	 _midi_volume = -1;
      else
	 _midi_volume = midi_volume;
   }
   if (digi_volume >= 0) {
   }
}


typedef struct FM_INSTRUMENT
{
   unsigned char characteristic1;
   unsigned char characteristic2;
   unsigned char level1;
   unsigned char level2;
   unsigned char attackdecay1;
   unsigned char attackdecay2;
   unsigned char sustainrelease1;
   unsigned char sustainrelease2;
   unsigned char wave1;
   unsigned char wave2;
   unsigned char feedback;
   unsigned char freq;
   unsigned char key;
   unsigned char type;
} FM_INSTRUMENT;

#define FM_HH     1
#define FM_CY     2
#define FM_TT     4
#define FM_SD     8
#define FM_BD     16

/* include the GM patch set (static data) */
#include "midimap.h"

/* is the OPL in percussion mode? */
 int fm_drum_mode = FALSE;

/* register offsets for each voice */
 int fm_offset[18] = {
   0x000, 0x001, 0x002, 0x008, 0x009, 0x00A, 0x010, 0x011, 0x012, 
   0x100, 0x101, 0x102, 0x108, 0x109, 0x10A, 0x110, 0x111, 0x112
};

/* for converting midi note numbers to FM frequencies */
 int fm_freq[13] = {
   0x157, 0x16B, 0x181, 0x198, 0x1B0, 0x1CA,
   0x1E5, 0x202, 0x220, 0x241, 0x263, 0x287, 0x2AE
};

/* logarithmic relationship between midi and FM volumes */
 int fm_vol_table[128] = {
   0,  11, 16, 19, 22, 25, 27, 29, 32, 33, 35, 37, 39, 40, 42, 43,
   45, 46, 48, 49, 50, 51, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62,
   64, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 75, 76, 77,
   78, 79, 80, 80, 81, 82, 83, 83, 84, 85, 86, 86, 87, 88, 89, 89,
   90, 91, 91, 92, 93, 93, 94, 95, 96, 96, 97, 97, 98, 99, 99, 100,
   101, 101, 102, 103, 103, 104, 104, 105, 106, 106, 107, 107, 108,
   109, 109, 110, 110, 111, 112, 112, 113, 113, 114, 114, 115, 115,
   116, 117, 117, 118, 118, 119, 119, 120, 120, 121, 121, 122, 122,
   123, 123, 124, 124, 125, 125, 126, 126, 127
};

/* drum channel tables:          BD       SD       TT       CY       HH    */
 int fm_drum_channel[] = { 6,       7,       8,       8,       7     };
 int fm_drum_op1[] =     { TRUE,    FALSE,   TRUE,    FALSE,   TRUE  };
 int fm_drum_op2[] =     { TRUE,    TRUE,    FALSE,   TRUE,    FALSE };

/* cached information about the state of the drum channels */
 FM_INSTRUMENT *fm_drum_cached_inst1[5];
 FM_INSTRUMENT *fm_drum_cached_inst2[5];
 int fm_drum_cached_vol1[5];
 int fm_drum_cached_vol2[5];
 long fm_drum_cached_time[5];

/* various bits of information about the current state of the FM chip */
 unsigned char fm_drum_mask;
 unsigned char fm_key[18];
 unsigned char fm_keyscale[18];
 unsigned char fm_feedback[18];
 int fm_level[18];
 int fm_patch[18];

#define VOICE_OFFSET(x)     ((x < 9) ? x : 0x100+x-9)
#define midi_adlib Midi_adlib
int        midi_card = MIDI_OPL3;
int           _volume_step = 8;
/* fm_reset:
 *  Resets the FM chip. If enable is set, puts OPL3 cards into OPL3 mode,
 *  otherwise puts them into OPL2 emulation mode.
 */
 void fm_reset(int enable)
{
   int i;

   for (i=0xF5; i>0; i--)
      FMWrite(i, 0);

   if (midi_card == MIDI_OPL3) {          /* if we have an OPL3... */
      lk_fm_delay1 = 1;
      lk_fm_delay2 = 2;

      FMWrite(0x105, 1);                 /* enable OPL3 mode */

      for (i=0x1F5; i>0x105; i--)
	 FMWrite(i, 0);

      for (i=0x104; i>0x100; i--)
	 FMWrite(i, 0);

      if (!enable)
	 FMWrite(0x105, 0);              /* turn OPL3 mode off again */
   }
   else {
      lk_fm_delay1 = 6;
      lk_fm_delay2 = 35;

      if (midi_card == MIDI_2XOPL2)     /* if we have a second OPL2... */
      {    
	 for (i=0x1F5; i>0x100; i--)
	    FMWrite(i, 0);

	 FMWrite(0x101, 0x20); 
	 FMWrite(0x1BD, 0xC0); 
      }
   }

   for (i=0; i<midi_adlib.voices; i++) {
      fm_key[i] = 0;
      fm_keyscale[i] = 0;
      fm_feedback[i] = 0;
      fm_level[i] = 0;
      fm_patch[i] = -1;
      FMWrite(0x40+fm_offset[i], 63);
      FMWrite(0x43+fm_offset[i], 63);
   }

   for (i=0; i<5; i++) {
      fm_drum_cached_inst1[i] = NULL;
      fm_drum_cached_inst2[i] = NULL;
      fm_drum_cached_vol1[i] = -1;
      fm_drum_cached_vol2[i] = -1;
      fm_drum_cached_time[i] = 0;
   }

   FMWrite(0x01, 0x20);                  /* turn on wave form control */

   fm_drum_mode = FALSE;
   fm_drum_mask = 0xC0;
   FMWrite(0xBD, fm_drum_mask);          /* set AM and vibrato to high */

   Midi_adlib.xmin = -1;
   Midi_adlib.xmax = -1;
}
/* fm_set_drum_mode:
 *  Switches the OPL synth between normal and percussion modes.
 */
 void fm_set_drum_mode(int usedrums)
{
   int i;

   fm_drum_mode = usedrums;
   fm_drum_mask = usedrums ? 0xE0 : 0xC0;

   midi_adlib.xmin = usedrums ? 6 : -1;
   midi_adlib.xmax = usedrums ? 8 : -1;

   for (i=6; i<9; i++)
      if (midi_card == MIDI_OPL3)
	 FMWrite(0xC0+VOICE_OFFSET(i), 0x30);
      else
	 FMWrite(0xC0+VOICE_OFFSET(i), 0);

   FMWrite(0xBD, fm_drum_mask);
}

/* fm_set_voice:
 *  Sets the sound to be used for the specified voice, from a structure
 *  containing eleven bytes of FM operator data. Note that it doesn't
 *  actually set the volume: it just stores volume data in the fm_level
 *  arrays for fm_set_volume() to use.
 */
 inline void fm_set_voice(int voice, FM_INSTRUMENT *inst)
{
   /* store some info */
   fm_keyscale[voice] = inst->level2 & 0xC0;
   fm_level[voice] = 63 - (inst->level2 & 63);
   fm_feedback[voice] = inst->feedback;

   /* write the new data */
   FMWrite(0x20+fm_offset[voice], inst->characteristic1);
   FMWrite(0x23+fm_offset[voice], inst->characteristic2);
   FMWrite(0x60+fm_offset[voice], inst->attackdecay1);
   FMWrite(0x63+fm_offset[voice], inst->attackdecay2);
   FMWrite(0x80+fm_offset[voice], inst->sustainrelease1);
   FMWrite(0x83+fm_offset[voice], inst->sustainrelease2);
   FMWrite(0xE0+fm_offset[voice], inst->wave1);
   FMWrite(0xE3+fm_offset[voice], inst->wave2);

   /* don't set operator1 level for additive synthesis sounds */
   if (!(inst->feedback & 1))
      FMWrite(0x40+fm_offset[voice], inst->level1);

   /* on OPL3, 0xC0 contains pan info, so don't set it until fm_key_on() */
   if (midi_card != MIDI_OPL3)
      FMWrite(0xC0+VOICE_OFFSET(voice), inst->feedback);
}
/* fm_set_drum_op1:
 *  Sets the sound for operator #1 of a drum channel.
 */
 inline void fm_set_drum_op1(int voice, FM_INSTRUMENT *inst)
{
   FMWrite(0x20+fm_offset[voice], inst->characteristic1);
   FMWrite(0x60+fm_offset[voice], inst->attackdecay1);
   FMWrite(0x80+fm_offset[voice], inst->sustainrelease1);
   FMWrite(0xE0+fm_offset[voice], inst->wave1);
}
/* fm_set_drum_op2:
 *  Sets the sound for operator #2 of a drum channel.
 */
 inline void fm_set_drum_op2(int voice, FM_INSTRUMENT *inst)
{
   FMWrite(0x23+fm_offset[voice], inst->characteristic2);
   FMWrite(0x63+fm_offset[voice], inst->attackdecay2);
   FMWrite(0x83+fm_offset[voice], inst->sustainrelease2);
   FMWrite(0xE3+fm_offset[voice], inst->wave2);
}
/* fm_set_drum_vol_op1:
 *  Sets the volume for operator #1 of a drum channel.
 */
 inline void fm_set_drum_vol_op1(int voice, int vol)
{
   vol = 63 * fm_vol_table[vol] / 128;
   vol = MIN((vol * _volume_step)>>2,63);
   FMWrite(0x40+fm_offset[voice], (63-vol));
}
/* fm_set_drum_vol_op2:
 *  Sets the volume for operator #2 of a drum channel.
 */
 inline void fm_set_drum_vol_op2(int voice, int vol)
{
   vol = 63 * fm_vol_table[vol] / 128;
   vol = MIN((vol * _volume_step)>>2,63);
   FMWrite(0x43+fm_offset[voice], (63-vol));
}



/* fm_set_drum_pitch:
 *  Sets the pitch of a drum channel.
 */
 inline void fm_set_drum_pitch(int voice, FM_INSTRUMENT *drum)
{
   FMWrite(0xA0+VOICE_OFFSET(voice), drum->freq);
   FMWrite(0xB0+VOICE_OFFSET(voice), drum->key & 0x1F);
}



/* fm_trigger_drum:
 *  Triggers a note on a drum channel.
 */
 inline void fm_trigger_drum(int inst, int vol)
{
   FM_INSTRUMENT *drum = fm_drum+inst;
   int d;

   if (!fm_drum_mode)
      fm_set_drum_mode(TRUE);

   if (drum->type == FM_BD)
      d = 0;
   else if (drum->type == FM_SD)
      d = 1;
   else if (drum->type == FM_TT)
      d = 2;
   else if (drum->type == FM_CY)
      d = 3;
   else
      d = 4;

   /* don't let drum sounds come too close together */
   if (fm_drum_cached_time[d] == _midi_tick)
      return;

   fm_drum_cached_time[d] = _midi_tick;

   fm_drum_mask &= (~drum->type);
   FMWrite(0xBD, fm_drum_mask);

   vol = vol*3/4;


   if (fm_drum_op1[d]) {
      if (fm_drum_cached_inst1[d] != drum) {
	 fm_drum_cached_inst1[d] = drum;
	 fm_set_drum_op1(fm_drum_channel[d], drum);
      }

      if (fm_drum_cached_vol1[d] != vol) {
	 fm_drum_cached_vol1[d] = vol;
	 fm_set_drum_vol_op1(fm_drum_channel[d], vol);
      }
   }

⌨️ 快捷键说明

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