Cog/Frameworks/libsidplay/sidplay-residfp-code/.svn/pristine/b7/b74bb59a28b099f20f32ebaed55075ca23a8ada9.svn-base

198 lines
4.7 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* This file is part of libsidplayfp, a SID player engine.
*
* Copyright 2011-2014 Leandro Nini <drfiemost@users.sourceforge.net>
* Copyright 2007-2010 Antti Lankila
* Copyright 2004,2010 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef FILTER8580_H
#define FILTER8580_H
#include <cmath>
#include <cstring>
#include <stdint.h>
#include "siddefs-fp.h"
#include "Filter.h"
#include "sidcxx11.h"
namespace reSIDfp
{
/**
* Simple white noise generator.
* Generates small low quality pseudo random numbers
* useful to prevent float denormals.
*
* Based on the paper [Denormal numbers in floating point signal
* processing applications](http://ldesoras.free.fr/prod.html#doc_denormal)
* from Laurent de Soras.
*/
class antiDenormalNoise
{
private:
uint32_t rand_state;
private:
/**
* Reduce 32bit integer to float with a magnitude of about 10^20.
*/
static inline float reduce(uint32_t val)
{
// FIXME may not be fully portable
// This code assumes IEEE-754 floating point representation
// and same endianness for integers and floats
const uint32_t mantissa = val & 0x807F0000; // Keep only most significant bits
const uint32_t flt_rnd = mantissa | 0x1E000000; // Set exponent
float temp;
memcpy(&temp, &flt_rnd, sizeof(float));
return temp;
}
public:
antiDenormalNoise() :
rand_state(1) {}
inline float get()
{
// LCG from Numerical Recipes
rand_state = rand_state * 1664525 + 1013904223;
return reduce(rand_state);
}
};
/**
* Filter for 8580 chip based on simple linear approximation
* of the FC control.
*/
class Filter8580 final : public Filter
{
private:
/// Cutoff frequency in Hertz
double highFreq;
/// Lowpass filter voltage
float Vlp;
/// Bandpass filter voltage
float Vbp;
/// Highpass filter voltage
float Vhp;
float w0;
/// Resonance parameter
float _1_div_Q;
/// External input voltage
int ve;
antiDenormalNoise noise;
public:
Filter8580() :
highFreq(12500.),
Vlp(0.f),
Vbp(0.f),
Vhp(0.f),
w0(0.f),
_1_div_Q(0.f),
ve(0) {}
int clock(int voice1, int voice2, int voice3) override;
/**
* Set filter cutoff frequency.
*/
void updatedCenterFrequency() override { w0 = static_cast<float>(2. * M_PI * highFreq * fc / 2047. / 1e6); }
/**
* Set filter resonance.
*
* The following function for 1/Q has been modeled in the MOS 8580:
*
* 1/Q = 2^(1/2)*2^(-x/8) = 2^(1/2 - x/8) = 2^((4 - x)/8)
*
* @param res the new resonance value
*/
void updateResonance(unsigned char res) override { _1_div_Q = static_cast<float>(pow(2., (4 - res) / 8.)); }
void input(int input) override { ve = input << 4; }
void updatedMixing() override {}
/**
* Set filter curve type based on single parameter.
*
* @param curvePosition filter's center frequency expressed in Hertz, default is 12500
*/
void setFilterCurve(double curvePosition) { highFreq = curvePosition; }
};
} // namespace reSIDfp
#if RESID_INLINING || defined(FILTER8580_CPP)
#include <cassert>
namespace reSIDfp
{
RESID_INLINE
int Filter8580::clock(int voice1, int voice2, int voice3)
{
int Vi = 0;
int Vo = 0;
(filt1 ? Vi : Vo) += voice1;
(filt2 ? Vi : Vo) += voice2;
// NB! Voice 3 is not silenced by voice3off if it is routed
// through the filter.
if (filt3) Vi += voice3;
else if (!voice3off) Vo += voice3;
(filtE ? Vi : Vo) += ve;
Vlp -= w0 * Vbp;
Vbp -= w0 * Vhp;
Vhp = (Vbp * _1_div_Q) - Vlp - static_cast<float>(Vi >> 7) + noise.get();
assert(std::fpclassify(Vlp) != FP_SUBNORMAL);
assert(std::fpclassify(Vbp) != FP_SUBNORMAL);
assert(std::fpclassify(Vhp) != FP_SUBNORMAL);
float Vof = static_cast<float>(Vo >> 7);
if (lp) Vof += Vlp;
if (bp) Vof += Vbp;
if (hp) Vof += Vhp;
return static_cast<int>(floor(Vof + 0.5f)) * vol >> 4;
}
} // namespace reSIDfp
#endif
#endif