]> git.sesse.net Git - nageru/commitdiff
Hook up the per-bus VU meters.
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Sat, 13 Aug 2016 20:47:26 +0000 (22:47 +0200)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Wed, 19 Oct 2016 22:55:44 +0000 (00:55 +0200)
audio_mixer.cpp
audio_mixer.h
mainwindow.cpp
mainwindow.h

index 5a7804582ce591f4b80432fe418c01ebe2c7c4e7..afff6f32fe4cec9beac774c75b2782d5cba01f2d 100644 (file)
@@ -350,12 +350,16 @@ vector<float> AudioMixer::get_output(double pts, unsigned num_samples, Resamplin
        }
 
        // 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]);
 
+               // 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) {
@@ -483,6 +487,15 @@ vector<float> AudioMixer::get_output(double pts, unsigned num_samples, Resamplin
        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.
@@ -492,7 +505,7 @@ void AudioMixer::update_meters(const vector<float> &samples)
        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];
@@ -509,7 +522,7 @@ void AudioMixer::update_meters(const vector<float> &samples)
        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);
        }
@@ -519,7 +532,7 @@ void AudioMixer::update_meters(const vector<float> &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();
@@ -533,13 +546,19 @@ void AudioMixer::send_audio_level_callback()
                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),
@@ -611,6 +630,17 @@ void AudioMixer::set_input_mapping(const InputMapping &new_input_mapping)
                }
        }
 
+       {
+               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;
 }
 
index 75b468a120f7d1f39aa293009e9b76153ae4e9a3..31611af095151b4f65b2cc40f7836ed39b06887d 100644 (file)
@@ -202,6 +202,7 @@ public:
        }
 
        typedef std::function<void(float level_lufs, float peak_db,
+                                  std::vector<float> bus_level_lufs,
                                   float global_level_lufs, float range_low_lufs, float range_high_lufs,
                                   float gain_staging_db, float final_makeup_gain_db,
                                   float correlation)> audio_level_callback_t;
@@ -229,6 +230,7 @@ private:
        void reset_alsa_mutex_held(DeviceSpec device_spec);
        std::map<DeviceSpec, DeviceInfo> get_devices_mutex_held() const;
        void update_meters(const std::vector<float> &samples);
+       void measure_bus_levels(unsigned bus_index, const std::vector<float> &left, const std::vector<float> &right);
        void send_audio_level_callback();
 
        unsigned num_cards;
@@ -273,6 +275,12 @@ private:
        CorrelationMeasurer correlation;  // Under audio_measure_mutex.
        Resampler peak_resampler;  // Under audio_measure_mutex.
        std::atomic<float> peak{0.0f};
+
+       // Under audio_measure_mutex. Note that Ebu_r128_proc has a broken
+       // copy constructor (it uses the default, but holds arrays),
+       // so we can't just use raw Ebu_r128_proc elements, but need to use
+       // unique_ptrs.
+       std::vector<std::unique_ptr<Ebu_r128_proc>> bus_r128;
 };
 
 #endif  // !defined(_AUDIO_MIXER_H)
index 28f0393fce2c4a20e1ef50a180cb8314cc57a1ae..c1a3836b2ff7a97b4e23c3b9acfd5c384a38cfcf 100644 (file)
@@ -217,7 +217,7 @@ void MainWindow::mixer_created(Mixer *mixer)
                global_mixer->get_audio_mixer()->set_compressor_enabled(state == Qt::Checked);
        });
        connect(ui->reset_meters_button, &QPushButton::clicked, this, &MainWindow::reset_meters_button_clicked);
-       mixer->get_audio_mixer()->set_audio_level_callback(bind(&MainWindow::audio_level_callback, this, _1, _2, _3, _4, _5, _6, _7, _8));
+       mixer->get_audio_mixer()->set_audio_level_callback(bind(&MainWindow::audio_level_callback, this, _1, _2, _3, _4, _5, _6, _7, _8, _9));
 
        struct sigaction act;
        memset(&act, 0, sizeof(act));
@@ -240,15 +240,18 @@ void MainWindow::setup_audio_miniview()
                delete item->widget();
                delete item;
        }
+       audio_miniviews.clear();
 
        // Set up brand new ones from the input mapping.
        InputMapping mapping = global_mixer->get_audio_mixer()->get_input_mapping();
+       audio_miniviews.resize(mapping.buses.size());
        for (unsigned bus_index = 0; bus_index < mapping.buses.size(); ++bus_index) {
                QWidget *channel = new QWidget(this);
                Ui::AudioMiniView *ui_audio_miniview = new Ui::AudioMiniView;
                ui_audio_miniview->setupUi(channel);
                ui_audio_miniview->bus_desc_label->setFullText(
                        QString::fromStdString(mapping.buses[bus_index].name));
+               audio_miniviews[bus_index] = ui_audio_miniview;
                // TODO: Set the fader position.
                ui->faders->addWidget(channel);
 
@@ -396,7 +399,8 @@ 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,
+void MainWindow::audio_level_callback(float level_lufs, float peak_db, vector<float> bus_level_lufs,
+                                      float global_level_lufs,
                                       float range_low_lufs, float range_high_lufs,
                                       float gain_staging_db, float final_makeup_gain_db,
                                       float correlation)
@@ -413,6 +417,12 @@ void MainWindow::audio_level_callback(float level_lufs, float peak_db, float glo
 
        post_to_main_thread([=]() {
                ui->vu_meter->set_level(level_lufs);
+               for (unsigned bus_index = 0; bus_index < bus_level_lufs.size(); ++bus_index) {
+                       if (bus_index < audio_miniviews.size()) {
+                               audio_miniviews[bus_index]->vu_meter_meter->set_level(
+                                       bus_level_lufs[bus_index]);
+                       }
+               }
                ui->lra_meter->set_levels(global_level_lufs, range_low_lufs, range_high_lufs);
                ui->correlation_meter->set_correlation(correlation);
 
index a930cd9912daa875a17b8b6512167d9605e2ce99..b93470a4306fba0573291f2d6a46571a58e0b395 100644 (file)
@@ -64,13 +64,14 @@ private:
        void report_disk_space(off_t free_bytes, double estimated_seconds_left);
 
        // Called from the mixer.
-       void 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, float final_makeup_gain_db, float correlation);
+       void audio_level_callback(float level_lufs, float peak_db, std::vector<float> bus_level_lufs, float global_level_lufs, float range_low_lufs, float range_high_lufs, float gain_staging_db, float final_makeup_gain_db, float correlation);
        std::chrono::steady_clock::time_point last_audio_level_callback;
 
        Ui::MainWindow *ui;
        QLabel *disk_free_label;
        QPushButton *transition_btn1, *transition_btn2, *transition_btn3;
        std::vector<Ui::Display *> previews;
+       std::vector<Ui::AudioMiniView *> audio_miniviews;
        int current_wb_pick_display = -1;
 };