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: ...@@ -3,4 +3,3 @@ possible improvements:
limiter: limiter:
- flush - flush
- multi-channel support
...@@ -7,7 +7,8 @@ ...@@ -7,7 +7,8 @@
using std::vector; using std::vector;
using std::max; using std::max;
Limiter::Limiter (int sample_rate) : Limiter::Limiter (int n_channels, int sample_rate) :
n_channels (n_channels),
sample_rate (sample_rate) sample_rate (sample_rate)
{ {
} }
...@@ -39,37 +40,47 @@ Limiter::process (const vector<float>& samples) ...@@ -39,37 +40,47 @@ Limiter::process (const vector<float>& samples)
assert (look_ahead >= 1); assert (look_ahead >= 1);
assert (release_factor > 0 && release_factor < 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); 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++) for (uint j = 0; j < look_ahead; j++)
{ {
if (int (i) - int (j) >= 0) if (int (i) - int (j) >= 0)
{ {
double alpha = double (j) / look_ahead; 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; 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++) for (size_t i = 0; i < todo; i++)
{ {
maximum = maximum * release_factor + max_buffer[i] * (1 - release_factor); maximum = maximum * release_factor + max_buffer[i] * (1 - release_factor);
if (maximum < max_buffer[i]) if (maximum < max_buffer[i])
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()); //printf ("%f %f\n", buffer[i], out.back());
} }
......
...@@ -10,12 +10,13 @@ class Limiter ...@@ -10,12 +10,13 @@ class Limiter
double maximum = 1; double maximum = 1;
double release_factor = 0; double release_factor = 0;
uint look_ahead = 0; uint look_ahead = 0;
uint n_channels = 0;
uint sample_rate = 0; uint sample_rate = 0;
std::vector<float> max_buffer; std::vector<float> max_buffer;
std::vector<float> buffer; std::vector<float> buffer;
public: public:
Limiter (int sample_rate); Limiter (int n_channels, int sample_rate);
void set_release (double value_ms); void set_release (double value_ms);
void set_attack (double value_ms); void set_attack (double value_ms);
......
...@@ -24,16 +24,16 @@ main (int argc, char **argv) ...@@ -24,16 +24,16 @@ main (int argc, char **argv)
Error err = in.open (argv[1]); Error err = in.open (argv[1]);
if (err) if (err)
{ {
fprintf (stderr, "teststream: open input failed: %s\n", err.message()); fprintf (stderr, "testlimiter: open input failed: %s\n", err.message());
return 1; return 1;
} }
err = out.open (argv[2], in.n_channels(), in.sample_rate(), 16, in.n_frames()); err = out.open (argv[2], in.n_channels(), in.sample_rate(), 16, in.n_frames());
if (err) if (err)
{ {
fprintf (stderr, "teststream: open output failed: %s\n", err.message()); fprintf (stderr, "testlimiter: open output failed: %s\n", err.message());
return 1; return 1;
} }
Limiter limiter (in.sample_rate()); Limiter limiter (in.n_channels(), in.sample_rate());
limiter.set_attack (5); limiter.set_attack (5);
limiter.set_release (50); limiter.set_release (50);
limiter.set_ceiling (0.9); limiter.set_ceiling (0.9);
......
...@@ -644,7 +644,7 @@ add_watermark (const string& infile, const string& outfile, const string& bits) ...@@ -644,7 +644,7 @@ add_watermark (const string& infile, const string& outfile, const string& bits)
if (!wm_resampler.init_ok()) if (!wm_resampler.init_ok())
return 1; 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_attack (Params::limiter_attack_ms);
limiter.set_release (Params::limiter_release_ms); limiter.set_release (Params::limiter_release_ms);
limiter.set_ceiling (Params::limiter_ceiling); 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