Created
December 3, 2018 18:18
-
-
Save zxmarcos/5bd9c32bb290a71a18dfffeef79bfbb5 to your computer and use it in GitHub Desktop.
Higan cubic resampler
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <nall/queue.hpp> | |
namespace nall { namespace DSP { namespace Resampler { | |
struct Cubic { | |
inline auto reset(double inputFrequency, double outputFrequency, uint queueSize = 0) -> void; | |
inline auto pending() const -> bool { return samples.pending(); } | |
inline auto read() -> double { return samples.read(); } | |
inline auto write(double sample) -> void; | |
private: | |
double inputFrequency; | |
double outputFrequency; | |
double ratio; | |
double fraction; | |
double history[4]; | |
queue<double> samples; | |
}; | |
auto Cubic::reset(double inputFrequency, double outputFrequency, uint queueSize) -> void { | |
this->inputFrequency = inputFrequency; | |
this->outputFrequency = outputFrequency; | |
if(!queueSize) queueSize = outputFrequency * 0.02; //20ms | |
ratio = inputFrequency / outputFrequency; | |
fraction = 0.0; | |
for(auto& sample: history) sample = 0.0; | |
samples.resize(queueSize); | |
} | |
auto Cubic::write(double sample) -> void { | |
auto& mu = fraction; | |
auto& s = history; | |
s[0] = s[1]; | |
s[1] = s[2]; | |
s[2] = s[3]; | |
s[3] = sample; | |
while(mu <= 1.0) { | |
double A = s[3] - s[2] - s[0] + s[1]; | |
double B = s[0] - s[1] - A; | |
double C = s[2] - s[0]; | |
double D = s[1]; | |
samples.write(A * mu * mu * mu + B * mu * mu + C * mu + D); | |
mu += ratio; | |
} | |
mu -= 1.0; | |
} | |
}}} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
//simple circular ring buffer | |
namespace nall { | |
template<typename T> | |
struct queue { | |
queue() = default; | |
queue(const queue& source) { | |
operator=(source); | |
} | |
queue(queue&& source) { | |
operator=(move(source)); | |
} | |
auto operator=(const queue& source) -> queue& { | |
if(this == &source) return *this; | |
reset(); | |
_size = source._size; | |
_data = new T[_size]; | |
for(auto n : range(_size)) _data[n] = source._data[n]; | |
_read = source._read; | |
_write = source._write; | |
return *this; | |
} | |
auto operator=(queue&& source) -> queue& { | |
if(this == &source) return *this; | |
_data = source._data; | |
_size = source._size; | |
_read = source._read; | |
_write = source._write; | |
source._data = nullptr; | |
source.reset(); | |
return *this; | |
} | |
~queue() { | |
reset(); | |
} | |
explicit operator bool() const { | |
return _size; | |
} | |
auto size() const -> uint { | |
return _size; | |
} | |
auto data() -> T* { | |
return _data; | |
} | |
auto data() const -> const T* { | |
return _data; | |
} | |
auto reset() { | |
delete[] _data; | |
_data = nullptr; | |
_size = 0; | |
_read = 0; | |
_write = 0; | |
} | |
auto resize(uint size, const T& value = {}) -> void { | |
reset(); | |
_size = size; | |
_data = new T[_size]; | |
for(auto n : range(_size)) _data[n] = value; | |
} | |
auto pending() const -> bool { | |
return _read != _write; | |
} | |
auto read() -> T { | |
T result = _data[_read]; | |
if(++_read >= _size) _read = 0; | |
return result; | |
} | |
auto last() const -> T { | |
return _data[_write]; | |
} | |
auto write(const T& value) -> void { | |
_data[_write] = value; | |
if(++_write >= _size) _write = 0; | |
} | |
private: | |
T* _data = nullptr; | |
uint _size = 0; | |
uint _read = 0; | |
uint _write = 0; | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment