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

📄 sound.c

📁 NES game Emulator in Linux.c and asm codes.
💻 C
📖 第 1 页 / 共 4 页
字号:
     SPC_VoicesOff(~SPC_MASK, "SPC_MASK");
    }

    if (SNDkeys & SPC_DSP[DSP_NON])
    {
     unsigned i;
     int samples_left = samples;

     for (i = first; samples_left && noise_update_count; samples_left--)
     {
      noise_countdown -= noise_update_count;

      if (noise_countdown <= 0)
      {
       noise_countdown = apu_counter_reset_value;
       noise_vol = rand();
      }

      noise_buffer [i] = noise_vol;
      if (++i >= buffer_size)
       i = 0;
     }

     for (; samples_left; samples_left--)
     {
      noise_buffer [i] = noise_vol;
      if (++i >= buffer_size)
       i = 0;
     }
    }

    voices_were_on = SNDkeys;

    main_jvol = (main_lvol + main_rvol) >> 1;
    echo_jvol = (echo_lvol + echo_rvol) >> 1;

    for (voice = 0, voice_bit = 1; voice < 8; voice++, voice_bit <<= 1)
    {
        struct voice_state *pvs;

        if (!(SNDkeys & voice_bit)) continue;

        pvs = &SNDvoices[voice];

        if (sound_enabled == 1)
        {
         pvs->jvol = (pvs->lvol + pvs->rvol) >> 1;
        }

        pvs->step = ((unsigned) *(unsigned short *)&SPC_DSP[(voice << 4) + DSP_VOICE_PITCH_L]);
    }

/* MMX mixing notes
 *  PMADDWD takes two sets of four 16-bit words. abcd(r), efgh(r/m).
 *  Each 16-bit word in source is multiplied by its respective word in
 *  destination. Then the high 2 results are added and stored as the
 *  high 32-bit result, and the low 2 results are added and stored
 *  as the low 32-bit result.
 *
 *  For audio channel mixing, propose that source contain channel volumes
 *  and destination contain channel sample height.
 *
 *  In Stereo, high pair of 16-bit words are for two channels, left side,
 *  and low pair of 16-bit words are for two channels, right side.
 *
 *  In Mono, instead of left and right side, two independent samples
 *  are processed at once.
 *
 *  After all channels have been volume-adjusted, PADDD is used to combine
 *  them, and PACKSSDW converts them back to 16-bit samples for output.
 */

    mix_voices(first, samples, buffer_size, sound_bits,
     sound_enabled == 2 ? 1 : 0);

    for (voice = 0, voice_bit = 1; voice < 8; voice++, voice_bit <<= 1)
    {
        if (voices_were_on & voice_bit)
        {
         /* If voice was on, but turned off for any reason */
         if (!(SNDkeys & voice_bit))
         {
          SPC_VoiceOff(voice, "?");
         }
         else
         {
          /* If voice was on, and is still on */
          SPC_DSP[(voice << 4) + DSP_VOICE_OUTX] =
           SNDvoices[voice].outx;
         }
        }
    }
}

