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

📄 midi.h

📁 这个版本修正了已知的Bug,同时添加了部分函数
💻 H
📖 第 1 页 / 共 4 页
字号:

   if (fm_drum_op2[d]) {
      if (fm_drum_cached_inst2[d] != drum) {
	 fm_drum_cached_inst2[d] = drum;
	 fm_set_drum_op2(fm_drum_channel[d], drum);
      }

      if (fm_drum_cached_vol2[d] != vol) {
	 fm_drum_cached_vol2[d] = vol;
	 fm_set_drum_vol_op2(fm_drum_channel[d], vol);
      }
   }

   fm_set_drum_pitch(fm_drum_channel[d], drum);

   fm_drum_mask |= drum->type;
   FMWrite(0xBD, fm_drum_mask);
}


/* fm_key_on:
 *  Triggers the specified voice. The instrument is specified as a GM
 *  patch number, pitch as a midi note number, and volume from 0-127.
 *  The bend parameter is _not_ expressed as a midi pitch bend value.
 *  It ranges from 0 (no pitch change) to 0xFFF (aost a semitone sharp).
 *  Drum sounds are indicated by passing an instrument number greater than
 *  128, in which case the sound is GM percussion key #(inst-128).
 */
int _midi_allocate_voice(int min,int max);
 void fm_key_on(int inst, int note, int bend, int vol, int pan)
{
   int voice;

   if (inst > 127) {                               /* drum sound? */
      inst -= 163;
      if (inst < 0)
	 inst = 0;
      else if (inst > 46)
	 inst = 46;

      fm_trigger_drum(inst, vol);
   }
   else {                                          /* regular instrument */
      if (midi_card == MIDI_2XOPL2) {
	 /* the SB Pro-1 has fixed pan positions per voice... */
	 if (pan < 64)
	    voice = _midi_allocate_voice(0, 5);
	 else
	    voice = _midi_allocate_voice(9, midi_driver->voices-1);
      }
      else
	 /* on other cards we can use any voices */
	 voice = _midi_allocate_voice(-1, -1);

      if (voice < 0)
	 return;

      /* make sure the voice isn't sounding */
      FMWrite(0x43+fm_offset[voice], 63);
      if (fm_feedback[voice] & 1)
	 FMWrite(0x40+fm_offset[voice], 63);

      /* make sure the voice is set up with the right sound */
      if (inst != fm_patch[voice]) {
	 fm_set_voice(voice, fm_instrument+inst);
	 fm_patch[voice] = inst;
      }

      /* set pan position */
      if (midi_card == MIDI_OPL3) {
	 if (pan < 48)
	    pan = 0x10;
	 else if (pan >= 80)
	    pan = 0x20;
	 else
	    pan = 0x30;

	 FMWrite(0xC0+VOICE_OFFSET(voice), pan | fm_feedback[voice]);
      }

      /* and play the note */
      fm_set_pitch(voice, note, bend);
      fm_set_volume(voice, vol);
   }
}
/* fm_key_off:
 *  Hey, guess what this does :-)
 */
 void fm_key_off(int voice)
{
   FMWrite(0xB0+VOICE_OFFSET(voice), fm_key[voice] & 0xDF);
}
/* fm_set_volume:
 *  Sets the volume of the specified voice (vol range 0-127).
 */
 void fm_set_volume(int voice, int vol)
{
   vol = fm_level[voice] * fm_vol_table[vol] / 128;
   vol = MIN((vol*_volume_step)>>2,63);    // by lin wei
   FMWrite(0x43+fm_offset[voice], (63-vol) | fm_keyscale[voice]);
   if (fm_feedback[voice] & 1)
      FMWrite(0x40+fm_offset[voice], (63-vol) | fm_keyscale[voice]);
}

/* fm_set_pitch:
 *  Sets the pitch of the specified voice.
 */
 void fm_set_pitch(int voice, int note, int bend)
{
   int oct = 1;
   int freq;

   note -= 24;
   while (note >= 12) {
      note -= 12;
      oct++;
   }

   freq = fm_freq[note];
   if (bend)
      freq += (fm_freq[note+1] - fm_freq[note]) * bend / 0x1000;

   fm_key[voice] = (oct<<2) | (freq >> 8);

   FMWrite(0xA0+VOICE_OFFSET(voice), freq & 0xFF); 
   FMWrite(0xB0+VOICE_OFFSET(voice), fm_key[voice] | 0x20);
}

/* fm_load_patches:
 *  Called before starting to play a MIDI file, to check if we need to be
 *  in rhythm mode or not.
 */
 int fm_load_patches(char *patches, char *drums)
{
   int i;
   int usedrums = FALSE;

   for (i=6; i<9; 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;
   }

   for (i=0; i<128; i++) {
      if (drums[i]) {
	 usedrums = TRUE;
	 break;
      }
   }

   fm_set_drum_mode(usedrums);

   return 0;
}

