//  ---------------------------------------------------------------------------
//  This file is part of reSID, a MOS6581 SID emulator engine.
//  Copyright (C) 2004  Dag Lem <resid@nimrod.no>
//
//  This program is free software; you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation; either version 2 of the License, or
//  (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with this program; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//  ---------------------------------------------------------------------------
// C64 DTV modifications written by
//   Daniel Kahlin <daniel@kahlin.net>
// Copyright (C) 2007  Daniel Kahlin <daniel@kahlin.net>

#ifdef _M_ARM
#undef _ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE
#define _ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE 1
#endif

#include "sid.h"
#include <math.h>

#if defined(__MMX__) && (HAVE_MMINTRIN_H==1)
#include <mmintrin.h>
#endif

unsigned int wave_train_lut[4096][128];
unsigned int env_train_lut[256][8];
unsigned int volume_train_lut[16];

static void init_lut() {
    /* this table needs 2 MB, but the alternative of doing 32M iterations
     * of this inner loop per second is worse. */
    for (int wave = 0; wave < 4096; wave ++) {
        for (int phase1 = 0; phase1 < 128; phase1 ++) {
            unsigned int wavecounter = phase1 * 32;

            unsigned int wavetrain = 0;
            for (int phase2 = 0; phase2 < 32; phase2 ++) {
                wavecounter += wave;
                wavetrain <<= 1;
                wavetrain |= wavecounter >> 12;
                wavecounter &= 0xfff;
            }
            wave_train_lut[wave][phase1] = wavetrain;
        }
    }

    for (int env = 0; env < 256; env ++) {
        for (int phase1 = 0; phase1 < 8; phase1 ++) {
            /* we always start envelope on particular phase value out of
             * 256, which corresponds to how many clocks we have been
             * running. */
            unsigned int envcounter = phase1 * 32;

            unsigned int envtrain = 0;
            for (int phase2 = 0; phase2 < 32; phase2 ++) {
                envcounter += env;
                envtrain <<= 1;
                envtrain |= envcounter >> 8;
                envcounter &= 0xff;
            }
            env_train_lut[env][phase1] = envtrain;
        }
    }
    
    for (int vol = 0; vol < 16; vol ++) {
        unsigned int volcounter = (16 - vol) & 0xf;
        unsigned int voltrain = 0;
        for (int phase2 = 0; phase2 < 32; phase2 ++) {
            volcounter += vol;
            voltrain <<= 1;
            voltrain |= volcounter >> 4;
            volcounter &= 0xf;
        }
        volume_train_lut[vol] = voltrain;
    }
}