void SPC_READ_DSP()
{
    int addr_lo = SPC_DSP_ADDR & 0xF;
    int addr_hi = SPC_DSP_ADDR >> 4;

#ifdef LOG_SOUND_DSP_READ
    printf("\nread @ %08X,%04X: %02X", TotalCycles, (unsigned) _SPC_PC, (unsigned) SPC_DSP_ADDR);
#endif

#ifdef DSP_SPEED_HACK
    /* if we're not reading endx */
    if (SPC_DSP_ADDR != DSP_ENDX)
    {
     /* if we're reading envx or outx but voice is off */
     if (addr_lo == DSP_VOICE_ENVX || addr_lo == DSP_VOICE_OUTX)
     {
      if (!(SNDkeys & (1 << addr_hi)))
      {
#ifdef LOG_SOUND_DSP_READ
       printf(" %02X", SPC_DSP[SPC_DSP_ADDR]);
#endif
       return;
      }
     }
     else
     {
#ifdef LOG_SOUND_DSP_READ
      printf(" %02X", SPC_DSP[SPC_DSP_ADDR]);
#endif
      return;
     }
    }
#endif

//  printf("\nSound update");

    update_sound();

    switch(addr_lo)
    {
    case DSP_VOICE_ENVX:
                if (!sound_enabled) SNDvoices[addr_hi].voice_sample_latch =
                 sound_sample_latch;
#if defined(ZERO_ENVX_ON_VOICE_OFF) && !defined(DSP_SPEED_HACK)
                if (ENVX_ENABLED && (SNDkeys & (1 << addr_hi)))
#else
                if (ENVX_ENABLED)
#endif
                 UpdateEnvelopeHeight(addr_hi); // >> ENVX_DOWNSHIFT_BITS;
                else
                 SPC_DSP[SPC_DSP_ADDR] = 0;

                break;
    }
#ifdef LOG_SOUND_DSP_READ
    printf(" %02X", SPC_DSP[SPC_DSP_ADDR]);
#endif
}

