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

📄 gus_wave.c

📁 LINUX1.0内核源代码,学习LINUX编程的一定要看。
💻 C
📖 第 1 页 / 共 5 页
字号:
{  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 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;#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 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;	/* 								 * 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 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 (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 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 (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 voidguswave_close (int dev){  gus_busy = 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;		/* 								 * 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)	    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 all moved 				 */    {      blk_size = sound_buffsizes[gus_devnum];      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))	{			/* 				 * Have to 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 

⌨️ 快捷键说明

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