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

📄 gus_wave.c

📁 内核是系统的心脏
💻 C
📖 第 1 页 / 共 5 页
字号:
      return;			/* 
				 * Sustain 
				 */
    }

  if (voices[voice].env_phase >= 5)
    {
      /* 
       * Shoot the voice off
       */

      gus_voice_init (voice);
      return;
    }

  prev_vol = voices[voice].current_volume;
  gus_voice_volume (prev_vol);
  phase = ++voices[voice].env_phase;

  compute_volume (voice, voices[voice].midi_volume);

  vol = voices[voice].initial_volume * voices[voice].env_offset[phase] / 255;
  rate = voices[voice].env_rate[phase];
  gus_write8 (0x06, rate);	/* 
				 * Ramping rate 
				 */

  voices[voice].volume_irq_mode = VMODE_ENVELOPE;

  if (((vol - prev_vol) / 64) == 0)	/* 
					 * No significant volume change 
					 */
    {
      step_envelope (voice);	/* 
				 * Continue with the next phase 
				 */
      return;
    }

  if (vol > prev_vol)
    {
      if (vol >= (4096 - 64))
	vol = 4096 - 65;
      gus_ramp_range (0, vol);
      gus_rampon (0x20);	/* 
				 * Increasing, irq 
				 */
    }
  else
    {
      if (vol <= 64)
	vol = 65;
      gus_ramp_range (vol, 4030);
      gus_rampon (0x60);	/* 
				 * Decreasing, irq 
				 */
    }
  voices[voice].current_volume = vol;
}

static void
init_envelope (int voice)
{
  voices[voice].env_phase = -1;
  voices[voice].current_volume = 64;

  step_envelope (voice);
}

static void
start_release (int voice)
{
  if (gus_read8 (0x00) & 0x03)
    return;			/* 
				 * Voice already stopped 
				 */

  voices[voice].env_phase = 2;	/* 
				 * Will be incremented by step_envelope 
				 */

  voices[voice].current_volume =
    voices[voice].initial_volume =
    gus_read16 (0x09) >> 4;	/* 
				 * Get current volume 
				 */

  voices[voice].mode &= ~WAVE_SUSTAIN_ON;
  gus_rampoff ();
  step_envelope (voice);
}

static void
gus_voice_fade (int voice)
{
  int             instr_no = sample_map[voice], is16bits;

  if (instr_no < 0 || instr_no > MAX_SAMPLE)
    {
      gus_write8 (0x00, 0x03);	/* 
				 * Hard stop 
				 */
      return;
    }

  is16bits = (samples[instr_no].mode & WAVE_16_BITS) ? 1 : 0;	/* 
								 * 8 or 16
								 * bit
								 * samples 
								 */

  if (voices[voice].mode & WAVE_ENVELOPES)
    {
      start_release (voice);
      return;
    }

  /* 
   * Ramp the volume down but not too quickly.
   */
  if ((gus_read16 (0x09) >> 4) < 100)	/* 
					 * Get current volume 
					 */
    {
      gus_voice_off ();
      gus_rampoff ();
      gus_voice_init (voice);
      return;
    }

  gus_ramp_range (65, 4030);
  gus_ramp_rate (2, 4);
  gus_rampon (0x40 | 0x20);	/* 
				 * Down, once, irq 
				 */
  voices[voice].volume_irq_mode = VMODE_HALT;
}

static void
gus_reset (void)
{
  int             i;

  gus_select_max_voices (24);
  volume_base = 3071;
  volume_scale = 4;
  volume_method = VOL_METHOD_ADAGIO;

  for (i = 0; i < 32; i++)
    {
      gus_voice_init (i);	/* 
				 * Turn voice off 
				 */
      gus_voice_init2 (i);
    }

  INB (u_Status);		/* 
				 * Touch the status register 
				 */

  gus_look8 (0x41);		/* 
				 * Clear any pending DMA IRQs 
				 */
  gus_look8 (0x49);		/* 
				 * Clear any pending sample IRQs 
				 */
  gus_read8 (0x0f);		/* 
				 * Clear pending IRQs 
				 */

}