void SPC_WRITE_DSP()
{
 int i;
 int addr_lo = SPC_DSP_ADDR & 0xF;
 int addr_hi = SPC_DSP_ADDR >> 4;

 if (addr_hi > 7)
 {
  SPC_DSP[SPC_DSP_ADDR] = SPC_DSP_DATA;
  return;
 }

#ifdef LOG_SOUND_DSP_WRITE
 printf("\nwrite @ %08X,%04X: %02X %02X", TotalCycles, (unsigned) _SPC_PC,
  (unsigned) SPC_DSP_ADDR, (unsigned) SPC_DSP_DATA);
#endif

#ifdef DSP_SPEED_HACK
 /* if we're not writing to flg or endx */
 if (addr_lo != 0x0C || addr_hi < 6)
 /* and write would not change data, return */
 if (SPC_DSP[SPC_DSP_ADDR] == SPC_DSP_DATA) return;

 /* if it's not a voice register for a voice that's not on */
 if (addr_lo > 9 ||
  ((SNDkeys | (SPC_DSP[DSP_KON] & ~SPC_DSP[DSP_KOF])) & (1 << addr_hi)))
 {
#endif

  update_sound();

//printf("\nSound update");
#ifdef DSP_SPEED_HACK
 }
#endif

 switch (addr_lo)
 {
 // break just means nothing needs to be done right now
 // Commented cases are unsupported registers, or do-nothing cases

 // Channel - volume left
 case DSP_VOICE_LVOL:
  SNDvoices[addr_hi].lvol = (signed char) SPC_DSP_DATA;
  break;

 // Channel - volume right
 case DSP_VOICE_RVOL:
  SNDvoices[addr_hi].rvol = (signed char) SPC_DSP_DATA;
  break;
/*
 // Channel - pitch low bits (0-7)
 case DSP_VOICE_PITCH_L:
  break;
 */

#ifdef MASK_PITCH_H
 // Channel - pitch high bits (8-13)
 case DSP_VOICE_PITCH_H:
  SPC_DSP_DATA &= 0x3F;
  break;
#endif
/*
 // Channel - source number
 case DSP_VOICE_SRCN:
  break;
 */
 // Channel - ADSR 1
 case DSP_VOICE_ADSR1:
  if (!sound_enabled) SNDvoices[addr_hi].voice_sample_latch =
   sound_sample_latch;
  if (SNDkeys & (1 << addr_hi)) UpdateEnvelopeHeight(addr_hi);

  SNDvoices[addr_hi].ar = attack_time(SPC_DSP_DATA & 0xF);
  SNDvoices[addr_hi].dr = decay_time((SPC_DSP_DATA >> 4) & 7);

  /* If voice releasing or not playing, nothing else to update */
  if (!(SNDkeys & (1 << addr_hi)) ||
   SNDvoices[addr_hi].env_state == RELEASE) break;

  if (SNDvoices[addr_hi].env_state == ATTACK)
   SNDvoices[addr_hi].env_update_count = SNDvoices[addr_hi].ar;
  else if (SNDvoices[addr_hi].env_state == DECAY)
   SNDvoices[addr_hi].env_update_count = SNDvoices[addr_hi].dr;

  if (SPC_DSP_DATA & 0x80)
  {
   // switch to ADSR (use old state if voice was switched since last key on)
   if (!(SPC_DSP[SPC_DSP_ADDR] & 0x80))
   {
    SNDvoices[addr_hi].env_state = SNDvoices[addr_hi].adsr_state;

    switch (SNDvoices[addr_hi].env_state)
    {
     case ATTACK:
      SNDvoices[addr_hi].env_update_count = SNDvoices[addr_hi].ar;
      break;
     case DECAY:
      SNDvoices[addr_hi].env_update_count = SNDvoices[addr_hi].dr;
      break;
     case SUSTAIN:
      SNDvoices[addr_hi].env_update_count = SNDvoices[addr_hi].sr;
      break;
    }
   }
  }
  else
  {
   // switch to a GAIN mode
   i = SPC_DSP[(addr_hi << 4) + DSP_VOICE_GAIN];

   SNDvoices[addr_hi].env_update_count =
    SNDvoices[addr_hi].gain_update_count;

   if (i & 0x80)
   {
    SNDvoices[addr_hi].env_state = i >> 5;
   }
   else
   {
    SNDvoices[addr_hi].env_state = DIRECT;
    SPC_DSP[(addr_hi << 4) + DSP_VOICE_ENVX] = (i & 0x7F);
    SNDvoices[addr_hi].envx = (i & 0x7F) << ENVX_DOWNSHIFT_BITS;
   }
  }
  break;

 // Channel - ADSR 2
 case DSP_VOICE_ADSR2:
  if (!sound_enabled) SNDvoices[addr_hi].voice_sample_latch =
   sound_sample_latch;
  if (SNDkeys & (1 << addr_hi)) UpdateEnvelopeHeight(addr_hi);

  SNDvoices[addr_hi].sr = exp_time(SPC_DSP_DATA & 0x1F);
  SNDvoices[addr_hi].sl = ((SPC_DSP_DATA >> 5) == 7) ? ENVX_MAX :
   (ENVX_MAX_BASE / 8) * ((SPC_DSP_DATA >> 5) + 1);

  if (SNDvoices[addr_hi].env_state == SUSTAIN)
   SNDvoices[addr_hi].env_update_count = SNDvoices[addr_hi].sr;

  break;

 // Channel - GAIN
 case DSP_VOICE_GAIN:
  if (!sound_enabled) SNDvoices[addr_hi].voice_sample_latch =
   sound_sample_latch;
  if (SNDkeys & (1 << addr_hi)) UpdateEnvelopeHeight(addr_hi);

  if (SPC_DSP_DATA & 0x80)
  {
   switch (SPC_DSP_DATA >> 5)
   {
    case INCREASE:
    case DECREASE:
     SNDvoices[addr_hi].gain_update_count =
      linear_time(SPC_DSP_DATA & 0x1F);
     break;

    case BENT:
     SNDvoices[addr_hi].gain_update_count =
      bent_time(SPC_DSP_DATA & 0x1F);
     break;

    case EXP:
     SNDvoices[addr_hi].gain_update_count =
      exp_time(SPC_DSP_DATA & 0x1F);
   }
  }
  else
  {
   SNDvoices[addr_hi].gain_update_count = 0;
  }

  /* If voice releasing or not playing, nothing else to update */
  if (!(SNDkeys & (1 << addr_hi)) ||
   SNDvoices[addr_hi].env_state == RELEASE) break;

  /* is gain enabled? */
  if (!(SPC_DSP[(addr_hi << 4) + DSP_VOICE_ADSR1] & 0x80))
  {
   SNDvoices[addr_hi].env_update_count =
    SNDvoices[addr_hi].gain_update_count;

   if (SPC_DSP_DATA & 0x80)
   {
    SNDvoices[addr_hi].env_state = SPC_DSP_DATA >> 5;
   }
   else
   {
    SNDvoices[addr_hi].env_state = DIRECT;
    SPC_DSP[(addr_hi << 4) + DSP_VOICE_ENVX] = (SPC_DSP_DATA & 0x7F);
    SNDvoices[addr_hi].envx = (SPC_DSP_DATA & 0x7F) << ENVX_DOWNSHIFT_BITS;
   }
  }

  break;

 case DSP_VOICE_ENVX:
 case DSP_VOICE_OUTX:
#ifdef DISALLOW_ENVX_OUTX_WRITE
  return;
#else
  break;
#endif

 // These are general registers
 case 0xC:
  switch (addr_hi)
  {
  // Main volume - left
  case DSP_MAIN_LVOL >> 4:
   main_lvol = (signed char) SPC_DSP_DATA;
   break;

  // Main volume - right
  case DSP_MAIN_RVOL >> 4:
   main_rvol = (signed char) SPC_DSP_DATA;
   break;

  // Echo volume - left
  case DSP_ECHO_LVOL >> 4:
   echo_lvol = (signed char) SPC_DSP_DATA;
   break;

  // Echo volume - right
  case DSP_ECHO_RVOL >> 4:
   echo_rvol = (signed char) SPC_DSP_DATA;
   break;

  // Key on
  case DSP_KON >> 4:
   break;

  // Key off
  case DSP_KOF >> 4:
   break;

  // Reset, mute, echo enable, noise clock select
  case DSP_FLG >> 4:
   noise_update_count = counter_update_table[SPC_DSP_DATA & 0x1F];

   if (SPC_DSP_DATA & DSP_FLG_RESET)
   {
    int voice;

    SPC_DSP[DSP_FLG] = SPC_DSP_DATA | DSP_FLG_NECEN | DSP_FLG_MUTE;

    for (voice = 0; voice < 7; voice++)
    {
     SPC_VoicesOff(SNDkeys, "DSP reset");
    }

    SPC_DSP[DSP_ENDX] = 0;
    SPC_DSP[DSP_KON] = 0;
    SPC_DSP[DSP_KOF] = 0;
   }
   break;

  // Sample end-block decoded
  case DSP_ENDX >> 4:
   SPC_DSP_DATA = 0;
   break;
  }

  break;

 case 0xD:
  switch (addr_hi)
  {
  // Echo Feedback
  case DSP_EFB >> 4:
   echo_feedback = (signed char) SPC_DSP_DATA;
   break;
  // Pitch modulation
//case DSP_PMON >> 4:
// break;
  // Noise enable
//case DSP_NON >> 4:
// break;
  // Echo enable
//case DSP_EON >> 4:
// break;
  // Source directory address
//case DSP_DIR >> 4:
// break;
  // Echo start address
  case DSP_ESA >> 4:
   echo_base = (unsigned) SPC_DSP_DATA << 8;
   break;
  // Echo delay
  case DSP_EDL >> 4:
   echo_delay = (SPC_DSP_DATA & 0x0F) << 11;
   break;
  }
  break;

 // FIR echo filter
 case 0xF:
  FIR_coeff[7 - addr_hi] = (signed char) SPC_DSP_DATA;
  break;
 }
 SPC_DSP[SPC_DSP_ADDR] = SPC_DSP_DATA;
}

void sound_pause(void)
{
 if (sound_enabled) voice_stop(stream_buffer->voice);
}

void sound_resume(void)
{
 if (sound_enabled) voice_start(stream_buffer->voice);
}

#ifdef ALLEGRO_DOS
BEGIN_DIGI_DRIVER_LIST
 DIGI_DRIVER_SOUNDSCAPE
 DIGI_DRIVER_AUDIODRIVE
 DIGI_DRIVER_WINSOUNDSYS
 DIGI_DRIVER_SB
END_DIGI_DRIVER_LIST

BEGIN_MIDI_DRIVER_LIST
END_MIDI_DRIVER_LIST
#endif

⌨️ 快捷键说明

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