/* fm_mixer_volume:
 *  For SB-Pro cards, sets the mixer volume for FM output.
 */
 int fm_mixer_volume(int volume)
{ 
   return SetMixer(-1, volume);
}
/* fm_is_there:
 *  Checks for the presence of an OPL synth at the current port.
 */
 int fm_is_there()
{
   FMWrite(1, 0);                        /* init test register */

   FMWrite(4, 0x60);                     /* reset both timers */
   FMWrite(4, 0x80);                     /* enable interrupts */

   if (inp(lk_fm_port) & 0xE0)
      return FALSE;

   FMWrite(2, 0xFF);                     /* write 0xFF to timer 1 */
   FMWrite(4, 0x21);                     /* start timer 1 */

   delay(100);

   if ((inp(lk_fm_port) & 0xE0) != 0xC0)
      return FALSE;

   FMWrite(4, 0x60);                     /* reset both timers */
   FMWrite(4, 0x80);                     /* enable interrupts */

   return TRUE;
}

/* fm_detect:
 *  Adlib detection routine.
 */
 int fm_detect()
{
    int ports[] = 
	 { 0x210, 0x220, 0x230, 0x240, 0x250, 0x260, 0x388, 0 };
   int i;
   char *s;
   int opl_type;

   if (lk_fm_port < 0||lk_sb_port < 0) {
      if (midi_card == MIDI_OPL2||midi_card == MIDI_OPL3) {
	 lk_fm_port = 0x388;
	 if (fm_is_there())
	    goto found_it;
      }
      for (i=0; ports[i]; i++) {          /* find the card */
	 lk_fm_port = ports[i];
	 if (fm_is_there())
	    goto found_it;
      }
   }
   if (!fm_is_there()) {
      sprintf(grp_err,"OPL synth not found");

      return FALSE;
   }
found_it:
   if ((inp(lk_fm_port) & 6) == 0) {    /* check for OPL3 */
      opl_type = MIDI_OPL3;
      GetDspVersion();
   }
   else {                                 /* check for second OPL2 */
      if (GetDspVersion() >= 0x300)
	 opl_type = MIDI_2XOPL2;
      else
	 opl_type = MIDI_OPL2;
   }

   if (midi_card == MIDI_OPL3) {
      if (opl_type != MIDI_OPL3) {
	sprintf(grp_err,"OPL3 synth not found");

	 return FALSE;
      }
   }
   else if (midi_card == MIDI_2XOPL2) {
      if (opl_type != MIDI_2XOPL2) {
	 sprintf(grp_err,"Second OPL2 synth not found");

	 return FALSE;
      }
   }
   else if (midi_card != MIDI_OPL2)
      midi_card = opl_type;

   if (midi_card == MIDI_OPL2)
      s = "OPL2 synth";
   else if (midi_card == MIDI_2XOPL2)
      s = "Dual OPL2 synths";
   else
      s = "OPL3 synth";

   sprintf(adlib_desc, "%s on port %X", s, lk_fm_port);
   midi_adlib.voices = (midi_card == MIDI_OPL2) ? 9 : 18;
   midi_adlib.def_voices = midi_adlib.max_voices = midi_adlib.voices;

   return TRUE;
}

/* load_ibk:
 *  Reads in a .IBK patch set file, for use by the Adlib driver.
 */
int FM_load_ibk(char *filename, int drums)
{
   char sig[4];
   FM_INSTRUMENT *inst;
   int c, note, oct, skip, count;

   FILE *f = fopen(filename, "rb");
   if (!f)
      return -1;

   fread(sig, 4, 1, f);
   if (memcmp(sig, "IBK\x1A", 4) != 0) {
      fclose(f);
      return -1;
   }

   if (drums) {
      inst = fm_drum;
      skip = 35;
      count = 47;
   }
   else {
      inst = fm_instrument;
      skip = 0;
      count = 128;
   }

   for (c=0; c<skip*16; c++)
      fgetc(f);

   for (c=0; c<count; c++) {
      inst->characteristic1 = fgetc(f);
      inst->characteristic2 = fgetc(f);
      inst->level1 = fgetc(f);
      inst->level2 = fgetc(f);
      inst->attackdecay1 = fgetc(f);
      inst->attackdecay2 = fgetc(f);
      inst->sustainrelease1 = fgetc(f);
      inst->sustainrelease2 = fgetc(f);
      inst->wave1 = fgetc(f);
      inst->wave2 = fgetc(f);
      inst->feedback = fgetc(f);

      if (drums) {
	 switch (fgetc(f)) {
	    case 6:  inst->type = FM_BD;  break;
	    case 7:  inst->type = FM_HH;  break;
	    case 8:  inst->type = FM_TT;  break;
	    case 9:  inst->type = FM_SD;  break;
	    case 10: inst->type = FM_CY;  break;
	    default: inst->type = 0;      break;
	 }

	 fgetc(f);

	 note = fgetc(f) - 24;
	 oct = 1;

	 while (note >= 12) {
	    note -= 12;
	    oct++;
	 }

	 inst->freq = fm_freq[note];
	 inst->key = (oct<<2) | (fm_freq[note] >> 8);
      }
      else {
	 inst->type = 0;
	 inst->freq = 0;
	 inst->key = 0;

	 fgetc(f);
	 fgetc(f);
	 fgetc(f);
      }

      fgetc(f);
      fgetc(f);

      inst++;
   }

   fclose(f);
   return 0;
}