static void
gus_initialize (void)
{
  unsigned long   flags;
  unsigned char   dma_image, irq_image, tmp;

  static unsigned char gus_irq_map[16] =
  {0, 0, 1, 3, 0, 2, 0, 4, 0, 0, 0, 5, 6, 0, 0, 7};

  static unsigned char gus_dma_map[8] =
  {0, 1, 0, 2, 0, 3, 4, 5};

  DISABLE_INTR (flags);

  gus_write8 (0x4c, 0);		/* 
				 * Reset GF1 
				 */
  gus_delay ();
  gus_delay ();

  gus_write8 (0x4c, 1);		/* 
				 * Release Reset 
				 */
  gus_delay ();
  gus_delay ();

  /* 
   * Clear all interrupts
   */

  gus_write8 (0x41, 0);		/* 
				 * DMA control 
				 */
  gus_write8 (0x45, 0);		/* 
				 * Timer control 
				 */
  gus_write8 (0x49, 0);		/* 
				 * Sample control 
				 */

  gus_select_max_voices (24);

  INB (u_Status);		/* 
				 * Touch the status register 
				 */

  gus_look8 (0x41);		/* 
				 * Clear any pending DMA IRQs 
				 */
  gus_look8 (0x49);		/* 
				 * Clear any pending sample IRQs 
				 */
  gus_read8 (0x0f);		/* 
				 * Clear pending IRQs 
				 */

  gus_reset ();			/* 
				 * Resets all voices 
				 */

  gus_look8 (0x41);		/* 
				 * Clear any pending DMA IRQs 
				 */
  gus_look8 (0x49);		/* 
				 * Clear any pending sample IRQs 
				 */
  gus_read8 (0x0f);		/* 
				 * Clear pending IRQs 
				 */

  gus_write8 (0x4c, 7);		/* 
				 * Master reset | DAC enable | IRQ enable 
				 */

  /* 
   * Set up for Digital ASIC
   */

  OUTB (0x05, gus_base + 0x0f);

  mix_image |= 0x02;		/* 
				 * Disable line out 
				 */
  OUTB (mix_image, u_Mixer);

  OUTB (0x00, u_IRQDMAControl);

  OUTB (0x00, gus_base + 0x0f);

  /* 
   * Now set up the DMA and IRQ interface
   * 
   * The GUS supports two IRQs and two DMAs.
   * 
   * Just one DMA channel is used. This prevents simultaneous ADC and DAC.
   * Adding this support requires significant changes to the dmabuf.c, dsp.c
   * and audio.c also.
   */

  irq_image = 0;
  tmp = gus_irq_map[gus_irq];
  if (!tmp)
    printk ("Warning! GUS IRQ not selected\n");
  irq_image |= tmp;
  irq_image |= 0x40;		/* 
				 * Combine IRQ1 (GF1) and IRQ2 (Midi) 
				 */

  dma_image = 0x40;		/* 
				 * Combine DMA1 (DRAM) and IRQ2 (ADC) 
				 */
  tmp = gus_dma_map[gus_dma];
  if (!tmp)
    printk ("Warning! GUS DMA not selected\n");
  dma_image |= tmp;

  /* 
   * For some reason the IRQ and DMA addresses must be written twice
   */

  /* 
   * Doing it first time 
   */

  OUTB (mix_image, u_Mixer);	/* 
				 * Select DMA control 
				 */
  OUTB (dma_image | 0x80, u_IRQDMAControl);	/* 
						 * Set DMA address 
						 */

  OUTB (mix_image | 0x40, u_Mixer);	/* 
					 * Select IRQ control 
					 */
  OUTB (irq_image, u_IRQDMAControl);	/* 
					 * Set IRQ address 
					 */

  /* 
   * Doing it second time 
   */

  OUTB (mix_image, u_Mixer);	/* 
				 * Select DMA control 
				 */
  OUTB (dma_image, u_IRQDMAControl);	/* 
					 * Set DMA address 
					 */

  OUTB (mix_image | 0x40, u_Mixer);	/* 
					 * Select IRQ control 
					 */
  OUTB (irq_image, u_IRQDMAControl);	/* 
					 * Set IRQ address 
					 */

  gus_select_voice (0);		/* 
				 * This disables writes to IRQ/DMA reg 
				 */

  mix_image &= ~0x02;		/* 
				 * Enable line out 
				 */
  mix_image |= 0x08;		/* 
				 * Enable IRQ 
				 */
  OUTB (mix_image, u_Mixer);	/* 
				 * Turn mixer channels on 
				 * Note! Mic in is left off.
				 */

  gus_select_voice (0);		/* 
				 * This disables writes to IRQ/DMA reg 
				 */

  gusintr (0);			/* 
				 * Serve pending interrupts 
				 */
  RESTORE_INTR (flags);
}

int
gus_wave_detect (int baseaddr)
{
  unsigned long   i;
  unsigned long   loc;

  gus_base = baseaddr;

  gus_write8 (0x4c, 0);		/* Reset GF1 */
  gus_delay ();
  gus_delay ();

  gus_write8 (0x4c, 1);		/* Release Reset */
  gus_delay ();
  gus_delay ();

  /* See if there is first block there.... */
  gus_poke (0L, 0xaa);
  if (gus_peek (0L) != 0xaa)
    return (0);

  /* Now zero it out so that I can check for mirroring .. */
  gus_poke (0L, 0x00);
  for (i = 1L; i < 1024L; i++)
    {
      int             n, failed;

      /* check for mirroring ... */
      if (gus_peek (0L) != 0)
	break;
      loc = i << 10;

      for (n = loc - 1, failed = 0; n <= loc; n++)
	{
	  gus_poke (loc, 0xaa);
	  if (gus_peek (loc) != 0xaa)
	    failed = 1;

	  gus_poke (loc, 0x55);
	  if (gus_peek (loc) != 0x55)
	    failed = 1;
	}

      if (failed)
	break;
    }
  gus_mem_size = i << 10;
  return 1;
}

