Commit 0ae708f9 authored by Stefan Westerfeld's avatar Stefan Westerfeld

Add multi channel support to Limiter.

Signed-off-by: Stefan Westerfeld's avatarStefan Westerfeld <stefan@space.twc.de>
parent 37028227
......@@ -3,4 +3,3 @@ possible improvements:
limiter:
- flush
- multi-channel support
......@@ -7,7 +7,8 @@
using std::vector;
using std::max;
Limiter::Limiter (int sample_rate) :
Limiter::Limiter (int n_channels, int sample_rate) :
n_channels (n_channels),
sample_rate (sample_rate)
{
}
......@@ -39,37 +40,47 @@ Limiter::process (const vector<float>& samples)
assert (look_ahead >= 1);
assert (release_factor > 0 && release_factor < 1);
for (size_t i = 0; i < samples.size(); i++)
const size_t n_frames = samples.size() / n_channels;
assert (n_frames * n_channels == samples.size()); // need all channels of each frame
for (size_t i = 0; i < n_frames; i++)
{
buffer.push_back (samples[i]);
for (uint c = 0; c < n_channels; c++)
buffer.push_back (samples[i * n_channels + c]);
max_buffer.push_back (ceiling);
}
for (size_t i = 0; i < buffer.size(); i++)
for (size_t i = 0; i < n_frames; i++)
{
if (fabs (buffer[i]) > ceiling)
float channel_max = 0;
for (uint c = 0; c < n_channels; c++)
channel_max = max (channel_max, fabs (samples[i * n_channels + c]));
if (channel_max > ceiling)
{
for (uint j = 0; j < look_ahead; j++)
{
if (int (i) - int (j) >= 0)
{
double alpha = double (j) / look_ahead;
max_buffer[i - j] = max<float> (max_buffer[i - j], fabs (buffer[i]) * (1 - alpha) + ceiling * alpha);
max_buffer[i - j] = max<float> (max_buffer[i - j], channel_max * (1 - alpha) + ceiling * alpha);
}
}
}
}
vector<float> out;
if (buffer.size() > look_ahead)
if (max_buffer.size() > look_ahead)
{
size_t todo = buffer.size() - look_ahead;
size_t todo = max_buffer.size() - look_ahead;
for (size_t i = 0; i < todo; i++)
{
maximum = maximum * release_factor + max_buffer[i] * (1 - release_factor);
if (maximum < max_buffer[i])
maximum = max_buffer[i];
out.push_back (buffer[i] / maximum * ceiling);
for (uint c = 0; c < n_channels; c++)
out.push_back (buffer[i * n_channels + c] / maximum * ceiling);
//printf ("%f %f\n", buffer[i], out.back());
}
......
......@@ -10,12 +10,13 @@ class Limiter
double maximum = 1;
double release_factor = 0;
uint look_ahead = 0;
uint n_channels = 0;
uint sample_rate = 0;
std::vector<float> max_buffer;
std::vector<float> buffer;
public:
Limiter (int sample_rate);
Limiter (int n_channels, int sample_rate);
void set_release (double value_ms);
void set_attack (double value_ms);
......
......@@ -24,16 +24,16 @@ main (int argc, char **argv)
Error err = in.open (argv[1]);
if (err)
{
fprintf (stderr, "teststream: open input failed: %s\n", err.message());
fprintf (stderr, "testlimiter: open input failed: %s\n", err.message());
return 1;
}
err = out.open (argv[2], in.n_channels(), in.sample_rate(), 16, in.n_frames());
if (err)
{
fprintf (stderr, "teststream: open output failed: %s\n", err.message());
fprintf (stderr, "testlimiter: open output failed: %s\n", err.message());
return 1;
}
Limiter limiter (in.sample_rate());
Limiter limiter (in.n_channels(), in.sample_rate());
limiter.set_attack (5);
limiter.set_release (50);
limiter.set_ceiling (0.9);
......
......@@ -644,7 +644,7 @@ add_watermark (const string& infile, const string& outfile, const string& bits)
if (!wm_resampler.init_ok())
return 1;
Limiter limiter (in_stream->sample_rate());
Limiter limiter (n_channels, in_stream->sample_rate());
limiter.set_attack (Params::limiter_attack_ms);
limiter.set_release (Params::limiter_release_ms);
limiter.set_ceiling (Params::limiter_ceiling);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment