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

📄 gus_wave.c

📁 内核是系统的心脏
💻 C
📖 第 1 页 / 共 5 页
字号:
  target = voices[voice].initial_volume;

  if (ramp_time == INSTANT_RAMP)
    {
      gus_rampoff ();
      gus_voice_volume (target);
      RESTORE_INTR (flags);
      return;
    }

  if (ramp_time == FAST_RAMP)
    rate = 63;
  else
    rate = 16;
  gus_ramp_rate (0, rate);

  if ((target - current) / 64 == 0)	/* 
					 * Too close 
					 */
    {
      gus_rampoff ();
      gus_voice_volume (target);
      RESTORE_INTR (flags);
      return;
    }

  if (target > current)
    {
      if (target > (4095 - 65))
	target = 4095 - 65;
      gus_ramp_range (current, target);
      gus_rampon (0x00);	/* 
				 * Ramp up, once, no irq 
				 */
    }
  else
    {
      if (target < 65)
	target = 65;

      gus_ramp_range (target, current);
      gus_rampon (0x40);	/* 
				 * Ramp down, once, no irq 
				 */
    }
  RESTORE_INTR (flags);
}

static void
dynamic_volume_change (int voice)
{
  unsigned char   status;
  unsigned long   flags;

  DISABLE_INTR (flags);
  gus_select_voice (voice);
  status = gus_read8 (0x00);	/* 
				 * Voice status 
				 */
  RESTORE_INTR (flags);

  if (status & 0x03)
    return;			/* 
				 * Voice not started 
				 */

  if (!(voices[voice].mode & WAVE_ENVELOPES))
    {
      compute_and_set_volume (voice, voices[voice].midi_volume, 1);
      return;
    }

  /* 
   * Voice is running and has envelopes.
   */

  DISABLE_INTR (flags);
  gus_select_voice (voice);
  status = gus_read8 (0x0d);	/* 
				 * Ramping status 
				 */
  RESTORE_INTR (flags);

  if (status & 0x03)		/* 
				 * Sustain phase? 
				 */
    {
      compute_and_set_volume (voice, voices[voice].midi_volume, 1);
      return;
    }

  if (voices[voice].env_phase < 0)
    return;

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

#if 0				/* 
				 * * * Is this really required   */
  voices[voice].current_volume =
    gus_read16 (0x09) >> 4;	/* 
				 * Get current volume 
				 */

  voices[voice].env_phase--;
  step_envelope (voice);
#endif
}

static void
guswave_controller (int dev, int voice, int ctrl_num, int value)
{
  unsigned long   flags;
  unsigned long   freq;

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

  switch (ctrl_num)
    {
    case CTRL_PITCH_BENDER:
      voices[voice].bender = value;

      if (voices[voice].volume_irq_mode != VMODE_START_NOTE)
        {
          freq = compute_finetune (voices[voice].orig_freq, value, voices[voice].bender_range);
          voices[voice].current_freq = freq;

          DISABLE_INTR (flags);
          gus_select_voice (voice);
          gus_voice_freq (freq);
          RESTORE_INTR (flags);
        }
      break;

    case CTRL_PITCH_BENDER_RANGE:
      voices[voice].bender_range = value;
      break;
#ifdef FUTURE_VERSION
    case CTL_EXPRESSION:
      value /= 128;
#endif
    case CTRL_EXPRESSION:
      volume_method = VOL_METHOD_ADAGIO;
      voices[voice].expression_vol = value;
      if (voices[voice].volume_irq_mode != VMODE_START_NOTE)
         dynamic_volume_change (voice);
      break;

#ifdef FUTURE_VERSION
    case CTL_PAN:
      voices[voice].panning = (value * 2) - 128;
      break;

    case CTL_MAIN_VOLUME:
      value = (value * 100) / 16383;
#endif

    case CTRL_MAIN_VOLUME:
      volume_method = VOL_METHOD_ADAGIO;
      voices[voice].main_vol = value;
      if (voices[voice].volume_irq_mode != VMODE_START_NOTE)
         dynamic_volume_change (voice);
      break;

    default:			/* 
				 * Ignore 
				 */
      break;
    }
}