static int
guswave_ioctl (int dev,
	       unsigned int cmd, unsigned int arg)
{

  switch (cmd)
    {
    case SNDCTL_SYNTH_INFO:
      gus_info.nr_voices = nr_voices;
      IOCTL_TO_USER ((char *) arg, 0, &gus_info, sizeof (gus_info));
      return 0;
      break;

    case SNDCTL_SEQ_RESETSAMPLES:
      reset_sample_memory ();
      return 0;
      break;

    case SNDCTL_SEQ_PERCMODE:
      return 0;
      break;

    case SNDCTL_SYNTH_MEMAVL:
      return gus_mem_size - free_mem_ptr - 32;

    default:
      return RET_ERROR (EINVAL);
    }
}

static int
guswave_set_instr (int dev, int voice, int instr_no)
{
  int             sample_no;

  if (instr_no < 0 || instr_no > MAX_PATCH)
    return RET_ERROR (EINVAL);

  if (voice < 0 || voice > 31)
    return RET_ERROR (EINVAL);

  if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
    {
      voices[voice].sample_pending = instr_no;
      return 0;
    }

  sample_no = patch_table[instr_no];
  patch_map[voice] = -1;

  if (sample_no < 0)
    {
      printk ("GUS: Undefined patch %d for voice %d\n", instr_no, voice);
      return RET_ERROR (EINVAL);	/* 
					 * Patch not defined 
					 */
    }

  if (sample_ptrs[sample_no] == -1)	/* 
					 * Sample not loaded 
					 */
    {
      printk ("GUS: Sample #%d not loaded for patch %d (voice %d)\n", sample_no, instr_no, voice);
      return RET_ERROR (EINVAL);
    }

  sample_map[voice] = sample_no;
  patch_map[voice] = instr_no;
  return 0;
}

static int
#ifdef FUTURE_VERSION
guswave_kill_note (int dev, int voice, int note, int velocity)
#else
guswave_kill_note (int dev, int voice, int velocity)
#endif
{
  unsigned long   flags;

  DISABLE_INTR (flags);
  if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
    voices[voice].kill_pending = 1;
  else
    {
      gus_select_voice (voice);
      gus_voice_fade (voice);
    }
  RESTORE_INTR (flags);

  return 0;
}

static void
guswave_aftertouch (int dev, int voice, int pressure)
{
  short           lo_limit, hi_limit;
  unsigned long   flags;

  return;			/* 
				 * Currently disabled 
				 */

  if (voice < 0 || voice > 31)
    return;

  if (voices[voice].mode & WAVE_ENVELOPES && voices[voice].env_phase != 2)
    return;			/* 
				 * Don't mix with envelopes 
				 */

  if (pressure < 32)
    {
      DISABLE_INTR (flags);
      gus_select_voice (voice);
      gus_rampoff ();
      compute_and_set_volume (voice, 255, 0);	/* 
						 * Back to original volume 
						 */
      RESTORE_INTR (flags);
      return;
    }

  hi_limit = voices[voice].current_volume;
  lo_limit = hi_limit * 99 / 100;
  if (lo_limit < 65)
    lo_limit = 65;

  DISABLE_INTR (flags);
  gus_select_voice (voice);
  if (hi_limit > (4095 - 65))
    {
      hi_limit = 4095 - 65;
      gus_voice_volume (hi_limit);
    }
  gus_ramp_range (lo_limit, hi_limit);
  gus_ramp_rate (3, 8);
  gus_rampon (0x58);		/* 
				 * Bidirectional, Down, Loop 
				 */
  RESTORE_INTR (flags);
}

static void
guswave_panning (int dev, int voice, int value)
{
  if (voice >= 0 || voice < 32)
    voices[voice].panning = value;
}

static void
compute_volume (int voice, int volume)
{
  if (volume < 128)
    voices[voice].midi_volume = volume;

    switch (volume_method)
      {
      case VOL_METHOD_ADAGIO:
	voices[voice].initial_volume =
	  gus_adagio_vol (voices[voice].midi_volume, voices[voice].main_vol,
			  voices[voice].expression_vol,
			  voices[voice].patch_vol);
	break;

      default:
	voices[voice].initial_volume = volume_base +
	  (voices[voice].midi_volume * volume_scale);
      }

  if (voices[voice].initial_volume > 4030)
    voices[voice].initial_volume = 4030;
}

static void
compute_and_set_volume (int voice, int volume, int ramp_time)
{
  int             current, target, rate;
  unsigned long   flags;

  DISABLE_INTR (flags);
/* 
 * CAUTION! Interrupts disabled. Enable them before returning
 */

  gus_select_voice (voice);

  compute_volume (voice, volume);
  voices[voice].current_volume = voices[voice].initial_volume;

  current = gus_read16 (0x09) >> 4;

⌨️ 快捷键说明

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