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

📄 nes_apu.c

📁 linux下的MPEG1
💻 C
📖 第 1 页 / 共 2 页
字号:
      chan = (address & 4) ? 1 : 0;      apu->rectangle[chan].regs[1] = value;      apu->rectangle[chan].sweep_on = (value & 0x80) ? TRUE : FALSE;      apu->rectangle[chan].sweep_shifts = value & 7;      apu->rectangle[chan].sweep_delay = decay_lut[(value >> 4) & 7];            apu->rectangle[chan].sweep_inc = (value & 0x08) ? TRUE : FALSE;      apu->rectangle[chan].freq_limit = APU_TO_FIXED(freq_limit[value & 7]);      break;   case APU_WRA2:   case APU_WRB2:      chan = (address & 4) ? 1 : 0;      apu->rectangle[chan].regs[2] = value;//      if (apu->rectangle[chan].enabled)         apu->rectangle[chan].freq = APU_TO_FIXED((((apu->rectangle[chan].regs[3] & 7) << 8) + value) + 1);      break;   case APU_WRA3:   case APU_WRB3:      chan = (address & 4) ? 1 : 0;      apu->rectangle[chan].regs[3] = value;//      if (apu->rectangle[chan].enabled)      {         apu->rectangle[chan].vbl_length = vbl_lut[value >> 3];         apu->rectangle[chan].env_vol = 0;         apu->rectangle[chan].freq = APU_TO_FIXED((((value & 7) << 8) + apu->rectangle[chan].regs[2]) + 1);         apu->rectangle[chan].adder = 0;      }      break;   /* triangle */   case APU_WRC0:/*      if (0 == (apu->triangle.regs[0] & 0x80))         apu->triangle.countmode = COUNTMODE_COUNT;      else      {         if (apu->triangle.countmode == COUNTMODE_LOAD && apu->triangle.vbl_length)            apu->triangle.linear_length = trilength_lut[value & 0x7F];         if (0 == (value & 0x80))            apu->triangle.countmode = COUNTMODE_COUNT;      }*/      apu->triangle.regs[0] = value;      apu->triangle.holdnote = (value & 0x80) ? TRUE : FALSE;//      if (apu->triangle.enabled)      {         if (FALSE == apu->triangle.counter_started && apu->triangle.vbl_length)            apu->triangle.linear_length = trilength_lut[value & 0x7F];      }      break;   case APU_WRC2:      apu->triangle.regs[1] = value;//      if (apu->triangle.enabled)         apu->triangle.freq = APU_TO_FIXED((((apu->triangle.regs[2] & 7) << 8) + value) + 1);      break;   case APU_WRC3:      apu->triangle.regs[2] = value;        /* this is somewhat of a hack.  there appears to be some latency on       ** the Real Thing between when trireg0 is written to and when the       ** linear length counter actually begins its countdown.  we want to       ** prevent the case where the program writes to the freq regs first,       ** then to reg 0, and the counter accidentally starts running because       ** of the sound queue's timestamp processing.      **      ** set latency to a couple scanlines -- should be plenty of time for       ** the 6502 code to do a couple of table dereferences and load up the      ** other triregs      */      /* 06/13/00 MPC -- seems to work OK */      apu->triangle.write_latency = (int) (2 * NES_SCANLINE_CYCLES / APU_FROM_FIXED(apu->cycle_rate));/*      apu->triangle.linear_length = trilength_lut[apu->triangle.regs[0] & 0x7F];      if (0 == (apu->triangle.regs[0] & 0x80))         apu->triangle.countmode = COUNTMODE_COUNT;      else         apu->triangle.countmode = COUNTMODE_LOAD;*///      if (apu->triangle.enabled)      {         apu->triangle.freq = APU_TO_FIXED((((value & 7) << 8) + apu->triangle.regs[1]) + 1);         apu->triangle.vbl_length = vbl_lut[value >> 3];         apu->triangle.counter_started = FALSE;         apu->triangle.linear_length = trilength_lut[apu->triangle.regs[0] & 0x7F];      }      break;   /* noise */   case APU_WRD0:      apu->noise.regs[0] = value;      apu->noise.env_delay = decay_lut[value & 0x0F];      apu->noise.holdnote = (value & 0x20) ? TRUE : FALSE;      apu->noise.fixed_envelope = (value & 0x10) ? TRUE : FALSE;      apu->noise.volume = value & 0x0F;      break;   case APU_WRD2:      apu->noise.regs[1] = value;      apu->noise.freq = APU_TO_FIXED(noise_freq[value & 0x0F]);#ifdef REALTIME_NOISE      apu->noise.xor_tap = (value & 0x80) ? 0x40: 0x02;#else      /* detect transition from long->short sample */      if ((value & 0x80) && FALSE == apu->noise.short_sample)      {         /* recalculate short noise buffer */         shift_register15(noise_short_lut, APU_NOISE_93);         apu->noise.cur_pos = 0;      }      apu->noise.short_sample = (value & 0x80) ? TRUE : FALSE;#endif      break;   case APU_WRD3:      apu->noise.regs[2] = value;//      if (apu->noise.enabled)      {         apu->noise.vbl_length = vbl_lut[value >> 3];         apu->noise.env_vol = 0; /* reset envelope */      }      break;   /* DMC */   case APU_WRE0:      apu->dmc.regs[0] = value;      apu->dmc.freq = APU_TO_FIXED(dmc_clocks[value & 0x0F]);      apu->dmc.looping = (value & 0x40) ? TRUE : FALSE;      if (value & 0x80)         apu->dmc.irq_gen = TRUE;      else      {         apu->dmc.irq_gen = FALSE;         apu->dmc.irq_occurred = FALSE;      }      break;   case APU_WRE1: /* 7-bit DAC */      /* add the _delta_ between written value and      ** current output level of the volume reg      */      value &= 0x7F; /* bit 7 ignored */      apu->dmc.output_vol += ((value - apu->dmc.regs[1]) << 8);      apu->dmc.regs[1] = value;/*            apu->dmc.output_vol = (value & 0x7F) << 8;      apu->dmc.regs[1] = (value & 0x7E) >> 1;*/      break;   case APU_WRE2:      apu->dmc.regs[2] = value;      apu->dmc.cached_addr = 0xC000 + (uint16) (value << 6);      break;   case APU_WRE3:      apu->dmc.regs[3] = value;      apu->dmc.cached_dmalength = ((value << 4) + 1) << 3;      break;   case APU_SMASK:      /* bodge for timestamp queue */      apu->dmc.enabled = (value & 0x10) ? TRUE : FALSE;      apu->enable_reg = value;      for (chan = 0; chan < 2; chan++)      {         if (value & (1 << chan))            apu->rectangle[chan].enabled = TRUE;         else         {            apu->rectangle[chan].enabled = FALSE;            apu->rectangle[chan].vbl_length = 0;         }      }      if (value & 0x04)         apu->triangle.enabled = TRUE;      else      {         apu->triangle.enabled = FALSE;         apu->triangle.vbl_length = 0;         apu->triangle.linear_length = 0;         apu->triangle.counter_started = FALSE;         apu->triangle.write_latency = 0;      }      if (value & 0x08)         apu->noise.enabled = TRUE;      else      {         apu->noise.enabled = FALSE;         apu->noise.vbl_length = 0;      }      if (value & 0x10)      {         if (0 == apu->dmc.dma_length)            apu_dmcreload(&apu->dmc);      }      else         apu->dmc.dma_length = 0;      apu->dmc.irq_occurred = FALSE;      break;      /* unused, but they get hit in some mem-clear loops */   case 0x4009:   case 0x400D:      break;      default:      break;   }}/* Read from $4000-$4017 */uint8 apu_read(uint32 address){   uint8 value;   ASSERT(apu);   switch (address)   {   case APU_SMASK:      /* seems that bit 6 denotes vblank -- return 1 for now */      value = 0x40;      /* Return 1 in 0-5 bit pos if a channel is playing */      if (apu->rectangle[0].enabled && apu->rectangle[0].vbl_length)         value |= 0x01;      if (apu->rectangle[1].enabled && apu->rectangle[1].vbl_length)         value |= 0x02;      if (apu->triangle.enabled && apu->triangle.vbl_length)         value |= 0x04;      if (apu->noise.enabled && apu->noise.vbl_length)         value |= 0x08;      //if (apu->dmc.dma_length)      /* bodge for timestamp queue */      if (apu->dmc.enabled)         value |= 0x10;      if (apu->dmc.irq_occurred)         value |= 0x80;      break;#ifndef NSF_PLAYER   case APU_JOY0:      value = input_get(INP_JOYPAD0);      break;   case APU_JOY1:      value = input_get(INP_ZAPPER | INP_JOYPAD1 /*| INP_ARKANOID*/ /*| INP_POWERPAD*/);      break;#endif /* !NSF_PLAYER */   default:      value = (address >> 8); /* heavy capacitance on data bus */      break;   }   return value;}void apu_write(uint32 address, uint8 value){#ifndef NSF_PLAYER   static uint8 last_write;#endif /* !NSF_PLAYER */   apudata_t d;   switch (address)   {   case 0x4015:      /* bodge for timestamp queue */      apu->dmc.enabled = (value & 0x10) ? TRUE : FALSE;   case 0x4000: case 0x4001: case 0x4002: case 0x4003:   case 0x4004: case 0x4005: case 0x4006: case 0x4007:   case 0x4008: case 0x4009: case 0x400A: case 0x400B:   case 0x400C: case 0x400D: case 0x400E: case 0x400F:   case 0x4010: case 0x4011: case 0x4012: case 0x4013:      d.timestamp = nes6502_getcycles(FALSE);      d.address = address;      d.value = value;      apu_enqueue(&d);      break;#ifndef NSF_PLAYER   case APU_OAMDMA:      ppu_oamdma(address, value);      break;   case APU_JOY0:      /* VS system VROM switching */      mmc_vsvrom(value & 4);      /* see if we need to strobe them joypads */      value &= 1;      if ((0 == value) && last_write)         input_strobe();      last_write = value;      break;   case APU_JOY1: /* Some kind of IRQ control business */      break;#endif /* !NSF_PLAYER */   default:      break;   }}void apu_getpcmdata(void **data, int *num_samples, int *sample_bits){   ASSERT(apu);   *data = apu->buffer;   *num_samples = apu->num_samples;   *sample_bits = apu->sample_bits;}void apu_process(void *buffer, int num_samples){   apudata_t *d;   uint32 elapsed_cycles;   static int32 prev_sample = 0;   int32 next_sample, accum;   ASSERT(apu);   /* grab it, keep it local for speed */   elapsed_cycles = (uint32) apu->elapsed_cycles;   /* BLEH */   apu->buffer = buffer;    while (num_samples--)   {      while ((FALSE == APU_QEMPTY()) && (apu->queue[apu->q_tail].timestamp <= elapsed_cycles))      {         d = apu_dequeue();         apu_regwrite(d->address, d->value);      }      elapsed_cycles += APU_FROM_FIXED(apu->cycle_rate);      accum = 0;      if (apu->mix_enable[0]) accum += apu_rectangle(&apu->rectangle[0]);      if (apu->mix_enable[1]) accum += apu_rectangle(&apu->rectangle[1]);      if (apu->mix_enable[2]) accum += apu_triangle(&apu->triangle);      if (apu->mix_enable[3]) accum += apu_noise(&apu->noise);      if (apu->mix_enable[4]) accum += apu_dmc(&apu->dmc);      if (apu->ext && apu->mix_enable[5]) accum += apu->ext->process();      /* do any filtering */      if (APU_FILTER_NONE != apu->filter_type)      {         next_sample = accum;         if (APU_FILTER_LOWPASS == apu->filter_type)         {            accum += prev_sample;            accum >>= 1;         }         else            accum = (accum + accum + accum + prev_sample) >> 2;         prev_sample = next_sample;      }      /* little extra kick for the kids */      accum <<= 1;      /* prevent clipping */      if (accum > 0x7FFF)         accum = 0x7FFF;      else if (accum < -0x8000)         accum = -0x8000;      /* signed 16-bit output, unsigned 8-bit */      if (16 == apu->sample_bits) {         *((int16 *) buffer) = (int16) accum;          buffer = (int16 *) buffer + 1;      } else {         *((uint8 *) buffer) = (accum >> 8) ^ 0x80;          buffer = (int8 *) buffer + 1;      }   }   /* resync cycle counter */   apu->elapsed_cycles = nes6502_getcycles(FALSE);}/* set the filter type */void apu_setfilter(int filter_type){   ASSERT(apu);   apu->filter_type = filter_type;}void apu_reset(void){   uint32 address;   ASSERT(apu);   apu->elapsed_cycles = 0;   memset(&apu->queue, 0, APUQUEUE_SIZE * sizeof(apudata_t));   apu->q_head = 0;   apu->q_tail = 0;   /* use to avoid bugs =) */   for (address = 0x4000; address <= 0x4013; address++)      apu_regwrite(address, 0);#ifdef NSF_PLAYER   apu_regwrite(0x400C, 0x10); /* silence noise channel on NSF start */   apu_regwrite(0x4015, 0x0F);#else   apu_regwrite(0x4015, 0);#endif /* NSF_PLAYER */   if (apu->ext)      apu->ext->reset();}static void apu_build_luts(int num_samples){   int i;   /* lut used for enveloping and frequency sweeps */   for (i = 0; i < 16; i++)      decay_lut[i] = num_samples * (i + 1);   /* used for note length, based on vblanks and size of audio buffer */   for (i = 0; i < 32; i++)      vbl_lut[i] = vbl_length[i] * num_samples;   /* triangle wave channel's linear length table */   for (i = 0; i < 128; i++)      trilength_lut[i] = (i * num_samples) / 4;#ifndef REALTIME_NOISE   /* generate noise samples */   shift_register15(noise_long_lut, APU_NOISE_32K);   shift_register15(noise_short_lut, APU_NOISE_93);#endif /* !REALTIME_NOISE */}static void apu_setactive(apu_t *active){   ASSERT(active);   apu = active;}/* Initializes emulated sound hardware, creates waveforms/voices */apu_t *apu_create(int sample_rate, int refresh_rate, int sample_bits, boolean stereo){   apu_t *temp_apu;   int channel;   temp_apu = malloc(sizeof(apu_t));   if (NULL == temp_apu)      return NULL;   temp_apu->sample_rate = sample_rate;   temp_apu->refresh_rate = refresh_rate;   temp_apu->sample_bits = sample_bits;   temp_apu->num_samples = sample_rate / refresh_rate;   /* turn into fixed point! */   temp_apu->cycle_rate = (int32) (APU_BASEFREQ * 65536.0 / (float) sample_rate);   /* build various lookup tables for apu */   apu_build_luts(temp_apu->num_samples);   /* set the update routine */   temp_apu->process = apu_process;   temp_apu->ext = NULL;   apu_setactive(temp_apu);   apu_reset();   for (channel = 0; channel < 6; channel++)      apu_setchan(channel, TRUE);   apu_setfilter(APU_FILTER_LOWPASS);   return temp_apu;}apu_t *apu_getcontext(void){   return apu;}void apu_destroy(apu_t *src_apu){   if (src_apu)   {      if (src_apu->ext)         src_apu->ext->shutdown();      free(src_apu);   }}void apu_setext(apu_t *src_apu, apuext_t *ext){   ASSERT(src_apu);   src_apu->ext = ext;   /* initialize it */   if (src_apu->ext)      src_apu->ext->init();}/* this exists for external mixing routines */int32 apu_getcyclerate(void){   ASSERT(apu);   return apu->cycle_rate;}/*** $Log: nes_apu.c,v $** Revision 1.4  2005/05/07 09:11:39  valtri** *BUGFIX*** gcc4 patches from Dams Nadé (livna.org) and Keenan Pepper.**** Revision 1.3  2004/12/12 06:55:59  athp** Code cleanups and elimination of some compiler warnings; patch courtesy of AL13N**** Revision 1.2  2003/08/25 21:51:43  f1rmb** Reduce GCC verbosity (various prototype declaration fixes). ffmpeg, wine and fft*post are untouched (fft: for now).**** Revision 1.1  2003/01/08 07:04:35  tmmm** initial import of Nosefart sources**** Revision 1.19  2000/07/04 04:53:26  matt** minor changes, sound amplification**** Revision 1.18  2000/07/03 02:18:53  matt** much better external module exporting**** Revision 1.17  2000/06/26 11:01:55  matt** made triangle a tad quieter**** Revision 1.16  2000/06/26 05:10:33  matt** fixed cycle rate generation accuracy**** Revision 1.15  2000/06/26 05:00:37  matt** cleanups**** Revision 1.14  2000/06/23 11:06:24  matt** more faithful mixing of channels**** Revision 1.13  2000/06/23 03:29:27  matt** cleaned up external sound inteface**** Revision 1.12  2000/06/20 00:08:39  matt** bugfix to rectangle wave**** Revision 1.11  2000/06/13 13:48:58  matt** fixed triangle write latency for fixed point apu cycle rate**** Revision 1.10  2000/06/12 01:14:36  matt** minor change to clipping extents**** Revision 1.9  2000/06/09 20:00:56  matt** fixed noise hiccup in NSF player mode**** Revision 1.8  2000/06/09 16:49:02  matt** removed all floating point from sound generation**** Revision 1.7  2000/06/09 15:12:28  matt** initial revision***/

⌨️ 快捷键说明

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