static int
guswave_start_note2 (int dev, int voice, int note_num, int volume)
{
  int             sample, best_sample, best_delta, delta_freq;
  int             is16bits, samplep, patch, pan;
  unsigned long   note_freq, base_note, freq, flags;
  unsigned char   mode = 0;

  if (voice < 0 || voice > 31)
    {
      printk ("GUS: Invalid voice\n");
      return RET_ERROR (EINVAL);
    }

  if (note_num == 255)
    {
      if (voices[voice].mode & WAVE_ENVELOPES)
	{
	  voices[voice].midi_volume = volume;
	  dynamic_volume_change (voice);
	  return 0;
	}

      compute_and_set_volume (voice, volume, 1);
      return 0;
    }

  if ((patch = patch_map[voice]) == -1)
    {
      return RET_ERROR (EINVAL);
    }

  if ((samplep = patch_table[patch]) == -1)
    {
      return RET_ERROR (EINVAL);
    }

  note_freq = note_to_freq (note_num);

  /* 
   * Find a sample within a patch so that the note_freq is between low_note
   * and high_note.
   */
  sample = -1;

  best_sample = samplep;
  best_delta = 1000000;
  while (samplep >= 0 && sample == -1)
    {
      delta_freq = note_freq - samples[samplep].base_note;
      if (delta_freq < 0)
	delta_freq = -delta_freq;
      if (delta_freq < best_delta)
	{
	  best_sample = samplep;
	  best_delta = delta_freq;
	}
      if (samples[samplep].low_note <= note_freq && note_freq <= samples[samplep].high_note)
	sample = samplep;
      else
	samplep = samples[samplep].key;		/* 
						 * Follow link 
						 */
    }
  if (sample == -1)
    sample = best_sample;

  if (sample == -1)
    {
      printk ("GUS: Patch %d not defined for note %d\n", patch, note_num);
      return 0;			/* 
				 * Should play default patch ??? 
				 */
    }

  is16bits = (samples[sample].mode & WAVE_16_BITS) ? 1 : 0;	/* 
								 * 8 or 16
								 * bit
								 * samples 
								 */
  voices[voice].mode = samples[sample].mode;
  voices[voice].patch_vol = samples[sample].volume;

  if (voices[voice].mode & WAVE_ENVELOPES)
    {
      int             i;

      for (i = 0; i < 6; i++)
	{
	  voices[voice].env_rate[i] = samples[sample].env_rate[i];
	  voices[voice].env_offset[i] = samples[sample].env_offset[i];
	}
    }

  sample_map[voice] = sample;

  base_note = samples[sample].base_note / 100;	/* 
						 * To avoid overflows 
						 */
  note_freq /= 100;

  freq = samples[sample].base_freq * note_freq / base_note;

  voices[voice].orig_freq = freq;

  /* 
   * Since the pitch bender may have been set before playing the note, we
   * have to calculate the bending now.
   */

  freq = compute_finetune (voices[voice].orig_freq, voices[voice].bender, voices[voice].bender_range);
  voices[voice].current_freq = freq;

  pan = (samples[sample].panning + voices[voice].panning) / 32;
  pan += 7;
  if (pan < 0)
    pan = 0;
  if (pan > 15)
    pan = 15;

  if (samples[sample].mode & WAVE_16_BITS)
    {
      mode |= 0x04;		/* 
				 * 16 bits 
				 */
      if ((sample_ptrs[sample] >> 18) !=
	  ((sample_ptrs[sample] + samples[sample].len) >> 18))
	printk ("GUS: Sample address error\n");
    }

  /*************************************************************************
   *    CAUTION!        Interrupts disabled. Don't return before enabling
   *************************************************************************/

  DISABLE_INTR (flags);
  gus_select_voice (voice);
  gus_voice_off ();		/* 
				 * It may still be running 
				 */
  gus_rampoff ();
  if (voices[voice].mode & WAVE_ENVELOPES)
    {
      compute_volume (voice, volume);
      init_envelope (voice);
    }
  else
    compute_and_set_volume (voice, volume, 0);

  if (samples[sample].mode & WAVE_LOOP_BACK)
    gus_write_addr (0x0a, sample_ptrs[sample] + samples[sample].len -
		    voices[voice].offset_pending, is16bits);	/* Sample
								 * start=end */
  else
    gus_write_addr (0x0a, sample_ptrs[sample] + voices[voice].offset_pending,
		    is16bits);	/* Sample start=begin */

  if (samples[sample].mode & WAVE_LOOPING)
    {
      mode |= 0x08;		/* 
				 * Looping on 
				 */

      if (samples[sample].mode & WAVE_BIDIR_LOOP)
	mode |= 0x10;		/* 
				 * Bidirectional looping on 
				 */

      if (samples[sample].mode & WAVE_LOOP_BACK)
	{
	  gus_write_addr (0x0a,
			  sample_ptrs[sample] + samples[sample].loop_end -
			  voices[voice].offset_pending, is16bits);
	  mode |= 0x40;
	}

      gus_write_addr (0x02, sample_ptrs[sample] + samples[sample].loop_start, is16bits);	/* 
												 * Loop 
												 * start 
												 * location 
												 */
      gus_write_addr (0x04, sample_ptrs[sample] + samples[sample].loop_end, is16bits);	/* 
											 * Loop 
											 * end 
											 * location 
											 */
    }
  else
    {
      mode |= 0x20;		/* 
				 * Loop irq at the end 
				 */
      voices[voice].loop_irq_mode = LMODE_FINISH;	/* 
							 * Ramp it down at
							 * the * end 
							 */
      voices[voice].loop_irq_parm = 1;
      gus_write_addr (0x02, sample_ptrs[sample], is16bits);	/* 
								 * Loop start 
								 * location 
								 */
      gus_write_addr (0x04, sample_ptrs[sample] + samples[sample].len-1, is16bits);	/* 
											 * Loop 
											 * end 
											 * location 
											 */
    }
  gus_voice_freq (freq);
  gus_voice_balance (pan);
  gus_voice_on (mode);
  RESTORE_INTR (flags);

  return 0;
}

