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

📄 lkeymidi.cpp

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



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



/* fm_trigger_drum:
 *  Triggers a note on a drum channel.
 */
static 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);
   lsFMWrite(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);
      }
   }

   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;
   lsFMWrite(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 (almost 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 lm_midi_allocate_voice(int min,int max);
static 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 = lm_midi_allocate_voice(0, 5);
	 else
	    voice = lm_midi_allocate_voice(9, midi_driver->voices-1);
      }
      else
	 /* on other cards we can use any voices */
	 voice = lm_midi_allocate_voice(-1, -1);

      if (voice < 0)
	 return;

      /* make sure the voice isn't sounding */
      lsFMWrite(0x43+fm_offset[voice], 63);
      if (fm_feedback[voice] & 1)
	 lsFMWrite(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;

	 lsFMWrite(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 :-)
 */
static void fm_key_off(int voice)
{
   lsFMWrite(0xB0+VOICE_OFFSET(voice), fm_key[voice] & 0xDF);
}
/* fm_set_volume:
 *  Sets the volume of the specified voice (vol range 0-127).
 */
static void fm_set_volume(int voice, int vol)
{
   vol = fm_level[voice] * fm_vol_table[vol] / 128;
   vol = MIN((vol*lm_volume_step)>>2,63);    // by lin wei
   lsFMWrite(0x43+fm_offset[voice], (63-vol) | fm_keyscale[voice]);
   if (fm_feedback[voice] & 1)
      lsFMWrite(0x40+fm_offset[voice], (63-vol) | fm_keyscale[voice]);
}

/* fm_set_pitch:
 *  Sets the pitch of the specified voice.
 */
static 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);

   lsFMWrite(0xA0+VOICE_OFFSET(voice), freq & 0xFF); 
   lsFMWrite(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.
 */
static 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;
      lsFMWrite(0x40+fm_offset[i], 63);
      lsFMWrite(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.
 */
static int fm_mixer_volume(int volume)
{ 
   return lsSetMixer(-1, volume);
}
/* fm_is_there:
 *  Checks for the presence of an OPL synth at the current port.
 */
static int fm_is_there()
{
   lsFMWrite(1, 0);                        /* init test register */

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

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

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

   delay(100);

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

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

   return TRUE;
}

/* fm_detect:
 *  Adlib detection routine.
 */
static int fm_detect()
{
   static 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()) {
      strcpy(lm_error_msg, "OPL synth not found");
      return FALSE;
   }
found_it:
   if ((inp(lk_fm_port) & 6) == 0) {    /* check for OPL3 */
      opl_type = MIDI_OPL3;
      lsGetDspVersion();
   }
   else {                                 /* check for second OPL2 */
      if (lsGetDspVersion() >= 0x300)
	 opl_type = MIDI_2XOPL2;
      else
	 opl_type = MIDI_OPL2;
   }

   if (midi_card == MIDI_OPL3) {
      if (opl_type != MIDI_OPL3) {
	 strcpy(lm_error_msg, "OPL3 synth not found");
	 return FALSE;
      }
   }
   else if (midi_card == MIDI_2XOPL2) {
      if (opl_type != MIDI_2XOPL2) {
	 strcpy(lm_error_msg, "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 lmFM_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 *lmFM_read_inst_loc(int drums)
{ if (drums) return (char*)fm_drum;
  return (char*)fm_instrument;
}
void lmFM_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.
 */
static int fm_init(int voices)
{
   char *s;
   int i;

   fm_reset(1);
   lmFM_load_map(0,0); lmFM_load_map(0,1);
   for (i=0; i<2; i++) {
      if (i==0) s=lmMidiMapFile[0]; else s=lmMidiMapFile[1];
      if ((s) && (s[0])) {
	 if (lmFM_load_ibk(s, (i > 0)) != 0) {
	    sprintf(lm_error_msg, "Error reading .IBK file '%s'", s);
	    return FALSE;
	 }
      }
   }

   return TRUE;
}

static void fm_exit()
{
   fm_reset(0);
}

⌨️ 快捷键说明

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