compressor(OUTPUT_FREQUENCY),
correlation(OUTPUT_FREQUENCY)
{
- locut.init(FILTER_HPF, 2);
-
- set_locut_enabled(global_flags.locut_enabled);
+ for (unsigned bus_index = 0; bus_index < MAX_BUSES; ++bus_index) {
+ locut[bus_index].init(FILTER_HPF, 2);
+ locut_enabled[bus_index] = global_flags.locut_enabled;
+ }
set_gain_staging_db(global_flags.initial_gain_staging_db);
set_gain_staging_auto(global_flags.gain_staging_auto);
set_compressor_enabled(global_flags.compressor_enabled);
if (device->interesting_channels.empty()) {
device->alsa_device.reset();
} else {
- device->alsa_device.reset(new ALSAInput(available_alsa_cards[card_index].address.c_str(), OUTPUT_FREQUENCY, 2, bind(&AudioMixer::add_audio, this, device_spec, _1, _2, _3, _4)));
+ const ALSAInput::Device &alsa_dev = available_alsa_cards[card_index];
+ device->alsa_device.reset(new ALSAInput(alsa_dev.address.c_str(), OUTPUT_FREQUENCY, alsa_dev.num_channels, bind(&AudioMixer::add_audio, this, device_spec, _1, _2, _3, _4)));
device->capture_frequency = device->alsa_device->get_sample_rate();
device->alsa_device->start_capture_thread();
}
}
// TODO: Move lo-cut etc. into each bus.
- vector<float> samples_out;
+ vector<float> samples_out, left, right;
samples_out.resize(num_samples * 2);
samples_bus.resize(num_samples * 2);
for (unsigned bus_index = 0; bus_index < input_mapping.buses.size(); ++bus_index) {
fill_audio_bus(samples_card, input_mapping.buses[bus_index], num_samples, &samples_bus[0]);
+ // Cut away everything under 120 Hz (or whatever the cutoff is);
+ // we don't need it for voice, and it will reduce headroom
+ // and confuse the compressor. (In particular, any hums at 50 or 60 Hz
+ // should be dampened.)
+ if (locut_enabled[bus_index]) {
+ locut[bus_index].render(samples_bus.data(), samples_bus.size() / 2, locut_cutoff_hz * 2.0 * M_PI / OUTPUT_FREQUENCY, 0.5f);
+ }
+
+ // TODO: We should measure post-fader.
+ deinterleave_samples(samples_bus, &left, &right);
+ measure_bus_levels(bus_index, left, right);
+
float volume = from_db(fader_volume_db[bus_index]);
if (bus_index == 0) {
for (unsigned i = 0; i < num_samples * 2; ++i) {
}
}
- // Cut away everything under 120 Hz (or whatever the cutoff is);
- // we don't need it for voice, and it will reduce headroom
- // and confuse the compressor. (In particular, any hums at 50 or 60 Hz
- // should be dampened.)
- if (locut_enabled) {
- locut.render(samples_out.data(), samples_out.size() / 2, locut_cutoff_hz * 2.0 * M_PI / OUTPUT_FREQUENCY, 0.5f);
- }
-
{
lock_guard<mutex> lock(compressor_mutex);
return samples_out;
}
+void AudioMixer::measure_bus_levels(unsigned bus_index, const vector<float> &left, const vector<float> &right)
+{
+ const float *ptrs[] = { left.data(), right.data() };
+ {
+ lock_guard<mutex> lock(audio_measure_mutex);
+ bus_r128[bus_index]->process(left.size(), const_cast<float **>(ptrs));
+ }
+}
+
void AudioMixer::update_meters(const vector<float> &samples)
{
// Upsample 4x to find interpolated peak.
vector<float> interpolated_samples;
interpolated_samples.resize(samples.size());
{
- unique_lock<mutex> lock(audio_measure_mutex);
+ lock_guard<mutex> lock(audio_measure_mutex);
while (peak_resampler.inp_count > 0) { // About four iterations.
peak_resampler.out_data = &interpolated_samples[0];
deinterleave_samples(samples, &left, &right);
float *ptrs[] = { left.data(), right.data() };
{
- unique_lock<mutex> lock(audio_measure_mutex);
+ lock_guard<mutex> lock(audio_measure_mutex);
r128.process(left.size(), ptrs);
correlation.process_samples(samples);
}
void AudioMixer::reset_meters()
{
- unique_lock<mutex> lock(audio_measure_mutex);
+ lock_guard<mutex> lock(audio_measure_mutex);
peak_resampler.reset();
peak = 0.0f;
r128.reset();
return;
}
- unique_lock<mutex> lock(audio_measure_mutex);
+ lock_guard<mutex> lock(audio_measure_mutex);
double loudness_s = r128.loudness_S();
double loudness_i = r128.integrated();
double loudness_range_low = r128.range_min();
double loudness_range_high = r128.range_max();
- audio_level_callback(loudness_s, to_db(peak),
+ vector<float> bus_loudness;
+ bus_loudness.resize(input_mapping.buses.size());
+ for (unsigned bus_index = 0; bus_index < bus_r128.size(); ++bus_index) {
+ bus_loudness[bus_index] = bus_r128[bus_index]->loudness_S();
+ }
+
+ audio_level_callback(loudness_s, to_db(peak), bus_loudness,
loudness_i, loudness_range_low, loudness_range_high,
gain_staging_db,
to_db(final_makeup_gain),
}
}
+ {
+ lock_guard<mutex> lock(audio_measure_mutex);
+ bus_r128.resize(new_input_mapping.buses.size());
+ for (unsigned bus_index = 0; bus_index < bus_r128.size(); ++bus_index) {
+ if (bus_r128[bus_index] == nullptr) {
+ bus_r128[bus_index].reset(new Ebu_r128_proc);
+ }
+ bus_r128[bus_index]->init(2, OUTPUT_FREQUENCY);
+ }
+ }
+
input_mapping = new_input_mapping;
}