/* 
 * * New guswave_start_note by Andrew J. Robinson attempts to minimize
 * clicking  * when the note playing on the voice is changed.  It uses volume 
 * ramping. */

static int
guswave_start_note (int dev, int voice, int note_num, int volume)
{
  long int        flags;
  int             mode;
  int             ret_val = 0;

  DISABLE_INTR (flags);
  if (note_num == 255)
    {
      if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
	voices[voice].volume_pending = volume;
      else
	ret_val = guswave_start_note2 (dev, voice, note_num, volume);
    }
  else
    {
       gus_select_voice (voice);
       mode = gus_read8 (0x00);
       if (mode & 0x20)
         gus_write8 (0x00, mode & 0xdf);    /* No interrupt! */

       voices[voice].offset_pending = 0;
       voices[voice].kill_pending = 0;
       voices[voice].volume_irq_mode = 0;
       voices[voice].loop_irq_mode = 0;

       if (voices[voice].sample_pending >= 0)
       {
         guswave_set_instr (voices[voice].dev_pending, voice,
         voices[voice].sample_pending);
         voices[voice].sample_pending = -1;
       }

      if ((mode & 0x01) || ((gus_read16 (0x09) >> 4) < 2065))
	{
	  ret_val = guswave_start_note2 (dev, voice, note_num, volume);
	}
      else
	{
	  voices[voice].dev_pending = dev;
	  voices[voice].note_pending = note_num;
	  voices[voice].volume_pending = volume;
	  voices[voice].volume_irq_mode = VMODE_START_NOTE;

	  gus_rampoff ();
	  gus_ramp_range (2000, 4065);
	  gus_ramp_rate (0, 63);	/* Fastest possible rate */
	  gus_rampon (0x20 | 0x40);	/* Ramp down, once, irq */
	}
    }
  RESTORE_INTR (flags);
  return ret_val;
}