char *FM_read_inst_loc(int drums)
{ if (drums) return (char*)fm_drum;
  return (char*)fm_instrument;
}

void FM_load_map(int choice,int drums)
{ FM_INSTRUMENT *inst,*source; int count,i;
   if (drums) {
      inst = fm_drum; 
      source = fm_drum_dat[choice];
      count = 47;
   }
   else {
      inst = fm_instrument;
      source = fm_instrument_dat[choice];
      count = 128;
   }
  for (i=0;i<count;i++,inst++,source++) 
      memcpy(inst,source,sizeof(FM_INSTRUMENT));
}

/* fm_init:
 *  Setup the adlib driver.
 */
int fm_init(int voices)
{
   char *s;
   int i;

   fm_reset(1);
   FM_load_map(0,0); FM_load_map(0,1);
   for (i=0; i<2; i++) {
      if (i==0) s=MidiMapFile[0]; else s=MidiMapFile[1];
      if ((s) && (s[0])) {
	 if (FM_load_ibk(s, (i > 0)) != 0) {
	    sprintf(grp_err,"Error reading .IBK file '%s'", s);

	    return FALSE;
	 }
      }
   }

   return TRUE;
}

void fm_exit()
{
   fm_reset(0);
}

char  gWritePortC(unsigned char value)
{ int i;
  for (i=0;i<0xffff ;i++ )
  { if (!(inp(0x0C+lk_sb_port) & 0x80)) {
       outp(lk_sb_port+0x0c,value);
	   return 0;
    }
  } return -1;
}

unsigned char gReadPortC()
{ short b;
  for (b=50;b>0&&inp(lk_sb_port+0x0e)<128;b--);
  return inp(lk_sb_port+0x0a);
}

short GetDspVersion()
{ short c;
  if (lk_dsp_ver>0) return lk_dsp_ver;
  gWritePortC(0xe1); c=gReadPortC();
  lk_dsp_ver=((unsigned)c<<8) + gReadPortC();
  return lk_dsp_ver;
}


void  MixerWrite(short reg,short data)
{ outp(lk_sb_port+4, reg);
  outp(lk_sb_port+5, data);
}

short MixerRead(short reg)
{ outp(lk_sb_port+4, reg);
  return inp(lk_sb_port+5);
}

short SetMixer(int digi_volume, int midi_volume)
{  short _sb_port=lk_sb_port;
   if (GetDspVersion() < 0x300)  return -1;

   if (digi_volume >= 0) {
      outp(_sb_port+4, 4);
      outp(_sb_port+5, (digi_volume & 0xF0) | (digi_volume >> 4));
   }

   if (midi_volume >= 0) {
      outp(_sb_port+4, 0x26);
      outp(_sb_port+5, (midi_volume & 0xF0) | (midi_volume >> 4));
   }

   return 0;
}



///////////////////////////////////////////////
void FMWrite(unsigned short reg, unsigned char data)
{ 
   short i;
   short port = (reg & 0x100) ? lk_fm_port+2 : lk_fm_port;

   outp(port, reg & 0xFF);      
   for (i=0; i<lk_fm_delay1; i++) inp(port);
   outp(port+1, data);         
   for (i=0; i<lk_fm_delay2; i++) inp(port);
}

unsigned char FMRead()
{ return (inp(lk_fm_port)); }

void FMInit()
{ FMWrite(1,0);
  FMWrite(8,0);
  FMWrite(0xbd,0x00);
  FMWrite(0x20+0,0x21);
  FMWrite(0x20+3,0x11);
  FMWrite(0x40+0,0x4c);
  FMWrite(0x40+3,0x00);
  FMWrite(0x60+0,0xd2);
  FMWrite(0x60+3,0xd2);
  FMWrite(0x80+0,0x32);
  FMWrite(0x80+3,0x11);
  FMWrite(0xe0+0,0x00);
  FMWrite(0xe0+3,0x00);
  FMWrite(0xc0+0,0x04);
  FMWrite(0x01,0x20);           /* turn on wave form control */
  FMWrite(0xBD, 0x0c);          /* set AM and vibrato to high */
}
/////////////////////////////////////
void FMSound(short frequency,short block)
{ short fnh, fnl, blfnh, kblfnh;
  fnl = frequency&0x00ff;
  fnh = frequency>>8;
  blfnh = fnh|(block<<2);
  kblfnh = blfnh|0x20;
  FMWrite(0xa0,fnl);
  FMWrite(0xb0,kblfnh);
}

void FMSoundOff(short frequency,short block)
{ short fnh, blfnh, kblfnh;
  fnh = frequency>>8;
  blfnh = fnh|(block<<2);
  kblfnh = blfnh|0x00;
  FMWrite(0xb0,kblfnh);
}

void FM(short frequency,short block)
{ FMSoundOff(frequency,block);
  FMSound(frequency,block);
}

⌨️ 快捷键说明

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