From 65d716be70e6295628dfa5bb0a72f3429b9696ba Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Mon, 11 Jan 2016 23:54:28 +0100 Subject: [PATCH] Make it possible to override the level compressor with the gain staging knob. --- mainwindow.cpp | 20 ++++++++++++++++---- mainwindow.h | 1 + mixer.cpp | 31 ++++++++++++++++++++----------- mixer.h | 25 +++++++++++++++++-------- 4 files changed, 54 insertions(+), 23 deletions(-) diff --git a/mainwindow.cpp b/mainwindow.cpp index fbfbecd..8cd0abd 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -109,8 +109,10 @@ void MainWindow::mixer_created(Mixer *mixer) connect(ui->locut_cutoff_knob, &QDial::valueChanged, this, &MainWindow::cutoff_knob_changed); cutoff_knob_changed(ui->locut_cutoff_knob->value()); + // Not QDial::valueChanged, as we call setValue() all the time. + connect(ui->gainstaging_knob, &QAbstractSlider::sliderMoved, this, &MainWindow::gain_staging_knob_changed); connect(ui->gainstaging_auto_checkbox, &QCheckBox::stateChanged, [this](int state){ - global_mixer->set_gainstaging_auto(state == Qt::Checked); + global_mixer->set_gain_staging_auto(state == Qt::Checked); }); connect(ui->limiter_threshold_knob, &QDial::valueChanged, this, &MainWindow::limiter_threshold_knob_changed); @@ -144,6 +146,16 @@ void MainWindow::exit_triggered() close(); } +void MainWindow::gain_staging_knob_changed(int value) +{ + ui->gainstaging_auto_checkbox->setCheckState(Qt::Unchecked); + + float gain_db = value * 0.1f; + global_mixer->set_gain_staging_db(gain_db); + + // The label will be updated by the audio level callback. +} + void MainWindow::cutoff_knob_changed(int value) { float octaves = value * 0.1f; @@ -182,7 +194,7 @@ void MainWindow::reset_meters_button_clicked() ui->peak_display->setStyleSheet(""); } -void MainWindow::audio_level_callback(float level_lufs, float peak_db, float global_level_lufs, float range_low_lufs, float range_high_lufs, float auto_gain_staging_db) +void MainWindow::audio_level_callback(float level_lufs, float peak_db, float global_level_lufs, float range_low_lufs, float range_high_lufs, float gain_staging_db) { timeval now; gettimeofday(&now, nullptr); @@ -209,8 +221,8 @@ void MainWindow::audio_level_callback(float level_lufs, float peak_db, float glo ui->peak_display->setStyleSheet(""); } - ui->gainstaging_knob->setValue(lrintf(auto_gain_staging_db * 10.0f)); - snprintf(buf, sizeof(buf), "%+.1f dB", auto_gain_staging_db); + ui->gainstaging_knob->setValue(lrintf(gain_staging_db * 10.0f)); + snprintf(buf, sizeof(buf), "%+.1f dB", gain_staging_db); ui->gainstaging_db_display->setText(buf); }); } diff --git a/mainwindow.h b/mainwindow.h index 82309c4..07bea73 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -39,6 +39,7 @@ public slots: void wb_button_clicked(int channel_number); void set_transition_names(std::vector transition_names); void update_channel_name(Mixer::Output output); + void gain_staging_knob_changed(int value); void cutoff_knob_changed(int value); void limiter_threshold_knob_changed(int value); void compressor_threshold_knob_changed(int value); diff --git a/mixer.cpp b/mixer.cpp index dd8cc60..7202202 100644 --- a/mixer.cpp +++ b/mixer.cpp @@ -526,7 +526,7 @@ void Mixer::thread_func() } if (audio_level_callback != nullptr) { - unique_lock lock(r128_mutex); + unique_lock lock(compressor_mutex); double loudness_s = r128.loudness_S(); double loudness_i = r128.integrated(); double loudness_range_low = r128.range_min(); @@ -534,7 +534,7 @@ void Mixer::thread_func() audio_level_callback(loudness_s, 20.0 * log10(peak), loudness_i, loudness_range_low, loudness_range_high, - last_gain_staging_db); + gain_staging_db); } for (unsigned card_index = 1; card_index < num_cards; ++card_index) { @@ -715,14 +715,23 @@ void Mixer::process_audio_one_frame(int64_t frame_pts_int, int num_samples) // then apply a makeup gain to get it to -14 dBFS. -14 dBFS is, of course, // entirely arbitrary, but from practical tests with speech, it seems to // put ut around -23 LUFS, so it's a reasonable starting point for later use. - if (level_compressor_enabled) { - float threshold = 0.01f; // -40 dBFS. - float ratio = 20.0f; - float attack_time = 0.5f; - float release_time = 20.0f; - float makeup_gain = pow(10.0f, (ref_level_dbfs - (-40.0f)) / 20.0f); // +26 dB. - level_compressor.process(samples_out.data(), samples_out.size() / 2, threshold, ratio, attack_time, release_time, makeup_gain); - last_gain_staging_db = 20.0 * log10(level_compressor.get_attenuation() * makeup_gain); + { + unique_lock lock(level_compressor_mutex); + if (level_compressor_enabled) { + float threshold = 0.01f; // -40 dBFS. + float ratio = 20.0f; + float attack_time = 0.5f; + float release_time = 20.0f; + float makeup_gain = pow(10.0f, (ref_level_dbfs - (-40.0f)) / 20.0f); // +26 dB. + level_compressor.process(samples_out.data(), samples_out.size() / 2, threshold, ratio, attack_time, release_time, makeup_gain); + gain_staging_db = 20.0 * log10(level_compressor.get_attenuation() * makeup_gain); + } else { + // Just apply the gain we already had. + float g = pow(10.0f, gain_staging_db / 20.0f); + for (size_t i = 0; i < samples_out.size(); ++i) { + samples_out[i] *= g; + } + } } #if 0 @@ -778,7 +787,7 @@ void Mixer::process_audio_one_frame(int64_t frame_pts_int, int num_samples) deinterleave_samples(samples_out, &left, &right); float *ptrs[] = { left.data(), right.data() }; { - unique_lock lock(r128_mutex); + unique_lock lock(compressor_mutex); r128.process(left.size(), ptrs); } diff --git a/mixer.h b/mixer.h index 682aea4..f50eb58 100644 --- a/mixer.h +++ b/mixer.h @@ -103,7 +103,7 @@ public: typedef std::function audio_level_callback_t; + float gain_staging_db)> audio_level_callback_t; void set_audio_level_callback(audio_level_callback_t callback) { audio_level_callback = callback; @@ -169,9 +169,17 @@ public: compressor_enabled = enabled; } - void set_gainstaging_auto(bool enabled) + void set_gain_staging_db(float gain_db) { - level_compressor = enabled; + std::unique_lock lock(level_compressor_mutex); + level_compressor_enabled = false; + gain_staging_db = gain_db; + } + + void set_gain_staging_auto(bool enabled) + { + std::unique_lock lock(level_compressor_mutex); + level_compressor_enabled = enabled; } void schedule_cut() @@ -265,8 +273,8 @@ private: std::atomic should_cut{false}; audio_level_callback_t audio_level_callback = nullptr; - std::mutex r128_mutex; - Ebu_r128_proc r128; // Under r128_mutex. + std::mutex compressor_mutex; + Ebu_r128_proc r128; // Under compressor_mutex. Resampler peak_resampler; std::atomic peak{0.0f}; @@ -275,9 +283,10 @@ private: std::atomic locut_cutoff_hz; // First compressor; takes us up to about -12 dBFS. - StereoCompressor level_compressor; - float last_gain_staging_db = 0.0f; - std::atomic level_compressor_enabled{true}; + std::mutex level_compressor_mutex; + StereoCompressor level_compressor; // Under compressor_mutex. Used to set/override gain_staging_db if . + float gain_staging_db = 0.0f; // Under compressor_mutex. + bool level_compressor_enabled = true; // Under compressor_mutex. static constexpr float ref_level_dbfs = -14.0f; -- 2.39.2