164 lines
3.5 KiB
C++
164 lines
3.5 KiB
C++
#pragma once
|
|
|
|
#include <math.h>
|
|
#include <vector>
|
|
#include <nall/stdint.hpp>
|
|
|
|
namespace nall {
|
|
|
|
struct DSP;
|
|
|
|
struct Resampler {
|
|
Resampler(DSP& dsp) : dsp(dsp) {}
|
|
virtual ~Resampler() {}
|
|
|
|
virtual auto setFrequency() -> void = 0;
|
|
virtual auto clear() -> void = 0;
|
|
virtual auto sample() -> void = 0;
|
|
|
|
DSP& dsp;
|
|
double frequency = 44100.0;
|
|
};
|
|
|
|
struct DSP {
|
|
enum class ResampleEngine : uint {
|
|
Nearest,
|
|
Linear,
|
|
Cosine,
|
|
Cubic,
|
|
Hermite,
|
|
Average,
|
|
Sinc,
|
|
};
|
|
|
|
inline DSP();
|
|
inline ~DSP();
|
|
|
|
inline auto setChannels(uint channels) -> void;
|
|
inline auto setPrecision(uint precision) -> void;
|
|
inline auto setFrequency(double frequency) -> void; //inputFrequency
|
|
inline auto setVolume(double volume) -> void;
|
|
inline auto setBalance(double balance) -> void;
|
|
|
|
inline auto setResampler(ResampleEngine resamplingEngine) -> void;
|
|
inline auto setResamplerFrequency(double frequency) -> void; //outputFrequency
|
|
|
|
inline auto sample(int channel[]) -> void;
|
|
inline auto pending() const -> bool;
|
|
inline auto read(int channel[]) -> void;
|
|
|
|
inline auto clear() -> void;
|
|
|
|
protected:
|
|
inline auto write(double channel[]) -> void;
|
|
inline auto adjustVolume() -> void;
|
|
inline auto adjustBalance() -> void;
|
|
inline auto clamp(const uint bits, const int input) -> int;
|
|
|
|
struct Settings {
|
|
uint channels;
|
|
uint precision;
|
|
double frequency;
|
|
double volume;
|
|
double balance;
|
|
|
|
//internal
|
|
double intensity;
|
|
double intensityInverse;
|
|
} settings;
|
|
|
|
Resampler* resampler = nullptr;
|
|
|
|
#include "buffer.hpp"
|
|
Buffer buffer;
|
|
Buffer output;
|
|
|
|
friend class ResampleNearest;
|
|
friend class ResampleLinear;
|
|
friend class ResampleCosine;
|
|
friend class ResampleCubic;
|
|
friend class ResampleAverage;
|
|
friend class ResampleHermite;
|
|
friend class ResampleSinc;
|
|
};
|
|
|
|
#include "resample/nearest.hpp"
|
|
#include "resample/linear.hpp"
|
|
#include "resample/cosine.hpp"
|
|
#include "resample/cubic.hpp"
|
|
#include "resample/hermite.hpp"
|
|
#include "resample/average.hpp"
|
|
#include "resample/sinc.hpp"
|
|
#include "settings.hpp"
|
|
|
|
DSP::DSP() {
|
|
setResampler(ResampleEngine::Hermite);
|
|
setResamplerFrequency(44100.0);
|
|
|
|
setChannels(2);
|
|
setPrecision(16);
|
|
setFrequency(44100.0);
|
|
setVolume(1.0);
|
|
setBalance(0.0);
|
|
|
|
clear();
|
|
}
|
|
|
|
DSP::~DSP() {
|
|
if(resampler) delete resampler;
|
|
}
|
|
|
|
auto DSP::sample(int channel[]) -> void {
|
|
for(auto c : range(settings.channels)) {
|
|
buffer.write(c) = (double)channel[c] * settings.intensityInverse;
|
|
}
|
|
buffer.wroffset++;
|
|
resampler->sample();
|
|
}
|
|
|
|
auto DSP::pending() const -> bool {
|
|
return output.rdoffset != output.wroffset;
|
|
}
|
|
|
|
auto DSP::read(int channel[]) -> void {
|
|
adjustVolume();
|
|
adjustBalance();
|
|
|
|
for(auto c : range(settings.channels)) {
|
|
channel[c] = clamp(settings.precision, output.read(c) * settings.intensity);
|
|
}
|
|
output.rdoffset++;
|
|
}
|
|
|
|
auto DSP::write(double channel[]) -> void {
|
|
for(auto c : range(settings.channels)) {
|
|
output.write(c) = channel[c];
|
|
}
|
|
output.wroffset++;
|
|
}
|
|
|
|
auto DSP::adjustVolume() -> void {
|
|
for(auto c : range(settings.channels)) {
|
|
output.read(c) *= settings.volume;
|
|
}
|
|
}
|
|
|
|
auto DSP::adjustBalance() -> void {
|
|
if(settings.channels != 2) return; //TODO: support > 2 channels
|
|
if(settings.balance < 0.0) output.read(1) *= 1.0 + settings.balance;
|
|
if(settings.balance > 0.0) output.read(0) *= 1.0 - settings.balance;
|
|
}
|
|
|
|
auto DSP::clamp(const uint bits, const int x) -> int {
|
|
const int b = 1U << (bits - 1);
|
|
const int m = (1U << (bits - 1)) - 1;
|
|
return (x > m) ? m : (x < -b) ? -b : x;
|
|
}
|
|
|
|
auto DSP::clear() -> void {
|
|
buffer.clear();
|
|
output.clear();
|
|
resampler->clear();
|
|
}
|
|
|
|
}
|