Beispiel #1
0
        /// <summary>
        /// SID clocking with audio sampling - delta clocking picking nearest sample
        /// </summary>
        /// <param name="delta_t"></param>
        /// <param name="buf"></param>
        /// <param name="n"></param>
        /// <param name="interleave"></param>
        /// <returns></returns>
        protected int clock_fast(CycleCount delta_t, short[] buf, int n, int interleave)
        {
            int s = 0;

            for (; ;)
            {
                int next_sample_offset = sample_offset + cycles_per_sample + (1 << (FIXP_SHIFT - 1));
                int delta_t_sample     = next_sample_offset >> FIXP_SHIFT;
                if (delta_t_sample > delta_t.delta_t)
                {
                    break;
                }
                if (s >= n)
                {
                    return(s);
                }
                clock(delta_t_sample);
                delta_t.delta_t     -= delta_t_sample;
                sample_offset        = (next_sample_offset & FIXP_MASK) - (1 << (FIXP_SHIFT - 1));
                buf[s++ *interleave] = (short)output();
            }

            clock(delta_t.delta_t);
            sample_offset  -= delta_t.delta_t << FIXP_SHIFT;
            delta_t.delta_t = 0;
            return(s);
        }
Beispiel #2
0
        /// <summary>
        /// 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
        /// </summary>
        /// <param name="delta_t"></param>
        /// <param name="buf"></param>
        /// <param name="n"></param>
        /// <param name="interleave"></param>
        /// <returns></returns>
        protected int clock_interpolate(CycleCount delta_t, short[] buf, int n, int interleave)
        {
            int s = 0;
            int i;

            for (; ;)
            {
                int next_sample_offset = sample_offset + cycles_per_sample;
                int delta_t_sample     = next_sample_offset >> FIXP_SHIFT;
                if (delta_t_sample > delta_t.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 = (short)output();
                    clock();
                }

                delta_t.delta_t -= delta_t_sample;
                sample_offset    = next_sample_offset & FIXP_MASK;

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

            for (i = 0; i < delta_t.delta_t - 1; i++)
            {
                clock();
            }
            if (i < delta_t.delta_t)
            {
                sample_prev = (short)output();
                clock();
            }
            sample_offset  -= delta_t.delta_t << FIXP_SHIFT;
            delta_t.delta_t = 0;
            return(s);
        }
Beispiel #3
0
        /// <summary>
        /// SID clocking with audio sampling
        /// </summary>
        /// <param name="delta_t"></param>
        /// <param name="buf"></param>
        /// <param name="n"></param>
        /// <param name="interleave"></param>
        /// <returns></returns>
        public int clock(CycleCount delta_t, short[] buf, int n, int interleave)
        {
            switch (sampling)
            {
            default:
            case SIDDefs.sampling_method.SAMPLE_FAST:
                return(clock_fast(delta_t, buf, n, interleave));

            case SIDDefs.sampling_method.SAMPLE_INTERPOLATE:
                return(clock_interpolate(delta_t, buf, n, interleave));

            case SIDDefs.sampling_method.SAMPLE_RESAMPLE_INTERPOLATE:
                return(clock_resample_interpolate(delta_t, buf, n, interleave));

            case SIDDefs.sampling_method.SAMPLE_RESAMPLE_FAST:
                return(clock_resample_fast(delta_t, buf, n, interleave));
            }
        }
Beispiel #4
0
        /// <summary>
        /// SID clocking with audio sampling - cycle based with audio resampling
        /// </summary>
        /// <param name="delta_t"></param>
        /// <param name="buf"></param>
        /// <param name="n"></param>
        /// <param name="interleave"></param>
        /// <returns></returns>
        protected int clock_resample_fast(CycleCount delta_t, short[] buf, int n, int interleave)
        {
            int s = 0;

            for (; ;)
            {
                int next_sample_offset = sample_offset + cycles_per_sample;
                int delta_t_sample     = next_sample_offset >> FIXP_SHIFT;
                if (delta_t_sample > delta_t.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] = (short)output();
                    ++sample_index;
                    sample_index &= 0x3fff;
                }
                delta_t.delta_t -= delta_t_sample;
                sample_offset    = next_sample_offset & FIXP_MASK;

                int fir_offset   = sample_offset * fir_RES >> FIXP_SHIFT;
                int fir_start    = (fir_offset * fir_N);
                int sample_start = (sample_index - fir_N + RINGSIZE);

                // Convolution with filter impulse response.
                int v = 0;
                for (int j = 0; j < fir_N; j++)
                {
                    v += sample[sample_start + j] * fir[fir_start + j];
                }

                v >>= FIR_SHIFT;

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

                buf[s++ *interleave] = (short)v;
            }

            for (int i = 0; i < delta_t.delta_t; i++)
            {
                clock();
                sample[sample_index] = sample[sample_index + RINGSIZE] = (short)output();
                ++sample_index;
                sample_index &= 0x3fff;
            }
            sample_offset  -= delta_t.delta_t << FIXP_SHIFT;
            delta_t.delta_t = 0;
            return(s);
        }
Beispiel #5
0
        /// <summary>
        /// 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 ]
        /// </summary>
        /// <param name="delta_t"></param>
        /// <param name="buf"></param>
        /// <param name="n"></param>
        /// <param name="interleave"></param>
        /// <returns></returns>
        protected int clock_resample_interpolate(CycleCount delta_t, short[] buf, int n, int interleave)
        {
            int s = 0;

            for (; ;)
            {
                int next_sample_offset = sample_offset + cycles_per_sample;
                int delta_t_sample     = next_sample_offset >> FIXP_SHIFT;
                if (delta_t_sample > delta_t.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] = (short)output();
                    ++sample_index;
                    sample_index &= 0x3fff;
                }
                delta_t.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;
                int fir_start      = (fir_offset * fir_N);
                int sample_start   = (sample_index - fir_N + RINGSIZE);

                // Convolution with filter impulse response.
                int v1 = 0;
                for (int j = 0; j < fir_N; j++)
                {
                    v1 += sample[sample_start + j] * fir[fir_start + j];
                }

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

                // Convolution with filter impulse response.
                int v2 = 0;
                for (int j = 0; j < fir_N; j++)
                {
                    v2 += sample[sample_start + j] * fir[fir_start + j];
                }

                // 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 + (fir_offset_rmd * (v2 - v1) >> FIXP_SHIFT);

                v >>= FIR_SHIFT;

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

                buf[s++ *interleave] = (short)v;
            }

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