}
// 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) {
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;
}
}
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;
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;
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)
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));
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);
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)
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);
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;
};