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

📄 gus_wave.c

📁 freebsd v4.4内核源码
💻 C
📖 第 1 页 / 共 5 页
字号:
  compute_volume (voice, voices[voice].midi_volume);}static voidguswave_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;    case CTL_EXPRESSION:      value /= 128;    case CTRL_EXPRESSION:      if (volume_method == VOL_METHOD_ADAGIO)	{	  voices[voice].expression_vol = value;	  if (voices[voice].volume_irq_mode != VMODE_START_NOTE)	    dynamic_volume_change (voice);	}      break;    case CTL_PAN:      voices[voice].panning = (value * 2) - 128;      break;    case CTL_MAIN_VOLUME:      value = (value * 100) / 16383;    case CTRL_MAIN_VOLUME:      voices[voice].main_vol = value;      if (voices[voice].volume_irq_mode != VMODE_START_NOTE)	dynamic_volume_change (voice);      break;    default:      break;    }}static intguswave_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;  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;	/* Try 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 ();  gus_rampoff ();  RESTORE_INTR (flags);  if (voices[voice].mode & WAVE_ENVELOPES)    {      compute_volume (voice, volume);      init_envelope (voice);    }  else    compute_and_set_volume (voice, volume, 0);  DISABLE_INTR (flags);  gus_select_voice (voice);  if (samples[sample].mode & WAVE_LOOP_BACK)    gus_write_addr (0x0a, sample_ptrs[sample] + samples[sample].len -		    voices[voice].offset_pending, is16bits);	/* 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;      if (samples[sample].mode & WAVE_BIDIR_LOOP)	mode |= 0x10;      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 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 intguswave_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 (gus_devnum, 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)	{	  RESTORE_INTR (flags);	/* Run temporarily with interrupts enabled */	  guswave_set_instr (voices[voice].dev_pending, voice,			     voices[voice].sample_pending);	  voices[voice].sample_pending = -1;	  DISABLE_INTR (flags);	  gus_select_voice (voice);	/* Reselect the voice (just to be sure) */	}      if ((mode & 0x01) || (int) ((gus_read16 (0x09) >> 4) < 2065))	{	  ret_val = guswave_start_note2 (gus_devnum, voice, note_num, volume);	}      else	{	  voices[voice].dev_pending = gus_devnum;	  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 voidguswave_reset (int dev){  int             i;  for (i = 0; i < 32; i++)    {      gus_voice_init (i);      gus_voice_init2 (i);    }}static intguswave_open (int dev, int mode){  int             err;  if (mode & OPEN_WRITE && gus_busy[gus_devnum] ||      mode & OPEN_READ && gus_busy[gus_dspnum])    return RET_ERROR (EBUSY);  if(gus_busy[gus_devnum] == 0 && gus_busy[gus_dspnum] == 0)    gus_initialize ();  voice_alloc->timestamp = 0;  if ((err = DMAbuf_open_dma (gus_devnum)) < 0)    return err;  RESET_WAIT_QUEUE (dram_sleeper, dram_sleep_flag);  gus_busy[gus_devnum] = 1;  active_device = GUS_DEV_WAVE;  gus_reset ();  return 0;}static voidguswave_close (int dev){  gus_busy[gus_devnum] = 0;  active_device = 0;  gus_reset ();  DMAbuf_close_dma (gus_devnum);}static intguswave_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;		/* Header size */  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;	/* 32 byte alignment */#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 =	/* Aling to 256K */	  ((free_mem_ptr / GUS_BANK_SIZE) + 1) * GUS_BANK_SIZE;	  if ((tmp_mem + patch.len) > gus_mem_size)	    return RET_ERROR (ENOSPC);	  free_mem_ptr = tmp_mem;	/* This leaves unusable memory */	}    }  if ((free_mem_ptr + patch.len) > gus_mem_size)    return RET_ERROR (ENOSPC);  sample_ptrs[free_sample] = free_mem_ptr;  /*   * Tremolo is not possible with envelopes   */  if (patch.mode & WAVE_ENVELOPES)    patch.mode &= ~WAVE_TREMOLO;  memcpy ((char *) &samples[free_sample], &patch, sizeof_patch);  /*   * Link this_one sample to the list of samples for patch 'instr'.   */  samples[free_sample].key = patch_table[instr];  patch_table[instr] = free_sample;  /*   * Use DMA to transfer the wave data to the DRAM   */  left = patch.len;  src_offs = 0;  target = free_mem_ptr;  while (left)			/* Not completely transferred yet */    {      blk_size = audio_devs[gus_devnum]->buffsize;      if (blk_size > left)	blk_size = left;      /*       * DMA cannot cross 256k bank boundaries. Check for that.       */      blk_end = target + blk_size;      if ((target >> 18) != (blk_end >> 18))	{			/* Split the block */	  blk_end &= ~(256 * 1024 - 1);	  blk_size = blk_end - target;	}#if defined(GUS_NO_DMA) || defined(GUS_PATCH_NO_DMA)      /*       * For some reason the DMA is not possible. We have to use PIO.       */      {	long            i;	unsigned char   data;	for (i = 0; i < blk_size; i++)	  {	    GET_BYTE_FROM_USER (data, addr, sizeof_patch + i);	    if (patch.mode & WAVE_UNSIGNED)	      if (!(patch.mode & WAVE_16_BITS) || (i & 0x01))		data ^= 0x80;	/* Convert to signed */	    gus_poke (target + i, data);	  }      }#else /* GUS_NO_DMA */      {	unsigned long   address, hold_address;	unsigned char   dma_command;	unsigned long   flags;	/*	 * OK, move now. First in and then out.	 */	COPY_FROM_USER (audio_devs[gus_devnum]->dmap->raw_buf[0],			addr, sizeof_patch + src_offs,			blk_size);	DISABLE_INTR (flags);/******** INTERRUPTS DISABLED NOW ********/	gus_write8 (0x41, 0);	/* Disable GF1 DMA */	DMAbuf_start_dma (gus_devnum,			  audio_devs[gus_devnum]->dmap->raw_buf_phys[0],			  blk_size, DMA_MODE_WRITE);	/*	 * Set the DRAM address for the wave data	 */	address = target;	if (audio_devs[gus_devnum]->dmachan > 3)	  {	    hold_address = address;

⌨️ 快捷键说明

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