static void
guswave_reset (int dev)
{
  int             i;

  for (i = 0; i < 32; i++)
    {
      gus_voice_init (i);
      gus_voice_init2 (i);
    }
}

static int
guswave_open (int dev, int mode)
{
  int             err;

  if (gus_busy)
    return RET_ERROR (EBUSY);

  gus_initialize ();

  if ((err = DMAbuf_open_dma (gus_devnum)))
    return err;

  RESET_WAIT_QUEUE (dram_sleeper, dram_sleep_flag);
  gus_busy = 1;
  active_device = GUS_DEV_WAVE;

  gus_reset ();

  return 0;
}

static void
guswave_close (int dev)
{
  gus_busy = 0;
  active_device = 0;
  gus_reset ();

  DMAbuf_close_dma (gus_devnum);
}

static int
guswave_load_patch (int dev, int format, snd_rw_buf * addr,
		    int offs, int count, int pmgr_flag)
{
  struct patch_info patch;
  int             instr;
  long            sizeof_patch;

  unsigned long   blk_size, blk_end, left, src_offs, target;

  sizeof_patch = (long) &patch.data[0] - (long) &patch;		/* 
								 * Size of
								 * the header
								 * * info 
								 */

  if (format != GUS_PATCH)
    {
      printk ("GUS Error: Invalid patch format (key) 0x%x\n", format);
      return RET_ERROR (EINVAL);
    }

  if (count < sizeof_patch)
    {
      printk ("GUS Error: Patch header too short\n");
      return RET_ERROR (EINVAL);
    }

  count -= sizeof_patch;

  if (free_sample >= MAX_SAMPLE)
    {
      printk ("GUS: Sample table full\n");
      return RET_ERROR (ENOSPC);
    }

  /* 
   * Copy the header from user space but ignore the first bytes which have
   * been transferred already.
   */

  COPY_FROM_USER (&((char *) &patch)[offs], addr, offs, sizeof_patch - offs);

  instr = patch.instr_no;

  if (instr < 0 || instr > MAX_PATCH)
    {
      printk ("GUS: Invalid patch number %d\n", instr);
      return RET_ERROR (EINVAL);
    }

  if (count < patch.len)
    {
      printk ("GUS Warning: Patch record too short (%d<%d)\n",
	      count, (int) patch.len);
      patch.len = count;
    }

  if (patch.len <= 0 || patch.len > gus_mem_size)
    {
      printk ("GUS: Invalid sample length %d\n", (int) patch.len);
      return RET_ERROR (EINVAL);
    }

  if (patch.mode & WAVE_LOOPING)
    {
      if (patch.loop_start < 0 || patch.loop_start >= patch.len)
	{
	  printk ("GUS: Invalid loop start\n");
	  return RET_ERROR (EINVAL);
	}

      if (patch.loop_end < patch.loop_start || patch.loop_end > patch.len)
	{
	  printk ("GUS: Invalid loop end\n");
	  return RET_ERROR (EINVAL);
	}
    }

  free_mem_ptr = (free_mem_ptr + 31) & ~31;	/* 
						 * Alignment 32 bytes 
						 */

#define GUS_BANK_SIZE (256*1024)

  if (patch.mode & WAVE_16_BITS)
    {
      /* 
       * 16 bit samples must fit one 256k bank.
       */
      if (patch.len >= GUS_BANK_SIZE)
	{
	  printk ("GUS: Sample (16 bit) too long %d\n", (int) patch.len);
	  return RET_ERROR (ENOSPC);
	}

      if ((free_mem_ptr / GUS_BANK_SIZE) !=
	  ((free_mem_ptr + patch.len) / GUS_BANK_SIZE))
	{
	  unsigned long   tmp_mem =	/* 
					 * Align to 256K*N 
					 */
	  ((free_mem_ptr / GUS_BANK_SIZE) + 1) * GUS_BANK_SIZE;

	  if ((tmp_mem + patch.len) > gus_mem_size)

⌨️ 快捷键说明

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