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

📄 gus_wave.c

📁 freebsd v4.4内核源码
💻 C
📖 第 1 页 / 共 5 页
字号:
  if (audio_devs[gus_devnum]->dmachan > 3)    {      hold_address = address;      address = address >> 1;      address &= 0x0001ffffL;      address |= (hold_address & 0x000c0000L);    }  gus_write16 (0x42, (address >> 4) & 0xffff);	/* DRAM DMA address */  dma_command = 0x21;		/* IRQ enable, DMA start */  if (gus_sampling_bits != 8)    dma_command |= 0x40;	/* 16 bit _DATA_ */  else    dma_command |= 0x80;	/* Invert MSB */  if (audio_devs[gus_devnum]->dmachan > 3)    dma_command |= 0x04;	/* 16 bit DMA channel */  gus_write8 (0x41, dma_command);	/* Kickstart */  if (chn == (gus_sampling_channels - 1))	/* Last channel */    {      /*       * Last (right or mono) channel data       */      dma_active = 1;		/* DMA started. There is a unacknowledged buffer */      active_device = GUS_DEV_PCM_DONE;      if (!pcm_active && (pcm_qlen > 0 || count < pcm_bsize))	{	  play_next_pcm_block ();	}    }  else    {      /*         * Left channel data. The right channel         * is transferred after DMA interrupt       */      active_device = GUS_DEV_PCM_CONTINUE;    }  RESTORE_INTR (flags);}static voidgus_sampling_output_block (int dev, unsigned long buf, int total_count,			   int intrflag, int restart_dma){  pcm_current_buf = buf;  pcm_current_count = total_count;  pcm_current_intrflag = intrflag;  pcm_current_dev = gus_devnum;  gus_transfer_output_block (gus_devnum, buf, total_count, intrflag, 0);}static voidgus_sampling_start_input (int dev, unsigned long buf, int count,			  int intrflag, int restart_dma){  unsigned long   flags;  unsigned char   mode;  DISABLE_INTR (flags);  DMAbuf_start_dma (gus_dspnum, buf, count, DMA_MODE_READ);  mode = 0xa0;			/* DMA IRQ enabled, invert MSB */  if (audio_devs[gus_dspnum]->dmachan > 3)    mode |= 0x04;		/* 16 bit DMA channel */  if (gus_sampling_channels > 1)    mode |= 0x02;		/* Stereo */  mode |= 0x01;			/* DMA enable */  gus_write8 (0x49, mode);  RESTORE_INTR (flags);}static intgus_sampling_prepare_for_input (int dev, int bsize, int bcount){  unsigned int    rate;  rate = (9878400 / (gus_sampling_speed + 2)) / 16;  gus_write8 (0x48, rate & 0xff);	/* Set sampling rate */  if (gus_sampling_bits != 8)    {      printk ("GUS Error: 16 bit recording not supported\n");      return RET_ERROR (EINVAL);    }  return 0;}static intgus_sampling_prepare_for_output (int dev, int bsize, int bcount){  int             i;  long            mem_ptr, mem_size;  mem_ptr = 0;  mem_size = gus_mem_size / gus_sampling_channels;  if (mem_size > (256 * 1024))    mem_size = 256 * 1024;  pcm_bsize = bsize / gus_sampling_channels;  pcm_head = pcm_tail = pcm_qlen = 0;  pcm_nblk = MAX_PCM_BUFFERS;  if ((pcm_bsize * pcm_nblk) > mem_size)    pcm_nblk = mem_size / pcm_bsize;  for (i = 0; i < pcm_nblk; i++)    pcm_datasize[i] = 0;  pcm_banksize = pcm_nblk * pcm_bsize;  if (gus_sampling_bits != 8 && pcm_banksize == (256 * 1024))    pcm_nblk--;  return 0;}static intgus_local_qlen (int dev){  return pcm_qlen;}static voidgus_copy_from_user (int dev, char *localbuf, int localoffs,		    snd_rw_buf * userbuf, int useroffs, int len){  if (gus_sampling_channels == 1)    {      COPY_FROM_USER (&localbuf[localoffs], userbuf, useroffs, len);    }  else if (gus_sampling_bits == 8)#if defined(__FreeBSD__)    {      char           *in_left = gus_copy_buf;      char           *in_right = in_left + 1;      char           *out_left = localbuf + (localoffs / 2);      char           *out_right = out_left + pcm_bsize;      int             i;      COPY_FROM_USER (gus_copy_buf, userbuf, useroffs, len);      len /= 2;      for (i = 0; i < len; i++)	{	  *out_left++ = *in_left++;	  in_left++;	  *out_right++ = *in_right++;	  in_right++;	}    }  else    {      short          *in_left = (short *)gus_copy_buf;      short          *in_right = in_left + 1;      short          *out_left = (short *)localbuf + (localoffs / 4);      short          *out_right = out_left + (pcm_bsize / 2);      int             i;      COPY_FROM_USER (gus_copy_buf, userbuf, useroffs, len);      len /= 4;      for (i = 0; i < len; i++)	{	  *out_left++ = *in_left++;	  in_left++;	  *out_right++ = *in_right++;	  in_right++;	}    }#else    {      int             in_left = useroffs;      int             in_right = useroffs + 1;      char           *out_left, *out_right;      int             i;      len /= 2;      localoffs /= 2;      out_left = &localbuf[localoffs];      out_right = out_left + pcm_bsize;      for (i = 0; i < len; i++)	{	  GET_BYTE_FROM_USER (*out_left++, userbuf, in_left);	  in_left += 2;	  GET_BYTE_FROM_USER (*out_right++, userbuf, in_right);	  in_right += 2;	}    }  else    {      int             in_left = useroffs / 2;      int             in_right = useroffs / 2 + 1;      short          *out_left, *out_right;      int             i;      len /= 4;      localoffs /= 2;      out_left = (short *) &localbuf[localoffs];      out_right = out_left + (pcm_bsize / 2);      for (i = 0; i < len; i++)	{#ifdef __FreeBSD__	  GET_SHORT_FROM_USER (*out_left++, userbuf, in_left);	  in_left += 2;	  GET_SHORT_FROM_USER (*out_right++, userbuf, in_right);	  in_right += 2;#else	  GET_SHORT_FROM_USER (*out_left++, (short *) userbuf, in_left);	  in_left += 2;	  GET_SHORT_FROM_USER (*out_right++, (short *) userbuf, in_right);	  in_right += 2;#endif	}    }#endif}static struct audio_operations gus_sampling_operations ={  "Gravis UltraSound",  NEEDS_RESTART,  AFMT_U8 | AFMT_S16_LE,  NULL,  gus_sampling_open,  gus_sampling_close,  gus_sampling_output_block,  gus_sampling_start_input,  gus_sampling_ioctl,  gus_sampling_prepare_for_input,  gus_sampling_prepare_for_output,  gus_sampling_reset,  gus_sampling_reset,  gus_local_qlen,  gus_copy_from_user};static struct audio_operations gus_sampling_operations_read ={      "Gravis UltraSound - read only",  NEEDS_RESTART,  AFMT_U8 | AFMT_S16_LE,  NULL,  gus_sampling_open,  gus_sampling_close,  gus_sampling_output_block,  gus_sampling_start_input,  gus_sampling_ioctl,   gus_sampling_prepare_for_input,  gus_sampling_prepare_for_output,  gus_sampling_reset,  gus_sampling_reset,  gus_local_qlen,  gus_copy_from_user};static voidguswave_setup_voice (int dev, int voice, int chn){  struct channel_info *info =  &synth_devs[gus_devnum]->chn_info[chn];  guswave_set_instr (gus_devnum, voice, info->pgm_num);  voices[voice].expression_vol =    info->controllers[CTL_EXPRESSION];	/* Just msb */  voices[voice].main_vol =    (info->controllers[CTL_MAIN_VOLUME] * 100) / 128;  voices[voice].panning =    (info->controllers[CTL_PAN] * 2) - 128;  voices[voice].bender = info->bender_value;}static voidguswave_bender (int dev, int voice, int value){  int             freq;  unsigned long   flags;  voices[voice].bender = value - 8192;  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);}static intguswave_patchmgr (int dev, struct patmgr_info *rec){  int             i, n;  switch (rec->command)    {    case PM_GET_DEVTYPE:      rec->parm1 = PMTYPE_WAVE;      return 0;      break;    case PM_GET_NRPGM:      rec->parm1 = MAX_PATCH;      return 0;      break;    case PM_GET_PGMMAP:      rec->parm1 = MAX_PATCH;      for (i = 0; i < MAX_PATCH; i++)	{	  int             ptr = patch_table[i];	  rec->data.data8[i] = 0;	  while (ptr >= 0 && ptr < free_sample)	    {	      rec->data.data8[i]++;	      ptr = samples[ptr].key;	/* Follow link */	    }	}      return 0;      break;    case PM_GET_PGM_PATCHES:      {	int             ptr = patch_table[rec->parm1];	n = 0;	while (ptr >= 0 && ptr < free_sample)	  {	    rec->data.data32[n++] = ptr;	    ptr = samples[ptr].key;	/* Follow link */	  }      }      rec->parm1 = n;      return 0;      break;    case PM_GET_PATCH:      {	int             ptr = rec->parm1;	struct patch_info *pat;	if (ptr < 0 || ptr >= free_sample)	  return RET_ERROR (EINVAL);	memcpy (rec->data.data8, (char *) &samples[ptr],		sizeof (struct patch_info));	pat = (struct patch_info *) rec->data.data8;	pat->key = GUS_PATCH;	/* Restore patch type */	rec->parm1 = sample_ptrs[ptr];	/* DRAM location */	rec->parm2 = sizeof (struct patch_info);      }      return 0;      break;    case PM_SET_PATCH:      {	int             ptr = rec->parm1;	struct patch_info *pat;	if (ptr < 0 || ptr >= free_sample)	  return RET_ERROR (EINVAL);	pat = (struct patch_info *) rec->data.data8;	if (pat->len > samples[ptr].len)	/* Cannot expand sample */	  return RET_ERROR (EINVAL);	pat->key = samples[ptr].key;	/* Ensure the link is correct */	memcpy ((char *) &samples[ptr], rec->data.data8,		sizeof (struct patch_info));	pat->key = GUS_PATCH;      }      return 0;      break;    case PM_READ_PATCH:	/* Returns a block of wave data from the DRAM */      {	int             sample = rec->parm1;	int             n;	long            offs = rec->parm2;	int             l = rec->parm3;	if (sample < 0 || sample >= free_sample)	  return RET_ERROR (EINVAL);	if (offs < 0 || offs >= samples[sample].len)	  return RET_ERROR (EINVAL);	/* Invalid offset */	n = samples[sample].len - offs;		/* Num of bytes left */	if (l > n)	  l = n;	if (l > sizeof (rec->data.data8))	  l = sizeof (rec->data.data8);	if (l <= 0)	  return RET_ERROR (EINVAL);	/*					 * Was there a bug?					 */	offs += sample_ptrs[sample];	/*					 * Begin offsess + offset to DRAM					 */	for (n = 0; n < l; n++)	  rec->data.data8[n] = gus_peek (offs++);	rec->parm1 = n;		/*				 * Nr of bytes copied				 */      }      return 0;      break;    case PM_WRITE_PATCH:	/*				 * Writes a block of wave data to the DRAM				 */      {	int             sample = rec->parm1;	int             n;	long            offs = rec->parm2;	int             l = rec->parm3;	if (sample < 0 || sample >= free_sample)	  return RET_ERROR (EINVAL);	if (offs < 0 || offs >= samples[sample].len)	  return RET_ERROR (EINVAL);	/*					 * Invalid offset					 */	n = samples[sample].len - offs;		/*						   * Nr of bytes left						 */	if (l > n)	  l = n;	if (l > sizeof (rec->data.data8))	  l = sizeof (rec->data.data8);	if (l <= 0)	  return RET_ERROR (EINVAL);	/*					 * Was there a bug?					 */	offs += sample_ptrs[sample];	/*					 * Begin offsess + offset to DRAM					 */	for (n = 0; n < l; n++)	  gus_poke (offs++, rec->data.data8[n]);	rec->parm1 = n;		/*				 * Nr of bytes copied				 */      }      return 0;      break;    default:      return RET_ERROR (EINVAL);    }}static intguswave_alloc (int dev, int chn, int note, struct voice_alloc_info *alloc){  int             i, p, best = -1, best_time = 0x7fffffff;  p = alloc->ptr;  /*     * First look for a completely stopped voice   */  for (i = 0; i < alloc->max_voice; i++)    {      if (alloc->map[p] == 0)	{	  alloc->ptr = p;	  return p;	}      if (alloc->alloc_times[p] < best_time)	{	  best = p;	  best_time = alloc->alloc_times[p];	}      p = (p + 1) % alloc->max_voice;    }  /*     * Then look for a releasing voice   */  for (i = 0; i < alloc->max_voice; i++)    {      if (alloc->map[p] == 0xffff)	{	  alloc->ptr = p;	  return p;	}      p = (p + 1) % alloc->max_voice;    }  if (best >= 0)    p = best;  alloc->ptr = p;  return p;}static struct synth_operations guswave_operations ={  &gus_info,  0,  SYNTH_TYPE_SAMPLE,  SAMPLE_TYPE_GUS,  guswave_open,  guswave_close,  guswave_ioctl,  guswave_kill_note,  guswave_start_note,  guswave_set_instr,  guswave_reset,  guswave_hw_control,  guswave_load_patch,  guswave_aftertouch,  guswave_controller,  guswave_panning,  guswave_volume_method,  guswave_patchmgr,  guswave_bender,  guswave_alloc,  guswave_setup_voice};st

⌨️ 快捷键说明

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