dolphin/Externals/FreeSurround/include/FreeSurround/FreeSurroundDecoder.h

210 lines
6.6 KiB
C++

// Copyright (C) 2007-2010 Christian Kothe
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// 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 for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
// USA.
#ifndef FREESURROUND_DECODER_H
#define FREESURROUND_DECODER_H
#include "KissFFTR.h"
#include <complex>
#include <vector>
typedef std::complex<double> cplx;
// Identifiers for the supported output channels (from front to back, left to
// right). The ordering here also determines the ordering of interleaved
// samples in the output signal.
typedef enum channel_id {
ci_none = 0,
ci_front_left = 1 << 1,
ci_front_center_left = 1 << 2,
ci_front_center = 1 << 3,
ci_front_center_right = 1 << 4,
ci_front_right = 1 << 5,
ci_side_front_left = 1 << 6,
ci_side_front_right = 1 << 7,
ci_side_center_left = 1 << 8,
ci_side_center_right = 1 << 9,
ci_side_back_left = 1 << 10,
ci_side_back_right = 1 << 11,
ci_back_left = 1 << 12,
ci_back_center_left = 1 << 13,
ci_back_center = 1 << 14,
ci_back_center_right = 1 << 15,
ci_back_right = 1 << 16,
ci_lfe = 1 << 31
} channel_id;
// The supported output channel setups. A channel setup is defined by the set
// of channels that are present. Here is a graphic of the cs_5point1 setup:
// http://en.wikipedia.org/wiki/File:5_1_channels_(surround_sound)_label.svg
typedef enum channel_setup {
cs_5point1 = ci_front_left | ci_front_center | ci_front_right | ci_back_left |
ci_back_right | ci_lfe,
cs_7point1 = ci_front_left | ci_front_center | ci_front_right |
ci_side_center_left | ci_side_center_right | ci_back_left |
ci_back_right | ci_lfe
} channel_setup;
// The FreeSurround decoder.
class DPL2FSDecoder {
public:
// Create an instance of the decoder.
// @param setup The output channel setup -- determines the number of output
// channels and their place in the sound field.
// @param blocksize Granularity at which data is processed by the decode()
// function. Must be a power of two and should correspond to ca. 10ms worth
// of single-channel samples (default is 4096 for 44.1Khz data). Do not make
// it shorter or longer than 5ms to 20ms since the granularity at which
// locations are decoded changes with this.
DPL2FSDecoder();
~DPL2FSDecoder();
void Init(channel_setup setup = cs_5point1, unsigned int blocksize = 4096,
unsigned int samplerate = 48000);
// Decode a chunk of stereo sound. The output is delayed by half of the
// blocksize. This function is the only one needed for straightforward
// decoding.
// @param input Contains exactly blocksize (multiplexed) stereo samples, i.e.
// 2*blocksize numbers.
// @return A pointer to an internal buffer of exactly blocksize (multiplexed)
// multichannel samples. The actual number of values depends on the number of
// output channels in the chosen channel setup.
float *decode(float *input);
// Flush the internal buffer.
void flush();
// set soundfield & rendering parameters
// for more information, see full FreeSurround source code
void set_circular_wrap(float v);
void set_shift(float v);
void set_depth(float v);
void set_focus(float v);
void set_center_image(float v);
void set_front_separation(float v);
void set_rear_separation(float v);
void set_low_cutoff(float v);
void set_high_cutoff(float v);
void set_bass_redirection(bool v);
// number of samples currently held in the buffer
unsigned int buffered();
private:
// constants
const float pi = 3.141592654f;
const float epsilon = 0.000001f;
// number of samples per input/output block, number of output channels
unsigned int N, C;
unsigned int samplerate;
// the channel setup
channel_setup setup;
bool initialized;
// parameters
// angle of the front soundstage around the listener (90\B0=default)
float circular_wrap;
// forward/backward offset of the soundstage
float shift;
// backward extension of the soundstage
float depth;
// localization of the sound events
float focus;
// presence of the center speaker
float center_image;
// front stereo separation
float front_separation;
// rear stereo separation
float rear_separation;
// LFE cutoff frequencies
float lo_cut, hi_cut;
// whether to use the LFE channel
bool use_lfe;
// FFT data structures
// left total, right total (source arrays), time-domain destination buffer
// array
std::vector<double> lt, rt, dst;
// left total / right total in frequency domain
std::vector<cplx> lf, rf;
// FFT buffers
kiss_fftr_cfg forward, inverse;
// buffers
// whether the buffer is currently empty or dirty
bool buffer_empty;
// stereo input buffer (multiplexed)
std::vector<float> inbuf;
// multichannel output buffer (multiplexed)
std::vector<float> outbuf;
// the window function, precomputed
std::vector<double> wnd;
// the signal to be constructed in every channel, in the frequency domain
// instantiate the decoder with a given channel setup and processing block
// size (in samples)
std::vector<std::vector<cplx>> signal;
// helper functions
inline float sqr(double x);
inline double amplitude(const cplx &x);
inline double phase(const cplx &x);
inline cplx polar(double a, double p);
inline float min(double a, double b);
inline float max(double a, double b);
inline float clamp(double x);
inline float sign(double x);
// get the distance of the soundfield edge, along a given angle
inline double edgedistance(double a);
// get the index (and fractional offset!) in a piecewise-linear channel
// allocation grid
int map_to_grid(double &x);
// decode a block of data and overlap-add it into outbuf
void buffered_decode(float *input);
// transform amp/phase difference space into x/y soundfield space
void transform_decode(double a, double p, double &x, double &y);
// apply a circular_wrap transformation to some position
void transform_circular_wrap(double &x, double &y, double refangle);
// apply a focus transformation to some position
void transform_focus(double &x, double &y, double focus);
};
#endif