Filter8580.h
/*
* 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"
namespace reSIDfp
{
class antiDenormalNoise
{
private:
uint32_t rand_state;
private:
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);
}
};
class Filter8580 : public Filter
{
private:
double highFreq;
float Vlp;
float Vbp;
float Vhp;
float w0;
float _1_div_Q;
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);
void updatedCenterFrequency() { w0 = static_cast<float>(2. * M_PI * highFreq * fc / 2047. / 1e6); }
void updatedResonance() { _1_div_Q = static_cast<float>(pow(2., (4 - res) / 8.)); }
void input(int input) { ve = input << 4; }
void updatedMixing() {}
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)
{
voice1 >>= 7;
voice2 >>= 7;
voice3 >>= 7;
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 - Vi + 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);
if (lp)
{
Vof += Vlp;
}
if (bp)
{
Vof += Vbp;
}
if (hp)
{
Vof += Vhp;
}
return static_cast<int>(Vof) * vol >> 4;
}
} // namespace reSIDfp
#endif
#endif
reSIDfp::Filter8580
Definition: Filter8580.h:85
reSIDfp::antiDenormalNoise
Definition: Filter8580.h:47
reSIDfp
Definition: Dac.cpp:25
reSIDfp::Filter8580::setFilterCurve
void setFilterCurve(double curvePosition)
Definition: Filter8580.h:145
reSIDfp::Filter8580::updatedResonance
void updatedResonance()
Definition: Filter8580.h:134
reSIDfp::Filter8580::updatedCenterFrequency
void updatedCenterFrequency()
Definition: Filter8580.h:125
reSIDfp::Filter8580::clock
int clock(int voice1, int voice2, int voice3)
Definition: Filter8580.h:158
reSIDfp::Filter8580::updatedMixing
void updatedMixing()
Definition: Filter8580.h:138
reSIDfp::Filter
Definition: Filter.h:32