From a4d923cbe664d1c9d8af1ac768e069d2dc70829f Mon Sep 17 00:00:00 2001 From: Christian Speckner Date: Wed, 8 Aug 2018 23:09:46 +0200 Subject: [PATCH] Remove high frequency artifacts from Lanczos resampling. Run the TIA signal through a high pass with 10Hz cutoff. --- src/common/audio/HighPass.cxx | 41 ++++++++++++++++++++++++++ src/common/audio/HighPass.hxx | 42 +++++++++++++++++++++++++++ src/common/audio/LanczosResampler.cxx | 10 +++++-- src/common/audio/LanczosResampler.hxx | 5 ++++ src/common/audio/module.mk | 3 +- 5 files changed, 97 insertions(+), 4 deletions(-) create mode 100644 src/common/audio/HighPass.cxx create mode 100644 src/common/audio/HighPass.hxx diff --git a/src/common/audio/HighPass.cxx b/src/common/audio/HighPass.cxx new file mode 100644 index 000000000..e4846012b --- /dev/null +++ b/src/common/audio/HighPass.cxx @@ -0,0 +1,41 @@ +//============================================================================ +// +// SSSS tt lll lll +// SS SS tt ll ll +// SS tttttt eeee ll ll aaaa +// SSSS tt ee ee ll ll aa +// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" +// SS SS tt ee ll ll aa aa +// SSSS ttt eeeee llll llll aaaaa +// +// Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony +// and the Stella Team +// +// See the file "License.txt" for information on usage and redistribution of +// this file, and for a DISCLAIMER OF ALL WARRANTIES. +//============================================================================ + +#include +#ifndef M_PI + #define M_PI 3.14159265358979323846f +#endif + +#include "HighPass.hxx" + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +HighPass::HighPass(float cutOffFrequency, float frequency) + : myLastValueIn(0), + myLastValueOut(0), + myAlpha(1.f / (1.f + 2.f*M_PI*cutOffFrequency/frequency)) +{} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +float HighPass::apply(float valueIn) +{ + float valueOut = myAlpha * (myLastValueOut + valueIn - myLastValueIn); + + myLastValueIn = valueIn; + myLastValueOut = valueOut; + + return valueOut; +} diff --git a/src/common/audio/HighPass.hxx b/src/common/audio/HighPass.hxx new file mode 100644 index 000000000..d479ce874 --- /dev/null +++ b/src/common/audio/HighPass.hxx @@ -0,0 +1,42 @@ +//============================================================================ +// +// SSSS tt lll lll +// SS SS tt ll ll +// SS tttttt eeee ll ll aaaa +// SSSS tt ee ee ll ll aa +// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" +// SS SS tt ee ll ll aa aa +// SSSS ttt eeeee llll llll aaaaa +// +// Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony +// and the Stella Team +// +// See the file "License.txt" for information on usage and redistribution of +// this file, and for a DISCLAIMER OF ALL WARRANTIES. +//============================================================================ + +#ifndef HIGH_PASS_HXX +#define HIGH_PASS_HXX + +class HighPass +{ + public: + + HighPass(float cutOffFrequency, float frequency); + + float apply(float value); + + private: + + float myLastValueIn; + + float myLastValueOut; + + float myAlpha; + + private: + + HighPass() = delete; +}; + +#endif // HIGH_PASS_HXX diff --git a/src/common/audio/LanczosResampler.cxx b/src/common/audio/LanczosResampler.cxx index 25ecd82ec..642f37274 100644 --- a/src/common/audio/LanczosResampler.cxx +++ b/src/common/audio/LanczosResampler.cxx @@ -25,6 +25,7 @@ namespace { constexpr float CLIPPING_FACTOR = 0.75; + constexpr float HIGH_PASS_CUT_OFF = 10; uInt32 reducedDenominator(uInt32 n, uInt32 d) { @@ -78,6 +79,9 @@ LanczosResampler::LanczosResampler( myCurrentFragment(nullptr), myFragmentIndex(0), myIsUnderrun(true), + myHighPassL(HIGH_PASS_CUT_OFF, formatFrom.sampleRate), + myHighPassR(HIGH_PASS_CUT_OFF, formatFrom.sampleRate), + myHighPass(HIGH_PASS_CUT_OFF, formatFrom.sampleRate), myTimeIndex(0) { myPrecomputedKernels = make_unique(myPrecomputedKernelCount * myKernelSize); @@ -184,11 +188,11 @@ inline void LanczosResampler::shiftSamples(uInt32 samplesToShift) { while (samplesToShift-- > 0) { if (myFormatFrom.stereo) { - myBufferL->shift(myCurrentFragment[2*myFragmentIndex] / static_cast(0x7fff)); - myBufferR->shift(myCurrentFragment[2*myFragmentIndex + 1] / static_cast(0x7fff)); + myBufferL->shift(myHighPassL.apply(myCurrentFragment[2*myFragmentIndex] / static_cast(0x7fff))); + myBufferR->shift(myHighPassR.apply(myCurrentFragment[2*myFragmentIndex + 1] / static_cast(0x7fff))); } else - myBuffer->shift(myCurrentFragment[myFragmentIndex] / static_cast(0x7fff)); + myBuffer->shift(myHighPass.apply(myCurrentFragment[myFragmentIndex] / static_cast(0x7fff))); myFragmentIndex++; diff --git a/src/common/audio/LanczosResampler.hxx b/src/common/audio/LanczosResampler.hxx index 0f92f48d5..17bcfefaa 100644 --- a/src/common/audio/LanczosResampler.hxx +++ b/src/common/audio/LanczosResampler.hxx @@ -21,6 +21,7 @@ #include "bspf.hxx" #include "Resampler.hxx" #include "ConvolutionBuffer.hxx" +#include "HighPass.hxx" class LanczosResampler : public Resampler { @@ -59,6 +60,10 @@ class LanczosResampler : public Resampler uInt32 myFragmentIndex; bool myIsUnderrun; + HighPass myHighPassL; + HighPass myHighPassR; + HighPass myHighPass; + uInt32 myTimeIndex; }; diff --git a/src/common/audio/module.mk b/src/common/audio/module.mk index 67ae01063..6c51ab2a0 100644 --- a/src/common/audio/module.mk +++ b/src/common/audio/module.mk @@ -3,7 +3,8 @@ MODULE := src/common/audio MODULE_OBJS := \ src/common/audio/SimpleResampler.o \ src/common/audio/ConvolutionBuffer.o \ - src/common/audio/LanczosResampler.o + src/common/audio/LanczosResampler.o \ + src/common/audio/HighPass.o MODULE_DIRS += \ src/emucore/tia