namespace reSID_dtv
{

// ----------------------------------------------------------------------------
// Constructor.
// ----------------------------------------------------------------------------
SID::SID()
{
  static bool tableinit = false;
  if (! tableinit) {
    init_lut();
    tableinit = true;
  }

  // Initialize pointers.
  sample = 0;
  fir = 0;

  voice[0].set_sync_source(&voice[2]);
  voice[1].set_sync_source(&voice[0]);
  voice[2].set_sync_source(&voice[1]);

  set_sampling_parameters(985248, SAMPLE_FAST, 44100);

  bus_value = 0;

  master_volume = 0;
}


// ----------------------------------------------------------------------------
// Destructor.
// ----------------------------------------------------------------------------
SID::~SID()
{
  delete[] sample;
  delete[] fir;
}

// ----------------------------------------------------------------------------
// SID reset.
// ----------------------------------------------------------------------------
void SID::reset()
{
  for (int i = 0; i < 3; i++) {
    voice[i].reset();
  }
  filter.reset();
  extfilt.reset();

  bus_value = 0;
}

// ----------------------------------------------------------------------------
// Read sample from audio output.
// ----------------------------------------------------------------------------
int SID::output()
{
  int v = extfilt.output();
  const int half = 1 << 15;
  if (v >= half) {
    v = half - 1;
  }
  else if (v < -half) {
    v = -half;
  }
  return v;
}

// ----------------------------------------------------------------------------
// Read registers.
//
// Reading a write only register returns the last byte written to any SID
// register. The individual bits in this value start to fade down towards
// zero after a few cycles. All bits reach zero within approximately
// $2000 - $4000 cycles.
// It has been claimed that this fading happens in an orderly fashion, however
// sampling of write only registers reveals that this is not the case.
// NB! This is not correctly modeled.
// The actual use of write only registers has largely been made in the belief
// that all SID registers are readable. To support this belief the read
// would have to be done immediately after a write to the same register
// (remember that an intermediate write to another register would yield that
// value instead). With this in mind we return the last value written to
// any SID register for $2000 cycles without modeling the bit fading.
// ----------------------------------------------------------------------------
reg8 SID::read(reg8 offset)
{
  switch (offset) {
  case 0x19:
    return 0x00;
  case 0x1a:
    return 0x00;
  case 0x1b:
    return voice[2].wave.readOSC();
  case 0x1c:
    return voice[2].envelope.readENV();
  default:
    return bus_value;
  }
}


// ----------------------------------------------------------------------------
// Write registers.
// ----------------------------------------------------------------------------
void SID::write(reg8 offset, reg8 value)
{
  bus_value = value;

  switch (offset) {
  case 0x00:
    voice[0].wave.writeFREQ_LO(value);
    break;
  case 0x01:
    voice[0].wave.writeFREQ_HI(value);
    break;
  case 0x02:
    voice[0].wave.writePW_LO(value);
    break;
  case 0x03:
    voice[0].wave.writePW_HI(value);
    break;
  case 0x04:
    voice[0].writeCONTROL_REG(value);
    break;
  case 0x05:
    voice[0].envelope.writeATTACK_DECAY(value);
    break;
  case 0x06:
    voice[0].envelope.writeSUSTAIN_RELEASE(value);
    break;
  case 0x07:
    voice[1].wave.writeFREQ_LO(value);
    break;
  case 0x08:
    voice[1].wave.writeFREQ_HI(value);
    break;
  case 0x09:
    voice[1].wave.writePW_LO(value);
    break;
  case 0x0a:
    voice[1].wave.writePW_HI(value);
    break;
  case 0x0b:
    voice[1].writeCONTROL_REG(value);
    break;
  case 0x0c:
    voice[1].envelope.writeATTACK_DECAY(value);
    break;
  case 0x0d:
    voice[1].envelope.writeSUSTAIN_RELEASE(value);
    break;
  case 0x0e:
    voice[2].wave.writeFREQ_LO(value);
    break;
  case 0x0f:
    voice[2].wave.writeFREQ_HI(value);
    break;
  case 0x10:
    voice[2].wave.writePW_LO(value);
    break;
  case 0x11:
    voice[2].wave.writePW_HI(value);
    break;
  case 0x12:
    voice[2].writeCONTROL_REG(value);
    break;
  case 0x13:
    voice[2].envelope.writeATTACK_DECAY(value);
    break;
  case 0x14:
    voice[2].envelope.writeSUSTAIN_RELEASE(value);
    break;
  case 0x18:
    filter.writeMODE_VOL(value);
    master_volume = value & 0xf;
    break;
  case 0x1e:
    voice[0].wave.writeACC_HI(value);
    break;
  case 0x1f:
    voice[1].envelope.writeENV(value);
    break;
  default:
    break;
  }
}


// ----------------------------------------------------------------------------
// Constructor.
// ----------------------------------------------------------------------------
SID::State::State()
{
  int i;

  for (i = 0; i < 0x20; i++) {
    sid_register[i] = 0;
  }

  bus_value = 0;

  for (i = 0; i < 3; i++) {
    accumulator[i] = 0;
    shift_register[i] = 0x7ffff8;
    rate_counter[i] = 0;
    rate_counter_period[i] = 8;
    exponential_counter[i] = 0;
    exponential_counter_period[i] = 1;
    envelope_counter[i] = 0;
    envelope_state[i] = EnvelopeGenerator::RELEASE;
    hold_zero[i] = true;
  }
}


// ----------------------------------------------------------------------------
// Read state.
// ----------------------------------------------------------------------------
SID::State SID::read_state()
{
  State state;
  int i, j;

  for (i = 0, j = 0; i < 3; i++, j += 7) {
    WaveformGenerator& wave = voice[i].wave;
    EnvelopeGenerator& envelope = voice[i].envelope;
    state.sid_register[j + 0] = wave.freq & 0xff;
    state.sid_register[j + 1] = wave.freq >> 8;
    state.sid_register[j + 2] = wave.pw & 0xff;
    state.sid_register[j + 3] = wave.pw >> 8;
    state.sid_register[j + 4] =
      (wave.waveform << 4)
      | (wave.test ? 0x08 : 0)
      | (wave.ring_mod ? 0x04 : 0)
      | (wave.sync ? 0x02 : 0)
      | (envelope.gate ? 0x01 : 0);
    state.sid_register[j + 5] = (envelope.attack << 4) | envelope.decay;
    state.sid_register[j + 6] = (envelope.sustain << 4) | envelope.release;
  }

  state.sid_register[j++] =
    (filter.voice3off ? 0x80 : 0)
    | filter.vol;

  // These registers are superfluous, but included for completeness.
  for (; j < 0x1d; j++) {
    state.sid_register[j] = read(j);
  }
  for (; j < 0x20; j++) {
    state.sid_register[j] = 0;
  }

  state.bus_value = bus_value;

  for (i = 0; i < 3; i++) {
    state.accumulator[i] = voice[i].wave.accumulator;
    state.shift_register[i] = voice[i].wave.shift_register;
    state.rate_counter[i] = voice[i].envelope.rate_counter;
    state.rate_counter_period[i] = voice[i].envelope.rate_period;
    state.exponential_counter[i] = voice[i].envelope.exponential_counter;
    state.exponential_counter_period[i] = voice[i].envelope.exponential_counter_period;
    state.envelope_counter[i] = voice[i].envelope.envelope_counter;
    state.envelope_state[i] = voice[i].envelope.state;
    state.hold_zero[i] = voice[i].envelope.hold_zero;
  }

  return state;
}


// ----------------------------------------------------------------------------
// Write state.
// ----------------------------------------------------------------------------
void SID::write_state(const State& state)
{
  int i;

  for (i = 0; i <= 0x18; i++) {
    write(i, state.sid_register[i]);
  }

  bus_value = state.bus_value;

  for (i = 0; i < 3; i++) {
    voice[i].wave.accumulator = state.accumulator[i];
    voice[i].wave.shift_register = state.shift_register[i];
    voice[i].envelope.rate_counter = state.rate_counter[i];
    voice[i].envelope.rate_period = state.rate_counter_period[i];
    voice[i].envelope.exponential_counter = state.exponential_counter[i];
    voice[i].envelope.exponential_counter_period = state.exponential_counter_period[i];
    voice[i].envelope.envelope_counter = state.envelope_counter[i];
    voice[i].envelope.state = state.envelope_state[i];
    voice[i].envelope.hold_zero = state.hold_zero[i];
  }
}


// ----------------------------------------------------------------------------
// Enable external filter.
// ----------------------------------------------------------------------------
void SID::enable_external_filter(bool enable)
{
  extfilt.enable_filter(enable);
}


// ----------------------------------------------------------------------------
// I0() computes the 0th order modified Bessel function of the first kind.
// This function is originally from resample-1.5/filterkit.c by J. O. Smith.
// ----------------------------------------------------------------------------
double SID::I0(double x)
{
  // Max error acceptable in I0.
  const double I0e = 1e-10;

  double sum, u, halfx, temp;
  int n;

  sum = u = n = 1;
  halfx = x/2.0;

  do {
    temp = halfx/n++;
    u *= temp*temp;
    sum += u;
  } while (u >= I0e*sum);

  return sum;
}


// ----------------------------------------------------------------------------
// Setting of SID sampling parameters.
//
// Use a clock freqency of 985248Hz for PAL C64, 1022730Hz for NTSC C64.
// The default end of passband frequency is pass_freq = 0.9*sample_freq/2
// for sample frequencies up to ~ 44.1kHz, and 20kHz for higher sample
// frequencies.
//
// For resampling, the ratio between the clock frequency and the sample
// frequency is limited as follows:
//   125*clock_freq/sample_freq < 16384
// E.g. provided a clock frequency of ~ 1MHz, the sample frequency can not
// be set lower than ~ 8kHz. A lower sample frequency would make the
// resampling code overfill its 16k sample ring buffer.
// 
// The end of passband frequency is also limited:
//   pass_freq <= 0.9*sample_freq/2

// E.g. for a 44.1kHz sampling rate the end of passband frequency is limited
// to slightly below 20kHz. This constraint ensures that the FIR table is
// not overfilled.
// ----------------------------------------------------------------------------
bool SID::set_sampling_parameters(double clock_freq, sampling_method method,
				  double sample_freq, double pass_freq,
				  double filter_scale)
{
  cycles_per_sample =
    cycle_count(clock_freq/sample_freq*(1 << FIXP_SHIFT) + 0.5);

  sample_offset = 0;
  sample_prev = 0;

  // FIR initialization is only necessary for resampling.
  if (method != SAMPLE_RESAMPLE && method != SAMPLE_RESAMPLE_FASTMEM)
  {
    sampling = method;
    delete[] sample;
    delete[] fir;
    sample = 0;
    fir = 0;
    return true;
  }

  const int bits = 16;

  if (pass_freq > 20000)
    pass_freq = 20000;  
  if (2*pass_freq/sample_freq > 0.9)
    pass_freq = 0.9f*sample_freq/2;

  const double pi = 3.1415926535897932385;

  // 16 bits -> -96dB stopband attenuation.
  const double A = -20*log10(1.0/(1 << bits));

  // For calculation of beta and N see the reference for the kaiserord
  // function in the MATLAB Signal Processing Toolbox:
  // http://www.mathworks.com/access/helpdesk/help/toolbox/signal/kaiserord.html
  const double beta = 0.1102*(A - 8.7);
  const double I0beta = I0(beta);
  
  double f_samples_per_cycle = sample_freq/clock_freq;
  double f_cycles_per_sample = clock_freq/sample_freq;

  /* This code utilizes the fact that aliasing back to 20 kHz from
   * sample_freq/2 is inaudible. This allows us to define a passband
   * wider than normally. We might also consider aliasing back to pass_freq,
   * but as this can be less than 20 kHz, it might become audible... */
  double aliasing_allowance = sample_freq / 2 - 20000;
  if (aliasing_allowance < 0)
    aliasing_allowance = 0;

  double transition_bandwidth = sample_freq/2 - pass_freq + aliasing_allowance;
  {
    /* Filter order according to Kaiser's paper. */
    int N = int((A - 7.95)/(2 * pi * 2.285 * transition_bandwidth/sample_freq) + 0.5);
    N += N & 1;

    // The filter length is equal to the filter order + 1.
    // The filter length must be an odd number (sinc is symmetric about x = 0).
    fir_N = int(N*f_cycles_per_sample) + 1;
    fir_N |= 1;

    // Check whether the sample ring buffer would overfill.
#if 0
    // Both FIR_N (125) and RINGSIZE (4096) are constants, and so 125 > 4095 is ALWAYS false
    if (FIR_N > RINGSIZE - 1) {
      return false;
    }
#endif

    /* Error is bound by 1.234 / L^2 */
    fir_RES = (int) (sqrt(1.234 * (1 << bits)) / f_cycles_per_sample + 0.5);
  }
  sampling = method;

  // Allocate memory for FIR tables.
  delete[] fir;
  fir = new short[fir_N*fir_RES];
  
  // The cutoff frequency is midway through the transition band.
  double wc = (pass_freq + transition_bandwidth/2) / sample_freq * pi * 2;

  // Calculate fir_RES FIR tables for linear interpolation.
  for (int i = 0; i < fir_RES; i++) {
    double j_offset = double(i)/fir_RES;
    // Calculate FIR table. This is the sinc function, weighted by the
    // Kaiser window.
    for (int j = 0; j < fir_N; j++) {
      double jx = j - fir_N/2. - j_offset;
      double wt = wc*jx/f_cycles_per_sample;
      double temp = jx/(fir_N/2);
      double Kaiser =
	fabs(temp) <= 1 ? I0(beta*sqrt(1 - temp*temp))/I0beta : 0;
      double sincwt =
	fabs(wt) >= 1e-8 ? sin(wt)/wt : 1;
      double val =
	(1 << FIR_SHIFT)*filter_scale*f_samples_per_cycle*wc/pi*sincwt*Kaiser;
      fir[i * fir_N + j] = short(val + 0.5);
    }
  }

  // Allocate sample buffer.
  if (!sample) {
    sample = new short[RINGSIZE*2];
  }
  // Clear sample buffer.
  for (int j = 0; j < RINGSIZE*2; j++) {
    sample[j] = 0;
  }
  sample_index = 0;

  return true;
}

// ----------------------------------------------------------------------------
// SID clocking - 1 cycle.
// ----------------------------------------------------------------------------
void SID::clock()
{
  int i;

  // Clock amplitude modulators.
  for (i = 0; i < 3; i++) {
    voice[i].envelope.clock();
  }

  // Clock oscillators.
  for (i = 0; i < 3; i++) {
    voice[i].wave.clock();
  }

  // Synchronize oscillators.
  for (i = 0; i < 3; i++) {
    voice[i].wave.synchronize();
  }

  // Clock filter.
  filter.clock(voice[0].output(master_volume), voice[1].output(master_volume), voice[2].output(master_volume));

  // Clock external filter.
  extfilt.clock(filter.output());
}

// ----------------------------------------------------------------------------
// SID clocking with audio sampling.
// Fixpoint arithmetics is used.
//
// The example below shows how to clock the SID a specified amount of cycles
// while producing audio output:
//
// while (delta_t) {
//   bufindex += sid.clock(delta_t, buf + bufindex, buflength - bufindex);
//   write(dsp, buf, bufindex*2);
//   bufindex = 0;
// }
// 
// ----------------------------------------------------------------------------
int SID::clock(cycle_count& delta_t, short* buf, int n, int interleave)
{
  switch (sampling) {
  default:
  case SAMPLE_FAST:
  case SAMPLE_INTERPOLATE:
    return clock_interpolate(delta_t, buf, n, interleave);
  case SAMPLE_RESAMPLE:
    return clock_resample_interpolate(delta_t, buf, n, interleave);
  case SAMPLE_RESAMPLE_FASTMEM:
    return clock_resample_fast(delta_t, buf, n, interleave);
  }
}

// ----------------------------------------------------------------------------
// SID clocking with audio sampling - cycle based with linear sample
// interpolation.
//
// Here the chip is clocked every cycle. This yields higher quality
// sound since the samples are linearly interpolated, and since the
// external filter attenuates frequencies above 16kHz, thus reducing
// sampling noise.
// ----------------------------------------------------------------------------
RESID_INLINE
int SID::clock_interpolate(cycle_count& delta_t, short* buf, int n,
			   int interleave)
{
  int s = 0;
  int i;

  for (;;) {
    cycle_count next_sample_offset = sample_offset + cycles_per_sample;
    cycle_count delta_t_sample = next_sample_offset >> FIXP_SHIFT;
    if (delta_t_sample > delta_t) {
      break;
    }
    if (s >= n) {
      return s;
    }
    for (i = 0; i < delta_t_sample - 1; i++) {
      clock();
    }
    if (i < delta_t_sample) {
      sample_prev = output();
      clock();
    }

    delta_t -= delta_t_sample;
    sample_offset = next_sample_offset & FIXP_MASK;

    short sample_now = output();
    buf[s++*interleave] =
      sample_prev + (sample_offset*(sample_now - sample_prev) >> FIXP_SHIFT);
    sample_prev = sample_now;
  }

  for (i = 0; i < delta_t - 1; i++) {
    clock();
  }
  if (i < delta_t) {
    sample_prev = output();
    clock();
  }
  sample_offset -= delta_t << FIXP_SHIFT;
  delta_t = 0;
  return s;
}

static inline int convolve(const short *a, const short *b, int n)
{
    int out = 0;
#if defined(__MMX__) && (HAVE_MMINTRIN_H==1)
    union {
        __m64 m64;
        int i32[2];
    } tmp;
    tmp.i32[0] = 0;
    tmp.i32[1] = 0;    
    while (n >= 4) {
        tmp.m64 = _mm_add_pi32(tmp.m64,
                               _mm_madd_pi16(*((__m64 *)a),
                                             *((__m64 *)b)));
        a += 4;
        b += 4;
        n -= 4;
    }
    out = tmp.i32[0] + tmp.i32[1];
    _mm_empty();
#endif
    while (n --)
        out += (*(a++)) * (*(b++));
    return out;
}

// ----------------------------------------------------------------------------
// SID clocking with audio sampling - cycle based with audio resampling.
//
// This is the theoretically correct (and computationally intensive) audio
// sample generation. The samples are generated by resampling to the specified
// sampling frequency. The work rate is inversely proportional to the
// percentage of the bandwidth allocated to the filter transition band.
//
// This implementation is based on the paper "A Flexible Sampling-Rate
// Conversion Method", by J. O. Smith and P. Gosset, or rather on the
// expanded tutorial on the "Digital Audio Resampling Home Page":
// http://www-ccrma.stanford.edu/~jos/resample/
//
// By building shifted FIR tables with samples according to the
// sampling frequency, this implementation dramatically reduces the
// computational effort in the filter convolutions, without any loss
// of accuracy. The filter convolutions are also vectorizable on
// current hardware.
//
// Further possible optimizations are:
// * An equiripple filter design could yield a lower filter order, see
//   http://www.mwrf.com/Articles/ArticleID/7229/7229.html
// * The Convolution Theorem could be used to bring the complexity of
//   convolution down from O(n*n) to O(n*log(n)) using the Fast Fourier
//   Transform, see http://en.wikipedia.org/wiki/Convolution_theorem
// * Simply resampling in two steps can also yield computational
//   savings, since the transition band will be wider in the first step
//   and the required filter order is thus lower in this step.
//   Laurent Ganier has found the optimal intermediate sampling frequency
//   to be (via derivation of sum of two steps):
//     2 * pass_freq + sqrt [ 2 * pass_freq * orig_sample_freq
//       * (dest_sample_freq - 2 * pass_freq) / dest_sample_freq ]
//
// NB! the result of right shifting negative numbers is really
// implementation dependent in the C++ standard.
// ----------------------------------------------------------------------------
RESID_INLINE
int SID::clock_resample_interpolate(cycle_count& delta_t, short* buf, int n,
				    int interleave)
{
  int s = 0;

  for (;;) {
    cycle_count next_sample_offset = sample_offset + cycles_per_sample;
    cycle_count delta_t_sample = next_sample_offset >> FIXP_SHIFT;
    if (delta_t_sample > delta_t) {
      break;
    }
    if (s >= n) {
      return s;
    }
    for (int i = 0; i < delta_t_sample; i++) {
      clock();
      sample[sample_index] = sample[sample_index + RINGSIZE] = output();
      ++sample_index;
      sample_index &= RINGSIZE - 1;
    }
    delta_t -= delta_t_sample;
    sample_offset = next_sample_offset & FIXP_MASK;

    int fir_offset = sample_offset*fir_RES >> FIXP_SHIFT;
    int fir_offset_rmd = sample_offset*fir_RES & FIXP_MASK;
    short* fir_start = fir + fir_offset*fir_N;
    short* sample_start = sample + sample_index - fir_N + RINGSIZE - 1;

    // Convolution with filter impulse response.
    int v1 = convolve(sample_start, fir_start, fir_N);

    // Use next FIR table, wrap around to first FIR table using
    // the next sample.
    if (++fir_offset == fir_RES) {
      fir_offset = 0;
      ++sample_start;
    }
    fir_start = fir + fir_offset*fir_N;

    // Convolution with filter impulse response.
    int v2 = convolve(sample_start, fir_start, fir_N);

    // Linear interpolation.
    // fir_offset_rmd is equal for all samples, it can thus be factorized out:
    // sum(v1 + rmd*(v2 - v1)) = sum(v1) + rmd*(sum(v2) - sum(v1))
    int v = v1 + int(unsigned(fir_offset_rmd)*unsigned(v2 - v1) >> FIXP_SHIFT);

    v >>= FIR_SHIFT;

    // Saturated arithmetics to guard against 16 bit sample overflow.
    const int half = 1 << 15;
    if (v >= half) {
      v = half - 1;
    }
    else if (v < -half) {
      v = -half;
    }

    buf[s++*interleave] = v;
  }

  for (int i = 0; i < delta_t; i++) {
    clock();
    sample[sample_index] = sample[sample_index + RINGSIZE] = output();
    ++sample_index;
    sample_index &= RINGSIZE - 1;
  }
  sample_offset -= delta_t << FIXP_SHIFT;
  delta_t = 0;
  return s;
}


// ----------------------------------------------------------------------------
// SID clocking with audio sampling - cycle based with audio resampling.
// ----------------------------------------------------------------------------
RESID_INLINE
int SID::clock_resample_fast(cycle_count& delta_t, short* buf, int n,
			     int interleave)
{
  int s = 0;

  for (;;) {
    cycle_count next_sample_offset = sample_offset + cycles_per_sample;
    cycle_count delta_t_sample = next_sample_offset >> FIXP_SHIFT;
    if (delta_t_sample > delta_t) {
      break;
    }
    if (s >= n) {
      return s;
    }
    for (int i = 0; i < delta_t_sample; i++) {
      clock();
      sample[sample_index] = sample[sample_index + RINGSIZE] = output();
      ++sample_index;
      sample_index &= RINGSIZE - 1;
    }
    delta_t -= delta_t_sample;
    sample_offset = next_sample_offset & FIXP_MASK;

    int fir_offset = sample_offset*fir_RES >> FIXP_SHIFT;
    short* fir_start = fir + fir_offset*fir_N;
    short* sample_start = sample + sample_index - fir_N + RINGSIZE;

    // Convolution with filter impulse response.
    int v = convolve(sample_start, fir_start, fir_N);
    v >>= FIR_SHIFT;

    // Saturated arithmetics to guard against 16 bit sample overflow.
    const int half = 1 << 15;
    if (v >= half) {
      v = half - 1;
    }
    else if (v < -half) {
      v = -half;
    }

    buf[s++*interleave] = v;
  }

  for (int i = 0; i < delta_t; i++) {
    clock();
    sample[sample_index] = sample[sample_index + RINGSIZE] = output();
    ++sample_index;
    sample_index &= RINGSIZE - 1;
  }
  sample_offset -= delta_t << FIXP_SHIFT;
  delta_t = 0;
  return s;
}

/* ReSID API adaptation hacks */
void SID::set_chip_model(chip_model model) { }
void SID::set_voice_mask(reg4 mask) { }
void SID::enable_filter(bool enable) { }
void SID::adjust_filter_bias(double bias) { }
void SID::input(short sample) { }

} // namespace reSID_dtv
