mirror of
https://github.com/libretro/gambatte-libretro.git
synced 2024-11-27 01:40:23 +00:00
Cleanup more stuff we don't need
This commit is contained in:
parent
281880de9a
commit
440e49b83d
@ -1,7 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
echo "cd libgambatte && scons"
|
|
||||||
(cd libgambatte && scons) || exit
|
|
||||||
|
|
||||||
echo "cd gambatte_qt && qmake && make"
|
|
||||||
(cd gambatte_qt && qmake && make)
|
|
@ -1,7 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
echo "cd libgambatte && scons"
|
|
||||||
(cd libgambatte && scons) || exit
|
|
||||||
|
|
||||||
echo "cd gambatte_sdl && scons"
|
|
||||||
(cd gambatte_sdl && scons)
|
|
16
clean.sh
16
clean.sh
@ -1,16 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
echo "cd gambatte_qt && make distclean"
|
|
||||||
(cd gambatte_qt && make distclean)
|
|
||||||
|
|
||||||
echo "cd gambatte_sdl && scons -c"
|
|
||||||
(cd gambatte_sdl && scons -c)
|
|
||||||
|
|
||||||
echo "cd libgambatte && scons -c"
|
|
||||||
(cd libgambatte && scons -c)
|
|
||||||
|
|
||||||
echo "rm -f *gambatte*/config.log"
|
|
||||||
rm -f *gambatte*/config.log
|
|
||||||
|
|
||||||
echo "rm -rf *gambatte*/.scon*"
|
|
||||||
rm -rf *gambatte*/.scon*
|
|
@ -1,56 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2008 by Sindre Aamås *
|
|
||||||
* aamas@stud.ntnu.no *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU General Public License version 2 as *
|
|
||||||
* published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 version 2 for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License *
|
|
||||||
* version 2 along with this program; if not, write to the *
|
|
||||||
* Free Software Foundation, Inc., *
|
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
||||||
***************************************************************************/
|
|
||||||
#include "adaptivesleep.h"
|
|
||||||
|
|
||||||
usec_t AdaptiveSleep::sleepUntil(usec_t base, usec_t inc) {
|
|
||||||
usec_t now = getusecs();
|
|
||||||
usec_t diff = now - base;
|
|
||||||
|
|
||||||
if (diff >= inc)
|
|
||||||
return diff - inc;
|
|
||||||
|
|
||||||
diff = inc - diff;
|
|
||||||
|
|
||||||
if (diff > oversleep + oversleepVar) {
|
|
||||||
diff -= oversleep + oversleepVar;
|
|
||||||
usecsleep(diff);
|
|
||||||
const usec_t ideal = now + diff;
|
|
||||||
now = getusecs();
|
|
||||||
|
|
||||||
{
|
|
||||||
usec_t curOversleep = now - ideal;
|
|
||||||
|
|
||||||
if (negate(curOversleep) < curOversleep)
|
|
||||||
curOversleep = 0;
|
|
||||||
|
|
||||||
oversleepVar = (oversleepVar * 15 + (curOversleep < oversleep ? oversleep - curOversleep : curOversleep - oversleep) + 8) >> 4;
|
|
||||||
oversleep = (oversleep * 15 + curOversleep + 8) >> 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
noSleep = 60;
|
|
||||||
} else if (--noSleep == 0) {
|
|
||||||
noSleep = 60;
|
|
||||||
oversleep = oversleepVar = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (now - base < inc)
|
|
||||||
now = getusecs();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
@ -1,34 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2008 by Sindre Aamås *
|
|
||||||
* aamas@stud.ntnu.no *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU General Public License version 2 as *
|
|
||||||
* published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 version 2 for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License *
|
|
||||||
* version 2 along with this program; if not, write to the *
|
|
||||||
* Free Software Foundation, Inc., *
|
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
||||||
***************************************************************************/
|
|
||||||
#ifndef ADAPTIVE_SLEEP_H
|
|
||||||
#define ADAPTIVE_SLEEP_H
|
|
||||||
|
|
||||||
#include "usec.h"
|
|
||||||
|
|
||||||
class AdaptiveSleep {
|
|
||||||
usec_t oversleep;
|
|
||||||
usec_t oversleepVar;
|
|
||||||
unsigned noSleep;
|
|
||||||
|
|
||||||
public:
|
|
||||||
AdaptiveSleep() : oversleep(0), oversleepVar(0), noSleep(60) {}
|
|
||||||
usec_t sleepUntil(usec_t base, usec_t inc);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,94 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2008 by Sindre Aamås *
|
|
||||||
* aamas@stud.ntnu.no *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU General Public License version 2 as *
|
|
||||||
* published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 version 2 for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License *
|
|
||||||
* version 2 along with this program; if not, write to the *
|
|
||||||
* Free Software Foundation, Inc., *
|
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
||||||
***************************************************************************/
|
|
||||||
#include "rateest.h"
|
|
||||||
#include <cstdlib>
|
|
||||||
|
|
||||||
void RateEst::SumQueue::reset() {
|
|
||||||
q.clear();
|
|
||||||
samples_ = usecs_ = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RateEst::SumQueue::push(const long samples, const usec_t usecs) {
|
|
||||||
q.push_back(pair_t(samples, usecs));
|
|
||||||
samples_ += samples;
|
|
||||||
usecs_ += usecs;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RateEst::SumQueue::pop() {
|
|
||||||
const pair_t &f = q.front();
|
|
||||||
samples_ -= f.first;
|
|
||||||
usecs_ -= f.second;
|
|
||||||
q.pop_front();
|
|
||||||
}
|
|
||||||
|
|
||||||
static usec_t sampleUsecs(long samples, long rate) {
|
|
||||||
return static_cast<usec_t>((samples * 1000000.0f) / (rate ? rate : 1) + 0.5f);
|
|
||||||
}
|
|
||||||
|
|
||||||
static long limit(long est, const long reference) {
|
|
||||||
if (est > reference + (reference >> 6))
|
|
||||||
est = reference + (reference >> 6);
|
|
||||||
else if (est < reference - (reference >> 6))
|
|
||||||
est = reference - (reference >> 6);
|
|
||||||
|
|
||||||
return est;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RateEst::init(long srate, long reference, const long maxSamplePeriod) {
|
|
||||||
maxPeriod = sampleUsecs(maxSamplePeriod, reference);
|
|
||||||
|
|
||||||
srate <<= UPSHIFT;
|
|
||||||
reference <<= UPSHIFT;
|
|
||||||
|
|
||||||
this->srate = limit(srate, reference);
|
|
||||||
last = 0;
|
|
||||||
this->reference = reference;
|
|
||||||
samples = ((this->srate >> UPSHIFT) * 12) << 5;
|
|
||||||
usecs = 12000000 << 5;
|
|
||||||
sumq.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
void RateEst::feed(long samplesIn, const usec_t now) {
|
|
||||||
usec_t usecsIn = now - last;
|
|
||||||
|
|
||||||
if (last && usecsIn < maxPeriod) {
|
|
||||||
sumq.push(samplesIn, usecsIn);
|
|
||||||
|
|
||||||
while ((usecsIn = sumq.usecs()) > 100000) {
|
|
||||||
samplesIn = sumq.samples();
|
|
||||||
sumq.pop();
|
|
||||||
|
|
||||||
if (std::abs(static_cast<long>(samplesIn * (1000000.0f * UP) / usecsIn) - reference) < reference >> 1) {
|
|
||||||
samples += (samplesIn - sumq.samples()) << 5;
|
|
||||||
usecs += (usecsIn - sumq.usecs()) << 5;
|
|
||||||
|
|
||||||
long est = static_cast<long>(samples * (1000000.0f * UP) / usecs + 0.5f);
|
|
||||||
est = limit((srate * 31 + est + 16) >> 5, reference);
|
|
||||||
srate = est;
|
|
||||||
|
|
||||||
if (usecs > 16000000 << 5) {
|
|
||||||
samples = (samples * 3 + 2) >> 2;
|
|
||||||
usecs = (usecs * 3 + 2) >> 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
last = now;
|
|
||||||
}
|
|
@ -1,66 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2008 by Sindre Aamås *
|
|
||||||
* aamas@stud.ntnu.no *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU General Public License version 2 as *
|
|
||||||
* published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 version 2 for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License *
|
|
||||||
* version 2 along with this program; if not, write to the *
|
|
||||||
* Free Software Foundation, Inc., *
|
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
||||||
***************************************************************************/
|
|
||||||
#ifndef RATEEST_H
|
|
||||||
#define RATEEST_H
|
|
||||||
|
|
||||||
#include "usec.h"
|
|
||||||
#include <deque>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
class RateEst {
|
|
||||||
class SumQueue {
|
|
||||||
typedef std::pair<long, usec_t> pair_t;
|
|
||||||
typedef std::deque<pair_t> q_t;
|
|
||||||
|
|
||||||
q_t q;
|
|
||||||
long samples_;
|
|
||||||
usec_t usecs_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
SumQueue() : samples_(0), usecs_(0) {}
|
|
||||||
void reset();
|
|
||||||
long samples() const { return samples_; }
|
|
||||||
usec_t usecs() const { return usecs_; }
|
|
||||||
void push(long samples, usec_t usecs);
|
|
||||||
void pop();
|
|
||||||
};
|
|
||||||
|
|
||||||
enum { UPSHIFT = 5 };
|
|
||||||
enum { UP = 1 << UPSHIFT };
|
|
||||||
|
|
||||||
long srate;
|
|
||||||
SumQueue sumq;
|
|
||||||
usec_t last;
|
|
||||||
usec_t usecs;
|
|
||||||
usec_t maxPeriod;
|
|
||||||
long reference;
|
|
||||||
long samples;
|
|
||||||
|
|
||||||
public:
|
|
||||||
RateEst(long srate = 0) { init(srate); }
|
|
||||||
RateEst(long srate, long reference) { init(srate, reference); }
|
|
||||||
void init(long srate) { init(srate, srate); }
|
|
||||||
void init(long srate, long reference) { init(srate, reference, reference); }
|
|
||||||
void init(long srate, long reference, long maxSamplePeriod);
|
|
||||||
void reset() { last = 0; }
|
|
||||||
void feed(long samples, usec_t usecs = getusecs());
|
|
||||||
long result() const { return (srate + UP / 2) >> UPSHIFT; }
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,73 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2008 by Sindre Aamås *
|
|
||||||
* aamas@stud.ntnu.no *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU General Public License version 2 as *
|
|
||||||
* published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 version 2 for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License *
|
|
||||||
* version 2 along with this program; if not, write to the *
|
|
||||||
* Free Software Foundation, Inc., *
|
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
||||||
***************************************************************************/
|
|
||||||
#ifndef RESAMPLER_H
|
|
||||||
#define RESAMPLER_H
|
|
||||||
|
|
||||||
#include <cstddef>
|
|
||||||
|
|
||||||
/** Interface to a Resampler. */
|
|
||||||
class Resampler {
|
|
||||||
long inRate_;
|
|
||||||
long outRate_;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void setRate(const long inRate, const long outRate) { inRate_ = inRate; outRate_ = outRate; }
|
|
||||||
Resampler() : inRate_(0), outRate_(0) {}
|
|
||||||
|
|
||||||
public:
|
|
||||||
/** Returns the sampling rate of the input that this resampler expects. */
|
|
||||||
long inRate() const { return inRate_; }
|
|
||||||
|
|
||||||
/** Returns the approximate sampling rate of the output. */
|
|
||||||
long outRate() const { return outRate_; }
|
|
||||||
|
|
||||||
/** Can be used to adjust the input and output sampling rates slightly with minimal disturbance in the output.
|
|
||||||
* Should only be used for slight changes or the quality could detoriate.
|
|
||||||
* It can for instance be useful to tweak the output rate slightly to synchronize production speed to playback
|
|
||||||
* speed when synchronizing video frame rate to refresh rate while playing back audio from the same source.
|
|
||||||
* This can reduce skipped or duplicated video frames (or avoid audio underruns if no frame skipping is done).
|
|
||||||
*
|
|
||||||
* @param inRate New input sampling rate.
|
|
||||||
* @param outRate Desired new output sampling rate.
|
|
||||||
*/
|
|
||||||
virtual void adjustRate(long inRate, long outRate) = 0;
|
|
||||||
|
|
||||||
/** Returns the exact ratio that this resampler is configured to use,
|
|
||||||
* such that the actual output sampling rate is (input rate) * mul / div.
|
|
||||||
* outRate() / inRate() is not necessarily equal to mul / div.
|
|
||||||
* Many resampler are intended for real-time purposes where it does not matter
|
|
||||||
* much whether the output sampling rate is 100% exact. Playback hardware is also slightly off.
|
|
||||||
*/
|
|
||||||
virtual void exactRatio(unsigned long &mul, unsigned long &div) const = 0;
|
|
||||||
|
|
||||||
/** Returns an upper bound on how many samples are produced for 'inlen' input samples.
|
|
||||||
* Can be used to calculate buffer sizes.
|
|
||||||
*/
|
|
||||||
virtual std::size_t maxOut(std::size_t inlen) const = 0;
|
|
||||||
|
|
||||||
/** Resamples the samples in 'in' and puts the resulting samples in 'out'.
|
|
||||||
*
|
|
||||||
* @param inlen The number of samples in 'in' to be resampled/consumed.
|
|
||||||
* @return The number of samples produced in 'out'.
|
|
||||||
*/
|
|
||||||
virtual std::size_t resample(short *out, const short *in, std::size_t inlen) = 0;
|
|
||||||
virtual ~Resampler() {}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,52 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2008 by Sindre Aamås *
|
|
||||||
* aamas@stud.ntnu.no *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU General Public License version 2 as *
|
|
||||||
* published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 version 2 for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License *
|
|
||||||
* version 2 along with this program; if not, write to the *
|
|
||||||
* Free Software Foundation, Inc., *
|
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
||||||
***************************************************************************/
|
|
||||||
#ifndef RESAMPLER_INFO_H
|
|
||||||
#define RESAMPLER_INFO_H
|
|
||||||
|
|
||||||
#include "resampler.h"
|
|
||||||
|
|
||||||
/** Used for creating instances of resamplers, and getting information on available resamplers.
|
|
||||||
* Currently creates resamplers that expect stereo samples. All 'numbers of samples' are in
|
|
||||||
* number of stereo samples. (This can be changed by adjusting the 'channels' enum in src/chainresampler.h
|
|
||||||
* to the number of desired channels.).
|
|
||||||
*/
|
|
||||||
struct ResamplerInfo {
|
|
||||||
/** Short character string description of the resampler. */
|
|
||||||
const char *desc;
|
|
||||||
|
|
||||||
/** Points to a function that can be used to create an instance of the resampler.
|
|
||||||
* @param inRate The input sampling rate.
|
|
||||||
* @param outRate The desired output sampling rate.
|
|
||||||
* @param periodSz The maximum number of input samples to resample at a time. That is the maximal inlen passed to Resampler::resample.
|
|
||||||
* @return Pointer to the created instance (on the heap). Caller must free this with the delete operator.
|
|
||||||
*/
|
|
||||||
Resampler* (*create)(long inRate, long outRate, std::size_t periodSz);
|
|
||||||
|
|
||||||
/** Returns the number of ResamplerInfos that can be gotten with get(). */
|
|
||||||
static unsigned num() { return num_; }
|
|
||||||
|
|
||||||
/** Returns ResamplerInfo number n. Where n is less than num(). */
|
|
||||||
static const ResamplerInfo& get(unsigned n) { return resamplers[n]; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
static const ResamplerInfo resamplers[];
|
|
||||||
static const unsigned num_;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,100 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2008 by Sindre Aamås *
|
|
||||||
* aamas@stud.ntnu.no *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU General Public License version 2 as *
|
|
||||||
* published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 version 2 for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License *
|
|
||||||
* version 2 along with this program; if not, write to the *
|
|
||||||
* Free Software Foundation, Inc., *
|
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
||||||
***************************************************************************/
|
|
||||||
#ifndef BLACKMANSINC_H
|
|
||||||
#define BLACKMANSINC_H
|
|
||||||
|
|
||||||
#include "convoluter.h"
|
|
||||||
#include "subresampler.h"
|
|
||||||
#include "makesinckernel.h"
|
|
||||||
#include "cic4.h"
|
|
||||||
#include "gambatte-array.h"
|
|
||||||
#include <cmath>
|
|
||||||
#include <cstdlib>
|
|
||||||
|
|
||||||
template<unsigned channels, unsigned phases>
|
|
||||||
class BlackmanSinc : public SubResampler {
|
|
||||||
PolyPhaseConvoluter<channels, phases> convoluters[channels];
|
|
||||||
Array<short> kernel;
|
|
||||||
|
|
||||||
static double blackmanWin(const long i, const long M) {
|
|
||||||
static const double PI = 3.14159265358979323846;
|
|
||||||
return 0.42 - 0.5 * std::cos(2 * PI * i / M) + 0.08 * std::cos(4 * PI * i / M);
|
|
||||||
}
|
|
||||||
|
|
||||||
void init(unsigned div, unsigned phaseLen, double fc);
|
|
||||||
|
|
||||||
public:
|
|
||||||
enum { MUL = phases };
|
|
||||||
|
|
||||||
typedef Cic4<channels> Cic;
|
|
||||||
static float cicLimit() { return 4.7f; }
|
|
||||||
|
|
||||||
class RollOff {
|
|
||||||
static unsigned toTaps(const float rollOffWidth) {
|
|
||||||
static const float widthTimesTaps = 4.5f;
|
|
||||||
return static_cast<unsigned>(std::ceil(widthTimesTaps / rollOffWidth));
|
|
||||||
}
|
|
||||||
|
|
||||||
static float toFc(const float rollOffStart, const int taps) {
|
|
||||||
static const float startToFcDeltaTimesTaps = 1.69f;
|
|
||||||
return startToFcDeltaTimesTaps / taps + rollOffStart;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
const unsigned taps;
|
|
||||||
const float fc;
|
|
||||||
|
|
||||||
RollOff(float rollOffStart, float rollOffWidth) : taps(toTaps(rollOffWidth)), fc(toFc(rollOffStart, taps)) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
BlackmanSinc(unsigned div, unsigned phaseLen, double fc) { init(div, phaseLen, fc); }
|
|
||||||
BlackmanSinc(unsigned div, RollOff ro) { init(div, ro.taps, ro.fc); }
|
|
||||||
std::size_t resample(short *out, const short *in, std::size_t inlen);
|
|
||||||
void adjustDiv(unsigned div);
|
|
||||||
unsigned mul() const { return MUL; }
|
|
||||||
unsigned div() const { return convoluters[0].div(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
template<unsigned channels, unsigned phases>
|
|
||||||
void BlackmanSinc<channels, phases>::init(const unsigned div, const unsigned phaseLen, const double fc) {
|
|
||||||
kernel.reset(phaseLen * phases);
|
|
||||||
|
|
||||||
makeSincKernel(kernel, phases, phaseLen, fc, blackmanWin);
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < channels; ++i)
|
|
||||||
convoluters[i].reset(kernel, phaseLen, div);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<unsigned channels, unsigned phases>
|
|
||||||
std::size_t BlackmanSinc<channels, phases>::resample(short *const out, const short *const in, const std::size_t inlen) {
|
|
||||||
std::size_t samplesOut;
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < channels; ++i)
|
|
||||||
samplesOut = convoluters[i].filter(out + i, in + i, inlen);
|
|
||||||
|
|
||||||
return samplesOut;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<unsigned channels, unsigned phases>
|
|
||||||
void BlackmanSinc<channels, phases>::adjustDiv(const unsigned div) {
|
|
||||||
for (unsigned i = 0; i < channels; ++i)
|
|
||||||
convoluters[i].adjustDiv(div);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,124 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2008 by Sindre Aamås *
|
|
||||||
* aamas@stud.ntnu.no *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU General Public License version 2 as *
|
|
||||||
* published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 version 2 for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License *
|
|
||||||
* version 2 along with this program; if not, write to the *
|
|
||||||
* Free Software Foundation, Inc., *
|
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
||||||
***************************************************************************/
|
|
||||||
#include "chainresampler.h"
|
|
||||||
|
|
||||||
float ChainResampler::get2ChainMidRatio(const float ratio, const float finalRollOffLen, const float midRollOffStartPlusEnd) {
|
|
||||||
return 0.5f * (std::sqrt(ratio * midRollOffStartPlusEnd * finalRollOffLen) + midRollOffStartPlusEnd);
|
|
||||||
}
|
|
||||||
|
|
||||||
float ChainResampler::get2ChainCost(const float ratio, const float finalRollOffLen, const float midRatio, const float midRollOffStartPlusEnd) {
|
|
||||||
const float midRollOffLen = midRatio * 2 - midRollOffStartPlusEnd;
|
|
||||||
return midRatio * ratio / midRollOffLen + get1ChainCost(midRatio, finalRollOffLen);
|
|
||||||
}
|
|
||||||
|
|
||||||
float ChainResampler::get3ChainRatio1(float ratio1, const float finalRollOffLen, const float ratio, const float midRollOffStartPlusEnd) {
|
|
||||||
for (unsigned n = 8; n--;) {
|
|
||||||
const float ratio2 = get3ChainRatio2(ratio1, finalRollOffLen, midRollOffStartPlusEnd);
|
|
||||||
ratio1 = 0.5f * (std::sqrt(ratio * midRollOffStartPlusEnd * (2 - midRollOffStartPlusEnd / ratio2)) + midRollOffStartPlusEnd);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ratio1;
|
|
||||||
}
|
|
||||||
|
|
||||||
float ChainResampler::get3ChainCost(const float ratio, const float finalRollOffLen,
|
|
||||||
const float ratio1, const float ratio2, const float midRollOffStartPlusEnd) {
|
|
||||||
const float firstRollOffLen = ratio1 * 2 - midRollOffStartPlusEnd;
|
|
||||||
return ratio1 * ratio / firstRollOffLen + get2ChainCost(ratio1, finalRollOffLen, ratio2, midRollOffStartPlusEnd);
|
|
||||||
}
|
|
||||||
|
|
||||||
ChainResampler::ChainResampler()
|
|
||||||
: bigSinc(0), buffer2(0), periodSize(0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t ChainResampler::reallocateBuffer() {
|
|
||||||
std::size_t bufSz[2] = { 0, 0 };
|
|
||||||
std::size_t inSz = periodSize;
|
|
||||||
int i = -1;
|
|
||||||
|
|
||||||
for (list_t::iterator it = list.begin(); it != list.end(); ++it) {
|
|
||||||
inSz = (inSz * (*it)->mul() - 1) / (*it)->div() + 1;
|
|
||||||
|
|
||||||
++i;
|
|
||||||
|
|
||||||
if (inSz > bufSz[i&1])
|
|
||||||
bufSz[i&1] = inSz;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inSz >= bufSz[i&1])
|
|
||||||
bufSz[i&1] = 0;
|
|
||||||
|
|
||||||
if (buffer.size() < (bufSz[0] + bufSz[1]) * channels)
|
|
||||||
buffer.reset((bufSz[0] + bufSz[1]) * channels);
|
|
||||||
|
|
||||||
buffer2 = bufSz[1] ? buffer + bufSz[0] * channels : 0;
|
|
||||||
|
|
||||||
return (maxOut_ = inSz);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ChainResampler::adjustRate(const long inRate, const long outRate) {
|
|
||||||
unsigned long mul, div;
|
|
||||||
|
|
||||||
exactRatio(mul, div);
|
|
||||||
|
|
||||||
bigSinc->adjustDiv(static_cast<int>(static_cast<double>(inRate) * mul / (static_cast<double>(div / bigSinc->div()) * outRate) + 0.5));
|
|
||||||
|
|
||||||
reallocateBuffer();
|
|
||||||
setRate(inRate, outRate);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ChainResampler::exactRatio(unsigned long &mul, unsigned long &div) const {
|
|
||||||
mul = 1;
|
|
||||||
div = 1;
|
|
||||||
|
|
||||||
for (list_t::const_iterator it = list.begin(); it != list.end(); ++it) {
|
|
||||||
mul *= (*it)->mul();
|
|
||||||
div *= (*it)->div();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t ChainResampler::resample(short *const out, const short *const in, std::size_t inlen) {
|
|
||||||
assert(inlen <= periodSize);
|
|
||||||
|
|
||||||
short *const buf = buffer != buffer2 ? buffer : out;
|
|
||||||
short *const buf2 = buffer2 ? buffer2 : out;
|
|
||||||
|
|
||||||
const short *inbuf = in;
|
|
||||||
short *outbuf = 0;
|
|
||||||
|
|
||||||
for (list_t::iterator it = list.begin(); it != list.end(); ++it) {
|
|
||||||
outbuf = ++list_t::iterator(it) == list.end() ? out : (inbuf == buf ? buf2 : buf);
|
|
||||||
inlen = (*it)->resample(outbuf, inbuf, inlen);
|
|
||||||
inbuf = outbuf;
|
|
||||||
}
|
|
||||||
|
|
||||||
return inlen;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ChainResampler::uninit() {
|
|
||||||
buffer2 = 0;
|
|
||||||
buffer.reset();
|
|
||||||
periodSize = 0;
|
|
||||||
bigSinc = 0;
|
|
||||||
|
|
||||||
for (list_t::iterator it = list.begin(); it != list.end(); ++it)
|
|
||||||
delete *it;
|
|
||||||
|
|
||||||
list.clear();
|
|
||||||
}
|
|
@ -1,196 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2008 by Sindre Aamås *
|
|
||||||
* aamas@stud.ntnu.no *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU General Public License version 2 as *
|
|
||||||
* published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 version 2 for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License *
|
|
||||||
* version 2 along with this program; if not, write to the *
|
|
||||||
* Free Software Foundation, Inc., *
|
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
||||||
***************************************************************************/
|
|
||||||
#ifndef CHAINRESAMPLER_H
|
|
||||||
#define CHAINRESAMPLER_H
|
|
||||||
|
|
||||||
#include <cmath>
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <cassert>
|
|
||||||
#include <cstddef>
|
|
||||||
#include <list>
|
|
||||||
#include "gambatte-array.h"
|
|
||||||
#include "subresampler.h"
|
|
||||||
#include "../resampler.h"
|
|
||||||
#include "upsampler.h"
|
|
||||||
|
|
||||||
class ChainResampler : public Resampler {
|
|
||||||
typedef std::list<SubResampler*> list_t;
|
|
||||||
|
|
||||||
list_t list;
|
|
||||||
SubResampler *bigSinc;
|
|
||||||
Array<short> buffer;
|
|
||||||
short *buffer2;
|
|
||||||
std::size_t periodSize;
|
|
||||||
std::size_t maxOut_;
|
|
||||||
|
|
||||||
static float get1ChainCost(float ratio, float finalRollOffLen) { return ratio / finalRollOffLen; }
|
|
||||||
|
|
||||||
static float get2ChainMidRatio(float ratio, float finalRollOffLen, float midRollOffStartPlusEnd);
|
|
||||||
static float get2ChainCost(float ratio, float finalRollOffLen, float midRatio, float midRollOffStartPlusEnd);
|
|
||||||
|
|
||||||
static float get3ChainRatio2(float ratio1, float finalRollOffLen, float midRollOffStartPlusEnd) {
|
|
||||||
return get2ChainMidRatio(ratio1, finalRollOffLen, midRollOffStartPlusEnd);
|
|
||||||
}
|
|
||||||
|
|
||||||
static float get3ChainRatio1(float ratio1, float finalRollOffLen, float ratio, float midRollOffStartPlusEnd);
|
|
||||||
static float get3ChainCost(float ratio, float finalRollOffLen, float ratio1, float ratio2, float midRollOffStartPlusEnd);
|
|
||||||
|
|
||||||
template<template<unsigned,unsigned> class Sinc>
|
|
||||||
std::size_t downinit(long inRate, long outRate, std::size_t periodSize);
|
|
||||||
|
|
||||||
template<template<unsigned,unsigned> class Sinc>
|
|
||||||
std::size_t upinit(long inRate, long outRate, std::size_t periodSize);
|
|
||||||
|
|
||||||
std::size_t reallocateBuffer();
|
|
||||||
|
|
||||||
public:
|
|
||||||
enum { channels = 2 };
|
|
||||||
ChainResampler();
|
|
||||||
~ChainResampler() { uninit(); }
|
|
||||||
|
|
||||||
void adjustRate(long inRate, long outRate);
|
|
||||||
void exactRatio(unsigned long &mul, unsigned long &div) const;
|
|
||||||
|
|
||||||
template<template<unsigned,unsigned> class Sinc>
|
|
||||||
std::size_t init(long inRate, long outRate, std::size_t periodSize);
|
|
||||||
std::size_t maxOut(std::size_t /*inlen*/) const { return maxOut_; }
|
|
||||||
std::size_t resample(short *out, const short *in, std::size_t inlen);
|
|
||||||
void uninit();
|
|
||||||
};
|
|
||||||
|
|
||||||
template<template<unsigned,unsigned> class Sinc>
|
|
||||||
std::size_t ChainResampler::init(const long inRate, const long outRate, const std::size_t periodSize) {
|
|
||||||
setRate(inRate, outRate);
|
|
||||||
|
|
||||||
if (outRate > inRate)
|
|
||||||
return upinit<Sinc>(inRate, outRate, periodSize);
|
|
||||||
else
|
|
||||||
return downinit<Sinc>(inRate, outRate, periodSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<template<unsigned,unsigned> class Sinc>
|
|
||||||
std::size_t ChainResampler::downinit(const long inRate, const long outRate, const std::size_t periodSize) {
|
|
||||||
typedef Sinc<channels,2048> BigSinc;
|
|
||||||
typedef Sinc<channels,32> SmallSinc;
|
|
||||||
|
|
||||||
uninit();
|
|
||||||
this->periodSize = periodSize;
|
|
||||||
|
|
||||||
double ratio = static_cast<double>(inRate) / outRate;
|
|
||||||
|
|
||||||
while (ratio >= BigSinc::cicLimit() * 2) {
|
|
||||||
const int div = std::min<int>(static_cast<int>(ratio / BigSinc::cicLimit()), BigSinc::Cic::MAX_DIV);
|
|
||||||
|
|
||||||
list.push_back(new typename BigSinc::Cic(div));
|
|
||||||
ratio /= div;
|
|
||||||
}
|
|
||||||
|
|
||||||
// For high outRate: Start roll-off at 36000 Hz continue until outRate Hz, then wrap around back down to 40000 Hz.
|
|
||||||
const float outPeriod = 1.0f / outRate;
|
|
||||||
const float finalRollOffLen = std::max((outRate - 36000.0f + outRate - 40000.0f) * outPeriod, 0.2f);
|
|
||||||
|
|
||||||
{
|
|
||||||
const float midRollOffStart = std::min(36000.0f * outPeriod, 1.0f);
|
|
||||||
const float midRollOffEnd = std::min(40000.0f * outPeriod, 1.0f); // after wrap at folding freq.
|
|
||||||
const float midRollOffStartPlusEnd = midRollOffStart + midRollOffEnd;
|
|
||||||
|
|
||||||
int div_2c = static_cast<int>(ratio * SmallSinc::MUL / get2ChainMidRatio(ratio, finalRollOffLen, midRollOffStartPlusEnd) + 0.5f);
|
|
||||||
double ratio_2c = ratio * SmallSinc::MUL / div_2c;
|
|
||||||
float cost_2c = get2ChainCost(ratio, finalRollOffLen, ratio_2c, midRollOffStartPlusEnd);
|
|
||||||
|
|
||||||
if (cost_2c < get1ChainCost(ratio, finalRollOffLen)) {
|
|
||||||
const int div1_3c = static_cast<int>(
|
|
||||||
ratio * SmallSinc::MUL / get3ChainRatio1(ratio_2c, finalRollOffLen, ratio, midRollOffStartPlusEnd) + 0.5f);
|
|
||||||
const double ratio1_3c = ratio * SmallSinc::MUL / div1_3c;
|
|
||||||
const int div2_3c = static_cast<int>(
|
|
||||||
ratio1_3c * SmallSinc::MUL / get3ChainRatio2(ratio1_3c, finalRollOffLen, midRollOffStartPlusEnd) + 0.5f);
|
|
||||||
const double ratio2_3c = ratio1_3c * SmallSinc::MUL / div2_3c;
|
|
||||||
|
|
||||||
if (get3ChainCost(ratio, finalRollOffLen, ratio1_3c, ratio2_3c, midRollOffStartPlusEnd) < cost_2c) {
|
|
||||||
list.push_back(new SmallSinc(div1_3c, typename SmallSinc::RollOff(
|
|
||||||
0.5f * midRollOffStart / ratio, (ratio1_3c - 0.5f * midRollOffStartPlusEnd) / ratio)));
|
|
||||||
ratio = ratio1_3c;
|
|
||||||
div_2c = div2_3c;
|
|
||||||
ratio_2c = ratio2_3c;
|
|
||||||
}
|
|
||||||
|
|
||||||
list.push_back(new SmallSinc(div_2c, typename SmallSinc::RollOff(
|
|
||||||
0.5f * midRollOffStart / ratio, (ratio_2c - 0.5f * midRollOffStartPlusEnd) / ratio)));
|
|
||||||
ratio = ratio_2c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
list.push_back(bigSinc = new BigSinc(static_cast<int>(BigSinc::MUL * ratio + 0.5), typename BigSinc::RollOff(
|
|
||||||
0.5f * (1.0f + std::max((outRate - 40000.0f) * outPeriod, 0.0f) - finalRollOffLen) / ratio, 0.5f * finalRollOffLen / ratio)));
|
|
||||||
|
|
||||||
return reallocateBuffer();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<template<unsigned,unsigned> class Sinc>
|
|
||||||
std::size_t ChainResampler::upinit(const long inRate, const long outRate, const std::size_t periodSize) {
|
|
||||||
typedef Sinc<channels,2048> BigSinc;
|
|
||||||
typedef Sinc<channels,32> SmallSinc;
|
|
||||||
|
|
||||||
uninit();
|
|
||||||
this->periodSize = periodSize;
|
|
||||||
|
|
||||||
double ratio = static_cast<double>(outRate) / inRate;
|
|
||||||
|
|
||||||
// Spectral images above 20 kHz assumed inaudible
|
|
||||||
{
|
|
||||||
const int div = outRate / std::max(inRate, 40000l);
|
|
||||||
|
|
||||||
if (div >= 2) {
|
|
||||||
list.push_front(new Upsampler<channels>(div));
|
|
||||||
ratio /= div;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const float rollOff = std::max((inRate - 36000.0f) / inRate, 0.2f);
|
|
||||||
|
|
||||||
/*{
|
|
||||||
int div_2c = get2ChainMidRatio(ratio, rollOff) * SmallSinc::MUL / ratio + 0.5f;
|
|
||||||
double ratio_2c = ratio * div_2c / SmallSinc::MUL;
|
|
||||||
float cost_2c = get2ChainCost(ratio, rollOff, ratio_2c);
|
|
||||||
|
|
||||||
if (cost_2c < get1ChainCost(ratio, rollOff)) {
|
|
||||||
const int div1_3c = get3ChainRatio1(ratio_2c, rollOff, ratio) * SmallSinc::MUL / ratio + 0.5f;
|
|
||||||
const double ratio1_3c = ratio * div1_3c / SmallSinc::MUL;
|
|
||||||
const int div2_3c = get3ChainRatio2(ratio1_3c, rollOff) * SmallSinc::MUL / ratio1_3c + 0.5f;
|
|
||||||
const double ratio2_3c = ratio1_3c * div2_3c / SmallSinc::MUL;
|
|
||||||
|
|
||||||
if (get3ChainCost(ratio, rollOff, ratio1_3c, ratio2_3c) < cost_2c) {
|
|
||||||
list.push_front(new SmallSinc(div1_3c, typename SmallSinc::RollOff(0.5f / ratio1_3c, (ratio1_3c - 1) / ratio1_3c)));
|
|
||||||
ratio = ratio1_3c;
|
|
||||||
div_2c = div2_3c;
|
|
||||||
ratio_2c = ratio2_3c;
|
|
||||||
}
|
|
||||||
|
|
||||||
list.push_front(new SmallSinc(div_2c, typename SmallSinc::RollOff(0.5f / ratio_2c, (ratio_2c - 1) / ratio_2c)));
|
|
||||||
ratio = ratio_2c;
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
list.push_front(bigSinc = new BigSinc(
|
|
||||||
static_cast<int>(BigSinc::MUL / ratio + 0.5), typename BigSinc::RollOff(0.5f * (1 - rollOff), 0.5f * rollOff)));
|
|
||||||
|
|
||||||
return reallocateBuffer();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,242 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2008 by Sindre Aamås *
|
|
||||||
* aamas@stud.ntnu.no *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU General Public License version 2 as *
|
|
||||||
* published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 version 2 for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License *
|
|
||||||
* version 2 along with this program; if not, write to the *
|
|
||||||
* Free Software Foundation, Inc., *
|
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
||||||
***************************************************************************/
|
|
||||||
#ifndef CIC2_H
|
|
||||||
#define CIC2_H
|
|
||||||
|
|
||||||
#include "subresampler.h"
|
|
||||||
#include "rshift16_round.h"
|
|
||||||
|
|
||||||
template<unsigned channels>
|
|
||||||
class Cic2Core {
|
|
||||||
// enum { BUFLEN = 64 };
|
|
||||||
// unsigned long buf[BUFLEN];
|
|
||||||
unsigned long sum1;
|
|
||||||
unsigned long sum2;
|
|
||||||
unsigned long prev1;
|
|
||||||
// unsigned long prev2;
|
|
||||||
unsigned div_;
|
|
||||||
unsigned nextdivn;
|
|
||||||
// unsigned bufpos;
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit Cic2Core(const unsigned div = 2) {
|
|
||||||
reset(div);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned div() const { return div_; }
|
|
||||||
std::size_t filter(short *out, const short *in, std::size_t inlen);
|
|
||||||
void reset(unsigned div);
|
|
||||||
};
|
|
||||||
|
|
||||||
template<unsigned channels>
|
|
||||||
void Cic2Core<channels>::reset(const unsigned div) {
|
|
||||||
sum2 = sum1 = 0;
|
|
||||||
/*prev2 = */prev1 = 0;
|
|
||||||
this->div_ = div;
|
|
||||||
nextdivn = div;
|
|
||||||
// bufpos = div - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<unsigned channels>
|
|
||||||
std::size_t Cic2Core<channels>::filter(short *out, const short *const in, std::size_t inlen) {
|
|
||||||
// const std::size_t produced = (inlen + div_ - (bufpos + 1)) / div_;
|
|
||||||
const std::size_t produced = (inlen + div_ - nextdivn) / div_;
|
|
||||||
const long mul = 0x10000 / (div_ * div_); // trouble if div is too large, may be better to only support power of 2 div
|
|
||||||
const short *s = in;
|
|
||||||
|
|
||||||
/*unsigned long sm1 = sum1;
|
|
||||||
unsigned long sm2 = sum2;
|
|
||||||
|
|
||||||
while (inlen >> 2) {
|
|
||||||
unsigned n = (inlen < BUFLEN ? inlen >> 2 : BUFLEN >> 2);
|
|
||||||
const unsigned end = n * 4;
|
|
||||||
unsigned i = 0;
|
|
||||||
|
|
||||||
do {
|
|
||||||
unsigned long s1 = sm1 += static_cast<long>(*s);
|
|
||||||
s += channels;
|
|
||||||
sm1 += static_cast<long>(*s);
|
|
||||||
s += channels;
|
|
||||||
buf[i++] = sm2 += s1;
|
|
||||||
buf[i++] = sm2 += sm1;
|
|
||||||
s1 = sm1 += static_cast<long>(*s);
|
|
||||||
s += channels;
|
|
||||||
sm1 += static_cast<long>(*s);
|
|
||||||
s += channels;
|
|
||||||
buf[i++] = sm2 += s1;
|
|
||||||
buf[i++] = sm2 += sm1;
|
|
||||||
} while (--n);
|
|
||||||
|
|
||||||
while (bufpos < end) {
|
|
||||||
const unsigned long out2 = buf[bufpos] - prev2;
|
|
||||||
prev2 = buf[bufpos];
|
|
||||||
bufpos += div_;
|
|
||||||
|
|
||||||
*out = rshift16_round(static_cast<long>(out2 - prev1) * mul);
|
|
||||||
prev1 = out2;
|
|
||||||
out += channels;
|
|
||||||
}
|
|
||||||
|
|
||||||
bufpos -= end;
|
|
||||||
inlen -= end;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inlen) {
|
|
||||||
unsigned n = inlen;
|
|
||||||
unsigned i = 0;
|
|
||||||
|
|
||||||
do {
|
|
||||||
sm1 += static_cast<long>(*s);
|
|
||||||
s += channels;
|
|
||||||
buf[i++] = sm2 += sm1;
|
|
||||||
} while (--n);
|
|
||||||
|
|
||||||
while (bufpos < inlen) {
|
|
||||||
const unsigned long out2 = buf[bufpos] - prev2;
|
|
||||||
prev2 = buf[bufpos];
|
|
||||||
bufpos += div_;
|
|
||||||
|
|
||||||
*out = rshift16_round(static_cast<long>(out2 - prev1) * mul);
|
|
||||||
prev1 = out2;
|
|
||||||
out += channels;
|
|
||||||
}
|
|
||||||
|
|
||||||
bufpos -= inlen;
|
|
||||||
}
|
|
||||||
|
|
||||||
sum1 = sm1;
|
|
||||||
sum2 = sm2;*/
|
|
||||||
|
|
||||||
unsigned long sm1 = sum1;
|
|
||||||
unsigned long sm2 = sum2;
|
|
||||||
|
|
||||||
if (inlen >= nextdivn) {
|
|
||||||
{
|
|
||||||
unsigned divn = nextdivn;
|
|
||||||
|
|
||||||
do {
|
|
||||||
sm1 += static_cast<long>(*s);
|
|
||||||
s += channels;
|
|
||||||
sm2 += sm1;
|
|
||||||
} while (--divn);
|
|
||||||
|
|
||||||
const unsigned long out2 = sm2;
|
|
||||||
sm2 = 0;
|
|
||||||
|
|
||||||
*out = rshift16_round(static_cast<long>(out2 - prev1) * mul);
|
|
||||||
prev1 = out2;
|
|
||||||
out += channels;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (div_ & 1) {
|
|
||||||
std::size_t n = produced;
|
|
||||||
|
|
||||||
while (--n) {
|
|
||||||
unsigned divn = div_ >> 1;
|
|
||||||
|
|
||||||
do {
|
|
||||||
sm1 += static_cast<long>(*s);
|
|
||||||
s += channels;
|
|
||||||
sm2 += sm1;
|
|
||||||
sm1 += static_cast<long>(*s);
|
|
||||||
s += channels;
|
|
||||||
sm2 += sm1;
|
|
||||||
} while (--divn);
|
|
||||||
|
|
||||||
sm1 += static_cast<long>(*s);
|
|
||||||
s += channels;
|
|
||||||
sm2 += sm1;
|
|
||||||
|
|
||||||
*out = rshift16_round(static_cast<long>(sm2 - prev1) * mul);
|
|
||||||
out += channels;
|
|
||||||
prev1 = sm2;
|
|
||||||
sm2 = 0;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
std::size_t n = produced;
|
|
||||||
|
|
||||||
while (--n) {
|
|
||||||
unsigned divn = div_ >> 1;
|
|
||||||
|
|
||||||
do {
|
|
||||||
sm1 += static_cast<long>(*s);
|
|
||||||
s += channels;
|
|
||||||
sm2 += sm1;
|
|
||||||
sm1 += static_cast<long>(*s);
|
|
||||||
s += channels;
|
|
||||||
sm2 += sm1;
|
|
||||||
} while (--divn);
|
|
||||||
|
|
||||||
*out = rshift16_round(static_cast<long>(sm2 - prev1) * mul);
|
|
||||||
out += channels;
|
|
||||||
prev1 = sm2;
|
|
||||||
sm2 = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
nextdivn = div_;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
unsigned divn = (in + inlen * channels - s) / channels;
|
|
||||||
nextdivn -= divn;
|
|
||||||
|
|
||||||
while (divn--) {
|
|
||||||
sm1 += static_cast<long>(*s);
|
|
||||||
s += channels;
|
|
||||||
sm2 += sm1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sum1 = sm1;
|
|
||||||
sum2 = sm2;
|
|
||||||
|
|
||||||
return produced;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<unsigned channels>
|
|
||||||
class Cic2 : public SubResampler {
|
|
||||||
Cic2Core<channels> cics[channels];
|
|
||||||
|
|
||||||
public:
|
|
||||||
enum { MAX_DIV = 64 };
|
|
||||||
explicit Cic2(unsigned div);
|
|
||||||
std::size_t resample(short *out, const short *in, std::size_t inlen);
|
|
||||||
unsigned mul() const { return 1; }
|
|
||||||
unsigned div() const { return cics[0].div(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
template<unsigned channels>
|
|
||||||
Cic2<channels>::Cic2(const unsigned div) {
|
|
||||||
for (unsigned i = 0; i < channels; ++i)
|
|
||||||
cics[i].reset(div);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<unsigned channels>
|
|
||||||
std::size_t Cic2<channels>::resample(short *const out, const short *const in, const std::size_t inlen) {
|
|
||||||
std::size_t samplesOut;
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < channels; ++i) {
|
|
||||||
samplesOut = cics[i].filter(out + i, in + i, inlen);
|
|
||||||
}
|
|
||||||
|
|
||||||
return samplesOut;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,383 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2008 by Sindre Aamås *
|
|
||||||
* aamas@stud.ntnu.no *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU General Public License version 2 as *
|
|
||||||
* published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 version 2 for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License *
|
|
||||||
* version 2 along with this program; if not, write to the *
|
|
||||||
* Free Software Foundation, Inc., *
|
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
||||||
***************************************************************************/
|
|
||||||
#ifndef CIC3_H
|
|
||||||
#define CIC3_H
|
|
||||||
|
|
||||||
#include "subresampler.h"
|
|
||||||
#include "rshift16_round.h"
|
|
||||||
|
|
||||||
template<unsigned channels>
|
|
||||||
class Cic3Core {
|
|
||||||
// enum { BUFLEN = 64 };
|
|
||||||
// unsigned long buf[BUFLEN];
|
|
||||||
unsigned long sum1;
|
|
||||||
unsigned long sum2;
|
|
||||||
unsigned long sum3;
|
|
||||||
unsigned long prev1;
|
|
||||||
unsigned long prev2;
|
|
||||||
unsigned long prev3;
|
|
||||||
unsigned div_;
|
|
||||||
unsigned nextdivn;
|
|
||||||
// unsigned bufpos;
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit Cic3Core(const unsigned div = 1) {
|
|
||||||
reset(div);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned div() const { return div_; }
|
|
||||||
std::size_t filter(short *out, const short *in, std::size_t inlen);
|
|
||||||
void reset(unsigned div);
|
|
||||||
};
|
|
||||||
|
|
||||||
template<unsigned channels>
|
|
||||||
void Cic3Core<channels>::reset(const unsigned div) {
|
|
||||||
sum3 = sum2 = sum1 = 0;
|
|
||||||
prev3 = prev2 = prev1 = 0;
|
|
||||||
this->div_ = div;
|
|
||||||
nextdivn = div;
|
|
||||||
// bufpos = div - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<unsigned channels>
|
|
||||||
std::size_t Cic3Core<channels>::filter(short *out, const short *const in, std::size_t inlen) {
|
|
||||||
// const std::size_t produced = (inlen + div_ - (bufpos + 1)) / div_;
|
|
||||||
const std::size_t produced = (inlen + div_ - nextdivn) / div_;
|
|
||||||
const long mul = 0x10000 / (div_ * div_ * div_); // trouble if div is too large, may be better to only support power of 2 div
|
|
||||||
const short *s = in;
|
|
||||||
|
|
||||||
/*unsigned long sm1 = sum1;
|
|
||||||
unsigned long sm2 = sum2;
|
|
||||||
unsigned long sm3 = sum3;
|
|
||||||
|
|
||||||
while (inlen >> 1) {
|
|
||||||
unsigned n = (inlen < BUFLEN ? inlen >> 1 : BUFLEN >> 1);
|
|
||||||
const unsigned end = n * 2;
|
|
||||||
unsigned i = 0;
|
|
||||||
|
|
||||||
do {
|
|
||||||
unsigned long s1 = sm1 += static_cast<long>(*s);
|
|
||||||
s += channels;
|
|
||||||
sm1 += static_cast<long>(*s);
|
|
||||||
s += channels;
|
|
||||||
unsigned long s2 = sm2 += s1;
|
|
||||||
sm2 += sm1;
|
|
||||||
buf[i++] = sm3 += s2;
|
|
||||||
buf[i++] = sm3 += sm2;
|
|
||||||
} while (--n);
|
|
||||||
|
|
||||||
while (bufpos < end) {
|
|
||||||
const unsigned long out3 = buf[bufpos] - prev3;
|
|
||||||
prev3 = buf[bufpos];
|
|
||||||
bufpos += div_;
|
|
||||||
|
|
||||||
const unsigned long out2 = out3 - prev2;
|
|
||||||
prev2 = out3;
|
|
||||||
|
|
||||||
*out = rshift16_round(static_cast<long>(out2 - prev1) * mul);
|
|
||||||
prev1 = out2;
|
|
||||||
out += channels;
|
|
||||||
}
|
|
||||||
|
|
||||||
bufpos -= end;
|
|
||||||
inlen -= end;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inlen) {
|
|
||||||
unsigned n = inlen;
|
|
||||||
unsigned i = 0;
|
|
||||||
|
|
||||||
do {
|
|
||||||
sm1 += static_cast<long>(*s);
|
|
||||||
s += channels;
|
|
||||||
sm2 += sm1;
|
|
||||||
buf[i++] = sm3 += sm2;
|
|
||||||
} while (--n);
|
|
||||||
|
|
||||||
while (bufpos < inlen) {
|
|
||||||
const unsigned long out3 = buf[bufpos] - prev3;
|
|
||||||
prev3 = buf[bufpos];
|
|
||||||
bufpos += div_;
|
|
||||||
|
|
||||||
const unsigned long out2 = out3 - prev2;
|
|
||||||
prev2 = out3;
|
|
||||||
|
|
||||||
*out = rshift16_round(static_cast<long>(out2 - prev1) * mul);
|
|
||||||
prev1 = out2;
|
|
||||||
out += channels;
|
|
||||||
}
|
|
||||||
|
|
||||||
bufpos -= inlen;
|
|
||||||
}
|
|
||||||
|
|
||||||
sum1 = sm1;
|
|
||||||
sum2 = sm2;
|
|
||||||
sum3 = sm3;*/
|
|
||||||
|
|
||||||
|
|
||||||
unsigned long sm1 = sum1;
|
|
||||||
unsigned long sm2 = sum2;
|
|
||||||
unsigned long sm3 = sum3;
|
|
||||||
|
|
||||||
if (inlen >= nextdivn) {
|
|
||||||
unsigned divn = nextdivn;
|
|
||||||
std::size_t n = produced;
|
|
||||||
|
|
||||||
do {
|
|
||||||
do {
|
|
||||||
sm1 += static_cast<long>(*s);
|
|
||||||
sm2 += sm1;
|
|
||||||
sm3 += sm2;
|
|
||||||
s += channels;
|
|
||||||
} while (--divn);
|
|
||||||
|
|
||||||
const unsigned long out3 = sm3 - prev3;
|
|
||||||
prev3 = sm3;
|
|
||||||
|
|
||||||
const unsigned long out2 = out3 - prev2;
|
|
||||||
prev2 = out3;
|
|
||||||
|
|
||||||
*out = rshift16_round(static_cast<long>(out2 - prev1) * mul);
|
|
||||||
prev1 = out2;
|
|
||||||
out += channels;
|
|
||||||
|
|
||||||
divn = div_;
|
|
||||||
} while (--n);
|
|
||||||
|
|
||||||
nextdivn = div_;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
unsigned divn = (in + inlen * channels - s) / channels;
|
|
||||||
nextdivn -= divn;
|
|
||||||
|
|
||||||
while (divn--) {
|
|
||||||
sm1 += static_cast<long>(*s);
|
|
||||||
sm2 += sm1;
|
|
||||||
sm3 += sm2;
|
|
||||||
s += channels;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sum1 = sm1;
|
|
||||||
sum2 = sm2;
|
|
||||||
sum3 = sm3;
|
|
||||||
|
|
||||||
return produced;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*template<unsigned channels>
|
|
||||||
class Cic3EvenOddCore {
|
|
||||||
unsigned long sum1;
|
|
||||||
unsigned long sum2;
|
|
||||||
unsigned long sum3;
|
|
||||||
unsigned long prev1;
|
|
||||||
unsigned long prev2;
|
|
||||||
unsigned long prev3;
|
|
||||||
unsigned div_;
|
|
||||||
unsigned nextdivn;
|
|
||||||
|
|
||||||
static int getMul(unsigned div) {
|
|
||||||
return 0x10000 / (div * div * div); // trouble if div is too large, may be better to only support power of 2 div
|
|
||||||
}
|
|
||||||
|
|
||||||
void filterEven(short *out, const short *s, std::size_t n);
|
|
||||||
void filterOdd(short *out, const short *s, std::size_t n);
|
|
||||||
|
|
||||||
public:
|
|
||||||
Cic3EvenOddCore(const unsigned div = 2) {
|
|
||||||
reset(div);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned div() const { return div_; }
|
|
||||||
std::size_t filter(short *out, const short *in, std::size_t inlen);
|
|
||||||
void reset(unsigned div);
|
|
||||||
};
|
|
||||||
|
|
||||||
template<unsigned channels>
|
|
||||||
void Cic3EvenOddCore<channels>::reset(const unsigned div) {
|
|
||||||
sum3 = sum2 = sum1 = 0;
|
|
||||||
prev3 = prev2 = prev1 = 0;
|
|
||||||
this->div_ = div;
|
|
||||||
nextdivn = div;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<unsigned channels>
|
|
||||||
void Cic3EvenOddCore<channels>::filterEven(short *out, const short *s, std::size_t n) {
|
|
||||||
const int mul = getMul(div_);
|
|
||||||
unsigned long sm1 = sum1;
|
|
||||||
unsigned long sm2 = sum2;
|
|
||||||
unsigned long sm3 = sum3;
|
|
||||||
|
|
||||||
while (n--) {
|
|
||||||
{
|
|
||||||
unsigned sn = div_ >> 1;
|
|
||||||
|
|
||||||
do {
|
|
||||||
unsigned long s1 = sm1 += static_cast<long>(*s);
|
|
||||||
s += channels;
|
|
||||||
sm1 += static_cast<long>(*s);
|
|
||||||
s += channels;
|
|
||||||
unsigned long s2 = sm2 += s1;
|
|
||||||
sm2 += sm1;
|
|
||||||
sm3 += s2;
|
|
||||||
sm3 += sm2;
|
|
||||||
} while (--sn);
|
|
||||||
}
|
|
||||||
|
|
||||||
const unsigned long out3 = sm3 - prev3;
|
|
||||||
prev3 = sm3;
|
|
||||||
const unsigned long out2 = out3 - prev2;
|
|
||||||
prev2 = out3;
|
|
||||||
*out = rshift16_round(static_cast<long>(out2 - prev1) * mul);
|
|
||||||
prev1 = out2;
|
|
||||||
out += channels;
|
|
||||||
}
|
|
||||||
|
|
||||||
sum1 = sm1;
|
|
||||||
sum2 = sm2;
|
|
||||||
sum3 = sm3;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<unsigned channels>
|
|
||||||
void Cic3EvenOddCore<channels>::filterOdd(short *out, const short *s, std::size_t n) {
|
|
||||||
const int mul = getMul(div_);
|
|
||||||
unsigned long sm1 = sum1;
|
|
||||||
unsigned long sm2 = sum2;
|
|
||||||
unsigned long sm3 = sum3;
|
|
||||||
|
|
||||||
while (n--) {
|
|
||||||
{
|
|
||||||
unsigned sn = div_ >> 1;
|
|
||||||
|
|
||||||
do {
|
|
||||||
unsigned long s1 = sm1 += static_cast<long>(*s);
|
|
||||||
s += channels;
|
|
||||||
sm1 += static_cast<long>(*s);
|
|
||||||
s += channels;
|
|
||||||
unsigned long s2 = sm2 += s1;
|
|
||||||
sm2 += sm1;
|
|
||||||
sm3 += s2;
|
|
||||||
sm3 += sm2;
|
|
||||||
} while (--sn);
|
|
||||||
}
|
|
||||||
|
|
||||||
sm1 += static_cast<long>(*s);
|
|
||||||
s += channels;
|
|
||||||
sm2 += sm1;
|
|
||||||
sm3 += sm2;
|
|
||||||
|
|
||||||
const unsigned long out3 = sm3 - prev3;
|
|
||||||
prev3 = sm3;
|
|
||||||
const unsigned long out2 = out3 - prev2;
|
|
||||||
prev2 = out3;
|
|
||||||
*out = rshift16_round(static_cast<long>(out2 - prev1) * mul);
|
|
||||||
prev1 = out2;
|
|
||||||
out += channels;
|
|
||||||
}
|
|
||||||
|
|
||||||
sum1 = sm1;
|
|
||||||
sum2 = sm2;
|
|
||||||
sum3 = sm3;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<unsigned channels>
|
|
||||||
std::size_t Cic3EvenOddCore<channels>::filter(short *out, const short *const in, std::size_t inlen) {
|
|
||||||
short *const outStart = out;
|
|
||||||
const short *s = in;
|
|
||||||
|
|
||||||
if (inlen >= nextdivn) {
|
|
||||||
{
|
|
||||||
{
|
|
||||||
unsigned divn = nextdivn;
|
|
||||||
|
|
||||||
do {
|
|
||||||
sum1 += static_cast<long>(*s);
|
|
||||||
s += channels;
|
|
||||||
sum2 += sum1;
|
|
||||||
sum3 += sum2;
|
|
||||||
} while (--divn);
|
|
||||||
}
|
|
||||||
|
|
||||||
const unsigned long out3 = sum3 - prev3;
|
|
||||||
prev3 = sum3;
|
|
||||||
const unsigned long out2 = out3 - prev2;
|
|
||||||
prev2 = out3;
|
|
||||||
*out = rshift16_round(static_cast<long>(out2 - prev1) * getMul(div_));
|
|
||||||
prev1 = out2;
|
|
||||||
out += channels;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t n = (inlen - nextdivn) / div_;
|
|
||||||
|
|
||||||
if (div_ & 1)
|
|
||||||
filterOdd(out, s, n);
|
|
||||||
else
|
|
||||||
filterEven(out, s, n);
|
|
||||||
|
|
||||||
s += n * div_ * channels;
|
|
||||||
out += n * channels;
|
|
||||||
nextdivn = div_;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
unsigned divn = inlen - (s - in) / channels;
|
|
||||||
nextdivn -= divn;
|
|
||||||
|
|
||||||
while (divn--) {
|
|
||||||
sum1 += static_cast<long>(*s);
|
|
||||||
s += channels;
|
|
||||||
sum2 += sum1;
|
|
||||||
sum3 += sum2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (out - outStart) / channels;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
template<unsigned channels>
|
|
||||||
class Cic3 : public SubResampler {
|
|
||||||
Cic3Core<channels> cics[channels];
|
|
||||||
|
|
||||||
public:
|
|
||||||
enum { MAX_DIV = 23 };
|
|
||||||
explicit Cic3(unsigned div);
|
|
||||||
std::size_t resample(short *out, const short *in, std::size_t inlen);
|
|
||||||
unsigned mul() const { return 1; }
|
|
||||||
unsigned div() const { return cics[0].div(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
template<unsigned channels>
|
|
||||||
Cic3<channels>::Cic3(const unsigned div) {
|
|
||||||
for (unsigned i = 0; i < channels; ++i)
|
|
||||||
cics[i].reset(div);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<unsigned channels>
|
|
||||||
std::size_t Cic3<channels>::resample(short *const out, const short *const in, const std::size_t inlen) {
|
|
||||||
std::size_t samplesOut;
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < channels; ++i) {
|
|
||||||
samplesOut = cics[i].filter(out + i, in + i, inlen);
|
|
||||||
}
|
|
||||||
|
|
||||||
return samplesOut;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,238 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2008 by Sindre Aamås *
|
|
||||||
* aamas@stud.ntnu.no *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU General Public License version 2 as *
|
|
||||||
* published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 version 2 for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License *
|
|
||||||
* version 2 along with this program; if not, write to the *
|
|
||||||
* Free Software Foundation, Inc., *
|
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
||||||
***************************************************************************/
|
|
||||||
#ifndef CIC4_H
|
|
||||||
#define CIC4_H
|
|
||||||
|
|
||||||
#include "subresampler.h"
|
|
||||||
#include "rshift16_round.h"
|
|
||||||
|
|
||||||
template<unsigned channels>
|
|
||||||
class Cic4Core {
|
|
||||||
enum { BUFLEN = 64 };
|
|
||||||
unsigned long buf[BUFLEN];
|
|
||||||
unsigned long sum1;
|
|
||||||
unsigned long sum2;
|
|
||||||
unsigned long sum3;
|
|
||||||
unsigned long sum4;
|
|
||||||
unsigned long prev1;
|
|
||||||
unsigned long prev2;
|
|
||||||
unsigned long prev3;
|
|
||||||
unsigned long prev4;
|
|
||||||
unsigned div_;
|
|
||||||
// unsigned nextdivn;
|
|
||||||
unsigned bufpos;
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit Cic4Core(const unsigned div = 1) {
|
|
||||||
reset(div);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned div() const { return div_; }
|
|
||||||
std::size_t filter(short *out, const short *in, std::size_t inlen);
|
|
||||||
void reset(unsigned div);
|
|
||||||
};
|
|
||||||
|
|
||||||
template<unsigned channels>
|
|
||||||
void Cic4Core<channels>::reset(const unsigned div) {
|
|
||||||
sum4 = sum3 = sum2 = sum1 = 0;
|
|
||||||
prev4 = prev3 = prev2 = prev1 = 0;
|
|
||||||
this->div_ = div;
|
|
||||||
// nextdivn = div;
|
|
||||||
bufpos = div - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<unsigned channels>
|
|
||||||
std::size_t Cic4Core<channels>::filter(short *out, const short *const in, std::size_t inlen) {
|
|
||||||
const std::size_t produced = (inlen + div_ - (bufpos + 1)) / div_;
|
|
||||||
// const std::size_t produced = (inlen + div_ - nextdivn) / div_;
|
|
||||||
const long mul = 0x10000 / (div_ * div_ * div_ * div_); // trouble if div is too large, may be better to only support power of 2 div
|
|
||||||
const short *s = in;
|
|
||||||
|
|
||||||
unsigned long sm1 = sum1;
|
|
||||||
unsigned long sm2 = sum2;
|
|
||||||
unsigned long sm3 = sum3;
|
|
||||||
unsigned long sm4 = sum4;
|
|
||||||
|
|
||||||
while (inlen >> 2) {
|
|
||||||
unsigned n = (inlen < BUFLEN ? inlen >> 2 : BUFLEN >> 2);
|
|
||||||
const unsigned end = n * 4;
|
|
||||||
unsigned i = 0;
|
|
||||||
|
|
||||||
do {
|
|
||||||
unsigned long s1 = sm1 += static_cast<long>(*s);
|
|
||||||
s += channels;
|
|
||||||
sm1 += static_cast<long>(*s);
|
|
||||||
s += channels;
|
|
||||||
unsigned long s2 = sm2 += s1;
|
|
||||||
sm2 += sm1;
|
|
||||||
unsigned long s3 = sm3 += s2;
|
|
||||||
sm3 += sm2;
|
|
||||||
buf[i++] = sm4 += s3;
|
|
||||||
buf[i++] = sm4 += sm3;
|
|
||||||
s1 = sm1 += static_cast<long>(*s);
|
|
||||||
s += channels;
|
|
||||||
sm1 += static_cast<long>(*s);
|
|
||||||
s += channels;
|
|
||||||
s2 = sm2 += s1;
|
|
||||||
sm2 += sm1;
|
|
||||||
s3 = sm3 += s2;
|
|
||||||
sm3 += sm2;
|
|
||||||
buf[i++] = sm4 += s3;
|
|
||||||
buf[i++] = sm4 += sm3;
|
|
||||||
} while (--n);
|
|
||||||
|
|
||||||
while (bufpos < end) {
|
|
||||||
const unsigned long out4 = buf[bufpos] - prev4;
|
|
||||||
prev4 = buf[bufpos];
|
|
||||||
bufpos += div_;
|
|
||||||
|
|
||||||
const unsigned long out3 = out4 - prev3;
|
|
||||||
prev3 = out4;
|
|
||||||
const unsigned long out2 = out3 - prev2;
|
|
||||||
prev2 = out3;
|
|
||||||
|
|
||||||
*out = rshift16_round(static_cast<long>(out2 - prev1) * mul);
|
|
||||||
prev1 = out2;
|
|
||||||
out += channels;
|
|
||||||
}
|
|
||||||
|
|
||||||
bufpos -= end;
|
|
||||||
inlen -= end;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inlen) {
|
|
||||||
unsigned n = inlen;
|
|
||||||
unsigned i = 0;
|
|
||||||
|
|
||||||
do {
|
|
||||||
sm1 += static_cast<long>(*s);
|
|
||||||
s += channels;
|
|
||||||
sm2 += sm1;
|
|
||||||
sm3 += sm2;
|
|
||||||
buf[i++] = sm4 += sm3;
|
|
||||||
} while (--n);
|
|
||||||
|
|
||||||
while (bufpos < inlen) {
|
|
||||||
const unsigned long out4 = buf[bufpos] - prev4;
|
|
||||||
prev4 = buf[bufpos];
|
|
||||||
bufpos += div_;
|
|
||||||
|
|
||||||
const unsigned long out3 = out4 - prev3;
|
|
||||||
prev3 = out4;
|
|
||||||
const unsigned long out2 = out3 - prev2;
|
|
||||||
prev2 = out3;
|
|
||||||
|
|
||||||
*out = rshift16_round(static_cast<long>(out2 - prev1) * mul);
|
|
||||||
prev1 = out2;
|
|
||||||
out += channels;
|
|
||||||
}
|
|
||||||
|
|
||||||
bufpos -= inlen;
|
|
||||||
}
|
|
||||||
|
|
||||||
sum1 = sm1;
|
|
||||||
sum2 = sm2;
|
|
||||||
sum3 = sm3;
|
|
||||||
sum4 = sm4;
|
|
||||||
|
|
||||||
/*unsigned long sm1 = sum1;
|
|
||||||
unsigned long sm2 = sum2;
|
|
||||||
unsigned long sm3 = sum3;
|
|
||||||
unsigned long sm4 = sum4;
|
|
||||||
|
|
||||||
if (produced) {
|
|
||||||
unsigned divn = nextdivn;
|
|
||||||
std::size_t n = produced;
|
|
||||||
|
|
||||||
do {
|
|
||||||
do {
|
|
||||||
sm1 += static_cast<long>(*s);
|
|
||||||
s += channels;
|
|
||||||
sm2 += sm1;
|
|
||||||
sm3 += sm2;
|
|
||||||
sm4 += sm3;
|
|
||||||
} while (--divn);
|
|
||||||
|
|
||||||
const unsigned long out4 = sm4 - prev4;
|
|
||||||
prev4 = sm4;
|
|
||||||
const unsigned long out3 = out4 - prev3;
|
|
||||||
prev3 = out4;
|
|
||||||
const unsigned long out2 = out3 - prev2;
|
|
||||||
prev2 = out3;
|
|
||||||
*out = rshift16_round(static_cast<long>(out2 - prev1) * mul);
|
|
||||||
prev1 = out2;
|
|
||||||
out += channels;
|
|
||||||
|
|
||||||
divn = div_;
|
|
||||||
} while (--n);
|
|
||||||
|
|
||||||
nextdivn = div_;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
unsigned divn = (in + inlen * channels - s) / channels;
|
|
||||||
nextdivn -= divn;
|
|
||||||
|
|
||||||
while (divn--) {
|
|
||||||
sm1 += static_cast<long>(*s);
|
|
||||||
s += channels;
|
|
||||||
sm2 += sm1;
|
|
||||||
sm3 += sm2;
|
|
||||||
sm4 += sm3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sum1 = sm1;
|
|
||||||
sum2 = sm2;
|
|
||||||
sum3 = sm3;
|
|
||||||
sum4 = sm4;*/
|
|
||||||
|
|
||||||
return produced;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<unsigned channels>
|
|
||||||
class Cic4 : public SubResampler {
|
|
||||||
Cic4Core<channels> cics[channels];
|
|
||||||
|
|
||||||
public:
|
|
||||||
enum { MAX_DIV = 13 };
|
|
||||||
explicit Cic4(unsigned div);
|
|
||||||
std::size_t resample(short *out, const short *in, std::size_t inlen);
|
|
||||||
unsigned mul() const { return 1; }
|
|
||||||
unsigned div() const { return cics[0].div(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
template<unsigned channels>
|
|
||||||
Cic4<channels>::Cic4(const unsigned div) {
|
|
||||||
for (unsigned i = 0; i < channels; ++i)
|
|
||||||
cics[i].reset(div);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<unsigned channels>
|
|
||||||
std::size_t Cic4<channels>::resample(short *const out, const short *const in, const std::size_t inlen) {
|
|
||||||
std::size_t samplesOut;
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < channels; ++i) {
|
|
||||||
samplesOut = cics[i].filter(out + i, in + i, inlen);
|
|
||||||
}
|
|
||||||
|
|
||||||
return samplesOut;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,162 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2008 by Sindre Aamås *
|
|
||||||
* aamas@stud.ntnu.no *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU General Public License version 2 as *
|
|
||||||
* published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 version 2 for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License *
|
|
||||||
* version 2 along with this program; if not, write to the *
|
|
||||||
* Free Software Foundation, Inc., *
|
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
||||||
***************************************************************************/
|
|
||||||
#ifndef CONVOLUTER_H
|
|
||||||
#define CONVOLUTER_H
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <cstring>
|
|
||||||
#include "gambatte-array.h"
|
|
||||||
#include "rshift16_round.h"
|
|
||||||
|
|
||||||
template<unsigned channels, unsigned phases>
|
|
||||||
class PolyPhaseConvoluter {
|
|
||||||
const short *kernel;
|
|
||||||
Array<short> prevbuf;
|
|
||||||
|
|
||||||
unsigned div_;
|
|
||||||
unsigned x_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
PolyPhaseConvoluter() : kernel(0), div_(0), x_(0) {}
|
|
||||||
PolyPhaseConvoluter(const short *kernel, unsigned phaseLen, unsigned div) { reset(kernel, phaseLen, div); }
|
|
||||||
void reset(const short *kernel, unsigned phaseLen, unsigned div);
|
|
||||||
std::size_t filter(short *out, const short *in, std::size_t inlen);
|
|
||||||
void adjustDiv(const unsigned div) { this->div_ = div; }
|
|
||||||
unsigned div() const { return div_; }
|
|
||||||
};
|
|
||||||
|
|
||||||
template<unsigned channels, unsigned phases>
|
|
||||||
void PolyPhaseConvoluter<channels, phases>::reset(const short *const kernel, const unsigned phaseLen, const unsigned div) {
|
|
||||||
this->kernel = kernel;
|
|
||||||
this->div_ = div;
|
|
||||||
x_ = 0;
|
|
||||||
prevbuf.reset(phaseLen);
|
|
||||||
std::fill(prevbuf.get(), prevbuf.get() + phaseLen, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<unsigned channels, unsigned phases>
|
|
||||||
std::size_t PolyPhaseConvoluter<channels, phases>::filter(short *out, const short *const in, std::size_t inlen) {
|
|
||||||
if (!kernel || !inlen)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
// The gist of what happens here is given by the commented pseudo-code below.
|
|
||||||
// Note that the order of the kernel elements has been changed for efficiency in the real implementation.
|
|
||||||
|
|
||||||
/*for (std::size_t x = 0; x < inlen + M; ++x) {
|
|
||||||
const int end = x < inlen ? M + 1 : inlen + M - x;
|
|
||||||
int j = x < M ? M - x : 0;
|
|
||||||
j += (phases - (x - M + j) % phases) % phases; // adjust j so we don't start on a virtual 0 sample
|
|
||||||
|
|
||||||
for (; j < end; j += phases) {
|
|
||||||
buffer[x] += kernel[j] * start[(x - M + j) / phases];
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
// Slightly more optimized version.
|
|
||||||
|
|
||||||
/*for (std::size_t x = 0; x < inlen + M; ++x) {
|
|
||||||
const int end = x < inlen ? M + 1 : inlen + M - x;
|
|
||||||
int j = x < M ? M - x : 0;
|
|
||||||
j += (phases - (x - M + j) % phases) % phases; // adjust j so we don't start on a virtual 0 sample
|
|
||||||
const short *k = kernel + (j % phases) * phaseLen + j / phases;
|
|
||||||
const short *s = start + (x - M + j) / phases;
|
|
||||||
int n = ((end - j) + phases - 1) / phases;
|
|
||||||
|
|
||||||
do {
|
|
||||||
buffer[x] += *k++ * *s++;
|
|
||||||
} while (--n);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
const std::size_t phaseLen = prevbuf.size();
|
|
||||||
const std::size_t M = phaseLen * phases - 1;
|
|
||||||
inlen *= phases;
|
|
||||||
std::size_t x = x_;
|
|
||||||
|
|
||||||
for (; x < (M < inlen ? M : inlen); x += div_) {
|
|
||||||
const short *k = kernel + ((x + 1) % phases) * phaseLen; // adjust phase so we don't start on a virtual 0 sample
|
|
||||||
const short *s = prevbuf + x / phases + 1;
|
|
||||||
long acc = 0;
|
|
||||||
unsigned n = prevbuf + phaseLen - s;
|
|
||||||
|
|
||||||
while (n--) {
|
|
||||||
acc += *k++ * *s++;
|
|
||||||
}
|
|
||||||
|
|
||||||
s = in;
|
|
||||||
n = x / phases + 1;
|
|
||||||
|
|
||||||
do {
|
|
||||||
acc += *k++ * *s;
|
|
||||||
s += channels;
|
|
||||||
} while (--n);
|
|
||||||
|
|
||||||
*out = rshift16_round(acc);
|
|
||||||
out += channels;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We could easily get rid of the division and modulus here by updating the
|
|
||||||
// k and s pointers incrementally. However, we currently only use powers of 2
|
|
||||||
// and we would end up referencing more variables which often compiles to bad
|
|
||||||
// code on x86, which is why I'm also hesistant to get rid of the template arguments.
|
|
||||||
for (; x < inlen; x += div_) {
|
|
||||||
const short *k = kernel + ((x + 1) % phases) * phaseLen; // adjust phase so we don't start on a virtual 0 sample
|
|
||||||
const short *s = in + (x / phases + 1 - phaseLen) * channels;
|
|
||||||
long acc = 0;
|
|
||||||
// unsigned n = (M + 1/* - phase + phases - 1*/) / phases;
|
|
||||||
unsigned n = phaseLen;
|
|
||||||
|
|
||||||
do {
|
|
||||||
acc += *k++ * *s;
|
|
||||||
s += channels;
|
|
||||||
} while (--n);
|
|
||||||
|
|
||||||
*out = rshift16_round(acc);
|
|
||||||
out += channels;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::size_t produced = (x - x_) / div_;
|
|
||||||
x_ = x - inlen;
|
|
||||||
|
|
||||||
inlen /= phases;
|
|
||||||
|
|
||||||
{
|
|
||||||
short *p = prevbuf;
|
|
||||||
const short *s = in + (inlen - phaseLen) * channels;
|
|
||||||
unsigned n = phaseLen;
|
|
||||||
|
|
||||||
if (inlen < phaseLen) {
|
|
||||||
const unsigned i = phaseLen - inlen;
|
|
||||||
|
|
||||||
std::memmove(p, p + inlen, i * sizeof(short));
|
|
||||||
|
|
||||||
p += i;
|
|
||||||
n -= i;
|
|
||||||
s = in;
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
|
||||||
*p++ = *s;
|
|
||||||
s += channels;
|
|
||||||
} while (--n);
|
|
||||||
}
|
|
||||||
|
|
||||||
return produced;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,100 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2008 by Sindre Aamås *
|
|
||||||
* aamas@stud.ntnu.no *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU General Public License version 2 as *
|
|
||||||
* published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 version 2 for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License *
|
|
||||||
* version 2 along with this program; if not, write to the *
|
|
||||||
* Free Software Foundation, Inc., *
|
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
||||||
***************************************************************************/
|
|
||||||
#ifndef HAMMINGSINC_H
|
|
||||||
#define HAMMINGSINC_H
|
|
||||||
|
|
||||||
#include "convoluter.h"
|
|
||||||
#include "subresampler.h"
|
|
||||||
#include "makesinckernel.h"
|
|
||||||
#include "cic3.h"
|
|
||||||
#include "gambatte-array.h"
|
|
||||||
#include <cmath>
|
|
||||||
#include <cstdlib>
|
|
||||||
|
|
||||||
template<unsigned channels, unsigned phases>
|
|
||||||
class HammingSinc : public SubResampler {
|
|
||||||
PolyPhaseConvoluter<channels, phases> convoluters[channels];
|
|
||||||
Array<short> kernel;
|
|
||||||
|
|
||||||
static double hammingWin(const long i, const long M) {
|
|
||||||
static const double PI = 3.14159265358979323846;
|
|
||||||
return 0.53836 - 0.46164 * std::cos(2 * PI * i / M);
|
|
||||||
}
|
|
||||||
|
|
||||||
void init(unsigned div, unsigned phaseLen, double fc);
|
|
||||||
|
|
||||||
public:
|
|
||||||
enum { MUL = phases };
|
|
||||||
|
|
||||||
typedef Cic3<channels> Cic;
|
|
||||||
static float cicLimit() { return 4.2f; }
|
|
||||||
|
|
||||||
class RollOff {
|
|
||||||
static unsigned toTaps(const float rollOffWidth) {
|
|
||||||
static const float widthTimesTaps = 3.0f;
|
|
||||||
return static_cast<unsigned>(std::ceil(widthTimesTaps / rollOffWidth));
|
|
||||||
}
|
|
||||||
|
|
||||||
static float toFc(const float rollOffStart, const int taps) {
|
|
||||||
static const float startToFcDeltaTimesTaps = 1.27f;
|
|
||||||
return startToFcDeltaTimesTaps / taps + rollOffStart;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
const unsigned taps;
|
|
||||||
const float fc;
|
|
||||||
|
|
||||||
RollOff(float rollOffStart, float rollOffWidth) : taps(toTaps(rollOffWidth)), fc(toFc(rollOffStart, taps)) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
HammingSinc(unsigned div, unsigned phaseLen, double fc) { init(div, phaseLen, fc); }
|
|
||||||
HammingSinc(unsigned div, RollOff ro) { init(div, ro.taps, ro.fc); }
|
|
||||||
std::size_t resample(short *out, const short *in, std::size_t inlen);
|
|
||||||
void adjustDiv(unsigned div);
|
|
||||||
unsigned mul() const { return MUL; }
|
|
||||||
unsigned div() const { return convoluters[0].div(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
template<unsigned channels, unsigned phases>
|
|
||||||
void HammingSinc<channels, phases>::init(const unsigned div, const unsigned phaseLen, const double fc) {
|
|
||||||
kernel.reset(phaseLen * phases);
|
|
||||||
|
|
||||||
makeSincKernel(kernel, phases, phaseLen, fc, hammingWin);
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < channels; ++i)
|
|
||||||
convoluters[i].reset(kernel, phaseLen, div);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<unsigned channels, unsigned phases>
|
|
||||||
std::size_t HammingSinc<channels, phases>::resample(short *const out, const short *const in, const std::size_t inlen) {
|
|
||||||
std::size_t samplesOut;
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < channels; ++i)
|
|
||||||
samplesOut = convoluters[i].filter(out + i, in + i, inlen);
|
|
||||||
|
|
||||||
return samplesOut;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<unsigned channels, unsigned phases>
|
|
||||||
void HammingSinc<channels, phases>::adjustDiv(const unsigned div) {
|
|
||||||
for (unsigned i = 0; i < channels; ++i)
|
|
||||||
convoluters[i].adjustDiv(div);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,36 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2009 by Sindre Aamås *
|
|
||||||
* aamas@stud.ntnu.no *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU General Public License version 2 as *
|
|
||||||
* published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 version 2 for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License *
|
|
||||||
* version 2 along with this program; if not, write to the *
|
|
||||||
* Free Software Foundation, Inc., *
|
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
||||||
***************************************************************************/
|
|
||||||
#include "i0.h"
|
|
||||||
|
|
||||||
double i0(double x) {
|
|
||||||
double sum = 1.0;
|
|
||||||
double xpm_dmfac = 1.0;
|
|
||||||
double m = 1.0;
|
|
||||||
unsigned n = 16;
|
|
||||||
|
|
||||||
x = 0.25 * x * x;
|
|
||||||
|
|
||||||
do {
|
|
||||||
xpm_dmfac *= x / (m*m);
|
|
||||||
sum += xpm_dmfac;
|
|
||||||
m += 1.0;
|
|
||||||
} while (--n);
|
|
||||||
|
|
||||||
return sum;
|
|
||||||
}
|
|
@ -1,24 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2009 by Sindre Aamås *
|
|
||||||
* aamas@stud.ntnu.no *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU General Public License version 2 as *
|
|
||||||
* published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 version 2 for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License *
|
|
||||||
* version 2 along with this program; if not, write to the *
|
|
||||||
* Free Software Foundation, Inc., *
|
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
||||||
***************************************************************************/
|
|
||||||
#ifndef I0_H
|
|
||||||
#define I0_H
|
|
||||||
|
|
||||||
double i0(double x);
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,107 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2008-2009 by Sindre Aamås *
|
|
||||||
* aamas@stud.ntnu.no *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU General Public License version 2 as *
|
|
||||||
* published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 version 2 for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License *
|
|
||||||
* version 2 along with this program; if not, write to the *
|
|
||||||
* Free Software Foundation, Inc., *
|
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
||||||
***************************************************************************/
|
|
||||||
#ifndef KAISER50SINC_H
|
|
||||||
#define KAISER50SINC_H
|
|
||||||
|
|
||||||
#include "convoluter.h"
|
|
||||||
#include "subresampler.h"
|
|
||||||
#include "makesinckernel.h"
|
|
||||||
#include "i0.h"
|
|
||||||
#include "cic3.h"
|
|
||||||
#include "gambatte-array.h"
|
|
||||||
#include <cmath>
|
|
||||||
#include <cstdlib>
|
|
||||||
|
|
||||||
template<unsigned channels, unsigned phases>
|
|
||||||
class Kaiser50Sinc : public SubResampler {
|
|
||||||
PolyPhaseConvoluter<channels, phases> convoluters[channels];
|
|
||||||
Array<short> kernel;
|
|
||||||
|
|
||||||
static double kaiserWin(const long n, const long M) {
|
|
||||||
static const double beta = 4.62;
|
|
||||||
static const double i0beta_rec = 1.0 / i0(beta);
|
|
||||||
|
|
||||||
double x = static_cast<double>(n * 2) / M - 1.0;
|
|
||||||
x = x * x;
|
|
||||||
x = beta * std::sqrt(1.0 - x);
|
|
||||||
|
|
||||||
return i0(x) * i0beta_rec;
|
|
||||||
}
|
|
||||||
|
|
||||||
void init(unsigned div, unsigned phaseLen, double fc);
|
|
||||||
|
|
||||||
public:
|
|
||||||
enum { MUL = phases };
|
|
||||||
|
|
||||||
typedef Cic3<channels> Cic;
|
|
||||||
static float cicLimit() { return 4.2f; }
|
|
||||||
|
|
||||||
class RollOff {
|
|
||||||
static unsigned toTaps(const float rollOffWidth) {
|
|
||||||
static const float widthTimesTaps = 2.715f;
|
|
||||||
return static_cast<unsigned>(std::ceil(widthTimesTaps / rollOffWidth));
|
|
||||||
}
|
|
||||||
|
|
||||||
static float toFc(const float rollOffStart, const int taps) {
|
|
||||||
static const float startToFcDeltaTimesTaps = 1.2f;
|
|
||||||
return startToFcDeltaTimesTaps / taps + rollOffStart;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
const unsigned taps;
|
|
||||||
const float fc;
|
|
||||||
|
|
||||||
RollOff(float rollOffStart, float rollOffWidth) : taps(toTaps(rollOffWidth)), fc(toFc(rollOffStart, taps)) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
Kaiser50Sinc(unsigned div, unsigned phaseLen, double fc) { init(div, phaseLen, fc); }
|
|
||||||
Kaiser50Sinc(unsigned div, RollOff ro) { init(div, ro.taps, ro.fc); }
|
|
||||||
std::size_t resample(short *out, const short *in, std::size_t inlen);
|
|
||||||
void adjustDiv(unsigned div);
|
|
||||||
unsigned mul() const { return MUL; }
|
|
||||||
unsigned div() const { return convoluters[0].div(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
template<unsigned channels, unsigned phases>
|
|
||||||
void Kaiser50Sinc<channels, phases>::init(const unsigned div, const unsigned phaseLen, const double fc) {
|
|
||||||
kernel.reset(phaseLen * phases);
|
|
||||||
|
|
||||||
makeSincKernel(kernel, phases, phaseLen, fc, kaiserWin);
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < channels; ++i)
|
|
||||||
convoluters[i].reset(kernel, phaseLen, div);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<unsigned channels, unsigned phases>
|
|
||||||
std::size_t Kaiser50Sinc<channels, phases>::resample(short *const out, const short *const in, const std::size_t inlen) {
|
|
||||||
std::size_t samplesOut;
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < channels; ++i)
|
|
||||||
samplesOut = convoluters[i].filter(out + i, in + i, inlen);
|
|
||||||
|
|
||||||
return samplesOut;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<unsigned channels, unsigned phases>
|
|
||||||
void Kaiser50Sinc<channels, phases>::adjustDiv(const unsigned div) {
|
|
||||||
for (unsigned i = 0; i < channels; ++i)
|
|
||||||
convoluters[i].adjustDiv(div);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,107 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2008-2009 by Sindre Aamås *
|
|
||||||
* aamas@stud.ntnu.no *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU General Public License version 2 as *
|
|
||||||
* published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 version 2 for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License *
|
|
||||||
* version 2 along with this program; if not, write to the *
|
|
||||||
* Free Software Foundation, Inc., *
|
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
||||||
***************************************************************************/
|
|
||||||
#ifndef KAISER70SINC_H
|
|
||||||
#define KAISER70SINC_H
|
|
||||||
|
|
||||||
#include "convoluter.h"
|
|
||||||
#include "subresampler.h"
|
|
||||||
#include "makesinckernel.h"
|
|
||||||
#include "i0.h"
|
|
||||||
#include "cic4.h"
|
|
||||||
#include "gambatte-array.h"
|
|
||||||
#include <cmath>
|
|
||||||
#include <cstdlib>
|
|
||||||
|
|
||||||
template<unsigned channels, unsigned phases>
|
|
||||||
class Kaiser70Sinc : public SubResampler {
|
|
||||||
PolyPhaseConvoluter<channels, phases> convoluters[channels];
|
|
||||||
Array<short> kernel;
|
|
||||||
|
|
||||||
static double kaiserWin(const long n, const long M) {
|
|
||||||
static const double beta = 6.9;
|
|
||||||
static const double i0beta_rec = 1.0 / i0(beta);
|
|
||||||
|
|
||||||
double x = static_cast<double>(n * 2) / M - 1.0;
|
|
||||||
x = x * x;
|
|
||||||
x = beta * std::sqrt(1.0 - x);
|
|
||||||
|
|
||||||
return i0(x) * i0beta_rec;
|
|
||||||
}
|
|
||||||
|
|
||||||
void init(unsigned div, unsigned phaseLen, double fc);
|
|
||||||
|
|
||||||
public:
|
|
||||||
enum { MUL = phases };
|
|
||||||
|
|
||||||
typedef Cic4<channels> Cic;
|
|
||||||
static float cicLimit() { return 4.7f; }
|
|
||||||
|
|
||||||
class RollOff {
|
|
||||||
static unsigned toTaps(const float rollOffWidth) {
|
|
||||||
static const float widthTimesTaps = 3.75f;
|
|
||||||
return static_cast<unsigned>(std::ceil(widthTimesTaps / rollOffWidth));
|
|
||||||
}
|
|
||||||
|
|
||||||
static float toFc(const float rollOffStart, const int taps) {
|
|
||||||
static const float startToFcDeltaTimesTaps = 1.5f;
|
|
||||||
return startToFcDeltaTimesTaps / taps + rollOffStart;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
const unsigned taps;
|
|
||||||
const float fc;
|
|
||||||
|
|
||||||
RollOff(float rollOffStart, float rollOffWidth) : taps(toTaps(rollOffWidth)), fc(toFc(rollOffStart, taps)) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
Kaiser70Sinc(unsigned div, unsigned phaseLen, double fc) { init(div, phaseLen, fc); }
|
|
||||||
Kaiser70Sinc(unsigned div, RollOff ro) { init(div, ro.taps, ro.fc); }
|
|
||||||
std::size_t resample(short *out, const short *in, std::size_t inlen);
|
|
||||||
void adjustDiv(unsigned div);
|
|
||||||
unsigned mul() const { return MUL; }
|
|
||||||
unsigned div() const { return convoluters[0].div(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
template<unsigned channels, unsigned phases>
|
|
||||||
void Kaiser70Sinc<channels, phases>::init(const unsigned div, const unsigned phaseLen, const double fc) {
|
|
||||||
kernel.reset(phaseLen * phases);
|
|
||||||
|
|
||||||
makeSincKernel(kernel, phases, phaseLen, fc, kaiserWin);
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < channels; ++i)
|
|
||||||
convoluters[i].reset(kernel, phaseLen, div);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<unsigned channels, unsigned phases>
|
|
||||||
std::size_t Kaiser70Sinc<channels, phases>::resample(short *const out, const short *const in, const std::size_t inlen) {
|
|
||||||
std::size_t samplesOut;
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < channels; ++i)
|
|
||||||
samplesOut = convoluters[i].filter(out + i, in + i, inlen);
|
|
||||||
|
|
||||||
return samplesOut;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<unsigned channels, unsigned phases>
|
|
||||||
void Kaiser70Sinc<channels, phases>::adjustDiv(const unsigned div) {
|
|
||||||
for (unsigned i = 0; i < channels; ++i)
|
|
||||||
convoluters[i].adjustDiv(div);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,134 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2008 by Sindre Aamås *
|
|
||||||
* aamas@stud.ntnu.no *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU General Public License version 2 as *
|
|
||||||
* published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 version 2 for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License *
|
|
||||||
* version 2 along with this program; if not, write to the *
|
|
||||||
* Free Software Foundation, Inc., *
|
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
||||||
***************************************************************************/
|
|
||||||
#ifndef LININT_H
|
|
||||||
#define LININT_H
|
|
||||||
|
|
||||||
#include <cstddef>
|
|
||||||
#include "../resampler.h"
|
|
||||||
#include "u48div.h"
|
|
||||||
#include "rshift16_round.h"
|
|
||||||
|
|
||||||
template<unsigned channels>
|
|
||||||
class LinintCore {
|
|
||||||
unsigned long ratio;
|
|
||||||
std::size_t pos_;
|
|
||||||
unsigned fracPos_;
|
|
||||||
int prevSample_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
LinintCore(long inRate = 1, long outRate = 1) { init(inRate, outRate); }
|
|
||||||
|
|
||||||
void adjustRate(long inRate, long outRate) {
|
|
||||||
ratio = static_cast<unsigned long>((static_cast<double>(inRate) / outRate) * 0x10000 + 0.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
void exactRatio(unsigned long &mul, unsigned long &div) const { mul = 0x10000; div = ratio; }
|
|
||||||
void init(long inRate, long outRate);
|
|
||||||
std::size_t maxOut(std::size_t inlen) const { return inlen ? u48div(inlen - 1, 0xFFFF, ratio) + 1 : 0; }
|
|
||||||
std::size_t resample(short *out, const short *in, std::size_t inlen);
|
|
||||||
};
|
|
||||||
|
|
||||||
template<unsigned channels>
|
|
||||||
void LinintCore<channels>::init(const long inRate, const long outRate) {
|
|
||||||
adjustRate(inRate, outRate);
|
|
||||||
pos_ = (ratio >> 16) + 1;
|
|
||||||
fracPos_ = ratio & 0xFFFF;
|
|
||||||
prevSample_ = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<unsigned channels>
|
|
||||||
std::size_t LinintCore<channels>::resample(short *const out, const short *const in, const std::size_t inlen) {
|
|
||||||
std::size_t opos = 0;
|
|
||||||
std::size_t pos = pos_;
|
|
||||||
unsigned fracPos = fracPos_;
|
|
||||||
int prevSample = prevSample_;
|
|
||||||
|
|
||||||
if (pos < inlen) {
|
|
||||||
if (pos != 0)
|
|
||||||
prevSample = in[(pos-1) * channels];
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
out[opos] = prevSample + rshift16_round((in[pos * channels] - prevSample) * static_cast<long>(fracPos));
|
|
||||||
opos += channels;
|
|
||||||
|
|
||||||
{
|
|
||||||
const unsigned long next = ratio + fracPos;
|
|
||||||
|
|
||||||
pos += next >> 16;
|
|
||||||
fracPos = next & 0xFFFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pos < inlen) {
|
|
||||||
prevSample = in[(pos-1) * channels];
|
|
||||||
} else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pos == inlen)
|
|
||||||
prevSample = in[(pos-1) * channels];
|
|
||||||
}
|
|
||||||
|
|
||||||
// const std::size_t produced = ((pos - pos_) * 0x10000 + fracPos - fracPos_) / ratio;
|
|
||||||
|
|
||||||
pos_ = pos - inlen;
|
|
||||||
fracPos_ = fracPos;
|
|
||||||
prevSample_ = prevSample;
|
|
||||||
|
|
||||||
return opos / channels;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<unsigned channels>
|
|
||||||
class Linint : public Resampler {
|
|
||||||
LinintCore<channels> cores[channels];
|
|
||||||
|
|
||||||
public:
|
|
||||||
Linint(long inRate, long outRate);
|
|
||||||
void adjustRate(long inRate, long outRate);
|
|
||||||
void exactRatio(unsigned long &mul, unsigned long &div) const { cores[0].exactRatio(mul, div); }
|
|
||||||
std::size_t maxOut(std::size_t inlen) const { return cores[0].maxOut(inlen); }
|
|
||||||
std::size_t resample(short *out, const short *in, std::size_t inlen);
|
|
||||||
};
|
|
||||||
|
|
||||||
template<unsigned channels>
|
|
||||||
Linint<channels>::Linint(const long inRate, const long outRate) {
|
|
||||||
setRate(inRate, outRate);
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < channels; ++i)
|
|
||||||
cores[i].init(inRate, outRate);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<unsigned channels>
|
|
||||||
void Linint<channels>::adjustRate(const long inRate, const long outRate) {
|
|
||||||
setRate(inRate, outRate);
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < channels; ++i)
|
|
||||||
cores[i].adjustRate(inRate, outRate);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<unsigned channels>
|
|
||||||
std::size_t Linint<channels>::resample(short *const out, const short *const in, const std::size_t inlen) {
|
|
||||||
std::size_t outlen = 0;
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < channels; ++i)
|
|
||||||
outlen = cores[i].resample(out + i, in + i, inlen);
|
|
||||||
|
|
||||||
return outlen;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,142 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2008 by Sindre Aamås *
|
|
||||||
* aamas@stud.ntnu.no *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU General Public License version 2 as *
|
|
||||||
* published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 version 2 for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License *
|
|
||||||
* version 2 along with this program; if not, write to the *
|
|
||||||
* Free Software Foundation, Inc., *
|
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
||||||
***************************************************************************/
|
|
||||||
#include "makesinckernel.h"
|
|
||||||
#include "gambatte-array.h"
|
|
||||||
|
|
||||||
void makeSincKernel(short *const kernel, const unsigned phases, const unsigned phaseLen, double fc, double (*win)(const long m, const long M)) {
|
|
||||||
static const double PI = 3.14159265358979323846;
|
|
||||||
fc /= phases;
|
|
||||||
|
|
||||||
/*{
|
|
||||||
const Array<double> dkernel(phaseLen * phases);
|
|
||||||
const long M = static_cast<long>(phaseLen) * phases - 1;
|
|
||||||
|
|
||||||
for (long i = 0; i < M + 1; ++i) {
|
|
||||||
const double sinc = i * 2 == M ?
|
|
||||||
PI * fc :
|
|
||||||
std::sin(PI * fc * (i * 2 - M)) / (i * 2 - M);
|
|
||||||
|
|
||||||
dkernel[((phases - (i % phases)) % phases) * phaseLen + i / phases] = win(i, M) * sinc;
|
|
||||||
}
|
|
||||||
|
|
||||||
double maxabsgain = 0;
|
|
||||||
|
|
||||||
for (unsigned ph = 0; ph < phases; ++ph) {
|
|
||||||
double gain = 0;
|
|
||||||
double absgain = 0;
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < phaseLen; ++i) {
|
|
||||||
gain += dkernel[ph * phaseLen + i];
|
|
||||||
absgain += std::abs(dkernel[ph * phaseLen + i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
gain = 1.0 / gain;
|
|
||||||
|
|
||||||
// Per phase normalization to avoid DC fluctuations.
|
|
||||||
for (unsigned i = 0; i < phaseLen; ++i)
|
|
||||||
dkernel[ph * phaseLen + i] *= gain;
|
|
||||||
|
|
||||||
absgain *= gain;
|
|
||||||
|
|
||||||
if (absgain > maxabsgain)
|
|
||||||
maxabsgain = absgain;
|
|
||||||
}
|
|
||||||
|
|
||||||
const double gain = (0x10000 - 0.5 * phaseLen) / maxabsgain;
|
|
||||||
|
|
||||||
for (long i = 0; i < M + 1; ++i)
|
|
||||||
kernel[i] = std::floor(dkernel[i] * gain + 0.5);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
// The following is equivalent to the more readable version above
|
|
||||||
|
|
||||||
const long M = static_cast<long>(phaseLen) * phases - 1;
|
|
||||||
|
|
||||||
const Array<double> dkernel(M / 2 + 1);
|
|
||||||
|
|
||||||
{
|
|
||||||
double *dk = dkernel;
|
|
||||||
|
|
||||||
for (unsigned ph = 0; ph < phases; ++ph) {
|
|
||||||
for (long i = ph; i < M / 2 + 1; i += phases) {
|
|
||||||
const double sinc = i * 2 == M ?
|
|
||||||
PI * fc :
|
|
||||||
std::sin(PI * fc * (i * 2 - M)) / (i * 2 - M);
|
|
||||||
|
|
||||||
*dk++ = win(i, M) * sinc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
double maxabsgain = 0.0;
|
|
||||||
|
|
||||||
{
|
|
||||||
double *dkp1 = dkernel;
|
|
||||||
double *dkp2 = dkernel + M / 2;
|
|
||||||
|
|
||||||
for (unsigned ph = 0; ph < (phases + 1) / 2; ++ph) {
|
|
||||||
double gain = 0.0;
|
|
||||||
double absgain = 0.0;
|
|
||||||
|
|
||||||
{
|
|
||||||
const double *kp1 = dkp1;
|
|
||||||
const double *kp2 = dkp2;
|
|
||||||
long i = ph;
|
|
||||||
|
|
||||||
for (; i < M / 2 + 1; i += phases) {
|
|
||||||
gain += *kp1;
|
|
||||||
absgain += std::abs(*kp1++);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (; i < M + 1; i += phases) {
|
|
||||||
gain += *kp2;
|
|
||||||
absgain += std::abs(*kp2--);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
gain = 1.0 / gain;
|
|
||||||
|
|
||||||
long i = ph;
|
|
||||||
|
|
||||||
for (; i < M / 2 + 1; i += phases)
|
|
||||||
*dkp1++ *= gain;
|
|
||||||
|
|
||||||
if (dkp1 < dkp2) {
|
|
||||||
for (; i < M + 1; i += phases)
|
|
||||||
*dkp2-- *= gain;
|
|
||||||
}
|
|
||||||
|
|
||||||
absgain *= gain;
|
|
||||||
|
|
||||||
if (absgain > maxabsgain)
|
|
||||||
maxabsgain = absgain;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const double gain = (0x10000 - 0.5 * phaseLen) / maxabsgain;
|
|
||||||
const double *dk = dkernel;
|
|
||||||
|
|
||||||
for (unsigned ph = 0; ph < phases; ++ph) {
|
|
||||||
short *k = kernel + ((phases - ph) % phases) * phaseLen;
|
|
||||||
short *km = kernel + phaseLen - 1 + ((ph + 1) % phases) * phaseLen;
|
|
||||||
|
|
||||||
for (long i = ph; i < M / 2 + 1; i += phases)
|
|
||||||
*km-- = *k++ = static_cast<short>(std::floor(*dk++ * gain + 0.5));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2008 by Sindre Aamås *
|
|
||||||
* aamas@stud.ntnu.no *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU General Public License version 2 as *
|
|
||||||
* published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 version 2 for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License *
|
|
||||||
* version 2 along with this program; if not, write to the *
|
|
||||||
* Free Software Foundation, Inc., *
|
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
||||||
***************************************************************************/
|
|
||||||
#ifndef MAKE_SINC_KERNEL_H
|
|
||||||
#define MAKE_SINC_KERNEL_H
|
|
||||||
|
|
||||||
#include <cmath>
|
|
||||||
#include <cstdlib>
|
|
||||||
|
|
||||||
void makeSincKernel(short *kernel, unsigned phases,
|
|
||||||
unsigned phaseLen, double fc, double (*win)(const long m, const long M));
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,99 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2008 by Sindre Aamås *
|
|
||||||
* aamas@stud.ntnu.no *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU General Public License version 2 as *
|
|
||||||
* published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 version 2 for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License *
|
|
||||||
* version 2 along with this program; if not, write to the *
|
|
||||||
* Free Software Foundation, Inc., *
|
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
||||||
***************************************************************************/
|
|
||||||
#ifndef RECTSINC_H
|
|
||||||
#define RECTSINC_H
|
|
||||||
|
|
||||||
#include "convoluter.h"
|
|
||||||
#include "subresampler.h"
|
|
||||||
#include "makesinckernel.h"
|
|
||||||
#include "cic2.h"
|
|
||||||
#include "gambatte-array.h"
|
|
||||||
#include <cmath>
|
|
||||||
#include <cstdlib>
|
|
||||||
|
|
||||||
template<unsigned channels, unsigned phases>
|
|
||||||
class RectSinc : public SubResampler {
|
|
||||||
PolyPhaseConvoluter<channels, phases> convoluters[channels];
|
|
||||||
Array<short> kernel;
|
|
||||||
|
|
||||||
static double rectWin(const long /*i*/, const long /*M*/) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void init(unsigned div, unsigned phaseLen, double fc);
|
|
||||||
|
|
||||||
public:
|
|
||||||
enum { MUL = phases };
|
|
||||||
|
|
||||||
typedef Cic2<channels> Cic;
|
|
||||||
static float cicLimit() { return 2.0f; }
|
|
||||||
|
|
||||||
class RollOff {
|
|
||||||
static unsigned toTaps(const float rollOffWidth) {
|
|
||||||
static const float widthTimesTaps = 0.9f;
|
|
||||||
return static_cast<unsigned>(std::ceil(widthTimesTaps / rollOffWidth));
|
|
||||||
}
|
|
||||||
|
|
||||||
static float toFc(const float rollOffStart, const int taps) {
|
|
||||||
static const float startToFcDeltaTimesTaps = 0.43f;
|
|
||||||
return startToFcDeltaTimesTaps / taps + rollOffStart;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
const unsigned taps;
|
|
||||||
const float fc;
|
|
||||||
|
|
||||||
RollOff(float rollOffStart, float rollOffWidth) : taps(toTaps(rollOffWidth)), fc(toFc(rollOffStart, taps)) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
RectSinc(unsigned div, unsigned phaseLen, double fc) { init(div, phaseLen, fc); }
|
|
||||||
RectSinc(unsigned div, RollOff ro) { init(div, ro.taps, ro.fc); }
|
|
||||||
std::size_t resample(short *out, const short *in, std::size_t inlen);
|
|
||||||
void adjustDiv(unsigned div);
|
|
||||||
unsigned mul() const { return MUL; }
|
|
||||||
unsigned div() const { return convoluters[0].div(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
template<unsigned channels, unsigned phases>
|
|
||||||
void RectSinc<channels, phases>::init(const unsigned div, const unsigned phaseLen, const double fc) {
|
|
||||||
kernel.reset(phaseLen * phases);
|
|
||||||
|
|
||||||
makeSincKernel(kernel, phases, phaseLen, fc, rectWin);
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < channels; ++i)
|
|
||||||
convoluters[i].reset(kernel, phaseLen, div);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<unsigned channels, unsigned phases>
|
|
||||||
std::size_t RectSinc<channels, phases>::resample(short *const out, const short *const in, const std::size_t inlen) {
|
|
||||||
std::size_t samplesOut;
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < channels; ++i)
|
|
||||||
samplesOut = convoluters[i].filter(out + i, in + i, inlen);
|
|
||||||
|
|
||||||
return samplesOut;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<unsigned channels, unsigned phases>
|
|
||||||
void RectSinc<channels, phases>::adjustDiv(const unsigned div) {
|
|
||||||
for (unsigned i = 0; i < channels; ++i)
|
|
||||||
convoluters[i].adjustDiv(div);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,50 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2008 by Sindre Aamås *
|
|
||||||
* aamas@stud.ntnu.no *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU General Public License version 2 as *
|
|
||||||
* published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 version 2 for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License *
|
|
||||||
* version 2 along with this program; if not, write to the *
|
|
||||||
* Free Software Foundation, Inc., *
|
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
||||||
***************************************************************************/
|
|
||||||
#include "../resamplerinfo.h"
|
|
||||||
#include "chainresampler.h"
|
|
||||||
#include "kaiser50sinc.h"
|
|
||||||
#include "kaiser70sinc.h"
|
|
||||||
// #include "hammingsinc.h"
|
|
||||||
// #include "blackmansinc.h"
|
|
||||||
#include "rectsinc.h"
|
|
||||||
#include "linint.h"
|
|
||||||
|
|
||||||
struct LinintInfo {
|
|
||||||
static Resampler* create(long inRate, long outRate, std::size_t) { return new Linint<ChainResampler::channels>(inRate, outRate); }
|
|
||||||
};
|
|
||||||
|
|
||||||
template<template<unsigned,unsigned> class T>
|
|
||||||
struct ChainSincInfo {
|
|
||||||
static Resampler* create(long inRate, long outRate, std::size_t periodSz) {
|
|
||||||
ChainResampler *r = new ChainResampler;
|
|
||||||
r->init<T>(inRate, outRate, periodSz);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const ResamplerInfo ResamplerInfo::resamplers[] = {
|
|
||||||
{ "Fast", LinintInfo::create },
|
|
||||||
{ "High quality (CIC + sinc chain)", ChainSincInfo<RectSinc>::create },
|
|
||||||
// { "Hamming windowed sinc (~50 dB SNR)", ChainSincInfo<HammingSinc>::create },
|
|
||||||
// { "Blackman windowed sinc (~70 dB SNR)", ChainSincInfo<BlackmanSinc>::create },
|
|
||||||
{ "Very high quality (CIC + sinc chain)", ChainSincInfo<Kaiser50Sinc>::create },
|
|
||||||
{ "Highest quality (CIC + sinc chain)", ChainSincInfo<Kaiser70Sinc>::create }
|
|
||||||
};
|
|
||||||
|
|
||||||
const unsigned ResamplerInfo::num_ = sizeof(ResamplerInfo::resamplers) / sizeof(ResamplerInfo);
|
|
@ -1,32 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2008 by Sindre Aamås *
|
|
||||||
* aamas@stud.ntnu.no *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU General Public License version 2 as *
|
|
||||||
* published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 version 2 for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License *
|
|
||||||
* version 2 along with this program; if not, write to the *
|
|
||||||
* Free Software Foundation, Inc., *
|
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
||||||
***************************************************************************/
|
|
||||||
#ifndef RSHIFT16_ROUND_H
|
|
||||||
#define RSHIFT16_ROUND_H
|
|
||||||
|
|
||||||
#ifdef NO_NEGATIVE_SHIFT
|
|
||||||
static inline long rshift16_round(const long l) {
|
|
||||||
return l < 0 ? -((-l + 0x8000) >> 16) : (l + 0x8000) >> 16;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
static inline long rshift16_round(const long l) {
|
|
||||||
return (l + 0x8000) >> 16;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,33 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2008 by Sindre Aamås *
|
|
||||||
* aamas@stud.ntnu.no *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU General Public License version 2 as *
|
|
||||||
* published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 version 2 for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License *
|
|
||||||
* version 2 along with this program; if not, write to the *
|
|
||||||
* Free Software Foundation, Inc., *
|
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
||||||
***************************************************************************/
|
|
||||||
#ifndef SUBRESAMPLER_H
|
|
||||||
#define SUBRESAMPLER_H
|
|
||||||
|
|
||||||
#include <cstddef>
|
|
||||||
|
|
||||||
class SubResampler {
|
|
||||||
public:
|
|
||||||
virtual std::size_t resample(short *out, const short *in, std::size_t inlen) = 0;
|
|
||||||
virtual unsigned mul() const = 0;
|
|
||||||
virtual unsigned div() const = 0;
|
|
||||||
virtual void adjustDiv(unsigned /*div*/) {}
|
|
||||||
virtual ~SubResampler() {}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,54 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2008 by Sindre Aamås *
|
|
||||||
* aamas@stud.ntnu.no *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU General Public License version 2 as *
|
|
||||||
* published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 version 2 for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License *
|
|
||||||
* version 2 along with this program; if not, write to the *
|
|
||||||
* Free Software Foundation, Inc., *
|
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
||||||
***************************************************************************/
|
|
||||||
#include "u48div.h"
|
|
||||||
|
|
||||||
unsigned long u48div(unsigned long num1, unsigned num2, const unsigned long den) {
|
|
||||||
unsigned long res = 0;
|
|
||||||
unsigned s = 16;
|
|
||||||
|
|
||||||
do {
|
|
||||||
if (num1 < 0x10000) {
|
|
||||||
num1 <<= s;
|
|
||||||
num1 |= num2 & ((1 << s) - 1);
|
|
||||||
s = 0;
|
|
||||||
} else {
|
|
||||||
if (num1 < 0x1000000) {
|
|
||||||
const unsigned maxs = s < 8 ? s : 8;
|
|
||||||
num1 <<= maxs;
|
|
||||||
num1 |= (num2 >> (s -= maxs)) & ((1 << maxs) - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (num1 < 0x10000000) {
|
|
||||||
const unsigned maxs = s < 4 ? s : 4;
|
|
||||||
num1 <<= maxs;
|
|
||||||
num1 |= (num2 >> (s -= maxs)) & ((1 << maxs) - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
while (num1 < den && s) {
|
|
||||||
num1 <<= 1; // if this overflows we're screwed
|
|
||||||
num1 |= num2 >> --s & 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
res += (num1 / den) << s;
|
|
||||||
num1 = (num1 % den);
|
|
||||||
} while (s);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
@ -1,24 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2008 by Sindre Aamås *
|
|
||||||
* aamas@stud.ntnu.no *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU General Public License version 2 as *
|
|
||||||
* published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 version 2 for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License *
|
|
||||||
* version 2 along with this program; if not, write to the *
|
|
||||||
* Free Software Foundation, Inc., *
|
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
||||||
***************************************************************************/
|
|
||||||
#ifndef U48DIV_H
|
|
||||||
#define U48DIV_H
|
|
||||||
|
|
||||||
unsigned long u48div(unsigned long num1, unsigned num2, unsigned long den);
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,51 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2008 by Sindre Aamås *
|
|
||||||
* aamas@stud.ntnu.no *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU General Public License version 2 as *
|
|
||||||
* published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 version 2 for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License *
|
|
||||||
* version 2 along with this program; if not, write to the *
|
|
||||||
* Free Software Foundation, Inc., *
|
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
||||||
***************************************************************************/
|
|
||||||
#ifndef UPSAMPLER_H
|
|
||||||
#define UPSAMPLER_H
|
|
||||||
|
|
||||||
#include "subresampler.h"
|
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
template<unsigned channels>
|
|
||||||
class Upsampler : public SubResampler {
|
|
||||||
unsigned mul_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
Upsampler(const unsigned mul) : mul_(mul) {}
|
|
||||||
std::size_t resample(short *out, const short *in, std::size_t inlen);
|
|
||||||
unsigned mul() const { return mul_; }
|
|
||||||
unsigned div() const { return 1; }
|
|
||||||
};
|
|
||||||
|
|
||||||
template<unsigned channels>
|
|
||||||
std::size_t Upsampler<channels>::resample(short *out, const short *in, std::size_t inlen) {
|
|
||||||
if (inlen) {
|
|
||||||
std::memset(out, 0, inlen * mul_ * sizeof(short) * channels);
|
|
||||||
|
|
||||||
do {
|
|
||||||
std::memcpy(out, in, sizeof(short) * channels);
|
|
||||||
in += channels;
|
|
||||||
out += mul_ * channels;
|
|
||||||
} while (--inlen);
|
|
||||||
}
|
|
||||||
|
|
||||||
return inlen * mul_;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,112 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2008 by Sindre Aamås *
|
|
||||||
* aamas@stud.ntnu.no *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU General Public License version 2 as *
|
|
||||||
* published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 version 2 for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License *
|
|
||||||
* version 2 along with this program; if not, write to the *
|
|
||||||
* Free Software Foundation, Inc., *
|
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
||||||
***************************************************************************/
|
|
||||||
#ifndef RINGBUFFER_H
|
|
||||||
#define RINGBUFFER_H
|
|
||||||
|
|
||||||
#include "gambatte-array.h"
|
|
||||||
#include <cstddef>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
class RingBuffer {
|
|
||||||
Array<T> buf;
|
|
||||||
std::size_t sz;
|
|
||||||
std::size_t rpos;
|
|
||||||
std::size_t wpos;
|
|
||||||
|
|
||||||
public:
|
|
||||||
RingBuffer(const std::size_t sz_in = 0) : sz(0), rpos(0), wpos(0) { reset(sz_in); }
|
|
||||||
|
|
||||||
std::size_t avail() const {
|
|
||||||
return (wpos < rpos ? 0 : sz) + rpos - wpos - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear() {
|
|
||||||
wpos = rpos = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void fill(T value);
|
|
||||||
|
|
||||||
void read(T *out, std::size_t num);
|
|
||||||
|
|
||||||
void reset(std::size_t sz_in);
|
|
||||||
|
|
||||||
std::size_t size() const {
|
|
||||||
return sz - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t used() const {
|
|
||||||
return (wpos < rpos ? sz : 0) + wpos - rpos;
|
|
||||||
}
|
|
||||||
|
|
||||||
void write(const T *in, std::size_t num);
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
void RingBuffer<T>::fill(const T value) {
|
|
||||||
std::fill(buf + 0, buf + sz, value);
|
|
||||||
rpos = 0;
|
|
||||||
wpos = sz - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
void RingBuffer<T>::read(T *out, std::size_t num) {
|
|
||||||
if (rpos + num > sz) {
|
|
||||||
const std::size_t n = sz - rpos;
|
|
||||||
|
|
||||||
std::memcpy(out, buf + rpos, n * sizeof(T));
|
|
||||||
|
|
||||||
rpos = 0;
|
|
||||||
num -= n;
|
|
||||||
out += n;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::memcpy(out, buf + rpos, num * sizeof(T));
|
|
||||||
|
|
||||||
if ((rpos += num) == sz)
|
|
||||||
rpos = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
void RingBuffer<T>::reset(const std::size_t sz_in) {
|
|
||||||
sz = sz_in + 1;
|
|
||||||
rpos = wpos = 0;
|
|
||||||
buf.reset(sz_in ? sz : 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
void RingBuffer<T>::write(const T *in, std::size_t num) {
|
|
||||||
if (wpos + num > sz) {
|
|
||||||
const std::size_t n = sz - wpos;
|
|
||||||
|
|
||||||
std::memcpy(buf + wpos, in, n * sizeof(T));
|
|
||||||
|
|
||||||
wpos = 0;
|
|
||||||
num -= n;
|
|
||||||
in += n;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::memcpy(buf + wpos, in, num * sizeof(T));
|
|
||||||
|
|
||||||
if ((wpos += num) == sz)
|
|
||||||
wpos = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,35 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2008 by Sindre Aamås *
|
|
||||||
* aamas@stud.ntnu.no *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU General Public License version 2 as *
|
|
||||||
* published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 version 2 for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License *
|
|
||||||
* version 2 along with this program; if not, write to the *
|
|
||||||
* Free Software Foundation, Inc., *
|
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
||||||
***************************************************************************/
|
|
||||||
#include "skipsched.h"
|
|
||||||
|
|
||||||
bool SkipSched::skipNext(bool skip) {
|
|
||||||
if (skipped) {
|
|
||||||
if (skipped < skippedmax / 2)
|
|
||||||
skip = true;
|
|
||||||
else
|
|
||||||
skipped = skip = 0;
|
|
||||||
} else if (skip) {
|
|
||||||
skippedmax += skippedmax / 2 < 8;
|
|
||||||
} else if (skippedmax / 2)
|
|
||||||
--skippedmax;
|
|
||||||
|
|
||||||
skipped += skip;
|
|
||||||
|
|
||||||
return skip;
|
|
||||||
}
|
|
@ -1,37 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2008 by Sindre Aamås *
|
|
||||||
* aamas@stud.ntnu.no *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU General Public License version 2 as *
|
|
||||||
* published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 version 2 for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License *
|
|
||||||
* version 2 along with this program; if not, write to the *
|
|
||||||
* Free Software Foundation, Inc., *
|
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
||||||
***************************************************************************/
|
|
||||||
#ifndef SKIPSCHED_H
|
|
||||||
#define SKIPSCHED_H
|
|
||||||
|
|
||||||
class SkipSched {
|
|
||||||
unsigned skipped;
|
|
||||||
unsigned skippedmax;
|
|
||||||
|
|
||||||
public:
|
|
||||||
SkipSched() { reset(); }
|
|
||||||
|
|
||||||
void reset() {
|
|
||||||
skipped = 0;
|
|
||||||
skippedmax = 2 - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool skipNext(bool wantskip);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,31 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2008 by Sindre Aamås *
|
|
||||||
* aamas@stud.ntnu.no *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU General Public License version 2 as *
|
|
||||||
* published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 version 2 for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License *
|
|
||||||
* version 2 along with this program; if not, write to the *
|
|
||||||
* Free Software Foundation, Inc., *
|
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
||||||
***************************************************************************/
|
|
||||||
#ifndef USEC_H
|
|
||||||
#define USEC_H
|
|
||||||
|
|
||||||
typedef unsigned long usec_t;
|
|
||||||
|
|
||||||
static inline usec_t negate(usec_t t) {
|
|
||||||
return usec_t(0) - t;
|
|
||||||
}
|
|
||||||
|
|
||||||
usec_t getusecs();
|
|
||||||
void usecsleep(usec_t usecs);
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,157 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2009 by Sindre Aamås *
|
|
||||||
* aamas@stud.ntnu.no *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU General Public License version 2 as *
|
|
||||||
* published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 version 2 for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License *
|
|
||||||
* version 2 along with this program; if not, write to the *
|
|
||||||
* Free Software Foundation, Inc., *
|
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
||||||
***************************************************************************/
|
|
||||||
#include "rgb32conv.h"
|
|
||||||
#include "videolink.h"
|
|
||||||
#include "gambatte-array.h"
|
|
||||||
#include "gbint.h"
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
class Rgb32ToUyvy {
|
|
||||||
struct CacheUnit {
|
|
||||||
gambatte::uint_least32_t rgb32;
|
|
||||||
gambatte::uint_least32_t uyvy;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum { cache_size = 0x100 };
|
|
||||||
enum { cache_mask = cache_size - 1 };
|
|
||||||
|
|
||||||
CacheUnit cache[cache_size];
|
|
||||||
|
|
||||||
public:
|
|
||||||
Rgb32ToUyvy();
|
|
||||||
void operator()(const gambatte::uint_least32_t *s, gambatte::uint_least32_t *d,
|
|
||||||
unsigned w, unsigned h, int srcPitch, int dstPitch);
|
|
||||||
};
|
|
||||||
|
|
||||||
Rgb32ToUyvy::Rgb32ToUyvy() {
|
|
||||||
#ifdef WORDS_BIGENDIAN
|
|
||||||
const CacheUnit c = { 0, 128ul << 24 | 16ul << 16 | 128 << 8 | 16 };
|
|
||||||
#else
|
|
||||||
const CacheUnit c = { 0, 16ul << 24 | 128ul << 16 | 16 << 8 | 128 };
|
|
||||||
#endif
|
|
||||||
std::fill(cache, cache + cache_size, c);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Rgb32ToUyvy::operator()(const gambatte::uint_least32_t *s,
|
|
||||||
gambatte::uint_least32_t *d, const unsigned w, unsigned h, const int s_pitch, const int d_pitch)
|
|
||||||
{
|
|
||||||
while (h--) {
|
|
||||||
unsigned n = w >> 1;
|
|
||||||
|
|
||||||
do {
|
|
||||||
if ((cache[*s & cache_mask].rgb32 - *s) | (cache[*(s+1) & cache_mask].rgb32 - *(s+1))) {
|
|
||||||
cache[*s & cache_mask].rgb32 = *s;
|
|
||||||
cache[*(s+1) & cache_mask].rgb32 = *(s+1);
|
|
||||||
|
|
||||||
const unsigned long r = (*s >> 16 & 0x000000FF) | (*(s+1) & 0x00FF0000);
|
|
||||||
const unsigned long g = (*s >> 8 & 0x000000FF) | (*(s+1) << 8 & 0x00FF0000);
|
|
||||||
const unsigned long b = (*s & 0x000000FF) | (*(s+1) << 16 & 0x00FF0000);
|
|
||||||
|
|
||||||
const unsigned long y = r * 66 + g * 129 + b * 25 + ( 16 * 256 + 128) * 0x00010001ul;
|
|
||||||
const unsigned long u = b * 112 - r * 38 - g * 74 + (128 * 256 + 128) * 0x00010001ul;
|
|
||||||
const unsigned long v = r * 112 - g * 94 - b * 18 + (128 * 256 + 128) * 0x00010001ul;
|
|
||||||
|
|
||||||
#ifdef WORDS_BIGENDIAN
|
|
||||||
cache[*s & cache_mask].uyvy = (u << 16 & 0xFF000000) | (y << 8 & 0x00FF0000) | (v & 0x0000FF00) | (y >> 8 & 0x000000FF);
|
|
||||||
cache[*(s+1) & cache_mask].uyvy = (u & 0xFF000000) | (y >> 8 & 0x00FF0000) | (v >> 16 & 0x0000FF00) | y >> 24;
|
|
||||||
#else
|
|
||||||
cache[*s & cache_mask].uyvy = (y << 16 & 0xFF000000) | (v << 8 & 0x00FF0000) | (y & 0x0000FF00) | (u >> 8 & 0x000000FF);
|
|
||||||
cache[*(s+1) & cache_mask].uyvy = (y & 0xFF000000) | (v >> 8 & 0x00FF0000) | (y >> 16 & 0x0000FF00) | u >> 24;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
*d = cache[*s & cache_mask].uyvy;
|
|
||||||
*(d+1) = cache[*(s+1) & cache_mask].uyvy;
|
|
||||||
s += 2;
|
|
||||||
d += 2;
|
|
||||||
} while (--n);
|
|
||||||
|
|
||||||
s += s_pitch - static_cast<int>(w);
|
|
||||||
d += d_pitch - static_cast<int>(w);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rgb32ToRgb16(const gambatte::uint_least32_t *s, gambatte::uint_least16_t *d,
|
|
||||||
const unsigned w, unsigned h, const int srcPitch, const int dstPitch)
|
|
||||||
{
|
|
||||||
do {
|
|
||||||
unsigned n = w;
|
|
||||||
|
|
||||||
do {
|
|
||||||
*d++ = (*s >> 8 & 0xF800) | (*s >> 5 & 0x07E0) | (*s >> 3 & 0x001F);
|
|
||||||
++s;
|
|
||||||
} while (--n);
|
|
||||||
|
|
||||||
s += srcPitch - static_cast<int>(w);
|
|
||||||
d += dstPitch - static_cast<int>(w);
|
|
||||||
} while (--h);
|
|
||||||
}
|
|
||||||
|
|
||||||
class Rgb32ToUyvyLink : public VideoLink {
|
|
||||||
const Array<gambatte::uint_least32_t> inbuf_;
|
|
||||||
Rgb32ToUyvy rgb32ToUyvy;
|
|
||||||
const unsigned width_;
|
|
||||||
const unsigned height_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
Rgb32ToUyvyLink(unsigned width, unsigned height)
|
|
||||||
: inbuf_(static_cast<std::size_t>(width) * height),
|
|
||||||
width_(width),
|
|
||||||
height_(height)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void* inBuf() const { return inbuf_; }
|
|
||||||
virtual int inPitch() const { return width_; }
|
|
||||||
|
|
||||||
virtual void draw(void *dst, int dstpitch) {
|
|
||||||
rgb32ToUyvy(inbuf_, static_cast<gambatte::uint_least32_t*>(dst), width_, height_, inPitch(), dstpitch);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class Rgb32ToRgb16Link : public VideoLink {
|
|
||||||
const Array<gambatte::uint_least32_t> inbuf_;
|
|
||||||
const unsigned width_;
|
|
||||||
const unsigned height_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
Rgb32ToRgb16Link(unsigned width, unsigned height)
|
|
||||||
: inbuf_(static_cast<std::size_t>(width) * height),
|
|
||||||
width_(width),
|
|
||||||
height_(height)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void* inBuf() const { return inbuf_; }
|
|
||||||
virtual int inPitch() const { return width_; }
|
|
||||||
|
|
||||||
virtual void draw(void *dst, int dstpitch) {
|
|
||||||
rgb32ToRgb16(inbuf_, static_cast<gambatte::uint_least16_t*>(dst), width_, height_, inPitch(), dstpitch);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
VideoLink* Rgb32Conv::create(PixelFormat pf, unsigned width, unsigned height) {
|
|
||||||
switch (pf) {
|
|
||||||
case RGB16: return new Rgb32ToRgb16Link(width, height);
|
|
||||||
case UYVY: return new Rgb32ToUyvyLink(width, height);
|
|
||||||
default: return 0;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,30 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2009 by Sindre Aamås *
|
|
||||||
* aamas@stud.ntnu.no *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU General Public License version 2 as *
|
|
||||||
* published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 version 2 for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License *
|
|
||||||
* version 2 along with this program; if not, write to the *
|
|
||||||
* Free Software Foundation, Inc., *
|
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
||||||
***************************************************************************/
|
|
||||||
#ifndef RGB32CONV_H
|
|
||||||
#define RGB32CONV_H
|
|
||||||
|
|
||||||
class VideoLink;
|
|
||||||
|
|
||||||
class Rgb32Conv {
|
|
||||||
public:
|
|
||||||
enum PixelFormat { RGB32, RGB16, UYVY };
|
|
||||||
static VideoLink* create(PixelFormat pf, unsigned width, unsigned height);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,48 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2009 by Sindre Aamås *
|
|
||||||
* aamas@stud.ntnu.no *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU General Public License version 2 as *
|
|
||||||
* published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 version 2 for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License *
|
|
||||||
* version 2 along with this program; if not, write to the *
|
|
||||||
* Free Software Foundation, Inc., *
|
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
||||||
***************************************************************************/
|
|
||||||
#include "vfilterinfo.h"
|
|
||||||
#include "vfilters/catrom2x.h"
|
|
||||||
#include "vfilters/catrom3x.h"
|
|
||||||
#include "vfilters/kreed2xsai.h"
|
|
||||||
#include "vfilters/maxsthq2x.h"
|
|
||||||
#include "vfilters/maxsthq3x.h"
|
|
||||||
|
|
||||||
static VideoLink* createNone() { return 0; }
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
static VideoLink* createT() { return new T; }
|
|
||||||
|
|
||||||
#define VFINFO(handle, Type) { handle, Type::OUT_WIDTH, Type::OUT_HEIGHT, createT<Type> }
|
|
||||||
|
|
||||||
static const VfilterInfo vfinfos[] = {
|
|
||||||
{ "None", VfilterInfo::IN_WIDTH, VfilterInfo::IN_HEIGHT, createNone },
|
|
||||||
VFINFO("Bicubic Catmull-Rom spline 2x", Catrom2x),
|
|
||||||
VFINFO("Bicubic Catmull-Rom spline 3x", Catrom3x),
|
|
||||||
VFINFO("Kreed's 2xSaI", Kreed2xSaI),
|
|
||||||
VFINFO("MaxSt's hq2x", MaxStHq2x),
|
|
||||||
VFINFO("MaxSt's hq3x", MaxStHq3x)
|
|
||||||
};
|
|
||||||
|
|
||||||
std::size_t VfilterInfo::numVfilters() {
|
|
||||||
return sizeof(vfinfos) / sizeof(vfinfos[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
const VfilterInfo& VfilterInfo::get(std::size_t n) {
|
|
||||||
return vfinfos[n];
|
|
||||||
}
|
|
@ -1,39 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2009 by Sindre Aamås *
|
|
||||||
* aamas@stud.ntnu.no *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU General Public License version 2 as *
|
|
||||||
* published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 version 2 for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License *
|
|
||||||
* version 2 along with this program; if not, write to the *
|
|
||||||
* Free Software Foundation, Inc., *
|
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
||||||
***************************************************************************/
|
|
||||||
#ifndef VFILTERINFO_H
|
|
||||||
#define VFILTERINFO_H
|
|
||||||
|
|
||||||
#include <cstddef>
|
|
||||||
|
|
||||||
class VideoLink;
|
|
||||||
|
|
||||||
struct VfilterInfo {
|
|
||||||
enum { IN_WIDTH = 160 };
|
|
||||||
enum { IN_HEIGHT = 144 };
|
|
||||||
|
|
||||||
const char *handle;
|
|
||||||
unsigned outWidth;
|
|
||||||
unsigned outHeight;
|
|
||||||
VideoLink* (*create)();
|
|
||||||
|
|
||||||
static const VfilterInfo& get(std::size_t n);
|
|
||||||
static std::size_t numVfilters();
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,179 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2007 by Sindre Aamås *
|
|
||||||
* aamas@stud.ntnu.no *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU General Public License version 2 as *
|
|
||||||
* published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 version 2 for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License *
|
|
||||||
* version 2 along with this program; if not, write to the *
|
|
||||||
* Free Software Foundation, Inc., *
|
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
||||||
***************************************************************************/
|
|
||||||
#include "catrom2x.h"
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
enum { WIDTH = VfilterInfo::IN_WIDTH };
|
|
||||||
enum { HEIGHT = VfilterInfo::IN_HEIGHT };
|
|
||||||
enum { PITCH = WIDTH + 3 };
|
|
||||||
|
|
||||||
struct Colorsum {
|
|
||||||
gambatte::uint_least32_t r, g, b;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void merge_columns(gambatte::uint_least32_t *dest, const Colorsum *sums) {
|
|
||||||
unsigned w = WIDTH;
|
|
||||||
|
|
||||||
while (w--) {
|
|
||||||
{
|
|
||||||
gambatte::uint_least32_t rsum = sums[1].r;
|
|
||||||
gambatte::uint_least32_t gsum = sums[1].g;
|
|
||||||
gambatte::uint_least32_t bsum = sums[1].b;
|
|
||||||
|
|
||||||
if (rsum & 0x80000000) rsum = 0;
|
|
||||||
if (gsum & 0x80000000) gsum = 0;
|
|
||||||
if (bsum & 0x80000000) bsum = 0;
|
|
||||||
|
|
||||||
rsum <<= 12;
|
|
||||||
rsum += 0x008000;
|
|
||||||
gsum >>= 4;
|
|
||||||
gsum += 0x0080;
|
|
||||||
bsum += 0x0008;
|
|
||||||
bsum >>= 4;
|
|
||||||
|
|
||||||
if (rsum > 0xFF0000) rsum = 0xFF0000;
|
|
||||||
if (gsum > 0x00FF00) gsum = 0x00FF00;
|
|
||||||
if (bsum > 0x0000FF) bsum = 0x0000FF;
|
|
||||||
|
|
||||||
*dest++ = (rsum & 0xFF0000) | (gsum & 0x00FF00) | bsum;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
gambatte::uint_least32_t rsum = sums[1].r * 9;
|
|
||||||
gambatte::uint_least32_t gsum = sums[1].g * 9;
|
|
||||||
gambatte::uint_least32_t bsum = sums[1].b * 9;
|
|
||||||
|
|
||||||
rsum -= sums[0].r;
|
|
||||||
gsum -= sums[0].g;
|
|
||||||
bsum -= sums[0].b;
|
|
||||||
|
|
||||||
rsum += sums[2].r * 9;
|
|
||||||
gsum += sums[2].g * 9;
|
|
||||||
bsum += sums[2].b * 9;
|
|
||||||
|
|
||||||
rsum -= sums[3].r;
|
|
||||||
gsum -= sums[3].g;
|
|
||||||
bsum -= sums[3].b;
|
|
||||||
|
|
||||||
if (rsum & 0x80000000) rsum = 0;
|
|
||||||
if (gsum & 0x80000000) gsum = 0;
|
|
||||||
if (bsum & 0x80000000) bsum = 0;
|
|
||||||
|
|
||||||
rsum <<= 8;
|
|
||||||
rsum += 0x008000;
|
|
||||||
gsum >>= 8;
|
|
||||||
gsum += 0x000080;
|
|
||||||
bsum += 0x000080;
|
|
||||||
bsum >>= 8;
|
|
||||||
|
|
||||||
if (rsum > 0xFF0000) rsum = 0xFF0000;
|
|
||||||
if (gsum > 0x00FF00) gsum = 0x00FF00;
|
|
||||||
if (bsum > 0x0000FF) bsum = 0x0000FF;
|
|
||||||
|
|
||||||
*dest++ = (rsum & 0xFF0000) | (gsum & 0x00FF00) | bsum;
|
|
||||||
}
|
|
||||||
|
|
||||||
++sums;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void filter(gambatte::uint_least32_t *dline, const int pitch, const gambatte::uint_least32_t *sline) {
|
|
||||||
Colorsum sums[PITCH];
|
|
||||||
|
|
||||||
for (unsigned h = HEIGHT; h--;) {
|
|
||||||
{
|
|
||||||
const gambatte::uint_least32_t *s = sline;
|
|
||||||
Colorsum *sum = sums;
|
|
||||||
unsigned n = PITCH;
|
|
||||||
|
|
||||||
while (n--) {
|
|
||||||
unsigned long pixel = *s;
|
|
||||||
sum->r = pixel >> 12 & 0x000FF0 ;
|
|
||||||
pixel <<= 4;
|
|
||||||
sum->g = pixel & 0x0FF000;
|
|
||||||
sum->b = pixel & 0x000FF0;
|
|
||||||
|
|
||||||
++s;
|
|
||||||
++sum;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
merge_columns(dline, sums);
|
|
||||||
dline += pitch;
|
|
||||||
|
|
||||||
{
|
|
||||||
const gambatte::uint_least32_t *s = sline;
|
|
||||||
Colorsum *sum = sums;
|
|
||||||
unsigned n = PITCH;
|
|
||||||
|
|
||||||
while (n--) {
|
|
||||||
unsigned long pixel = *s;
|
|
||||||
unsigned long rsum = (pixel >> 16) * 9;
|
|
||||||
unsigned long gsum = (pixel & 0x00FF00) * 9;
|
|
||||||
unsigned long bsum = (pixel & 0x0000FF) * 9;
|
|
||||||
|
|
||||||
pixel = s[-1*PITCH];
|
|
||||||
rsum -= pixel >> 16;
|
|
||||||
gsum -= pixel & 0x00FF00;
|
|
||||||
bsum -= pixel & 0x0000FF;
|
|
||||||
|
|
||||||
pixel = s[1*PITCH];
|
|
||||||
rsum += (pixel >> 16) * 9;
|
|
||||||
gsum += (pixel & 0x00FF00) * 9;
|
|
||||||
bsum += (pixel & 0x0000FF) * 9;
|
|
||||||
|
|
||||||
pixel = s[2*PITCH];
|
|
||||||
rsum -= pixel >> 16;
|
|
||||||
gsum -= pixel & 0x00FF00;
|
|
||||||
bsum -= pixel & 0x0000FF;
|
|
||||||
|
|
||||||
sum->r = rsum;
|
|
||||||
sum->g = gsum;
|
|
||||||
sum->b = bsum;
|
|
||||||
|
|
||||||
++s;
|
|
||||||
++sum;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
merge_columns(dline, sums);
|
|
||||||
dline += pitch;
|
|
||||||
sline += PITCH;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Catrom2x::Catrom2x()
|
|
||||||
: buffer_((HEIGHT + 3UL) * PITCH)
|
|
||||||
{
|
|
||||||
std::fill_n(buffer_.get(), buffer_.size(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void* Catrom2x::inBuf() const {
|
|
||||||
return buffer_ + PITCH + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int Catrom2x::inPitch() const {
|
|
||||||
return PITCH;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Catrom2x::draw(void *const dbuffer, const int pitch) {
|
|
||||||
::filter(static_cast<gambatte::uint_least32_t*>(dbuffer), pitch, buffer_ + PITCH);
|
|
||||||
}
|
|
@ -1,39 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2009 by Sindre Aamås *
|
|
||||||
* aamas@stud.ntnu.no *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU General Public License version 2 as *
|
|
||||||
* published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 version 2 for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License *
|
|
||||||
* version 2 along with this program; if not, write to the *
|
|
||||||
* Free Software Foundation, Inc., *
|
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
||||||
***************************************************************************/
|
|
||||||
#ifndef CATROM2X_H
|
|
||||||
#define CATROM2X_H
|
|
||||||
|
|
||||||
#include "../videolink.h"
|
|
||||||
#include "../vfilterinfo.h"
|
|
||||||
#include "gambatte-array.h"
|
|
||||||
#include "gbint.h"
|
|
||||||
|
|
||||||
class Catrom2x : public VideoLink {
|
|
||||||
const Array<gambatte::uint_least32_t> buffer_;
|
|
||||||
public:
|
|
||||||
enum { OUT_WIDTH = VfilterInfo::IN_WIDTH * 2 };
|
|
||||||
enum { OUT_HEIGHT = VfilterInfo::IN_HEIGHT * 2 };
|
|
||||||
|
|
||||||
Catrom2x();
|
|
||||||
virtual void* inBuf() const;
|
|
||||||
virtual int inPitch() const;
|
|
||||||
virtual void draw(void *dst, int dstpitch);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,345 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2007 by Sindre Aamås *
|
|
||||||
* aamas@stud.ntnu.no *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU General Public License version 2 as *
|
|
||||||
* published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 version 2 for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License *
|
|
||||||
* version 2 along with this program; if not, write to the *
|
|
||||||
* Free Software Foundation, Inc., *
|
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
||||||
***************************************************************************/
|
|
||||||
#include "catrom3x.h"
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
enum { WIDTH = VfilterInfo::IN_WIDTH };
|
|
||||||
enum { HEIGHT = VfilterInfo::IN_HEIGHT };
|
|
||||||
enum { PITCH = WIDTH + 3 };
|
|
||||||
|
|
||||||
struct Colorsum {
|
|
||||||
gambatte::uint_least32_t r, g, b;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void merge_columns(gambatte::uint_least32_t *dest, const Colorsum *sums) {
|
|
||||||
unsigned w = WIDTH;
|
|
||||||
|
|
||||||
while (w--) {
|
|
||||||
{
|
|
||||||
gambatte::uint_least32_t rsum = sums[1].r;
|
|
||||||
gambatte::uint_least32_t gsum = sums[1].g;
|
|
||||||
gambatte::uint_least32_t bsum = sums[1].b;
|
|
||||||
|
|
||||||
if (rsum & 0x80000000)
|
|
||||||
rsum = 0;
|
|
||||||
else if (rsum > 6869)
|
|
||||||
rsum = 0xFF0000;
|
|
||||||
else {
|
|
||||||
rsum *= 607;
|
|
||||||
rsum <<= 2;
|
|
||||||
rsum += 0x008000;
|
|
||||||
rsum &= 0xFF0000;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gsum & 0x80000000)
|
|
||||||
gsum = 0;
|
|
||||||
else if (gsum > 1758567)
|
|
||||||
gsum = 0xFF00;
|
|
||||||
else {
|
|
||||||
gsum *= 607;
|
|
||||||
gsum >>= 14;
|
|
||||||
gsum += 0x000080;
|
|
||||||
gsum &= 0x00FF00;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bsum & 0x80000000)
|
|
||||||
bsum = 0;
|
|
||||||
else if (bsum > 6869)
|
|
||||||
bsum = 0xFF;
|
|
||||||
else {
|
|
||||||
bsum *= 607;
|
|
||||||
bsum += 8192;
|
|
||||||
bsum >>= 14;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*rsum/=27;
|
|
||||||
rsum<<=8;
|
|
||||||
gsum/=27;
|
|
||||||
gsum<<=5;
|
|
||||||
bsum<<=4;
|
|
||||||
bsum+=27;
|
|
||||||
bsum/=54;
|
|
||||||
rsum+=0x008000;
|
|
||||||
gsum+=0x000080;
|
|
||||||
|
|
||||||
if(rsum>0xFF0000) rsum=0xFF0000;
|
|
||||||
if(gsum>0x00FF00) gsum=0x00FF00;
|
|
||||||
if(bsum>0x0000FF) bsum=0x0000FF;*/
|
|
||||||
|
|
||||||
*dest++ = rsum/*&0xFF0000*/ | gsum/*&0x00FF00*/ | bsum;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
gambatte::uint_least32_t rsum = sums[1].r * 21;
|
|
||||||
gambatte::uint_least32_t gsum = sums[1].g * 21;
|
|
||||||
gambatte::uint_least32_t bsum = sums[1].b * 21;
|
|
||||||
|
|
||||||
rsum -= sums[0].r << 1;
|
|
||||||
gsum -= sums[0].g << 1;
|
|
||||||
bsum -= sums[0].b << 1;
|
|
||||||
|
|
||||||
rsum += sums[2].r * 9;
|
|
||||||
gsum += sums[2].g * 9;
|
|
||||||
bsum += sums[2].b * 9;
|
|
||||||
|
|
||||||
rsum -= sums[3].r;
|
|
||||||
gsum -= sums[3].g;
|
|
||||||
bsum -= sums[3].b;
|
|
||||||
|
|
||||||
if (rsum & 0x80000000)
|
|
||||||
rsum = 0;
|
|
||||||
else if (rsum > 185578)
|
|
||||||
rsum = 0xFF0000;
|
|
||||||
else {
|
|
||||||
rsum *= 719;
|
|
||||||
rsum >>= 3;
|
|
||||||
rsum += 0x008000;
|
|
||||||
rsum &= 0xFF0000;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gsum & 0x80000000)
|
|
||||||
gsum = 0;
|
|
||||||
else if (gsum > 47508223)
|
|
||||||
gsum = 0x00FF00;
|
|
||||||
else {
|
|
||||||
gsum >>= 8;
|
|
||||||
gsum *= 719;
|
|
||||||
gsum >>= 11;
|
|
||||||
gsum += 0x000080;
|
|
||||||
gsum &= 0x00FF00;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bsum & 0x80000000)
|
|
||||||
bsum = 0;
|
|
||||||
else if (bsum > 185578)
|
|
||||||
bsum = 0x0000FF;
|
|
||||||
else {
|
|
||||||
bsum *= 719;
|
|
||||||
bsum += 0x040000;
|
|
||||||
bsum >>= 19;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*rsum/=729;
|
|
||||||
rsum<<=8;
|
|
||||||
gsum/=729;
|
|
||||||
gsum<<=5;
|
|
||||||
bsum<<=4;
|
|
||||||
bsum+=729;
|
|
||||||
bsum/=1458;
|
|
||||||
rsum+=0x008000;
|
|
||||||
gsum+=0x000080;
|
|
||||||
|
|
||||||
if(rsum>0xFF0000) rsum=0xFF0000;
|
|
||||||
if(gsum>0x00FF00) gsum=0x00FF00;
|
|
||||||
if(bsum>0x0000FF) bsum=0x0000FF;*/
|
|
||||||
|
|
||||||
*dest++ = rsum/*&0xFF0000*/ | gsum/*&0x00FF00*/ | bsum;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
gambatte::uint_least32_t rsum = sums[1].r * 9;
|
|
||||||
gambatte::uint_least32_t gsum = sums[1].g * 9;
|
|
||||||
gambatte::uint_least32_t bsum = sums[1].b * 9;
|
|
||||||
|
|
||||||
rsum -= sums[0].r;
|
|
||||||
gsum -= sums[0].g;
|
|
||||||
bsum -= sums[0].b;
|
|
||||||
|
|
||||||
rsum += sums[2].r * 21;
|
|
||||||
gsum += sums[2].g * 21;
|
|
||||||
bsum += sums[2].b * 21;
|
|
||||||
|
|
||||||
rsum -= sums[3].r << 1;
|
|
||||||
gsum -= sums[3].g << 1;
|
|
||||||
bsum -= sums[3].b << 1;
|
|
||||||
|
|
||||||
if (rsum & 0x80000000)
|
|
||||||
rsum = 0;
|
|
||||||
else if (rsum > 185578)
|
|
||||||
rsum = 0xFF0000;
|
|
||||||
else {
|
|
||||||
rsum *= 719;
|
|
||||||
rsum >>= 3;
|
|
||||||
rsum += 0x008000;
|
|
||||||
rsum &= 0xFF0000;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gsum & 0x80000000)
|
|
||||||
gsum = 0;
|
|
||||||
else if (gsum > 47508223)
|
|
||||||
gsum = 0xFF00;
|
|
||||||
else {
|
|
||||||
gsum >>= 8;
|
|
||||||
gsum *= 719;
|
|
||||||
gsum >>= 11;
|
|
||||||
gsum += 0x000080;
|
|
||||||
gsum &= 0x00FF00;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bsum & 0x80000000)
|
|
||||||
bsum = 0;
|
|
||||||
else if (bsum > 185578)
|
|
||||||
bsum = 0x0000FF;
|
|
||||||
else {
|
|
||||||
bsum *= 719;
|
|
||||||
bsum += 0x040000;
|
|
||||||
bsum >>= 19;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*rsum/=729;
|
|
||||||
rsum<<=8;
|
|
||||||
gsum/=729;
|
|
||||||
gsum<<=5;
|
|
||||||
bsum<<=4;
|
|
||||||
bsum+=729;
|
|
||||||
bsum/=1458;
|
|
||||||
rsum+=0x008000;
|
|
||||||
gsum+=0x000080;
|
|
||||||
|
|
||||||
if(rsum>0xFF0000) rsum=0xFF0000;
|
|
||||||
if(gsum>0x00FF00) gsum=0x00FF00;
|
|
||||||
if(bsum>0x0000FF) bsum=0x0000FF;*/
|
|
||||||
|
|
||||||
*dest++ = rsum/*&0xFF0000*/ | gsum/*&0x00FF00*/ | bsum;
|
|
||||||
}
|
|
||||||
++sums;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void filter(gambatte::uint_least32_t *dline, const int pitch, const gambatte::uint_least32_t *sline) {
|
|
||||||
Colorsum sums[PITCH];
|
|
||||||
|
|
||||||
for (unsigned h = HEIGHT; h--;) {
|
|
||||||
{
|
|
||||||
const gambatte::uint_least32_t *s = sline;
|
|
||||||
Colorsum *sum = sums;
|
|
||||||
unsigned n = PITCH;
|
|
||||||
|
|
||||||
while (n--) {
|
|
||||||
const unsigned long pixel = *s;
|
|
||||||
sum->r = (pixel >> 16) * 27;
|
|
||||||
sum->g = (pixel & 0x00FF00) * 27;
|
|
||||||
sum->b = (pixel & 0x0000FF) * 27;
|
|
||||||
|
|
||||||
++s;
|
|
||||||
++sum;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
merge_columns(dline, sums);
|
|
||||||
dline += pitch;
|
|
||||||
|
|
||||||
{
|
|
||||||
const gambatte::uint_least32_t *s = sline;
|
|
||||||
Colorsum *sum = sums;
|
|
||||||
unsigned n = PITCH;
|
|
||||||
|
|
||||||
while (n--) {
|
|
||||||
unsigned long pixel = *s;
|
|
||||||
unsigned long rsum = (pixel >> 16) * 21;
|
|
||||||
unsigned long gsum = (pixel & 0x00FF00) * 21;
|
|
||||||
unsigned long bsum = (pixel & 0x0000FF) * 21;
|
|
||||||
|
|
||||||
pixel = s[-1 * PITCH];
|
|
||||||
rsum -= (pixel >> 16) << 1;
|
|
||||||
pixel <<= 1;
|
|
||||||
gsum -= pixel & 0x01FE00;
|
|
||||||
bsum -= pixel & 0x0001FE;
|
|
||||||
|
|
||||||
pixel = s[1 * PITCH];
|
|
||||||
rsum += (pixel >> 16) * 9;
|
|
||||||
gsum += (pixel & 0x00FF00) * 9;
|
|
||||||
bsum += (pixel & 0x0000FF) * 9;
|
|
||||||
|
|
||||||
pixel = s[2 * PITCH];
|
|
||||||
rsum -= pixel >> 16;
|
|
||||||
gsum -= pixel & 0x00FF00;
|
|
||||||
bsum -= pixel & 0x0000FF;
|
|
||||||
|
|
||||||
sum->r = rsum;
|
|
||||||
sum->g = gsum;
|
|
||||||
sum->b = bsum;
|
|
||||||
|
|
||||||
++s;
|
|
||||||
++sum;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
merge_columns(dline, sums);
|
|
||||||
dline += pitch;
|
|
||||||
|
|
||||||
{
|
|
||||||
const gambatte::uint_least32_t *s = sline;
|
|
||||||
Colorsum *sum = sums;
|
|
||||||
unsigned n = PITCH;
|
|
||||||
|
|
||||||
while (n--) {
|
|
||||||
unsigned long pixel = *s;
|
|
||||||
unsigned long rsum = (pixel >> 16) * 9;
|
|
||||||
unsigned long gsum = (pixel & 0x00FF00) * 9;
|
|
||||||
unsigned long bsum = (pixel & 0x0000FF) * 9;
|
|
||||||
|
|
||||||
pixel = s[-1 * PITCH];
|
|
||||||
rsum -= pixel >> 16;
|
|
||||||
gsum -= pixel & 0x00FF00;
|
|
||||||
bsum -= pixel & 0x0000FF;
|
|
||||||
|
|
||||||
pixel = s[1 * PITCH];
|
|
||||||
rsum += (pixel >> 16) * 21;
|
|
||||||
gsum += (pixel & 0x00FF00) * 21;
|
|
||||||
bsum += (pixel & 0x0000FF) * 21;
|
|
||||||
|
|
||||||
pixel = s[2 * PITCH];
|
|
||||||
rsum -= (pixel >> 16) << 1;
|
|
||||||
pixel <<= 1;
|
|
||||||
gsum -= pixel & 0x01FE00;
|
|
||||||
bsum -= pixel & 0x0001FE;
|
|
||||||
|
|
||||||
sum->r = rsum;
|
|
||||||
sum->g = gsum;
|
|
||||||
sum->b = bsum;
|
|
||||||
|
|
||||||
++s;
|
|
||||||
++sum;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
merge_columns(dline, sums);
|
|
||||||
dline += pitch;
|
|
||||||
sline += PITCH;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Catrom3x::Catrom3x()
|
|
||||||
: buffer_((HEIGHT + 3UL) * PITCH)
|
|
||||||
{
|
|
||||||
std::fill_n(buffer_.get(), buffer_.size(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void* Catrom3x::inBuf() const {
|
|
||||||
return buffer_ + PITCH + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int Catrom3x::inPitch() const {
|
|
||||||
return PITCH;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Catrom3x::draw(void *const dbuffer, const int pitch) {
|
|
||||||
::filter(static_cast<gambatte::uint_least32_t*>(dbuffer), pitch, buffer_ + PITCH);
|
|
||||||
}
|
|
@ -1,39 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2009 by Sindre Aamås *
|
|
||||||
* aamas@stud.ntnu.no *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU General Public License version 2 as *
|
|
||||||
* published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 version 2 for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License *
|
|
||||||
* version 2 along with this program; if not, write to the *
|
|
||||||
* Free Software Foundation, Inc., *
|
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
||||||
***************************************************************************/
|
|
||||||
#ifndef CATROM3X_H
|
|
||||||
#define CATROM3X_H
|
|
||||||
|
|
||||||
#include "../videolink.h"
|
|
||||||
#include "../vfilterinfo.h"
|
|
||||||
#include "gambatte-array.h"
|
|
||||||
#include "gbint.h"
|
|
||||||
|
|
||||||
class Catrom3x : public VideoLink {
|
|
||||||
const Array<gambatte::uint_least32_t> buffer_;
|
|
||||||
public:
|
|
||||||
enum { OUT_WIDTH = VfilterInfo::IN_WIDTH * 3 };
|
|
||||||
enum { OUT_HEIGHT = VfilterInfo::IN_HEIGHT * 3 };
|
|
||||||
|
|
||||||
Catrom3x();
|
|
||||||
virtual void* inBuf() const;
|
|
||||||
virtual int inPitch() const;
|
|
||||||
virtual void draw(void *dst, int dstpitch);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,234 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2007 by Sindre Aamås *
|
|
||||||
* aamas@stud.ntnu.no *
|
|
||||||
* *
|
|
||||||
* Copyright (C) 1999 Derek Liauw Kie Fa (Kreed) *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU General Public License version 2 as *
|
|
||||||
* published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 version 2 for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License *
|
|
||||||
* version 2 along with this program; if not, write to the *
|
|
||||||
* Free Software Foundation, Inc., *
|
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
||||||
***************************************************************************/
|
|
||||||
#include "kreed2xsai.h"
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
static inline int getResult1(const unsigned long a, const unsigned long b, const unsigned long c, const unsigned long d) {
|
|
||||||
int x = 0;
|
|
||||||
int y = 0;
|
|
||||||
int r = 0;
|
|
||||||
|
|
||||||
if (a == c) ++x;
|
|
||||||
else if (b == c) ++y;
|
|
||||||
|
|
||||||
if (a == d) ++x;
|
|
||||||
else if (b == d) ++y;
|
|
||||||
|
|
||||||
if (x <= 1) ++r;
|
|
||||||
|
|
||||||
if (y <= 1) --r;
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int getResult2(const unsigned long a, const unsigned long b, const unsigned long c, const unsigned long d) {
|
|
||||||
int x = 0;
|
|
||||||
int y = 0;
|
|
||||||
int r = 0;
|
|
||||||
|
|
||||||
if (a == c) ++x;
|
|
||||||
else if (b == c) ++y;
|
|
||||||
|
|
||||||
if (a == d) ++x;
|
|
||||||
else if (b == d) ++y;
|
|
||||||
|
|
||||||
if (x <= 1) --r;
|
|
||||||
|
|
||||||
if (y <= 1) ++r;
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline unsigned long interpolate(const unsigned long a, const unsigned long b) {
|
|
||||||
return (a + b - ((a ^ b) & 0x010101)) >> 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline unsigned long qInterpolate(const unsigned long a, const unsigned long b, const unsigned long c, const unsigned long d) {
|
|
||||||
const unsigned long lowBits = ((a & 0x030303) + (b & 0x030303) + (c & 0x030303) + (d & 0x030303)) & 0x030303;
|
|
||||||
|
|
||||||
return (a + b + c + d - lowBits) >> 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<unsigned srcPitch, unsigned width, unsigned height>
|
|
||||||
static void filter(gambatte::uint_least32_t *dstPtr, const int dstPitch, const gambatte::uint_least32_t *srcPtr)
|
|
||||||
{
|
|
||||||
unsigned h = height;
|
|
||||||
|
|
||||||
while (h--) {
|
|
||||||
const gambatte::uint_least32_t *bP = srcPtr;
|
|
||||||
gambatte::uint_least32_t *dP = dstPtr;
|
|
||||||
|
|
||||||
for (unsigned finish = width; finish--;) {
|
|
||||||
register unsigned long colorA, colorB;
|
|
||||||
unsigned long colorC, colorD,
|
|
||||||
colorE, colorF, colorG, colorH,
|
|
||||||
colorI, colorJ, colorK, colorL,
|
|
||||||
|
|
||||||
colorM, colorN, colorO, colorP;
|
|
||||||
unsigned long product, product1, product2;
|
|
||||||
|
|
||||||
//---------------------------------------
|
|
||||||
// Map of the pixels: I|E F|J
|
|
||||||
// G|A B|K
|
|
||||||
// H|C D|L
|
|
||||||
// M|N O|P
|
|
||||||
colorI = *(bP - srcPitch - 1);
|
|
||||||
colorE = *(bP - srcPitch);
|
|
||||||
colorF = *(bP - srcPitch + 1);
|
|
||||||
colorJ = *(bP - srcPitch + 2);
|
|
||||||
|
|
||||||
colorG = *(bP - 1);
|
|
||||||
colorA = *(bP);
|
|
||||||
colorB = *(bP + 1);
|
|
||||||
colorK = *(bP + 2);
|
|
||||||
|
|
||||||
colorH = *(bP + srcPitch - 1);
|
|
||||||
colorC = *(bP + srcPitch);
|
|
||||||
colorD = *(bP + srcPitch + 1);
|
|
||||||
colorL = *(bP + srcPitch + 2);
|
|
||||||
|
|
||||||
colorM = *(bP + srcPitch * 2 - 1);
|
|
||||||
colorN = *(bP + srcPitch * 2);
|
|
||||||
colorO = *(bP + srcPitch * 2 + 1);
|
|
||||||
colorP = *(bP + srcPitch * 2 + 2);
|
|
||||||
|
|
||||||
if (colorA == colorD && colorB != colorC) {
|
|
||||||
if ((colorA == colorE && colorB == colorL) ||
|
|
||||||
(colorA == colorC && colorA == colorF
|
|
||||||
&& colorB != colorE && colorB == colorJ)) {
|
|
||||||
product = colorA;
|
|
||||||
} else {
|
|
||||||
product = interpolate(colorA, colorB);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((colorA == colorG && colorC == colorO) ||
|
|
||||||
(colorA == colorB && colorA == colorH
|
|
||||||
&& colorG != colorC && colorC == colorM)) {
|
|
||||||
product1 = colorA;
|
|
||||||
} else {
|
|
||||||
product1 = interpolate(colorA, colorC);
|
|
||||||
}
|
|
||||||
product2 = colorA;
|
|
||||||
} else if (colorB == colorC && colorA != colorD) {
|
|
||||||
if ((colorB == colorF && colorA == colorH) ||
|
|
||||||
(colorB == colorE && colorB == colorD
|
|
||||||
&& colorA != colorF && colorA == colorI)) {
|
|
||||||
product = colorB;
|
|
||||||
} else {
|
|
||||||
product = interpolate(colorA, colorB);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((colorC == colorH && colorA == colorF) ||
|
|
||||||
(colorC == colorG && colorC == colorD
|
|
||||||
&& colorA != colorH && colorA == colorI)) {
|
|
||||||
product1 = colorC;
|
|
||||||
} else {
|
|
||||||
product1 = interpolate(colorA, colorC);
|
|
||||||
}
|
|
||||||
product2 = colorB;
|
|
||||||
} else if (colorA == colorD && colorB == colorC) {
|
|
||||||
if (colorA == colorB) {
|
|
||||||
product = colorA;
|
|
||||||
product1 = colorA;
|
|
||||||
product2 = colorA;
|
|
||||||
} else {
|
|
||||||
register int r = 0;
|
|
||||||
|
|
||||||
product1 = interpolate(colorA, colorC);
|
|
||||||
product = interpolate(colorA, colorB);
|
|
||||||
|
|
||||||
r += getResult1(colorA, colorB, colorG, colorE);
|
|
||||||
r += getResult2(colorB, colorA, colorK, colorF);
|
|
||||||
r += getResult2(colorB, colorA, colorH, colorN);
|
|
||||||
r += getResult1(colorA, colorB, colorL, colorO);
|
|
||||||
|
|
||||||
if (r > 0)
|
|
||||||
product2 = colorA;
|
|
||||||
else if (r < 0)
|
|
||||||
product2 = colorB;
|
|
||||||
else {
|
|
||||||
product2 = qInterpolate(colorA, colorB, colorC, colorD);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
product2 = qInterpolate(colorA, colorB, colorC, colorD);
|
|
||||||
|
|
||||||
if (colorA == colorC && colorA == colorF
|
|
||||||
&& colorB != colorE && colorB == colorJ) {
|
|
||||||
product = colorA;
|
|
||||||
} else if (colorB == colorE && colorB == colorD
|
|
||||||
&& colorA != colorF && colorA == colorI) {
|
|
||||||
product = colorB;
|
|
||||||
} else {
|
|
||||||
product = interpolate(colorA, colorB);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (colorA == colorB && colorA == colorH
|
|
||||||
&& colorG != colorC && colorC == colorM) {
|
|
||||||
product1 = colorA;
|
|
||||||
} else if (colorC == colorG && colorC == colorD
|
|
||||||
&& colorA != colorH && colorA == colorI) {
|
|
||||||
product1 = colorC;
|
|
||||||
} else {
|
|
||||||
product1 = interpolate(colorA, colorC);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*dP = colorA;
|
|
||||||
*(dP + 1) = product;
|
|
||||||
*(dP + dstPitch) = product1;
|
|
||||||
*(dP + dstPitch + 1) = product2;
|
|
||||||
|
|
||||||
++bP;
|
|
||||||
dP += 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
srcPtr += srcPitch;
|
|
||||||
dstPtr += dstPitch * 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum { WIDTH = VfilterInfo::IN_WIDTH };
|
|
||||||
enum { HEIGHT = VfilterInfo::IN_HEIGHT };
|
|
||||||
enum { PITCH = WIDTH + 3 };
|
|
||||||
enum { BUF_SIZE = (HEIGHT + 3) * PITCH };
|
|
||||||
enum { BUF_OFFSET = PITCH + 1 };
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Kreed2xSaI::Kreed2xSaI()
|
|
||||||
: buffer_(BUF_SIZE)
|
|
||||||
{
|
|
||||||
std::fill_n(buffer_.get(), buffer_.size(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void* Kreed2xSaI::inBuf() const {
|
|
||||||
return buffer_ + BUF_OFFSET;
|
|
||||||
}
|
|
||||||
|
|
||||||
int Kreed2xSaI::inPitch() const {
|
|
||||||
return PITCH;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Kreed2xSaI::draw(void *const dbuffer, const int pitch) {
|
|
||||||
::filter<PITCH, WIDTH, HEIGHT>(static_cast<gambatte::uint_least32_t*>(dbuffer), pitch, buffer_ + BUF_OFFSET);
|
|
||||||
}
|
|
@ -1,39 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2009 by Sindre Aamås *
|
|
||||||
* aamas@stud.ntnu.no *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU General Public License version 2 as *
|
|
||||||
* published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 version 2 for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License *
|
|
||||||
* version 2 along with this program; if not, write to the *
|
|
||||||
* Free Software Foundation, Inc., *
|
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
||||||
***************************************************************************/
|
|
||||||
#ifndef KREED2XSAI_H
|
|
||||||
#define KREED2XSAI_H
|
|
||||||
|
|
||||||
#include "../videolink.h"
|
|
||||||
#include "../vfilterinfo.h"
|
|
||||||
#include "gambatte-array.h"
|
|
||||||
#include "gbint.h"
|
|
||||||
|
|
||||||
class Kreed2xSaI : public VideoLink {
|
|
||||||
const Array<gambatte::uint_least32_t> buffer_;
|
|
||||||
public:
|
|
||||||
enum { OUT_WIDTH = VfilterInfo::IN_WIDTH * 2 };
|
|
||||||
enum { OUT_HEIGHT = VfilterInfo::IN_HEIGHT * 2 };
|
|
||||||
|
|
||||||
Kreed2xSaI();
|
|
||||||
virtual void* inBuf() const;
|
|
||||||
virtual int inPitch() const;
|
|
||||||
virtual void draw(void *dst, int dstpitch);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
File diff suppressed because it is too large
Load Diff
@ -1,39 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2009 by Sindre Aamås *
|
|
||||||
* aamas@stud.ntnu.no *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU General Public License version 2 as *
|
|
||||||
* published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 version 2 for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License *
|
|
||||||
* version 2 along with this program; if not, write to the *
|
|
||||||
* Free Software Foundation, Inc., *
|
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
||||||
***************************************************************************/
|
|
||||||
#ifndef MAXSTHQ2X_H
|
|
||||||
#define MAXSTHQ2X_H
|
|
||||||
|
|
||||||
#include "../videolink.h"
|
|
||||||
#include "../vfilterinfo.h"
|
|
||||||
#include "gambatte-array.h"
|
|
||||||
#include "gbint.h"
|
|
||||||
|
|
||||||
class MaxStHq2x : public VideoLink {
|
|
||||||
const Array<gambatte::uint_least32_t> buffer_;
|
|
||||||
public:
|
|
||||||
enum { OUT_WIDTH = VfilterInfo::IN_WIDTH * 2 };
|
|
||||||
enum { OUT_HEIGHT = VfilterInfo::IN_HEIGHT * 2 };
|
|
||||||
|
|
||||||
MaxStHq2x();
|
|
||||||
virtual void* inBuf() const;
|
|
||||||
virtual int inPitch() const;
|
|
||||||
virtual void draw(void *dst, int dstpitch);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
File diff suppressed because it is too large
Load Diff
@ -1,39 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2009 by Sindre Aamås *
|
|
||||||
* aamas@stud.ntnu.no *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU General Public License version 2 as *
|
|
||||||
* published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 version 2 for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License *
|
|
||||||
* version 2 along with this program; if not, write to the *
|
|
||||||
* Free Software Foundation, Inc., *
|
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
||||||
***************************************************************************/
|
|
||||||
#ifndef MAXSTHQ3X_H
|
|
||||||
#define MAXSTHQ3X_H
|
|
||||||
|
|
||||||
#include "../videolink.h"
|
|
||||||
#include "../vfilterinfo.h"
|
|
||||||
#include "gambatte-array.h"
|
|
||||||
#include "gbint.h"
|
|
||||||
|
|
||||||
class MaxStHq3x : public VideoLink {
|
|
||||||
const Array<gambatte::uint_least32_t> buffer_;
|
|
||||||
public:
|
|
||||||
enum { OUT_WIDTH = VfilterInfo::IN_WIDTH * 3 };
|
|
||||||
enum { OUT_HEIGHT = VfilterInfo::IN_HEIGHT * 3 };
|
|
||||||
|
|
||||||
MaxStHq3x();
|
|
||||||
virtual void* inBuf() const;
|
|
||||||
virtual int inPitch() const;
|
|
||||||
virtual void draw(void *dst, int dstpitch);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,30 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2009 by Sindre Aamås *
|
|
||||||
* aamas@stud.ntnu.no *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU General Public License version 2 as *
|
|
||||||
* published by the Free Software Foundation. *
|
|
||||||
* *
|
|
||||||
* 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 version 2 for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License *
|
|
||||||
* version 2 along with this program; if not, write to the *
|
|
||||||
* Free Software Foundation, Inc., *
|
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
||||||
***************************************************************************/
|
|
||||||
#ifndef VIDEOLINK_H
|
|
||||||
#define VIDEOLINK_H
|
|
||||||
|
|
||||||
class VideoLink {
|
|
||||||
public:
|
|
||||||
virtual ~VideoLink() {}
|
|
||||||
virtual void* inBuf() const = 0;
|
|
||||||
virtual int inPitch() const = 0;
|
|
||||||
virtual void draw(void *dst, int dstpitch) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
Loading…
Reference in New Issue
Block a user