mirror of
https://github.com/Zelda64Recomp/Zelda64Recomp.git
synced 2026-03-21 18:41:47 +00:00
Surround.
This commit is contained in:
parent
dacf76962e
commit
d2e771d321
1 changed files with 116 additions and 0 deletions
116
include/sound_matrix_decoder.h
Normal file
116
include/sound_matrix_decoder.h
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cmath>
|
||||
#include <array>
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Passive matrix decoder for stereo to 5.1 surround upmixing.
|
||||
* Implements standard audio matrix decoding techniques using:
|
||||
* - Linkwitz-Riley crossover filters for frequency band separation
|
||||
* - All-pass filters for phase manipulation
|
||||
* - Delay lines for surround channel timing
|
||||
*/
|
||||
class SoundMatrixDecoder {
|
||||
public:
|
||||
/**
|
||||
* Construct and initialize the decoder with a specific sample rate.
|
||||
* @param sampleRate The audio sample rate in Hz
|
||||
*/
|
||||
SoundMatrixDecoder(int32_t sampleRate);
|
||||
~SoundMatrixDecoder() = default;
|
||||
|
||||
/**
|
||||
* Reset filter states without recomputing coefficients.
|
||||
* Useful when audio is interrupted to prevent clicks.
|
||||
*/
|
||||
void ResetState();
|
||||
|
||||
/**
|
||||
* Decode stereo to 5.1 surround
|
||||
* @param stereoInput Interleaved stereo samples [L0, R0, L1, R1, ...]
|
||||
* @param samplePairs Number of stereo sample pairs to process
|
||||
* @return Pointer to internal buffer with interleaved 5.1 samples [FL, FR, C, LFE, SL, SR, ...]
|
||||
*/
|
||||
std::tuple<const float*, size_t> Process(const float* stereoInput, size_t samplePairs);
|
||||
|
||||
private:
|
||||
// 4th-order IIR filter (Linkwitz-Riley) for 24dB/octave slopes
|
||||
struct BiquadCascade {
|
||||
double X[4] = {}; // Input history
|
||||
double Y[4] = {}; // Output history
|
||||
};
|
||||
|
||||
struct FilterCoefficients {
|
||||
double A[5]; // Feedforward (numerator)
|
||||
double B[4]; // Feedback (denominator, excluding b0=1)
|
||||
};
|
||||
|
||||
// Sweeping all-pass for phase decorrelation
|
||||
struct AllPassChain {
|
||||
double Freq = 0;
|
||||
double FreqMin = 0;
|
||||
double FreqMax = 0;
|
||||
double SweepRate = 0;
|
||||
double XHist[4] = {};
|
||||
double YHist[4] = {};
|
||||
bool Ready = false;
|
||||
};
|
||||
|
||||
// Circular delay buffer
|
||||
static constexpr int gMaxDelay = 1024;
|
||||
struct CircularDelay {
|
||||
std::array<float, gMaxDelay> Data = {};
|
||||
int Head = 0;
|
||||
int Length = 0;
|
||||
};
|
||||
|
||||
// Filter design
|
||||
FilterCoefficients DesignLowPass(double frequency, int32_t sampleRate);
|
||||
FilterCoefficients DesignHighPass(double frequency, int32_t sampleRate);
|
||||
|
||||
// Signal processing
|
||||
float ProcessFilter(float sample, BiquadCascade& state, const FilterCoefficients& coef);
|
||||
void PrepareAllPass(AllPassChain& chain, int32_t sampleRate);
|
||||
float ProcessAllPass(float sample, AllPassChain& chain, bool negate);
|
||||
float ProcessDelay(float sample, CircularDelay& buffer);
|
||||
|
||||
static float Saturate(float value);
|
||||
|
||||
int32_t mDelayLength = 0;
|
||||
double mAllPassBaseRate = 1.0; // Precomputed for ProcessAllPass
|
||||
|
||||
// Filter coefficients (computed once per sample rate)
|
||||
FilterCoefficients mCoefCenterHP;
|
||||
FilterCoefficients mCoefCenterLP;
|
||||
FilterCoefficients mCoefSurroundHP;
|
||||
FilterCoefficients mCoefSubLP;
|
||||
|
||||
// Per-channel filter states
|
||||
BiquadCascade mCenterHighPass;
|
||||
BiquadCascade mCenterLowPass;
|
||||
BiquadCascade mSurrLeftMainHP;
|
||||
BiquadCascade mSurrLeftCrossHP;
|
||||
BiquadCascade mSurrRightMainHP;
|
||||
BiquadCascade mSurrRightCrossHP;
|
||||
BiquadCascade mSubLowPass;
|
||||
|
||||
// Phase processing
|
||||
AllPassChain mPhaseLeftMain;
|
||||
AllPassChain mPhaseLeftCross;
|
||||
AllPassChain mPhaseRightMain;
|
||||
AllPassChain mPhaseRightCross;
|
||||
|
||||
// Timing
|
||||
CircularDelay mDelaySurrLeft;
|
||||
CircularDelay mDelaySurrRight;
|
||||
|
||||
// Output buffer
|
||||
std::vector<float> mSurroundBuffer;
|
||||
};
|
||||
Loading…
Add table
Reference in a new issue