// --------------------------------------------------------------------------- // This file is part of reSID, a MOS6581 SID emulator engine. // Copyright (C) 2004 Dag Lem // // 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 // --------------------------------------------------------------------------- #include "sid.h" #include #include extern float convolve(const float *a, const float *b, int n); extern float convolve_sse(const float *a, const float *b, int n); enum host_cpu_feature { HOST_CPU_MMX=1, HOST_CPU_SSE=2, HOST_CPU_SSE2=4, HOST_CPU_SSE3=8 }; /* This code is appropriate for 32-bit and 64-bit x86 CPUs. */ #if defined(__x86_64__) || defined(__i386__) || defined(_M_IX86) || (defined(_M_X64) && !(defined(_MSC_VER) && !defined(__clang__))) struct cpu_x86_regs_s { unsigned int eax; unsigned int ebx; unsigned int ecx; unsigned int edx; }; typedef struct cpu_x86_regs_s cpu_x86_regs_t; static cpu_x86_regs_t get_cpuid_regs(unsigned int index) { cpu_x86_regs_t retval; #if defined(_MSC_VER) && !defined(__clang__) /* MSVC assembly */ __asm { mov eax, [index] cpuid mov [retval.eax], eax mov [retval.ebx], ebx mov [retval.ecx], ecx mov [retval.edx], edx } #else /* GNU assembly */ asm("movl %1, %%eax; cpuid; movl %%eax, %0;" : "=m" (retval.eax) : "r" (index) : "eax", "ebx", "ecx", "edx"); asm("movl %1, %%eax; cpuid; movl %%ebx, %0;" : "=m" (retval.ebx) : "r" (index) : "eax", "ebx", "ecx", "edx"); asm("movl %1, %%eax; cpuid; movl %%ecx, %0;" : "=m" (retval.ecx) : "r" (index) : "eax", "ebx", "ecx", "edx"); asm("movl %1, %%eax; cpuid; movl %%edx, %0;" : "=m" (retval.edx) : "r" (index) : "eax", "ebx", "ecx", "edx"); #endif return retval; } static int host_cpu_features_by_cpuid(void) { cpu_x86_regs_t regs = get_cpuid_regs(1); int features = 0; if (regs.edx & (1 << 23)) features |= HOST_CPU_MMX; if (regs.edx & (1 << 25)) features |= HOST_CPU_SSE; if (regs.edx & (1 << 26)) features |= HOST_CPU_SSE2; if (regs.ecx & (1 << 0)) features |= HOST_CPU_SSE3; return features; } #if (RESID_USE_SSE==1) static int host_cpu_features(void) { static int features = 0; static int features_detected = 0; /* 32-bit only */ #if defined(__i386__) || (defined(_MSC_VER) && defined(_M_IX86)) unsigned long temp1, temp2; #endif if (features_detected) return features; features_detected = 1; #if defined(_MSC_VER) && defined(_M_IX86) /* MSVC compatible assembly appropriate for 32-bit Windows */ /* see if we are dealing with a cpu that has the cpuid instruction */ __asm { pushf pop eax mov [temp1], eax xor eax, 0x200000 push eax popf pushf pop eax mov [temp2], eax push [temp1] popf } #endif #if defined(__i386__) /* GNU assembly */ asm("pushfl; popl %%eax; movl %%eax, %0; xorl $0x200000, %%eax; pushl %%eax; popfl; pushfl; popl %%eax; movl %%eax, %1; pushl %0; popfl " : "=r" (temp1), "=r" (temp2) : : "eax"); #endif #if defined(__i386__) || (defined(_MSC_VER) && defined(_M_IX86)) temp1 &= 0x200000; temp2 &= 0x200000; if (temp1 == temp2) { /* no cpuid support, so we can't test for SSE availability -> false */ return 0; } #endif /* find the highest supported cpuid function, returned in %eax */ if (get_cpuid_regs(0).eax < 1) { /* no cpuid 1 function, we can't test for features -> no features */ return 0; } features = host_cpu_features_by_cpuid(); return features; } #else /* !__x86_64__ && !__i386__ && !_MSC_VER */ static int host_cpu_features(void) { return 0; } #endif #endif float SIDFP::kinked_dac(const int x, const float nonlinearity, const int max) { float value = 0.f; int bit = 1; float weight = 1.f; const float dir = 2.0f * nonlinearity; for (int i = 0; i < max; i ++) { if (x & bit) value += weight; bit <<= 1; weight *= dir; } return value / (weight / nonlinearity) * (1 << max); } // ---------------------------------------------------------------------------- // Constructor. // ---------------------------------------------------------------------------- SIDFP::SIDFP() { #if (RESID_USE_SSE==1) can_use_sse = (host_cpu_features() & HOST_CPU_SSE) != 0; #else can_use_sse = false; #endif // 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_INTERPOLATE, 44100); bus_value = 0; bus_value_ttl = 0; input(0); } // ---------------------------------------------------------------------------- // Destructor. // ---------------------------------------------------------------------------- SIDFP::~SIDFP() { delete[] sample; delete[] fir; } // ---------------------------------------------------------------------------- // Set chip model. // ---------------------------------------------------------------------------- void SIDFP::set_chip_model(chip_model model) { for (int i = 0; i < 3; i++) { voice[i].set_chip_model(model); } filter.set_chip_model(model); extfilt.set_chip_model(model); } /* nonlinear DAC support, set 1 for 8580 / no effect, about 0.96 otherwise */ void SIDFP::set_voice_nonlinearity(float nl) { for (int i = 0; i < 3; i++) { voice[i].set_nonlinearity(nl); } } // ---------------------------------------------------------------------------- // SID reset. // ---------------------------------------------------------------------------- void SIDFP::reset() { for (int i = 0; i < 3; i++) { voice[i].reset(); } filter.reset(); extfilt.reset(); bus_value = 0; bus_value_ttl = 0; } // ---------------------------------------------------------------------------- // Write 16-bit sample to audio input. // NB! The caller is responsible for keeping the value within 16 bits. // Note that to mix in an external audio signal, the signal should be // resampled to 1MHz first to avoid sampling noise. // ---------------------------------------------------------------------------- void SIDFP::input(int sample) { // Voice outputs are 20 bits. Scale up to match three voices in order // to facilitate simulation of the MOS8580 "digi boost" hardware hack. ext_in = (float) ( (sample << 4) * 3 ); } float SIDFP::output() { const float range = 1 << 15; return extfilt.output() / (4095.f * 255.f * 3.f * 1.5f / range); } // ---------------------------------------------------------------------------- // 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 SIDFP::read(reg8 offset) { switch (offset) { case 0x19: return potx.readPOT(); case 0x1a: return poty.readPOT(); case 0x1b: return voice[2].wave.readOSC(); case 0x1c: return voice[2].envelope.readENV(); default: return bus_value; } } // ---------------------------------------------------------------------------- // Write registers. // ---------------------------------------------------------------------------- void SIDFP::write(reg8 offset, reg8 value) { bus_value = value; bus_value_ttl = 0x4000; 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 0x15: filter.writeFC_LO(value); break; case 0x16: filter.writeFC_HI(value); break; case 0x17: filter.writeRES_FILT(value); break; case 0x18: filter.writeMODE_VOL(value); break; default: break; } } // ---------------------------------------------------------------------------- // Constructor. // ---------------------------------------------------------------------------- SIDFP::State::State() { int i; for (i = 0; i < 0x20; i++) { sid_register[i] = 0; } bus_value = 0; bus_value_ttl = 0; for (i = 0; i < 3; i++) { accumulator[i] = 0; shift_register[i] = 0x7ffff8; rate_counter[i] = 0; rate_counter_period[i] = 9; exponential_counter[i] = 0; exponential_counter_period[i] = 1; envelope_counter[i] = 0; envelope_state[i] = EnvelopeGeneratorFP::RELEASE; hold_zero[i] = true; } } // ---------------------------------------------------------------------------- // Read state. // ---------------------------------------------------------------------------- SIDFP::State SIDFP::read_state() { State state; int i, j; for (i = 0, j = 0; i < 3; i++, j += 7) { WaveformGeneratorFP& wave = voice[i].wave; EnvelopeGeneratorFP& 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.fc & 0x007; state.sid_register[j++] = filter.fc >> 3; state.sid_register[j++] = (filter.res << 4) | filter.filt; state.sid_register[j++] = (filter.voice3off ? 0x80 : 0) | (filter.hp_bp_lp << 4) | 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; state.bus_value_ttl = bus_value_ttl; 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 SIDFP::write_state(const State& state) { int i; for (i = 0; i <= 0x18; i++) { write(i, state.sid_register[i]); } bus_value = state.bus_value; bus_value_ttl = state.bus_value_ttl; 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 filter. // ---------------------------------------------------------------------------- void SIDFP::enable_filter(bool enable) { filter.enable_filter(enable); } // ---------------------------------------------------------------------------- // Enable external filter. // ---------------------------------------------------------------------------- void SIDFP::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 SIDFP::I0(double x) { // Max error acceptable in I0 could be 1e-6, which gives that 96 dB already. // I'm overspecify these errors to get a beautiful FFT dump of the FIR. 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 SIDFP::set_sampling_parameters(float clock_freq, sampling_method method, float sample_freq, float pass_freq) { clock_frequency = clock_freq; sampling = method; filter.set_clock_frequency(clock_freq); extfilt.set_clock_frequency(clock_freq); adjust_sampling_frequency(sample_freq); sample_offset = 0; sample_prev = 0; // FIR initialization is only necessary for resampling. if (method != SAMPLE_RESAMPLE_INTERPOLATE) { 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; // 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 * M_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 (fir_N > RINGSIZE - 1) return false; /* Error is bound by 1.234 / L^2 */ fir_RES = (int) (sqrt(1.234 * (1 << bits)) / f_cycles_per_sample + 0.5); } // Allocate memory for FIR tables. delete[] fir; fir = new float[fir_N*fir_RES]; // The cutoff frequency is midway through the transition band. double wc = (pass_freq + transition_bandwidth/2) / sample_freq * M_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; fir[i * fir_N + j] = (float) (f_samples_per_cycle*wc/M_PI*sincwt*Kaiser); } } // Allocate sample buffer. if (!sample) { sample = new float[RINGSIZE*2]; } // Clear sample buffer. for (int j = 0; j < RINGSIZE*2; j++) { sample[j] = 0; } sample_index = 0; return true; } // ---------------------------------------------------------------------------- // Adjustment of SID sampling frequency. // // In some applications, e.g. a C64 emulator, it can be desirable to // synchronize sound with a timer source. This is supported by adjustment of // the SID sampling frequency. // // NB! Adjustment of the sampling frequency may lead to noticeable shifts in // frequency, and should only be used for interactive applications. Note also // that any adjustment of the sampling frequency will change the // characteristics of the resampling filter, since the filter is not rebuilt. // ---------------------------------------------------------------------------- void SIDFP::adjust_sampling_frequency(float sample_freq) { cycles_per_sample = clock_frequency/sample_freq; } void SIDFP::age_bus_value(cycle_count n) { if (bus_value_ttl != 0) { bus_value_ttl -= n; if (bus_value_ttl <= 0) { bus_value = 0; bus_value_ttl = 0; } } } // ---------------------------------------------------------------------------- // SID clocking - 1 cycle. // ---------------------------------------------------------------------------- void SIDFP::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. extfilt.clock(filter.clock(voice[0].output(), voice[1].output(), voice[2].output(), ext_in)); } // ---------------------------------------------------------------------------- // 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 SIDFP::clock(cycle_count& delta_t, short* buf, int n, int interleave) { /* XXX I assume n is generally large enough for delta_t here... */ age_bus_value(delta_t); int res; switch (sampling) { default: case SAMPLE_INTERPOLATE: res = clock_interpolate(delta_t, buf, n, interleave); break; case SAMPLE_RESAMPLE_INTERPOLATE: res = clock_resample_interpolate(delta_t, buf, n, interleave); break; } filter.nuke_denormals(); extfilt.nuke_denormals(); return res; } // ---------------------------------------------------------------------------- // 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 SIDFP::clock_interpolate(cycle_count& delta_t, short* buf, int n, int interleave) { int s = 0; int i; for (;;) { float next_sample_offset = sample_offset + cycles_per_sample; int delta_t_sample = (int) next_sample_offset; 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 - delta_t_sample; float sample_now = output(); int v = (int)(sample_prev + (sample_offset * (sample_now - sample_prev))); // 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; 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; delta_t = 0; return s; } // ---------------------------------------------------------------------------- // 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 SIDFP::clock_resample_interpolate(cycle_count& delta_t, short* buf, int n, int interleave) { int s = 0; for (;;) { float next_sample_offset = sample_offset + cycles_per_sample; /* full clocks left to next sample */ int delta_t_sample = (int) next_sample_offset; if (delta_t_sample > delta_t || s >= n) break; /* clock forward delta_t_sample samples */ 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; /* Phase of the sample in terms of clock, [0 .. 1[. */ sample_offset = next_sample_offset - (float) delta_t_sample; /* find the first of the nearest fir tables close to the phase */ float fir_offset_rmd = sample_offset * fir_RES; int fir_offset = (int) fir_offset_rmd; /* [0 .. 1[ */ fir_offset_rmd -= (float) fir_offset; /* find fir_N most recent samples, plus one extra in case the FIR wraps. */ float* sample_start = sample + sample_index - fir_N + RINGSIZE - 1; float v1 = #if (RESID_USE_SSE==1) can_use_sse ? convolve_sse(sample_start, fir + fir_offset*fir_N, fir_N) : #endif convolve(sample_start, fir + fir_offset*fir_N, fir_N); // Use next FIR table, wrap around to first FIR table using // previous sample. if (++ fir_offset == fir_RES) { fir_offset = 0; ++ sample_start; } float v2 = #if (RESID_USE_SSE==1) can_use_sse ? convolve_sse(sample_start, fir + fir_offset*fir_N, fir_N) : #endif convolve(sample_start, fir + fir_offset*fir_N, fir_N); // Linear interpolation between the sinc tables yields good approximation // for the exact value. int v = (int) (v1 + fir_offset_rmd * (v2 - v1)); // 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; } /* clock forward delta_t samples */ 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 -= (float) delta_t; delta_t = 0; return s; }